核心流程概述
connection.py中的chat方法是处理用户输入、调用LLM进行意图识别并执行工具调用的核心入口。该方法实现了完整的多轮工具调用机制,支持递归调用和并行工具执行。
详细流程分析
1. 方法入口与初始化
def chat(self, query, depth=0):
# 记录用户消息
# 初始化会话ID和发送FIRST请求
# 设置最大递归深度(默认5层)
# ...
2. 函数列表准备
当intent_type为function_call且未达到最大深度时,获取可用函数列表:
if self.intent_type == "function_call" and hasattr(self, "func_handler") and not force_final_answer:
functions = self.func_handler.get_functions()
3. LLM调用
根据是否使用function_call模式,调用不同的LLM方法:
if self.intent_type == "function_call" and functions is not None:
# 使用带工具调用支持的响应方法
llm_responses = self.llm.response_with_functions(
self.session_id,
self.dialogue.get_llm_dialogue_with_memory(memory_str, self.config.get("voiceprint", {})),
functions=functions,
)
else:
# 使用普通响应方法
llm_responses = self.llm.response(...)
4. 流式响应处理
遍历LLM返回的流式响应,检测工具调用:
for response in llm_responses:
# 检测是否包含工具调用
if self.intent_type == "function_call" and functions is not None:
content, tools_call = response
# 处理工具调用信息
if tools_call is not None and len(tools_call) > 0:
tool_call_flag = True
self._merge_tool_calls(tool_calls_list, tools_call)
# ...
5. 工具调用解析与执行
当检测到工具调用时,解析调用信息并执行:
if tool_call_flag:
# 解析工具调用格式
# 执行工具调用
futures_with_data = [ ]
for tool_call_data in tool_calls_list:
future = asyncio.run_coroutine_threadsafe(
self.func_handler.handle_llm_function_call(self, tool_call_data),
self.loop,
)
futures_with_data.append((future, tool_call_data))
# 等待所有工具调用完成
tool_results = [ ]
for future, tool_call_data in futures_with_data:
result = future.result()
tool_results.append((result, tool_call_data))
# 处理工具调用结果
self._handle_function_result(tool_results, depth=depth)
6. 工具结果处理
根据工具返回的Action类型进行不同处理:
def _handle_function_result(self, tool_results, depth):
for result, tool_call_data in tool_results:
if result.action in [Action.RESPONSE, Action.NOTFOUND, Action.ERROR]:
# 直接回复前端
text = result.response if result.response else result.result
self.tts.tts_one_sentence(self, ContentType.TEXT, content_detail=text)
self.dialogue.put(Message(role="assistant", content=text))
elif result.action == Action.REQLLM:
# 需要LLM进一步处理,添加到对话历史并递归调用
# ...
self.dialogue.put(Message(role="tool", content=text))
self.chat(None, depth=depth + 1)
7. 递归调用机制
当工具返回Action.REQLLM时,表示需要LLM基于工具结果进一步处理,此时会:
-
将工具结果添加到对话历史
-
递归调用
chat方法,深度加1 -
LLM基于新的对话历史生成最终回复
8. 会话结束
-
存储完整对话内容
-
发送LAST请求标记会话结束
-
记录对话日志
关键特性
-
最大递归深度限制:防止无限循环,默认设置为5层
-
并行工具调用:支持同时调用多个工具
-
多种工具调用格式:支持JSON格式和文本格式的工具调用
-
灵活的结果处理:根据不同的
Action类型进行不同的处理逻辑 -
记忆集成:结合记忆模块提供更智能的对话体验
流程图
┌─────────────────────────────────────────────────────────┐
│ 调用 chat 方法 │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 初始化与配置检查 │
│ - 记录用户消息 │
│ - 初始化会话ID │
│ - 设置最大递归深度 │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 获取可用函数列表 │
│ - 仅当intent_type为function_call且未达到最大深度时执行 │
│ - 调用func_handler.get_functions() │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 调用LLM生成响应 │
│ - 带工具调用支持的response_with_functions() │
│ - 或普通的response() │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 处理流式响应 │
│ - 遍历LLM返回的流式响应 │
│ - 检测工具调用标志 │
│ - 收集响应内容和工具调用信息 │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 检测工具调用标志 │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 是 │ │
│ └───────────┬───────────────────────────────────────┘ │
│ │ │
│ ┌───────────▼───────────────────────────────────────┐ │
│ │ 解析工具调用信息 │ │
│ │ - 支持JSON格式和文本格式 │ │
│ └───────────┬───────────────────────────────────────┘ │
│ │ │
│ ┌───────────▼───────────────────────────────────────┐ │
│ │ 执行工具调用 │ │
│ │ - 并行调用多个工具 │ │
│ │ - 等待所有工具调用完成 │ │
│ └───────────┬───────────────────────────────────────┘ │
│ │ │
│ ┌───────────▼───────────────────────────────────────┐ │
│ │ 处理工具调用结果 │ │
│ │ - 直接回复型结果(RESPONSE, NOTFOUND, ERROR) │ │
│ │ - 需要LLM进一步处理的结果(REQLLM) │ │
│ │ - 将结果添加到对话历史 │ │
│ │ - 递归调用chat方法,深度+1 │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 否 │ │
│ └───────────┬───────────────────────────────────────┘ │
│ │ │
│ ┌───────────▼───────────────────────────────────────┐ │
│ │ 直接处理LLM响应 │ │
│ │ - 存储对话内容 │ │
│ │ - 发送响应给用户 │ │
│ └───────────────────────────────────────────────────┘ │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ 结束会话 │
│ - 发送LAST请求 │
│ - 标记LLM任务完成 │
│ - 记录对话日志 │
└─────────────────────────────────────────────────────────┘
代码优化建议
-
增加工具调用超时机制:当前实现中,
future.result()调用会无限等待,建议添加超时参数,防止单个工具调用阻塞整个流程。 -
优化并行工具调用:考虑使用
asyncio.gather()替代手动管理多个Future,提高代码可读性和性能。 -
增强错误处理:在工具调用和结果处理过程中增加更详细的错误日志和恢复机制。
-
添加工具调用缓存:对于相同参数的工具调用,可以考虑添加缓存机制,减少重复调用,提高响应速度。
-
优化递归调用:考虑使用迭代方式替代递归,避免深度过大时的栈溢出问题。
总结
connection.py中的chat方法实现了完整的意图识别和工具调用流程,支持多轮递归调用、并行工具执行和灵活的结果处理。该设计能够很好地满足复杂对话场景下的工具调用需求,为用户提供更智能、更丰富的交互体验。