Pi 的 JSON Event Stream 模式:用pi --mode json消费结构化 Agent 事件流
【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills
导读
本文围绕 Pi(一个极简终端编码代理工具,安装包为@earendil-works/pi-coding-agent)的JSON Event Stream 模式展开,讲解如何通过pi --mode json "prompt"让 Pi 以"一次性提示"方式运行,并将整个会话过程中产生的全部 Agent 事件以 JSON Lines(JSONL)形式输出到 stdout。读完本文,你将掌握 JSON 模式的适用场景、完整的事件类型体系(会话级事件与基础 Agent 事件)、线性的增量式输出格式(message_update的 delta-only 设计),以及如何用jq等标准命令行工具过滤、消费这些事件流。对于需要双向控制的场景,本文也会给出与 RPC 模式、SDK 的取舍建议。
一、JSON 模式是什么:一次性脚本管道的首选
Pi 提供四种运行模式,JSON 模式是其中专门为"一次性、单向、脚本化"场景设计的形态:
- 交互模式(TUI):
pi,面向日常对话; - 打印模式:
pi -p "prompt",打印结果后退出; - JSON Event Stream 模式:
pi --mode json "prompt",所有会话事件以 JSONL 逐行输出到 stdout; - RPC 模式:
pi --mode rpc,通过 stdin/stdout 的 JSONL 协议实现双向控制。
JSON 模式的定位在 SKILL.md 中有明确表述:"Prefer JSON mode for one-shot command-line pipelines that only need streamed events, not bidirectional control",即只适合一次性提示、只需要读取流式事件、不需要反向控制的命令行管道。它不具备 RPC 模式的双向通信能力——RPC 模式可以接收prompt、steer、abort、bash等命令,而 JSON 模式只能"发一个提示,收一串事件"。
基本用法
pi --mode json "Your prompt"一行命令即可把 Agent 会话的所有事件推送到 stdout。配合2>/dev/null丢弃日志、jq过滤事件类型,就能快速构建无侵入的 Agent 观测管道:
pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'这条命令是 json.md 中给出的典型示例:仅提取每条消息的最终结果(message_end),屏蔽掉中间的text_delta增量噪音。
二、输出格式:首行会话头 + 逐行事件流
JSON 模式的输出遵循严格的"首行头 + 事件流"结构。
会话头(session header)
输出流的第一行是会话元数据:
{"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}该行对应会话文件的 header 条目(见 session-format.md):version为会话格式版本(当前为 3),id是会话 UUID,timestamp为创建时间,cwd为工作目录。注意 header 与后续事件不同——它没有id/parentId字段,仅承载元数据。
事件流示例
随后事件按发生顺序逐行输出,每行一个独立 JSON 对象:
{"type":"agent_start"} {"type":"turn_start"} {"type":"message_start","message":{"role":"assistant","content":[]}} {"type":"message_update","usage":{},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}} {"type":"message_end","message":{}} {"type":"turn_end","message":{},"toolResults":[]} {"type":"agent_end","messages":[]}一个典型的会话生命周期大致为:agent_start→turn_start→message_start→(若干message_update)→message_end→turn_end→agent_end。若 Agent 调用了工具,中间还会插入tool_execution_start/tool_execution_update/tool_execution_end事件。
三、事件类型全景:会话级事件 + 基础 Agent 事件
JSON 模式下的事件使用JsonAgentSessionEvent类型,它与 Pi 内部的AgentSessionEvent基本一致,唯一区别是流式消息更新(message_update)省略了累积快照:
type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T; type JsonAgentSessionEvent = | Exclude<AgentSessionEvent, { type: "message_update" }> | { type: "message_update"; usage: Usage; assistantMessageEvent: WithoutPartial<AssistantMessageEvent> };AgentSessionEvent是基础AgentEvent与会话级事件的并集。
会话级事件
| 事件类型 | 载荷 |
|---|---|
queue_update | { steering: readonly string[], followUp: readonly string[] },只要任一队列发生变化即触发 |
compaction_start | { reason: "manual" \| "threshold" \| "overflow" } |
compaction_end | { reason, result: CompactionResult \| undefined, aborted, willRetry, errorMessage? } |
auto_retry_start | { attempt, maxAttempts, delayMs, errorMessage } |
auto_retry_end | { success, attempt, finalError? } |
summarization_retry_scheduled | { attempt, maxAttempts, delayMs, errorMessage } |
summarization_retry_attempt_start | { source: "branchSummary" }或{ source: "compaction", reason } |
summarization_retry_finished | 无额外载荷 |
其中compaction_start的reason三值与 compaction.md 中的触发机制一一对应:manual(/compact手动触发)、threshold(上下文超阈值自动压缩)、overflow(溢出恢复)。compaction_end中willRetry为 true 表示溢出压缩成功后会自动重试原提示词。
基础 Agent 事件
agent_start、agent_end(后者携带messages);turn_start、turn_end(后者携带message与toolResults);message_start(携带message)、message_update(携带usage与assistantMessageEvent)、message_end(携带message);tool_execution_start(携带toolCallId、toolName、args)、tool_execution_update(在前者基础上增加partialResult)、tool_execution_end(携带result、isError)。
需要说明:RPC 模式下的完整事件清单还包含agent_settled、bash_execution_update、extension_error等(见 rpc.md),且 RPC 的message_update同样采用 delta-only 设计——这一设计在 JSON 模式下被严格化:JSON 模式的JsonAgentSessionEvent直接通过类型层面剔除了partial字段。
四、核心设计:为什么message_update是 delta-only
JSON 模式最值得理解的设计决策是message_update记录的增量(delta)性质:
- 省略累积
message字段:常规事件流中message_update会携带当前累积的完整消息对象,JSON 模式将其省略; - 省略
assistantMessageEvent.partial:增量事件本身不再包含累积的 partial 快照。
这样做的直接收益是流大小保持线性——无论生成多长的回复,每个增量记录只携带新增的一小段文本,而不是反复传输越来越大的累积快照。
组装实时文本的规则
由于累积快照被省略,消费方需要自己"拼装"实时内容:
- 通过
assistantMessageEvent中的contentIndex定位内容块(文本、思考内容或工具调用参数各有独立的内容块索引); - 通过
delta字段累积增量文本; - 对于工具调用,需要缓存
toolcall_delta.delta,因为只有toolcall_end.toolCall才持有完整调用(RPC 文档对此有同样的说明,见 rpc.md); - 最终以
message_end中携带的message作为权威的最终消息。
usage 字段的语义
message_update顶层的usage字段携带最新一次累积的、由供应商上报的用量。它有一个值得注意的边界:当供应商只在生成完成时才上报用量时,中间过程的usage可能一直是 0。因此不要依赖流式过程中的 usage 数值做实时统计,应等待message_end或会话结束后的权威数据。
Usage对象的结构在 session-format.md 中有精确定义:包含input、output、cacheRead、cacheWrite、totalTokens,以及同样含四字段加total的cost。
五、与 RPC 模式的分工:何时不用 JSON 模式
json.md 文档结尾给出了明确的边界:"For bidirectional control, use RPC instead of JSON mode."
二者的定位对比如下:
| 维度 | JSON 模式 | RPC 模式 |
|---|---|---|
| 命令 | pi --mode json "prompt" | pi --mode rpc |
| 方向 | 单向(一次提示 → 事件流) | 双向(stdin 发命令,stdout 收事件) |
| 典型场景 | 一次性脚本管道、日志观测 | IDE 集成、自定义 UI、跨语言客户端 |
| 增量事件 | delta-only(无partial) | 同样 delta-only |
| 会话持久化 | 默认与普通会话一致 | 可用--no-session实现无状态子进程 |
在 SKILL.md 的"Build-On-Pi Defaults"中给出了更细的三级选择建议:
- Node/TypeScript 进程内应用(需要类型安全、直接状态访问、自定义工具/扩展)→ 首选SDK(
createAgentSession()/createAgentSessionRuntime()); - 非 Node.js 客户端或需要进程隔离→ 首选RPC(
pi --mode rpc --no-session起步,按需加会话标志); - 一次性命令行管道、只需要流式事件→ 首选JSON 模式。
此外,JSON 模式与打印模式(pi -p)都适用于"跑一次拿结果"的场景,但 JSON 模式额外提供完整的事件级可观测性——你可以看到思考增量、工具调用过程、token 用量与压缩事件,而打印模式只给你最终文本。
六、实战:用 jq 消费 JSON 事件流
结合上述事件结构,可以构建若干高价值的消费管道。
只取助手最终消息
pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'message_end的message字段是权威的最终消息(含文本、思考与工具调用块),适合作为"结果抽取"的入口。
监控工具调用序列
pi --mode json "Refactor this file" 2>/dev/null \ | jq -c 'select(.type == "tool_execution_start") | {tool: .toolName, args: .args}'tool_execution_start携带toolCallId、toolName与args,可按toolCallId关联tool_execution_end的result与isError,从而重建完整的工具调用闭环。
观测压缩与重试
pi --mode json "Process a large codebase" 2>/dev/null \ | jq -c 'select(.type | startswith("compaction") or startswith("auto_retry") or startswith("summarization_retry"))'上下文超限触发压缩、溢出重试等生命周期事件(compaction_start/end、auto_retry_start/end、summarization_retry_*)均可在此过滤下可见,便于评估长会话的上下文管理行为。
实时输出流式文本
利用 delta-only 设计,可以用jq把流式增量拼成实时文本:
pi --mode json "Write a haiku" 2>/dev/null \ | jq -r 'select(.type == "message_update" and .assistantMessageEvent.type == "text_delta") | .assistantMessageEvent.delta'按contentIndex+delta拼装即可;工具调用参数与思考内容同理,分别消费toolcall_delta与thinking_delta增量。
七、补充:事件与会话格式的一致性
JSON 模式输出的事件结构与 Pi 的会话持久化格式同源。会话文件本身也是 JSONL(存储于~/.pi/agent/sessions/--<path>--/<timestamp>_<uuid>.jsonl),其中的消息类型与事件体系一一对应:
UserMessage(role: "user")、AssistantMessage(content含 text/thinking/toolCall 块,stopReason∈stop/length/toolUse/error/aborted)、ToolResultMessage(含isError)、BashExecutionMessage、CustomMessage等七种消息共同构成AgentMessage联合类型;- 会话条目类型(
session、message、model_change、compaction、custom等)通过id/parentId构成树结构。
理解这层同源性有两个实践价值:
- 事件语义即持久化语义:JSON 模式里看到的
compaction_end.reason、message_end.message.stopReason,与落盘会话文件中对应条目的字段完全一致; - 结果可跨模式续接:JSON 模式跑完的事件流,其最终
message_end与agent_end.messages中携带的消息对象,可直接对应到会话文件中的持久化消息,方便后续用/resume或--session无缝续接。
更完整的会话文件格式、SessionManagerAPI 与解析建议(逐行读取、按entry.type分派、忽略未知类型以兼容未来版本)参见 session-format.md。
结语
pi --mode json是 Pi 四种运行模式中最适合脚本化消费的一种:它以"首行会话头 + 逐行 JSONL 事件流"的线性格式,把 Agent 的思考、文本生成、工具调用、上下文压缩与重试等全生命周期暴露为标准事件,并通过 delta-only 的message_update设计保证了流体积随生成长度线性增长。结合jq即可搭建轻量的 Agent 观测、结果抽取与自动化管道;一旦需求升级为双向控制(如流式打断、中途注入指令、执行 bash),则应迁移到 RPC 模式(见 rpc.md),进程内 Node/TypeScript 应用则优先考虑 SDK。
【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考