diff --git a/api/db/services/llm_service.py b/api/db/services/llm_service.py index 2a41918be9..148cba7373 100644 --- a/api/db/services/llm_service.py +++ b/api/db/services/llm_service.py @@ -86,6 +86,18 @@ class LLMBundle(LLM4Tenant): """Release resources held by this LLMBundle instance.""" super().close() + def clone(self): + kwargs = { + "trace_context": dict(self.trace_context or {}), + "langfuse_session_id": self.langfuse_session_id, + "verbose_tool_use": self.verbose_tool_use, + } + for attr, key in (("max_retries", "max_retries"), ("base_delay", "retry_interval"), ("max_rounds", "max_rounds")): + value = getattr(self.mdl, attr, None) + if value is not None: + kwargs[key] = value + return LLMBundle(self.tenant_id, dict(self.model_config), lang=getattr(self, "lang", "Chinese"), **kwargs) + def __enter__(self): """Enter context manager.""" return self diff --git a/api/db/services/tenant_llm_service.py b/api/db/services/tenant_llm_service.py index 511ee1a950..efe47f1a6d 100644 --- a/api/db/services/tenant_llm_service.py +++ b/api/db/services/tenant_llm_service.py @@ -508,6 +508,7 @@ class LLM4Tenant: self.trace_context = kwargs.pop("trace_context", None) or {} self.langfuse_session_id = kwargs.pop("langfuse_session_id", None) self.tenant_id = tenant_id + self.lang = lang self.llm_name = model_config["llm_name"] self.model_config = model_config self.mdl = TenantLLMService.model_instance(model_config, lang=lang, **kwargs) diff --git a/rag/advanced_rag/agentic_rag.py b/rag/advanced_rag/agentic_rag.py index ac617d1c7e..32d0db729b 100644 --- a/rag/advanced_rag/agentic_rag.py +++ b/rag/advanced_rag/agentic_rag.py @@ -82,7 +82,7 @@ class RAGTools: thinking_mode: str = "medium", ): self.tenant_ids = tenant_ids - self.chat_mdl = chat_mdl + self.chat_mdl = chat_mdl.clone() self.embed_mdl = embed_mdl self.thinking_mode = thinking_mode self.field_map = {} diff --git a/rag/advanced_rag/harness/agent.py b/rag/advanced_rag/harness/agent.py index 1fe2223b5a..c12a6ab286 100644 --- a/rag/advanced_rag/harness/agent.py +++ b/rag/advanced_rag/harness/agent.py @@ -1,6 +1,6 @@ """Research Agent — inner tool-calling loop for high/ultra modes. -Native tool-calling: a chat model deep-copied from ``tools.chat_mdl`` is bound +Native tool-calling: a chat model cloned from ``tools.chat_mdl`` is bound (via ``bind_tools``) to the phase-gated tool schemas plus ``think_tool`` / ``generate_report``, and a lightweight session routes each tool call to the harness pipeline. Binding onto a *copy* keeps the shared ``tools.chat_mdl`` @@ -14,7 +14,6 @@ that the loop parses. import json import logging import re -from copy import deepcopy from rag.advanced_rag.harness.types import ClaimTarget, ExecutionStrategy, ToolResult from rag.advanced_rag.harness.pipeline import Pipeline @@ -158,8 +157,8 @@ async def research_agent_loop( has_routed_scope=bool(getattr(pipeline, "_routed_docs", None)), ) - # Deep-copy so binding tools never leaks onto the shared chat model. - agent_mdl = deepcopy(tools.chat_mdl) + # Clone so binding tools never leaks onto the shared chat model. + agent_mdl = tools.chat_mdl.clone() if getattr(agent_mdl, "is_tools", False): return await _research_native(claim, agent_mdl, pipeline, phase, phase_config, gated_defs, mode)