# AIChat 函数调用框架与开发指南 > 适用范围:`WechatHookBot/plugins/AIChat/main.py` 及所有通过 `ToolRegistry` 注册的插件工具。 > 更新时间:2026-02-09 ## 1. 目标与设计原则 当前 AIChat 的函数调用框架,核心目标是: 1. **少误触发**:只在用户明确有工具意图时暴露工具。 2. **少泄露中间态**:不向用户输出半截 `function_call/tool_calls` 或 JSON。 3. **可扩展**:插件只需实现 `get_llm_tools()` + `execute_llm_tool()`。 4. **可控输出**:工具执行后,默认由 AI 再生成一条自然语言总结(Eridanus 风格)。 --- ## 2. 总体架构 ### 2.1 核心模块 - AI 编排入口:`WechatHookBot/plugins/AIChat/main.py` - 工具注册中心:`WechatHookBot/utils/tool_registry.py` - 工具执行器:`WechatHookBot/utils/tool_executor.py` - 工具结果标准化:`WechatHookBot/utils/llm_tooling.py` ### 2.2 数据流(简化) 1. 接收消息(文本/图片) 2. AIChat 按规则筛选本轮可用工具 3. 预处理工具 schema(补全描述、约束参数) 4. 注入函数调用规则到 system prompt 5. 请求模型(流式或非流式) 6. 提取 `tool_calls`(兼容旧 `function_call`) 7. 通过 `ToolExecutor` 并发/串行执行工具 8. 工具结果回填上下文,二次请求 AI 输出最终自然语言 --- ## 3. 关键流程(按代码路径) ### 3.1 主入口 - 文本入口:`_call_ai_api(...)` - 图片入口:`_call_ai_api_with_image(...)` 两条链路逻辑保持一致:都支持工具选择、工具执行、二次总结回复。 ### 3.2 工具选择(Smart Select) 函数:`_select_tools_for_message(...)` 特点: - 当 `tools.smart_select=true` 时,按意图正则筛选工具。 - 无明显工具意图时,返回空工具列表(严格模式)。 - 对“自拍/生图”口语增加专门识别:`_looks_like_image_generation_request(...)`。 ### 3.3 工具声明标准化 函数: - `_normalize_tool_schema_for_llm(...)` - `_prepare_tools_for_llm(...)` 标准化动作: - 补函数描述(缺失时自动补) - 补参数类型与描述(缺失时自动补) - 统一 `parameters.additionalProperties = false` ### 3.4 规则注入(System Prompt) 函数:`_build_tool_rules_prompt(...)` 注入规则包括: - 仅基于【当前消息】决定是否调用工具 - 参数不全先追问 - 禁止输出工具调用 JSON 片段 - 工具后输出自然语言总结 开关:`tools.rule_prompt_enabled` ### 3.5 工具调用提取 函数:`_extract_tool_calls_data(...)` 支持: - 标准 `tool_calls` - 旧格式 `function_call` 兼容转换 并且在流式链路中组装增量 `tool_calls`,避免丢参数。 ### 3.6 工具执行与回传 函数: - `_execute_tools_async(...)` - `_execute_tools_async_with_image(...)` - `_continue_with_tool_results(...)` 行为: - 通过 `ToolExecutor.execute_batch(...)` 统一执行。 - 根据返回标志决定是否直接发送、是否二次 AI 总结。 - 默认启用二次 AI 总结(`tools.followup_ai_reply=true`)。 --- ## 4. 关键配置项(`plugins/AIChat/config.toml`) `[tools]` 相关: - `smart_select`: 是否启用意图筛选 - `loose_image_tool`: 文本形态绘图调用的宽松映射 - `async_execute`: 工具是否后台执行 - `followup_ai_reply`: 工具后是否二次 AI 总结 - `rule_prompt_enabled`: 是否注入函数调用规则提示 建议线上默认: - `smart_select = true` - `followup_ai_reply = true` - `rule_prompt_enabled = true` --- ## 5. 插件开发规范 ## 5.1 工具定义接口 插件实现: - `get_llm_tools() -> List[dict]` - `execute_llm_tool(tool_name, arguments, bot, from_wxid) -> dict` `get_llm_tools()` 建议: 1. `description` 里明确:**何时调用**、**何时不要调用**。 2. 参数写清语义、可选值、默认行为。 3. `required` 只保留真正必需参数。 4. 加 `additionalProperties: false`,减少幻觉参数。 ### 5.2 工具返回结构约定 基础字段: - `success: bool` - `message: str` 可选控制字段(由 `ToolResult/ToolCallResult` 消费): - `need_ai_reply`: 强制进入二次 AI 总结 - `already_sent`: 工具内部已发送过消息 - `send_result_text`: 是否直接发送 `message` - `no_reply`: 本轮不需要任何回复 - `save_to_memory`: 是否保存到上下文记忆 --- ## 6. 推荐模板 ### 6.1 工具声明模板 ```python { "type": "function", "function": { "name": "search_xxx", "description": "仅当用户明确要求检索XXX时调用;普通闲聊不要调用。", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "检索关键词,尽量简洁明确。" } }, "required": ["query"], "additionalProperties": False } } } ``` ### 6.2 工具执行返回模板 ```python return { "success": True, "message": "已完成检索", "need_ai_reply": True } ``` --- ## 7. 常见问题排查 ### 7.1 用户说“看看自拍”却不触发生图 先检查: 1. `tools.smart_select` 是否开启 2. 生图插件工具是否在白名单中 3. 日志里“本次启用工具”是否包含生图工具名 当前已加入自拍口语识别(`_looks_like_image_generation_request`),如仍异常优先看意图文本是否被预处理掉关键字。 ### 7.2 出现半截 JSON / function_call 泄露 检查: 1. `rule_prompt_enabled` 是否开启 2. 流式链路是否提前发送 preview(应禁用) 3. 是否落入旧模型 `function_call` 兼容分支但未成功转工具 ### 7.3 工具执行后无最终文本 检查: 1. `followup_ai_reply` 是否开启 2. 工具返回是否误设 `no_reply=true` 3. `_continue_with_tool_results` 是否收到有效 `tool_results` --- ## 8. 后续建议 1. 继续统一所有插件工具描述风格(触发边界 + 禁用条件)。 2. 在日志中增加“本轮 allow 工具集合”调试行,提升定位速度。 3. 为高频工具加回归用例(最少做 py_compile + simulate 场景脚本)。