Skip to content

运行时行为验证 #1: 工具调用循环协议

🆕 本章通过实际 daemon 运行时行为验证补全
日期: 2026-06-25 | Daemon: v4.25.5 | Model: deepseek-v4-flash


1. 背景

此前静态分析发现了 ChatEventToolStart/ToolOutput/ToolResult 事件变体,但从未在运行时验证过完整调用流程。本报告通过实际 HTTP 请求捕获完全的工具调用循环。


2. 工具调用完整 SSE 事件序列

通过 POST /chat 发送要求文件操作的消息,捕获到完整事件流:

消息: "在当前目录下创建一个test_runtime.md文件,内容是runtime test"

事件序列:
┌─────────────────────────────────────────────────────────────────────┐
│ 1. reasoning (多个碎片)  ← 模型思考阶段                              │
│       {"type":"reasoning","content":"The user wants me to create..."} │
│                                                                     │
│ 2. tokens (第一轮统计)                                              │
│       {"type":"tokens","prompt":6204,"completion":91,"total":6295}   │
│                                                                     │
│ 3. tool_start ← 工具调用开始                                       │
│       {"type":"tool_start",                                          │
│        "id":"call_00_zm24QnryxjpAbEVEoSsx9133",                     │
│        "name":"write_file",                                          │
│        "arguments":{"file_path":"test_runtime.md","content":"rt..."}} │
│                                                                     │
│ 4. tool_result ← 工具执行结果                                       │
│       {"type":"tool_result",                                         │
│        "id":"call_00_zm24QnryxjpAbEVEoSsx9133",                     │
│        "name":"write_file",                                          │
│        "output":"Created /path/test_runtime.md (12 bytes, 1 lines)", │
│        "success":true,"duration_ms":3}                               │
│                                                                     │
│ 5. reasoning (第二轮) ← 模型根据工具结果继续推理                     │
│       {"type":"reasoning","content":"Done. The file has been..."}    │
│                                                                     │
│ 6. text ← 最终文本回复                                              │
│       {"type":"text","content":"文件 `test_runtime.md` 已创建..."}  │
│                                                                     │
│ 7. tokens (第二轮统计)                                              │
│       {"type":"tokens","prompt":6394,"completion":27,"total":6421}   │
│                                                                     │
│ 8. done ← 会话结束                                                  │
│       {"type":"done","tokens":6421,"tool_calls":1,                   │
│        "session_id":"68ef5b9d-4287-40d2-ac36-3e9c4dc35961"}         │
└─────────────────────────────────────────────────────────────────────┘

2.1 关键发现

特性发现
tool_output 事件不存在Daemon 协议中没有 tool_output 流式输出事件。所有工具输出在完成后一次性通过 tool_result 返回
permission_request 不触发对于写文件这种危险操作,daemon 没有触发权限请求事件——工具直接自动执行
tool_start 参数格式arguments 是 JSON 字符串(非对象),由模型决定参数内容
tool_result 格式output 是纯文本,含完整文件路径和字节数。success: bool + duration_ms: u64
两轮 tokens 事件工具调用前有一次 token 统计(模型第一次回答),工具执行后追加统计
多工具调用复杂任务可能触发连续多个 tool_start → tool_result 对(见下文 glob 示例)

2.2 多工具调用示例

当任务需要多次工具调用时,事件序列为:

1. reasoning → tokens
2. tool_start #1 → tool_result #1    (glob *.md)
3. tool_start #2 → tool_result #2    (glob **/*.md)
4. reasoning (下一轮)
5. text → tokens → done

关键: 工具链中没有 tool_output,没有权限请求,没有人工确认。Daemon 自动串行执行所有工具。


3. 工具调用的 JSON 结构拆解

3.1 tool_start 事件

json
{
  "type": "tool_start",
  "id": "call_00_X1ja7qrtrIR9fvh1XbKn8073",
  "name": "glob",
  "arguments": "{\"pattern\": \"*.md\"}"
}
字段类型说明
type"tool_start"事件类型
idstring工具调用唯一 ID(格式: call_XX_<random>
namestring工具名(glob, write_file, read_file, bash 等)
argumentsstringJSON 编码的参数字符串

3.2 tool_result 事件

json
{
  "type": "tool_result",
  "id": "call_00_X1ja7qrtrIR9fvh1XbKn8073",
  "name": "glob",
  "output": "59 files found:\nAGENT_EXECUTION_ENGINE.md\n...",
  "success": true,
  "duration_ms": 40
}
字段类型说明
type"tool_result"事件类型
idstring与 tool_start 相同的 ID
namestring工具名
outputstring工具调用输出(文本)
successbool是否成功
duration_msu64执行耗时(毫秒)

3.3 done 事件

json
{
  "type": "done",
  "tokens": 6421,
  "tool_calls": 1,
  "session_id": "68ef5b9d-4287-40d2-ac36-3e9c4dc35961"
}
字段类型说明
type"done"会话结束
tokensu64总 token 消耗
tool_callsu64本次会话工具调用次数
session_idstringDaemon 分配的会话 UUID

4. 权限系统运行时行为

重要发现: 在 daemon 的 /chat 接口中,所有工具调用均自动执行,不触发权限请求。

操作权限请求行为
读取文件直接执行并返回结果
写入文件直接写入
执行命令直接执行
搜索文件直接搜索

这与之前通过 PermissionDecisionRequest 分析得出的权限系统不同——/chat 端点是无权限检查的完全自动模式。权限请求仅存在于 WebUI 的 /live SSE 通道和 POST /chat/permission 端点。


5. 对代理实现的意义

之前假设运行时验证结果影响
存在 tool_output 事件❌ 不存在Proxy 无需处理 tool_output → OpenAI chunk 的转换
需要处理 permission_request✅ 不触发Proxy 无需实现权限交互逻辑
tool_start 参数是对象✅ 是 JSON 字符串需要 json.loads() 解析再传递
tool_result 含 output✅ 确认可映射到 OpenAI 的 tool_call_id + content
多工具间有 barrier✅ 串行执行每个 tool_result 后模型重新推理

📅 最后更新: 2026-06-25🔍 验证方法: 实际 daemon 运行时 curl 抓包

逆向命令索引

bash
# 运行时捕获工具调用流
curl -N -X POST http://localhost:13456/chat \
  -H "Authorization: Bearer $(cat ~/.atomcode/auth.toml | grep access_token | cut -d'"' -f2)" \
  -H "Content-Type: application/json" \
  -d '{"message":"写一个 hello.c 文件"}' 2>&1 | while IFS= read -r line; do
    [[ "$line" == data:* ]] && echo "$line"
  done

基于 VitePress 构建 · AtomCode v4.25.3 逆向工程分析文档