Skip to content

沿调用链打开 Pi ​

概念篇读完,小a觉得自己“懂”了:模型怎么生成、工具怎么调用、循环怎么转、会话怎么存。他把概念书一合,打开了 pi-mono 的源码目录,打算挑一个真实 Agent 看看。

十分钟后,他盯着满屏的 packages/ 目录发呆——ai、agent、coding-agent、tui、protocol……几十个文件夹,哪个是入口?哪条是主路?

他去找老z:“概念我会背了,可这代码我看不懂从哪下手。”

老z笑了:“概念回答的是‘通常如何工作’;你现在要回答的是——一个真实 Agent 在哪里创建请求、怎样推进状态、何时中断或保存会话。这需要一份能复核的源码快照,而不是凭印象猜。我们选 pi-mono,按包边界和一条端到端调用链来读。”

小a:“那我看的是哪个版本?会不会过两天又变了?”

本篇的基线与证据规则

  • 仓库: pi-mono
  • 固定提交: 583f153d502aa8e958eefdb9af0fbd3344e68f95
  • 版本边界: 根仓库 0.0.3;本书选取的九个核心/产品范围包 0.83.0
  • 提交日期: 2026-08-01

本书根目录的 pi-mono/ 是被 Git 忽略的本地参考 clone,并非本文档站的受版本控制内容;仅克隆本书仓库不等于已获得源码基线。本文以该本地 clone 中的固定提交作为证据位置。

小a:“那书里的代码和结论,我该怎么核对?”

老z:“记住三条证据规则,读到哪都用得上:”

证据规则

  • 已确认事实必须能回到该快照的文件路径、符号名或官方原始资料;行号仅是该快照下的辅助定位。
  • 基于源码的推断只从结构和调用关系说明“这意味着”或“可以推断”,不把它写成作者意图。
  • 示意或简化的伪代码、删节代码、流程图和假设场景会明确标注;它们不是完整真实源码。

“还有,”老z补了一句,“**‘讲清源码’不等于逐行讲完所有源码。**本篇承诺讲清核心入口、关键类型、主要调用链、状态变化、错误路径和设计代价,并给出能继续独立阅读的走查路线。没有覆盖的边缘功能会在相应章节说明,而不会被暗示为已完整解释。”

小a:“那我带着什么问题开始读?”

老z在屏幕上敲了一行字:“一次用户输入,如何从命令行进入系统,变成模型流、工具执行、会话记录和终端更新?答案就藏在这条链路上。”

本篇解决什么

读完源码篇,你能沿 pi-mono 的调用链独立走查:从入口找到模型请求怎么发出、流怎么穿过适配层、循环怎么推进状态、会话怎么活过进程重启、终端怎么刷新、工具与扩展怎么接入、协议怎么变成字节、远程会话怎么保持一致、评测怎么判断一次修改。核心是建立一张可验证的地图——遇到 bug 或想扩展时,你知道该往哪个文件看。

这里暂不解决:逐行讲完所有源码、覆盖全部边缘功能、把有限样本升级成全局结论。没有覆盖的部分会在对应章节标明,而不会被暗示为已完整解释。

小a:“那为什么选 pi-mono,不选别的仓库?”

“因为它是一个真实的、能端到端跑通的 TypeScript Agent 仓库,而且它的包边界和我们概念篇画的边界对得上。”老z说,“概念篇讲的 Provider、循环、会话、工具、协议、评测,在 pi-mono 里都能找到对应的包和调用链——概念有落点,源码有归属。选一个具体仓库,你才不是对着抽象概念空谈,而是能指着某一行说‘就是这里实现了它’。”

“那读源码有没有什么通用方法?”小a问。

“有,但记住三条就够起步。”老z说,

读源码的三个习惯

  1. 先入口后细节——从 index.ts 的导出和某个 create*/run* 函数进,先看清主路径再钻分支
  2. 先契约后实现——读模块前先读它的 types.ts 或接口定义,实现细节只在怀疑 bug 时才需要
  3. 先状态后逻辑——一个类有哪些成员、谁在何时改它们,比某个 if 写得巧不巧重要十倍

