6.0 KiB
6.0 KiB
AIChat 函数调用框架与开发指南
适用范围:
WechatHookBot/plugins/AIChat/main.py及所有通过ToolRegistry注册的插件工具。
更新时间:2026-02-09
1. 目标与设计原则
当前 AIChat 的函数调用框架,核心目标是:
- 少误触发:只在用户明确有工具意图时暴露工具。
- 少泄露中间态:不向用户输出半截
function_call/tool_calls或 JSON。 - 可扩展:插件只需实现
get_llm_tools()+execute_llm_tool()。 - 可控输出:工具执行后,默认由 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 数据流(简化)
- 接收消息(文本/图片)
- AIChat 按规则筛选本轮可用工具
- 预处理工具 schema(补全描述、约束参数)
- 注入函数调用规则到 system prompt
- 请求模型(流式或非流式)
- 提取
tool_calls(兼容旧function_call) - 通过
ToolExecutor并发/串行执行工具 - 工具结果回填上下文,二次请求 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 = truefollowup_ai_reply = truerule_prompt_enabled = true
5. 插件开发规范
5.1 工具定义接口
插件实现:
get_llm_tools() -> List[dict]execute_llm_tool(tool_name, arguments, bot, from_wxid) -> dict
get_llm_tools() 建议:
description里明确:何时调用、何时不要调用。- 参数写清语义、可选值、默认行为。
required只保留真正必需参数。- 加
additionalProperties: false,减少幻觉参数。
5.2 工具返回结构约定
基础字段:
success: boolmessage: str
可选控制字段(由 ToolResult/ToolCallResult 消费):
need_ai_reply: 强制进入二次 AI 总结already_sent: 工具内部已发送过消息send_result_text: 是否直接发送messageno_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 用户说“看看自拍”却不触发生图
先检查:
tools.smart_select是否开启- 生图插件工具是否在白名单中
- 日志里“本次启用工具”是否包含生图工具名
当前已加入自拍口语识别(_looks_like_image_generation_request),如仍异常优先看意图文本是否被预处理掉关键字。
7.2 出现半截 JSON / function_call 泄露
检查:
rule_prompt_enabled是否开启- 流式链路是否提前发送 preview(应禁用)
- 是否落入旧模型
function_call兼容分支但未成功转工具
7.3 工具执行后无最终文本
检查:
followup_ai_reply是否开启- 工具返回是否误设
no_reply=true _continue_with_tool_results是否收到有效tool_results
8. 后续建议
- 继续统一所有插件工具描述风格(触发边界 + 禁用条件)。
- 在日志中增加“本轮 allow 工具集合”调试行,提升定位速度。
- 为高频工具加回归用例(最少做 py_compile + simulate 场景脚本)。