Message 与 Tool 的时序关系
985 字
5 分钟
Message 与 Tool 的时序关系
Message 与 Tool 的时序关系
工具调用分为两个阶段:
阶段一:LLM 生成参数(message_* 事件) 阶段二:Agent 执行工具(tool_execution_* 事件)
message_end 的 stopReason=“toolUse” 是两者的边界。
为什么分两阶段?
用具体场景说明:用户问”北京天气”,AI 调用工具查询。
LLM 只负责”说”要调用什么工具——生成工具名称和参数。 Agent 才负责实际”执行”工具函数——调用代码,获取结果。
这个分离是职责边界:
- LLM 是生成者(生成调用意图)
- Agent 是执行者(执行调用动作)
完整时序图
用户输入: "北京今天天气怎么样"││├── turn_start ← 开始本轮对话│├── message_start ← LLM 开始生成│ │ message: AssistantMessage(初始空状态)│├── message_update (多次) ← 流式生成工具调用参数│ │ assistantMessageEvent: toolcall_start│ │ assistantMessageEvent: toolcall_delta '{"query"'│ │ assistantMessageEvent: toolcall_delta ': "北京天气"'│ │ assistantMessageEvent: toolcall_end│ │ → toolCall完整: { id: "tc1", name: "search", arguments: { query: "北京天气" } }│├── message_end ← 参数生成完成│ │ message.content[0]: ToolCall { name: "search", ... }│ │ stopReason: "toolUse" ← 关键:表示需要执行工具││ ─────────── 阶段边界 ───────────│ LLM 完成 → Agent 开始执行│ ─────────── 阶段边界 ───────────│├── tool_execution_start ← Agent 执行工具│ │ toolCallId: "tc1"│ │ toolName: "search"│ │ args: { query: "北京天气" }│├── tool_execution_end ← 工具执行完成│ │ result: "北京晴天,25°C"│ │ isError: false│├── turn_end ← 本轮结束│ │ toolResults: [工具结果消息]││ ─────── Agent 用结果继续生成 ───────│├── turn_start(新一轮)├── message_start├── message_update (text_delta)├── message_end ← stopReason = "stop"├── turn_end│└── agent_end ← 所有消息汇总时序关键点:
- message_end 之后才有 tool_execution(阶段边界)
- tool_execution_end 之后可能触发新一轮 turn(用结果继续生成)
- agent_end 是最终汇总点
两阶段监听协作
一个完整的工具调用监听,展示两阶段如何衔接:
agent.subscribe((event) => { // ===== 阶段一:LLM生成参数 ===== if (event.type === "message_update") { const e = event.assistantMessageEvent;
if (e.type === "toolcall_start") { console.log("[LLM] 开始生成:", e.contentIndex); }
if (e.type === "toolcall_delta") { // 参数JSON片段,如 '{"query": "天气"' console.log("[LLM] 参数增量:", e.delta); }
if (e.type === "toolcall_end") { // 参数完整,即将进入阶段二 console.log("[LLM] 参数完整:", e.toolCall.arguments); console.log("─── 阶段边界 ───"); } }
if (event.type === "message_end") { // stopReason = "toolUse" 表示即将执行工具 if (event.message.stopReason === "toolUse") { console.log("[边界] LLM完成,Agent开始执行"); } }
// ===== 阶段二:Agent执行工具 ===== if (event.type === "tool_execution_start") { console.log("[Agent] 执行:", event.toolName); }
if (event.type === "tool_execution_end") { console.log("[Agent] 结果:", event.result); }});阶段边界判断:
message_end.stopReason === "toolUse"→ 即将执行工具tool_execution_start→ 开始执行tool_execution_end→ 执行完成
一个 message 可能包含多个工具调用
LLM 可以在一次响应中生成多个工具调用,Agent 会并行执行:
message_update: toolcall_end (contentIndex=0) → 工具 A: search toolcall_end (contentIndex=1) → 工具 B: translate toolcall_end (contentIndex=2) → 工具 C: summarize
message_end: message.content = [ToolCall_A, ToolCall_B, ToolCall_C] stopReason = "toolUse"
────────────────── 然后并行执行 ──────────────────
tool_execution_start → 工具 A 开始tool_execution_start → 工具 B 开始tool_execution_start → 工具 C 开始
tool_execution_end → 工具 A 完成tool_execution_end → 工具 B 完成tool_execution_end → 工具 C 完成
turn_end: toolResults = [结果_A, 结果_B, 结果_C]监听时,通过 contentIndex 区分不同的工具调用:
agent.subscribe((event) => { if (event.type === "message_update") { const e = event.assistantMessageEvent;
if (e.type === "toolcall_end") { console.log(`[工具${e.contentIndex}] ${e.toolCall.name}`); } }
if (event.type === "tool_execution_start") { console.log(`[执行] ${event.toolName} (${event.toolCallId})`); }});选择指南:监听哪层?
| 需求 | 监听哪层 | 具体事件 |
|---|---|---|
| 显示”正在生成工具调用…” | 底层 | message_update + toolcall_start |
| 显示参数生成过程(预览) | 底层 | message_update + toolcall_delta |
| 显示”正在执行工具…” | 高层 | tool_execution_start |
| 获取工具执行结果 | 高层 | tool_execution_end |
| 判断本轮是否有工具调用 | 高层 | turn_end.toolResults.length |
| 处理工具执行错误 | 高层 | tool_execution_end.isError |
原则:
- 需要实时预览参数生成过程 → 监听底层(toolcall_*)
- 其他情况 → 优先用高层(tool_execution_*)
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
Message 与 Tool 的时序关系
https://firefly.cuteleaf.cn/posts/learn-pi/event&message/05-时序关系理解/ 相关文章 智能推荐
1
AbortController 与 terminate 设计原理
pi 深入理解两种中断机制的设计原理:AbortController的预先注册模式与terminate的返回值携带模式
2
message_update 事件深入
pi 理解 message_update 如何连接高层 AgentEvent 和底层 AssistantMessageEvent,掌握两个关联字段的使用
3
AgentEvent 核心使用场景
pi 掌握流式输出、状态获取、工具处理、错误处理这四大核心场景,覆盖90%的开发需求
4
AgentEvent 类型系统详解
pi 深入理解 AgentEvent 的7种业务事件和 AssistantMessageEvent 的13种技术事件
5
AgentEvent 系统分层设计理念
pi 理解 pi-agent-core 和 pi-ai 的分层设计,掌握 AgentEvent 与 AssistantMessageEvent 的职责边界
随机文章 随机推荐