九包,不是九个孤岛 ​

小a打开 packages/ 目录,发现 workspace 里不止九个文件夹。老z提醒他:

“本书从全部 workspace 中选取九个核心/产品范围包:pi-ai、pi-agent-core、pi-coding-agent、pi-tui、pi-protocol、pi-server、pi-client、pi-evals 与 pi-storage-sqlite-node。它们不是九个孤立目录,而是端到端调用链上的不同责任边界;扩展示例等其他 workspace 不在这份九包清单里。”

12 章源码路线 ​

  1. 第18章 地图的比例尺——pi-mono:建立仓库、包边界、依赖方向和主调用链的地图。
  2. 第19章 目录与户口——pi-ai:追踪 pi-ai 的 Provider、模型目录、鉴权与请求入口。
  3. 第20章 先开票,后办事——pi-ai:检查消息转换、事件流、重试、中止、错误与兼容层。
  4. 第21章 双层循环——pi-agent-core:阅读 pi-agent-core 的 Agent、循环、消息队列、工具事件与停止路径。
  5. 第22章 调度台——pi-agent-core:分析 AgentHarness、会话仓库、JSONL、fork、compaction、skills 与 SQLite 存储;明确它不等于 Git worktree。
  6. 第23章 调度台与工位——pi-tui:走查 pi-tui 的组件树、差分渲染、宽度计算、输入与降级。
  7. 第24章 户口本上的住址——pi-coding-agent:从 pi-coding-agent 的参数、配置和资源加载走到模型、会话与交互装配。
  8. 第25章 收银台排队——pi-coding-agent:检查内置工具、文件并发队列、输出截断、扩展 runner、Hooks、项目信任与沙箱边界。
  9. 第26章 发货与报关——pi-protocol:阅读 pi-protocol 的 schema、CBOR、framing、版本、错误和 snapshot/progress 语义。
  10. 第27章 黑板与便签——pi-server+pi-client:追踪 pi-server 与 pi-client 的连接、握手、请求、快照、重连与一致性边界。
  11. 第28章 每次考试换新考场——pi-evals:区分 pi-evals 的行为验证、judge 结果与主观质量局限。
  12. 第29章 接力赛——End-to-End:把 CLI 输入、模型流、工具执行、会话记录与 TUI 更新收束为一条控制流和数据流。

小a:“每章都怎么读?”

老z:“每章都会从一条可走查的主路径出发,同时至少检查一个错误、中断或边界路径;它不会替代你对整个仓库每个文件的阅读。”

“那如果时间有限,只读主干,该读哪几章?”小a问。

“挑一条贯穿主线就够了。”老z说,“第18章看地图,第19章看模型请求怎么发,第21章看循环怎么转,第22章看会话怎么活过进程,第27章看一次完整请求怎么从 CLI 走到 TUI。这五章串起来就是源码篇的主干——其余章节是主干上的分支,按需再回头补。”

源码篇的主干阅读线

第18章 地图 → 第19章 模型请求 → 第21章 循环 → 第22章 会话 → 第27章 端到端

时间充裕时再沿主干横向铺开:第20章 流式适配、第23-24章 终端与启动、第25章 工具与扩展、第26章 协议、第28章 评测。

“那读完源码篇,和读之前比,差在哪?”小a问。

“差在‘能不能指着一行代码说清楚它为什么存在’。”老z说,“概念篇你知道了边界应该怎么画;源码篇你看到了一个真实系统真的这么画了——还看到了画得不彻底时会出什么问题。读完源码篇,你手里的概念从‘听过’变成‘核对过’。”

“还有一个提醒,”老z补了一句,“**源码篇的结论都锚定在一个提交上。**你读到的行号、符号、调用关系,都以 583f153d 为基准;如果去看更新版本的代码,结构可能已经变了。这不是书的问题,是源码阅读的固有属性——把‘这个快照里如此’和‘永远如此’分开,是读源码篇的基本功。”

从这里开始:第18章 地图的比例尺——pi-mono