Files
WeChatHookBot/docs/AIChat函数调用框架与开发指南.md

6.0 KiB
Raw Blame History

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 工具声明模板

{
  "type": "function",
  "function": {
    "name": "search_xxx",
    "description": "仅当用户明确要求检索XXX时调用普通闲聊不要调用。",
    "parameters": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "检索关键词,尽量简洁明确。"
        }
      },
      "required": ["query"],
      "additionalProperties": False
    }
  }
}

6.2 工具执行返回模板

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 场景脚本)。