feat: restore source parity and harden agent runtime
This commit is contained in:
@@ -570,7 +570,7 @@ class ConfirmNode(BaseNode):
|
||||
|
||||
return False, False
|
||||
|
||||
def _llm_intent_recognition(self, user_input: str, context_content: str, model_id: str) -> bool:
|
||||
def _llm_intent_recognition(self, user_input: str, context_content: str, model_id: str, db_session=None) -> bool:
|
||||
"""
|
||||
使用 LLM 进行意图识别
|
||||
|
||||
@@ -595,7 +595,7 @@ class ConfirmNode(BaseNode):
|
||||
|
||||
请判断用户意图:"""
|
||||
|
||||
llm_service = LLMService()
|
||||
llm_service = LLMService(db_session)
|
||||
response = llm_service.chat(
|
||||
model_id=model_id,
|
||||
messages=[
|
||||
@@ -639,7 +639,9 @@ class ConfirmNode(BaseNode):
|
||||
if not matched and use_llm_intent and llm_model_id:
|
||||
# 关键词未匹配,使用 LLM 意图识别
|
||||
logger.info(f'关键词未匹配,使用 LLM 意图识别: {user_input}')
|
||||
confirmed = self._llm_intent_recognition(str(user_input), content, llm_model_id)
|
||||
confirmed = self._llm_intent_recognition(
|
||||
str(user_input), content, llm_model_id, context.db_session
|
||||
)
|
||||
elif not matched:
|
||||
# 关键词未匹配且未启用 LLM,默认为取消
|
||||
logger.info(f'关键词未匹配,默认取消: {user_input}')
|
||||
|
||||
@@ -313,6 +313,7 @@ class LLMNode(BaseNode):
|
||||
messages.append({'role': 'user', 'content': user_prompt})
|
||||
|
||||
llm_service = LLMService(context.db_session)
|
||||
model_id = llm_service.resolve_chat_model_id_sync(model_id)
|
||||
output_var = self.config.get('output_variable', 'llm_response')
|
||||
|
||||
# 根据输出模式选择执行方式
|
||||
|
||||
@@ -64,6 +64,26 @@ class LLMService:
|
||||
|
||||
logger.info("No model_id supplied, fallback to default chat model %s", model.id)
|
||||
return str(model.id)
|
||||
|
||||
@staticmethod
|
||||
def _run_async_sync(coro):
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
return asyncio.run(coro)
|
||||
|
||||
if loop.is_running():
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
return executor.submit(asyncio.run, coro).result()
|
||||
|
||||
return loop.run_until_complete(coro)
|
||||
|
||||
def resolve_chat_model_id_sync(self, model_id: Optional[str]) -> str:
|
||||
"""同步解析 chat 模型,供同步节点和流式生成器复用。"""
|
||||
return self._run_async_sync(self.resolve_chat_model_id(model_id))
|
||||
|
||||
async def _get_provider_async(self, model_id: str) -> tuple:
|
||||
"""
|
||||
@@ -272,6 +292,34 @@ class LLMService:
|
||||
return provider.chat(llm_messages, config)
|
||||
except Exception as exc:
|
||||
raise RuntimeError(self._format_provider_error(exc, provider, model_name)) from exc
|
||||
|
||||
def chat(
|
||||
self,
|
||||
model_id: Optional[str],
|
||||
messages: List[Dict[str, str]],
|
||||
temperature: float = 0.7,
|
||||
max_tokens: int = 2048,
|
||||
tools: List[Dict] = None,
|
||||
tool_choice: str = 'auto',
|
||||
**kwargs
|
||||
) -> LLMResponse:
|
||||
"""
|
||||
同步对话入口。
|
||||
|
||||
旧节点仍会调用该方法;这里统一走 provider 解析和默认 chat 模型兜底,
|
||||
避免不同节点各自处理 model_id 为空的情况。
|
||||
"""
|
||||
provider, model_name = self._run_async_sync(self._get_provider_async(model_id))
|
||||
return self.chat_with_provider(
|
||||
provider=provider,
|
||||
model_name=model_name,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
tools=tools,
|
||||
tool_choice=tool_choice,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def _convert_messages(self, messages: List[Dict]) -> List[LLMMessage]:
|
||||
"""转换消息格式,支持 tool 消息"""
|
||||
|
||||
Reference in New Issue
Block a user