mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-05 07:10:29 +08:00
Fix: support tool call config (#14616)
### What problem does this PR solve? support tool call config ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@@ -29,6 +29,23 @@ from rag.utils.base64_image import test_image
|
||||
from rag.llm import EmbeddingModel, ChatModel, RerankModel, CvModel, TTSModel, OcrModel, Seq2txtModel
|
||||
|
||||
|
||||
def _resolve_my_llm_is_tools(o_dict: dict) -> bool:
|
||||
decode_api_key_config = getattr(TenantLLMService, "_decode_api_key_config", None)
|
||||
if callable(decode_api_key_config):
|
||||
_, is_tools, _ = decode_api_key_config(o_dict.get("api_key", ""))
|
||||
if is_tools is not None:
|
||||
return bool(is_tools)
|
||||
|
||||
try:
|
||||
base_name, fid = TenantLLMService.split_model_name_and_factory(o_dict["llm_name"])
|
||||
llm_cfg = LLMService.query(llm_name=base_name, fid=fid) if fid else LLMService.query(llm_name=base_name)
|
||||
if not llm_cfg and fid:
|
||||
llm_cfg = LLMService.query(llm_name=base_name)
|
||||
return bool(llm_cfg[0].is_tools) if llm_cfg else False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
@manager.route("/factories", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def factories():
|
||||
@@ -229,6 +246,19 @@ async def add_llm():
|
||||
elif factory == "OpenDataLoader":
|
||||
api_key = apikey_json(["api_key", "provider_order"])
|
||||
|
||||
existing_llm = None
|
||||
existing_api_key = None
|
||||
if req.get("api_key") is None:
|
||||
existing_llms = TenantLLMService.query(tenant_id=current_user.id, llm_factory=factory, llm_name=llm_name)
|
||||
if existing_llms:
|
||||
existing_llm = existing_llms[0]
|
||||
existing_api_key, _, existing_api_key_payload = TenantLLMService._decode_api_key_config(existing_llm.api_key)
|
||||
if existing_api_key_payload is not None:
|
||||
existing_api_key = existing_api_key_payload
|
||||
|
||||
if req.get("api_key") is None:
|
||||
api_key = existing_api_key if existing_api_key is not None else "x"
|
||||
|
||||
llm = {
|
||||
"tenant_id": current_user.id,
|
||||
"llm_factory": factory,
|
||||
@@ -353,6 +383,9 @@ async def add_llm():
|
||||
if msg:
|
||||
return get_data_error_result(message=msg)
|
||||
|
||||
if "is_tools" in req:
|
||||
llm["api_key"] = TenantLLMService._encode_api_key_config(llm["api_key"], bool(req["is_tools"]))
|
||||
|
||||
if not TenantLLMService.filter_update([TenantLLM.tenant_id == current_user.id, TenantLLM.llm_factory == factory, TenantLLM.llm_name == llm["llm_name"]], llm):
|
||||
TenantLLMService.save(**llm)
|
||||
|
||||
@@ -421,6 +454,7 @@ def my_llms():
|
||||
"api_base": o_dict["api_base"] or "",
|
||||
"max_tokens": o_dict["max_tokens"] or 8192,
|
||||
"status": o_dict["status"] or "1",
|
||||
"is_tools": _resolve_my_llm_is_tools(o_dict),
|
||||
}
|
||||
)
|
||||
else:
|
||||
|
||||
@@ -26,8 +26,14 @@ def get_model_config_by_id(tenant_model_id: int) -> dict:
|
||||
if not found:
|
||||
raise LookupError(f"Tenant Model with id {tenant_model_id} not found")
|
||||
config_dict = model_config.to_dict()
|
||||
api_key, is_tools, api_key_payload = TenantLLMService._decode_api_key_config(config_dict.get("api_key", ""))
|
||||
config_dict["api_key"] = api_key
|
||||
if api_key_payload is not None:
|
||||
config_dict["api_key_payload"] = api_key_payload
|
||||
if is_tools is not None:
|
||||
config_dict["is_tools"] = is_tools
|
||||
llm = LLMService.query(llm_name=config_dict["llm_name"])
|
||||
if llm:
|
||||
if "is_tools" not in config_dict and llm:
|
||||
config_dict["is_tools"] = llm[0].is_tools
|
||||
return config_dict
|
||||
|
||||
@@ -73,6 +79,12 @@ def get_model_config_by_type_and_name(tenant_id: str, model_type: str, model_nam
|
||||
else:
|
||||
# model_name without @factory
|
||||
config_dict = model_config.to_dict()
|
||||
api_key, is_tools, api_key_payload = TenantLLMService._decode_api_key_config(config_dict.get("api_key", ""))
|
||||
config_dict["api_key"] = api_key
|
||||
if api_key_payload is not None:
|
||||
config_dict["api_key_payload"] = api_key_payload
|
||||
if is_tools is not None:
|
||||
config_dict["is_tools"] = is_tools
|
||||
config_model_type = config_dict.get("model_type")
|
||||
config_model_type = config_model_type.value if hasattr(config_model_type, "value") else config_model_type
|
||||
if config_model_type != model_type_val and not (
|
||||
@@ -83,7 +95,7 @@ def get_model_config_by_type_and_name(tenant_id: str, model_type: str, model_nam
|
||||
f"Tenant Model with name {model_name} has type {config_model_type}, expected {model_type_val}"
|
||||
)
|
||||
llm = LLMService.query(llm_name=config_dict["llm_name"])
|
||||
if llm:
|
||||
if "is_tools" not in config_dict and llm:
|
||||
config_dict["is_tools"] = llm[0].is_tools
|
||||
return config_dict
|
||||
|
||||
|
||||
@@ -34,6 +34,42 @@ class LLMFactoriesService(CommonService):
|
||||
class TenantLLMService(CommonService):
|
||||
model = TenantLLM
|
||||
|
||||
@staticmethod
|
||||
def _decode_api_key_config(raw_api_key: str) -> tuple[str, bool | None, str | None]:
|
||||
if not raw_api_key:
|
||||
return raw_api_key, None, None
|
||||
|
||||
try:
|
||||
parsed = json.loads(raw_api_key)
|
||||
except Exception:
|
||||
return raw_api_key, None, None
|
||||
|
||||
if not isinstance(parsed, dict):
|
||||
return raw_api_key, None, None
|
||||
|
||||
is_tools = bool(parsed["is_tools"]) if "is_tools" in parsed else None
|
||||
if set(parsed.keys()) <= {"api_key", "is_tools"}:
|
||||
return parsed.get("api_key", ""), is_tools, None
|
||||
|
||||
return parsed.get("api_key", raw_api_key), is_tools, raw_api_key
|
||||
|
||||
@staticmethod
|
||||
def _encode_api_key_config(raw_api_key: str, is_tools: bool | None) -> str:
|
||||
if is_tools is None:
|
||||
return raw_api_key
|
||||
|
||||
try:
|
||||
parsed = json.loads(raw_api_key or "{}")
|
||||
except Exception:
|
||||
parsed = None
|
||||
|
||||
if isinstance(parsed, dict):
|
||||
payload = dict(parsed)
|
||||
payload["is_tools"] = bool(is_tools)
|
||||
return json.dumps(payload)
|
||||
|
||||
return json.dumps({"api_key": raw_api_key or "", "is_tools": bool(is_tools)})
|
||||
|
||||
@classmethod
|
||||
@DB.connection_context()
|
||||
def get_api_key(cls, tenant_id, model_name, model_type=None):
|
||||
@@ -123,6 +159,12 @@ class TenantLLMService(CommonService):
|
||||
model_config = cls.get_api_key(tenant_id, mdlnm, llm_type)
|
||||
if model_config:
|
||||
model_config = model_config.to_dict()
|
||||
api_key, is_tools, api_key_payload = cls._decode_api_key_config(model_config.get("api_key", ""))
|
||||
model_config["api_key"] = api_key
|
||||
if api_key_payload is not None:
|
||||
model_config["api_key_payload"] = api_key_payload
|
||||
if is_tools is not None:
|
||||
model_config["is_tools"] = is_tools
|
||||
elif llm_type == LLMType.EMBEDDING and fid == "Builtin" and "tei-" in os.getenv("COMPOSE_PROFILES", "") and mdlnm == os.getenv("TEI_MODEL", ""):
|
||||
embedding_cfg = settings.EMBEDDING_CFG
|
||||
model_config = {"llm_factory": "Builtin", "api_key": embedding_cfg["api_key"], "llm_name": mdlnm, "api_base": embedding_cfg["base_url"]}
|
||||
@@ -132,7 +174,7 @@ class TenantLLMService(CommonService):
|
||||
llm = LLMService.query(llm_name=mdlnm) if not fid else LLMService.query(llm_name=mdlnm, fid=fid)
|
||||
if not llm and fid: # for some cases seems fid mismatch
|
||||
llm = LLMService.query(llm_name=mdlnm)
|
||||
if llm:
|
||||
if "is_tools" not in model_config and llm:
|
||||
model_config["is_tools"] = llm[0].is_tools
|
||||
return model_config
|
||||
|
||||
@@ -142,35 +184,36 @@ class TenantLLMService(CommonService):
|
||||
if not model_config:
|
||||
raise LookupError("Model config is required")
|
||||
kwargs.update({"provider": model_config["llm_factory"]})
|
||||
api_key = model_config.get("api_key_payload", model_config["api_key"])
|
||||
if model_config["model_type"] == LLMType.EMBEDDING.value:
|
||||
if model_config["llm_factory"] not in EmbeddingModel:
|
||||
return None
|
||||
return EmbeddingModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"], base_url=model_config["api_base"])
|
||||
return EmbeddingModel[model_config["llm_factory"]](api_key, model_config["llm_name"], base_url=model_config["api_base"])
|
||||
|
||||
elif model_config["model_type"] == LLMType.RERANK:
|
||||
if model_config["llm_factory"] not in RerankModel:
|
||||
return None
|
||||
return RerankModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"], base_url=model_config["api_base"])
|
||||
return RerankModel[model_config["llm_factory"]](api_key, model_config["llm_name"], base_url=model_config["api_base"])
|
||||
|
||||
elif model_config["model_type"] == LLMType.IMAGE2TEXT.value:
|
||||
if model_config["llm_factory"] not in CvModel:
|
||||
return None
|
||||
return CvModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"], lang, base_url=model_config["api_base"], **kwargs)
|
||||
return CvModel[model_config["llm_factory"]](api_key, model_config["llm_name"], lang, base_url=model_config["api_base"], **kwargs)
|
||||
|
||||
elif model_config["model_type"] == LLMType.CHAT.value:
|
||||
if model_config["llm_factory"] not in ChatModel:
|
||||
return None
|
||||
return ChatModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"], base_url=model_config["api_base"], **kwargs)
|
||||
return ChatModel[model_config["llm_factory"]](api_key, model_config["llm_name"], base_url=model_config["api_base"], **kwargs)
|
||||
|
||||
elif model_config["model_type"] == LLMType.SPEECH2TEXT:
|
||||
if model_config["llm_factory"] not in Seq2txtModel:
|
||||
return None
|
||||
return Seq2txtModel[model_config["llm_factory"]](key=model_config["api_key"], model_name=model_config["llm_name"], lang=lang, base_url=model_config["api_base"])
|
||||
return Seq2txtModel[model_config["llm_factory"]](key=api_key, model_name=model_config["llm_name"], lang=lang, base_url=model_config["api_base"])
|
||||
elif model_config["model_type"] == LLMType.TTS:
|
||||
if model_config["llm_factory"] not in TTSModel:
|
||||
return None
|
||||
return TTSModel[model_config["llm_factory"]](
|
||||
model_config["api_key"],
|
||||
api_key,
|
||||
model_config["llm_name"],
|
||||
base_url=model_config["api_base"],
|
||||
)
|
||||
@@ -179,7 +222,7 @@ class TenantLLMService(CommonService):
|
||||
if model_config["llm_factory"] not in OcrModel:
|
||||
return None
|
||||
return OcrModel[model_config["llm_factory"]](
|
||||
key=model_config["api_key"],
|
||||
key=api_key,
|
||||
model_name=model_config["llm_name"],
|
||||
base_url=model_config.get("api_base", ""),
|
||||
**kwargs,
|
||||
|
||||
Reference in New Issue
Block a user