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

235 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 场景脚本)。