Harness 一旦被当成”功能越多越好”,讨论就会失焦。Pi 这类极简实现让我想清楚:哪些能力该由运行时提供,哪些该交给调用方。
Q1: 什么是 Agent Harness?为什么它成了新的面试考点?
1
2023-2024:模型能力决定一切
这一阶段产品竞争的核心是”模型聪不聪明”。开发者做的事情是写 Prompt、接 Function Calling,把模型当成一个会说话的函数。
2
2025:Coding Agent 证明 Harness 的价值
Claude Code、Codex 等产品让行业意识到:同一个模型,放在不同的工具集、上下文策略和权限系统里,完成复杂任务的成功率可以差出数倍。差距不在模型,而在模型外面的那层运行时。
3
2026:Harness 成为独立基础设施
Pi、DeepSeek Harness 等项目把 Harness 本身开源出来。面试开始问”你怎么设计工具契约""上下文怎么组装""一次任务怎么回放”,而不是”你用过哪个模型”。
模型决定”能不能想明白”,Harness 决定”能不能稳定做完”。面试问 Harness,问的是你把不确定性关进工程笼子的能力。
Q2: Pi 是什么?它为什么敢”什么都不内置”?
Pi 是一个用 TypeScript 编写的开源 Coding Agent / Agent Harness,MIT 协议,官网是 pi.dev。它最早由 Mario Zechner 以badlogic/pi-mono 的名字开发,2026 年 4 月被 Armin Ronacher 等人创立的 Earendil 收购,仓库迁移到 earendil-works/pi。OpenClaw 等项目就构建在 Pi 之上。
Pi 的核心数字很反直觉:
官方 README 的一句话概括了它的哲学:“Adapt Pi to your workflows, not the other way around.”(让 Pi 适应你的工作流,而不是反过来。)
为什么”少”反而是一种竞争力
- 上下文可控。 Harness 不偷偷往系统提示里塞规则,也不在你不知情时注入工具说明。模型看到的每一条上下文都能在会话里找到来源。
- 行为可解释。 工具少、提示短,出问题时容易判断是模型决策错、工具契约错,还是上下文缺信息。
- 避免功能诅咒。 每个内置功能都会带来新的状态、新的失败模式和新的维护成本。Pi 把这些交给扩展,核心保持稳定。
- 适配私有工作流。 企业的差异在流程、权限和数据,“有没有内置子 Agent”不是关键。Pi 选择给你一个可编程内核,把决定权留给团队。
Pi 的极简边界
Q3: Pi 的架构是怎么拆的?
Pi 由一组可独立使用的 npm 包组成。四种运行形态
会话树:Pi 最值得学的设计
大多数 Agent 的会话是一条直线。Pi 把会话存成树:每次从历史节点继续都会产生分支,用/tree 可以跳回任意节点重新开始,用 /resume 恢复历史会话。
这带来三个工程收益:
- 可回放。 出问题时能定位到具体哪一轮、哪个工具结果导致了错误决策。
- 可分支实验。 同一个任务可以从分叉点尝试两种策略,不需要重跑前面几十轮。
- 可压缩。 长会话通过 compaction 生成摘要节点,原始消息仍保留在树里,需要时可以回溯。
Q4: Pi 的 Agent 主循环是怎么跑的?
Pi 的循环本身非常朴素:组装上下文 → 调模型 → 执行工具 → 把结果写回会话 → 判断是否继续。真正复杂的是每一步的边界处理。这段循环里,Pi 刻意做对的四件事
Q5: Pi 的运行时状态机长什么样?会话树如何支撑回放、分支和恢复?
Pi 的循环很朴素,但”一次 run 的状态放在哪”决定了它能不能恢复、能不能回放、能不能做分支实验。Pi 的答案是:状态外置到会话文件,进程只做执行器。会话文件就是事件日志
Pi 把会话存成 JSONL:一行一个条目,通过id / parentId 组成树。公开文档列出的条目类型包括会话头、用户/助手/工具结果消息、bash 执行、模型切换、思考等级切换、压缩(compaction)、分支摘要和自定义条目[1]。这实际上是一个面向消息的事件日志,只是它没有把每个事件都拆成 step/started 这种细粒度事实。
需要诚实说明:Pi 公开文档没有像 DeepSeek Harness 那样明确暴露
turn/step 事件模型,也没有承诺一套”run 事件总线”。它的可回放性主要来自会话文件不可变追加 + 树形分支,而不是完整的事件溯源 API。
分支、压缩与恢复的机制
- 分支:
/tree跳到任意历史节点继续,产生新的parentId,旧分支保留。适合”同一任务试两种策略”,不用重跑前几十轮。 - 压缩:接近上下文上限时自动或手动
/compact生成摘要条目,保留最近 token;摘要采用结构化格式(目标、约束、进度、决策、文件操作),原始消息仍在树里。Pi 还支持在切换分支时生成分支摘要,保持上下文连续[1]。 - 恢复:
/resume选择历史会话,从文件重建上下文。因为文件是真相,进程崩溃不会丢会话;但工具副作用不会自动回滚,这是事件日志方案的固有边界。 - 热重载:扩展放在可发现目录时,
/reload可以重载扩展,不必重启会话。
Pi 没给你的恢复能力(生产必须补)
什么场景会坏: 压缩把关键约束摘要掉,后续模型反复犯同一个错;
/tree 回到旧节点后,工作区文件已经是新分支的状态,模型看到”代码与历史不一致”;两个终端同时打开同一会话。
怎么验证: 构造一条含工具调用、压缩、分支的会话,逐个节点 /tree 后检查上下文构造结果;kill 进程后 /resume,对比工具副作用是否重复;把”摘要前后关键约束是否保留”做成 fixture 断言。
Q6: Pi 的上下文是怎么组装的?预算、压缩和 Prompt Cache 怎么配合?
Pi 的核心卖点是”模型看到的每一条上下文都能在会话里找到来源”。这句话要落到工程上,需要看清组装顺序和每部分的成本。组装顺序
AGENTS.md在启动时从 agent 目录、父目录和当前目录加载;.pi/SYSTEM.md替换系统提示,.pi/APPEND_SYSTEM.md只追加不替换[2]。- Skills 每轮只注入名称和不超过 1024 字符的描述,形成
<available_skills>块,避免把SKILL.md全文塞进上下文;“调用 Skill”本质是让模型去读对应的SKILL.md。这是渐进式披露,目的就是避免一次性撑爆上下文、破坏缓存[3]。 - Prompt Templates 是 Markdown 片段,通过
/name展开,属于”用户输入侧”的复用,不占系统提示的常驻预算。
预算与压缩
Pi 没有公开一套固定的预算比例,但提供了可操作的杠杆:
这里有一个容易忽略的权衡:动态切换 active tools 会重建基础提示。它节省了工具 schema 的常驻 token,但如果切换频繁,前缀稳定性被破坏,Prompt Cache 可能失效。正确做法是按任务阶段切换(探索阶段只读工具、实现阶段加写工具),而不是每轮都切。
前缀稳定与缓存
Pi 的 footer 会显示 token、cache read/write 和缓存命中率,这让”缓存是否真的命中”变成可观测指标[2]。工程上要守住三条不变量:- 系统提示、工具定义、AGENTS.md 的内容和顺序在会话内尽量不变。
- 时间戳、随机 ID、动态排序的工具数组不要放在断点之前。
- 压缩摘要不要每轮重写;摘要一旦生成,应作为稳定节点参与后续前缀。
Q7: Pi 的工具运行时:注册、并发、超时、截断和错误契约怎么落地?
注册与可见性
- 参数用 TypeBox 定义,模型看到的是 name + description + JSON Schema。
execute收到toolCallId、参数、AbortSignal、onUpdate和扩展上下文,取消可以端到端传递[3]。executionMode: "sequential"可以让某个工具显式串行,避免共享状态竞争;官方示例里的井字棋工具就用它防止并发改同一个游标[5]。- 注册是 eager 的,没有
unregisterTool;通过getAllTools()/getActiveTools()/setActiveTools()控制模型可见子集[3]。 tool_call事件可以在执行前拦截(返回{ block: true, reason }),tool_result在执行后携带{ toolName, input, content, isError },适合审计和纠错[3]。
并发矩阵
Pi 公开文档没有承诺一个默认并发度,也没有内置工具侧幂等账本。默认值不等于生产契约,这两件事要在扩展层补。
超时、取消与截断
Promise.race 而不把 signal 传给子进程,会留下继续写文件的僵尸进程。bash 工具要杀进程组。
截断不要只截不留:保留头尾 + 明确写出”已截断、共多少字符”,完整内容落到工作区文件或产物,返回路径/ID,让模型按需读取。Pi 官方 truncated-tool 示例对 ripgrep 输出做 50KB / 2000 行截断,可以作为起点[5]。
错误契约
isError,没有强制的错误结构,所以团队要自己约定。可重试性必须由工具声明:参数错误不重试,超时/429/5xx 指数退避重试并尊重 Retry-After。错误信息要可执行,例如”路径必须在工作区内,请改用相对路径”,而不是”失败”。
什么场景会坏: 两个 edit 并行改同一文件导致覆盖;工具超时后进程仍在写;截断把关键报错信息截掉;错误返回给模型但模型不知道能否重试,反复调用。
怎么验证: 对每个写工具做并发测试;注入超时并检查子进程是否被杀;对截断做”信息仍可被找回”的测试;统计工具误调用率和重试率。
Q8: Pi 的沙箱与产物:默认没有,怎么补成可交接的工程链路?
Pi 的默认姿态是”没有权限弹窗、没有沙箱”,把安全边界交给运行环境和扩展。这是刻意的边界选择:Pi 认为自己不该替团队决定安全策略。但生产落地必须补。可用的沙箱接缝
官方示例目录里同时提供 permission-gate、protected-paths、sandbox、gondolin、ssh 这些实现,说明”默认没有”不等于”做不到”[5]。但要注意:扩展运行在 Pi 进程内,拥有完整系统权限。权限拦截扩展本身如果被绕过,边界就没了;强隔离要放在进程外(容器、微 VM、远程执行)。
产物链路:会话 → 工作区 → 对象存储 → 下一个 Agent
Pi 没有公开的内置产物存储/清单机制。会话可以/export 成 HTML 或分享成 gist,但那是会话导出,不是可被下游消费的产物契约。所以需要自己设计。一个可用的参考架构:
生命周期与权限
什么场景会坏: 沙箱/进程先死,产物没上传;
../../.ssh 路径穿越;不同租户共用 bucket 前缀导致越权;产物无 TTL 把磁盘撑满;manifest 记录了但文件被就地修改。
怎么验证: 提交前后注入 kill;用第二个 Agent 真实读取并跑 schema 校验;做路径穿越和越权读取的负向测试;GC 时断言”被引用的产物不能删”。
Q9: 多 Provider、成本分级和失败切换怎么做?
Pi 已有的能力
pi-ai提供统一 LLM API,内置 15+ Provider,支持订阅登录(Claude Pro/Max、ChatGPT Plus/Pro、GitHub Copilot)和 API Key[2]。/model或 Ctrl+L 可在会话中切换模型;自定义 Provider 写在~/.pi/agent/models.json,支持 OpenAI/Anthropic/Google 兼容协议;更特殊的 API/OAuth 通过扩展注册[2]。- footer 显示当前模型、token、cache 和成本,
pi-ai本身也做 token/成本跟踪[9]。
公开资料未披露的部分
Pi 的公开文档描述的是模型切换,没有承诺一套自动的跨 Provider 故障切换/降级策略。不要假设它有”主模型失败自动切备用”的内置行为。生产需要自己在 Provider 层或外层网关做:成本分级的三个原则
什么场景会坏: 会话中途频繁切模型,缓存全失效,账单反而更高;跨 Provider 的 tool schema 不支持并行调用,工具调用静默丢失;订阅额度与 API Key 混用导致 401/429 难以归因;降级后模型不知道工具变少。
怎么验证: 用故障代理制造 429/500;统计每档成功率、P95 延迟、单任务成本、缓存命中率;对工具 schema 做跨 Provider 契约测试。
Q10: Pi 的扩展体系怎么设计?Extension、Skill、Package 有什么区别?
一个最小 Extension
为什么 Skill 不等于 Extension
- Skill 是给模型看的说明书,不执行代码,适合流程、规范、判断标准。
- Extension 是给 Harness 执行的能力,适合接系统、做校验、改 UI。
- 能用 Skill 解决的就别写 Extension,因为 Prompt 可以快速迭代;涉及权限、密钥、外部副作用的,必须放到 Extension 里,不能交给模型自觉。
Pi 的扩展体系把”知识”和”能力”分开:Skill 管怎么做,Extension 管能做什么,Package 管怎么分发。
扩展的生命周期:加载、信任、热重载、卸载
很多文章把 Pi 扩展讲成”写个 TypeScript 文件就行”,但真正决定生产可用性的是生命周期:什么时候加载、谁有权加载、改了怎么生效、卸载后残留什么。Pi 的公开设计在这四点上有明确取舍。
为什么用 jiti 而不是预编译? 因为 Pi 的核心卖点是”改一行立刻生效”。预编译插件需要 build、发布、再安装,迭代一次要几分钟;jiti 把”写扩展”变成和”改配置”一样的体验。代价是:扩展作者必须自己保证语法/类型正确,且启动时执行任意代码意味着扩展就是完全信任的代码,不是沙箱里的插件。
为什么项目扩展要 trust? 这是 Pi 少有的默认安全机制。
git clone 一个仓库就自动执行其中的 .pi/extensions/*.ts,等于把”打开项目”变成”运行陌生人的代码”。trust 门把这一步变成显式决策。但要注意:trust 只解决”要不要加载”,不解决”加载后能做什么”——一旦信任,扩展拥有与 Pi 进程相同的文件、网络、进程权限。
和 Cordis 的机制级对比
DeepSeek Harness 用 Cordis 做插件内核,Pi 用”运行时加载 + 事件钩子”做扩展。两者都能扩展,但保证的东西完全不同:
一句话:Pi 的扩展是”改自己的工具”,Cordis 的插件是”换运行时的一个器官”。 前者的成本低、心智负担小;后者的约束强、能保证卸载干净,但要求每个能力都先定义接缝。
什么场景会坏: 两个扩展注册同名工具,后加载的静默覆盖;扩展在
session_start 里开了定时器/连接,/reload 后旧实例泄漏;项目扩展在 trust 前被其他机制加载;把密钥写进扩展源码再提交到仓库。
怎么验证: 写一个”注册工具 + 开 interval + 注册事件”的扩展,连续 /reload 十次,观察句柄数量是否增长;构造同名工具冲突,确认是否有告警;在未 trust 的仓库里检查项目扩展是否真的没执行。
Q11: Pi、Claude Code、Codex、DeepSeek Harness、LangGraph 怎么选?
机制级差异:不要只看功能表
功能表会骗人——“都有工具调用”不代表运行时的保证一样。真正决定选型的是四个机制:
几条容易踩的事实边界:
- Claude Code 的沙箱是 OS 级的:Linux 用 bubblewrap,macOS 用 seatbelt,网络走沙箱外代理[6]。这意味着”文件系统与网络”由运行时强制,而不是靠模型自觉。
- Codex CLI 的沙箱同样是 OS 级(macOS Seatbelt、Linux bubblewrap + Landlock、Windows 受限令牌/DACL),并把
.git、.codex设为只读[7]。它的审批策略与沙箱是两件事:沙箱限制”能碰什么”,审批决定”要不要问人”。 - LangGraph 的 checkpointer 是图状态持久化,不是 Agent 会话日志。
MemorySaver只适合测试,生产要用PostgresSaver/SqliteSaver,并且要自己设计保留策略[8]。 - Pi 和 DeepSeek Harness 都能”换实现”,但换的层次不同:Pi 换的是扩展,DSH 换的是能力 Provider。前者改行为,后者改运行时本身。
选择决策
Q12: 把 Pi 用到生产,需要补哪些工程能力?
Pi 的默认值适合个人开发者,生产环境至少要补齐六层:生产化清单:八个维度,每个都要有”最低可接受答案”
上面的六层是能力清单,真正上线前还要回答八个工程问题。表格里的”失败长什么样”比”该做什么”更重要,因为它决定了你能否验收。升级与回滚:Pi 最容易被忽略的风险
Pi 迭代快,扩展 API、会话条目格式、事件名都可能变。生产环境要把三件事当成契约来管理:- 锁版本:
package.json里锁死@earendil-works/pi-coding-agent与所有扩展版本,升级走 PR 而不是latest。 - 会话格式带版本:自定义条目里写
schemaVersion;读取端遇到未知版本要能降级或明确报错,而不是静默丢数据。 - 可回滚:升级前用固定任务集跑一遍评测;保留旧版本二进制和旧会话的只读访问,出问题能切回。
成本控制的核心:缓存友好
Pi 的上下文是显式组装的,这带来一个额外好处:前缀稳定。把系统提示、工具定义、AGENTS.md 放在最前面并保持稳定,只把变化部分追加到后面,就能命中 Provider 的 Prompt Cache。Q13: Pi 的可观测性接点应该怎么设计?
Pi 本身只给了”能看见”的基础设施:JSONL 会话、footer 的 token/cache/cost、--print/--json/RPC 三种非交互输出[2]。它没有内置 OpenTelemetry 导出,也没有 Langfuse 集成。所以关键问题在于你要在哪些接点埋什么事件,Pi 本身并不缺可观测性。
五类事件:最小可用集合
映射到 OTel / Langfuse
- 层级:run 是根 span,step 是子 span,tool 和 model call 挂在 step 下。Langfuse 里对应 trace → span → generation;OTel 里对应嵌套 span,字段命名可参考 GenAI 语义约定[10]。
- 模型调用单独成 span:把 model、input/output token、cache read/write、首 token 延迟、结束原因作为属性,才能算出真实单步成本。
- 默认脱敏:工具参数和结果里可能有密钥、用户数据。记录摘要或哈希,完整内容留在会话归档里,按权限访问。
Pi 的优势与缺口
什么场景会坏: 只记日志不记 trace,出问题只能按时间顺序猜;把完整工具参数打进日志,密钥进了 ELK;只统计总 token,不知道是上下文膨胀还是工具结果太大。
怎么验证: 用一个固定任务跑一次,检查能否从 run 根 span 下钻到具体 tool span;人为让某工具超时,确认 error 事件带得上 toolCallId;做一次日志脱敏扫描,确认无密钥模式。
Q14: 深度面试追问(Harness 运行时方向)
会话文件已经是 append-only 了,为什么还需要事件溯源?
会话文件已经是 append-only 了,为什么还需要事件溯源?
及格回答(60-70 分):
“因为事件溯源可以回放,出问题能重跑。”满分回答(90-100 分):
“append-only 只保证’不丢’,不保证’可解释’。事件溯源要求每个事件是语义明确的事实(run 开始、step 结束、工具调用、产物提交),状态是事件的 fold 结果。区别在恢复能力:只有消息日志,你只能重建上下文;有事件流,你能知道崩溃时卡在第几步、哪个工具调用没有结果、重试是否安全。代价是事件设计要稳定、存储更大、还要处理快照和版本迁移。验证方法是杀掉进程后从事件流恢复,对比状态与预期是否一致。”
工具执行到一半进程崩了,恢复后怎么保证不重复副作用?
工具执行到一半进程崩了,恢复后怎么保证不重复副作用?
及格回答(60-70 分):
“重试的时候注意一下,别重复执行。”满分回答(90-100 分):
“三层:第一,工具调用要有幂等键,服务端按 key 去重;第二,会话里要有 pending tool call 记录,恢复时先查这个调用有没有外部结果,而不是直接重跑;第三,写操作尽量设计成可校验的(先读 checksum 或版本号,再提交)。如果外部系统不支持幂等,就要人工确认或走补偿。验证方法是注入 kill 在工具执行中点,恢复后检查外部系统只产生一次效果。”
上下文压缩和 Prompt Cache 为什么经常互相打架?
上下文压缩和 Prompt Cache 为什么经常互相打架?
及格回答(60-70 分):
“压缩会改上下文,缓存就失效了。”满分回答(90-100 分):
“Prompt Cache 命中依赖前缀逐字节稳定。压缩会重写历史,等于把缓存断点之前的内容全改了,下一次必然重新写缓存。所以压缩要低频、成块发生,而不是每轮微调;压缩后的摘要要作为稳定节点固定下来。另一个冲突是动态工具集:切换 active tools 会重建基础提示。解法是按阶段切换、在阶段边界压缩,把’变化’集中到同一次,减少缓存失效次数。验证看 footer 的 cache read/write 比例和单任务成本。”
为什么沙箱不能只靠 system prompt 约束?
为什么沙箱不能只靠 system prompt 约束?
及格回答(60-70 分):
“因为模型可能不听话,所以要在提示里写清楚不能做什么。”满分回答(90-100 分):
“提示是建议,边界要靠运行时。Prompt injection、模型误判、上下文被污染都会让约束失效。边界必须落在模型之外:OS 级沙箱限制文件与网络,工具层 allowlist 限制可执行命令,审批策略决定高风险动作要不要人确认。Pi 默认把这一层留空,所以生产必须用 gondolin、容器或远程执行补上。验证方法是做红队测试:让模型尝试读
~/.ssh、访问内网、写 .git/,看是否被运行时而不是提示拦住。”Pi 的扩展没有 unregisterTool,这会带来什么工程问题?
Pi 的扩展没有 unregisterTool,这会带来什么工程问题?
及格回答(60-70 分):
“工具注册了就不能删,可能会冲突。”满分回答(90-100 分):
“三个问题:第一,同名工具冲突只能靠约定,后加载会覆盖或并存,行为不确定;第二,
/reload 重载后旧扩展注册的定时器、连接、事件监听可能泄漏,因为没有自动副作用回收;第三,工具集只能’隐藏’不能’销毁’,长期运行会累积状态。解法是把扩展当成需要自己管理生命周期的模块:显式在 session_start 注册、在重载前清理句柄、用命名空间避免冲突,并在 CI 里做连续 reload 的泄漏测试。”怎么证明一次失败是模型问题还是 Harness 问题?
怎么证明一次失败是模型问题还是 Harness 问题?
及格回答(60-70 分):
“看日志,如果模型输出不对就是模型的问题。”满分回答(90-100 分):
“要做控制变量。先固定模型和任务,只换 Harness 版本或提示组装方式;再看失败点的上下文:模型看到的工具定义是否完整、工具结果是否被截断、是否有报错被吞掉。如果同一模型在另一个 Harness 上成功,问题大概率在上下文组装或工具契约;如果换了模型仍失败,可能是任务本身或工具能力不足。证据要落到事件流:哪一步、哪个工具、返回了什么。”
长任务里,为什么 step 数比 token 数更能反映健康度?
长任务里,为什么 step 数比 token 数更能反映健康度?
及格回答(60-70 分):
“step 多了说明 Agent 一直在试错。”满分回答(90-100 分):
“token 只反映’读了多少’,step 反映’做了多少次决策’。同样 10 万 token,一次读完和五十次来回,后者意味着反复试错、工具误调用或上下文不足。健康的长任务应该 step 数随任务复杂度线性增长,而不是指数增长。监控上要给 step 数设阈值和告警,并结合工具成功率、重复调用率一起看。token 高但 step 正常,通常是上下文材料多;step 高但 token 正常,通常是策略或工具契约有问题。”
如果让你从零设计一个 Harness,最先定哪三个接口?
如果让你从零设计一个 Harness,最先定哪三个接口?
及格回答(60-70 分):
“模型调用、工具调用、会话存储。”满分回答(90-100 分):
“先定三个边界:会话(append-only 的事件存储,能按位置读取和回放)、工具执行(统一的
execute(name, input, signal) 契约,带超时、取消和错误结构)、模型调用(可替换的 Provider 接口,带 token/成本/结束原因)。这三个接口决定了系统能不能恢复、能不能换模型、能不能换沙箱。UI、子 Agent、MCP 都应建在这三个之上,而不是反过来让核心依赖它们。定接口时优先保证’实现可替换’,而不是’功能齐全’。“Q15: 满分回答 vs 及格回答
问题:“Pi 为什么不内置子 Agent 和 MCP?这算优点还是缺点?”
及格回答(60-70分):“Pi 是一个很小的 Agent 工具,只有四个工具,子 Agent 和 MCP 需要装扩展。优点是轻量,缺点是功能少。”问题出在:只描述了现象,没有解释设计取舍。 满分回答(90-100分):
“这是有意的边界设计,不是能力缺失。Harness 每内置一个功能,就多一套状态、失败模式和维护成本;而子 Agent、MCP、审批流恰恰是最因团队而异的层。Pi 把核心压到四个工具和千 token 级提示,保证上下文可控、行为可解释,再把差异交给 Extension 和 Package。”
“代价是团队要自己补权限、沙箱、评测这些生产化能力。所以 Pi 适合把 Harness 当产品一部分来改的团队,不适合只想开箱即用的人。判断标准是是否愿意为可控性支付维护成本,跟功能多少关系不大。“
常见追问
Harness 和 Agent Framework 的区别是什么?
Harness 和 Agent Framework 的区别是什么?
答题要点:
从”谁拥有主循环”切入。高分回答:
“Framework 提供编排原语,主循环通常由你写;Harness 直接拥有主循环、工具执行、上下文组装和会话状态,模型只是其中一个依赖。LangGraph 是 Framework,Pi 和 DeepSeek Harness 是 Harness。二者可以组合:用 Harness 跑单个 Agent,用 Framework 编排多个 Harness。”
为什么 Pi 的会话要设计成树,而不是线性数组?
为什么 Pi 的会话要设计成树,而不是线性数组?
答题要点:
回放、分支实验、压缩。高分回答:
“线性会话只能前进,出错就只能重跑。树结构保留每个分支点,既能回放定位问题,也能从同一节点尝试不同策略;压缩时生成摘要节点但不丢原始消息,需要时可以回溯。代价是存储和 UI 更复杂,所以适合长任务和需要审计的场景。”
Pi 只有四个工具,为什么够用?
Pi 只有四个工具,为什么够用?
答题要点:
组合能力 + 扩展。高分回答:
“read、write、edit、bash 覆盖了文件读写和任意命令执行,理论上可以组合出绝大多数操作。工具少意味着选择空间小、误调用率低、上下文便宜。真正缺失的能力通过 Extension 补,而不是把核心工具集做大。这是把’通用性’放在 bash,把’安全性’放在沙箱和权限层。”
如果把 Pi 接到生产,最先补什么?
如果把 Pi 接到生产,最先补什么?
答题要点:
权限、沙箱、可观测性优先。高分回答:
“先补权限和沙箱,因为 bash 的破坏半径最大;再补 trace 和会话归档,否则出了问题无法定位;最后才是评测和成本优化。顺序不能反:没有安全边界就上线,一次误删比省下的 token 贵得多。”
Pi 的显式上下文设计对 Prompt Cache 有什么影响?
Pi 的显式上下文设计对 Prompt Cache 有什么影响?
答题要点:
前缀稳定才能命中缓存。高分回答:
“显式组装本身不保证缓存,关键是前缀稳定。把系统提示、工具定义、AGENTS.md 固定在最前面,变化内容追加到后面,缓存断点放在稳定区末尾。如果每轮重排工具或插入时间戳,缓存全失效。Pi 的优势是你能看见上下文,从而主动维护这个不变量。”
什么时候不该用 Pi?
什么时候不该用 Pi?
答题要点:
无维护能力、强合规开箱需求。高分回答:
“团队没有精力维护 Harness、又需要开箱即用的权限和审计时,不该用 Pi。它的价值在于可改造,而不是省事。另一个不适合的场景是需要大量内置多 Agent 协作的产品,直接用 DeepSeek Harness 或 LangGraph 更划算。”
如何证明换 Harness 后 Agent 变强了?
如何证明换 Harness 后 Agent 变强了?
答题要点:
固定模型、固定任务集、只改 Harness。高分回答:
“控制变量:同一模型、同一温度、同一任务集,只改 Harness。指标看任务成功率、平均步数、工具误调用率、单任务成本和人工接管率。用固定 fixture 做回归,避免’这次感觉不错’。如果成功率没变但步数和成本下降,也是有效提升。”
Pi 的极简哲学在团队协作中会带来什么问题?
Pi 的极简哲学在团队协作中会带来什么问题?
答题要点:
标准不统一、重复造轮子。高分回答:
“每个人都按自己习惯写扩展,最后工具命名、错误格式、权限策略全不一致,协作成本反而上升。解法是把团队约定沉淀成 Pi Package:统一工具契约、统一错误结构、统一审批扩展,再通过 npm 私服分发。极简内核必须配强约定,否则自由会变成混乱。“
延伸阅读与引用参考
- [1] Pi 仓库文档目录(sessions / session format):会话 JSONL 条目类型、树形分支、压缩与恢复。
- [2] @earendil-works/pi-coding-agent(npm):README、运行模式、
/model、/reload、footer 与成本显示。 - [3] Pi extensions 文档:jiti 运行时加载、TypeBox、
registerTool、tool_call/tool_result、project trust、getAllTools/setActiveTools与无unregisterTool的说明。 - [4] Anthropic Prompt Caching:断点数量、回看窗口、TTL 与读写计费倍率。
- [5] Pi 官方扩展示例:
executionMode: "sequential"、truncated-tool、permission-gate、protected-paths、sandbox、gondolin、ssh。 - [6] Claude Code sandboxing:Linux bubblewrap、macOS seatbelt 与网络代理边界。
- [7] Codex 沙箱实现整理:Seatbelt、bubblewrap + Landlock、Windows 受限令牌,以及
.git/.codex只读。 - [8] LangGraph Persistence:checkpointer、
thread_id、MemorySaver与生产级 saver 的取舍。 - [9] pi-ai 文档:统一 LLM API、模型目录、token 与成本跟踪。
- [10] OpenTelemetry GenAI Semantic Conventions:
gen_ai.*属性与 agent/tool span 的命名约定。 - pi.dev:官网与安装入口。
- Pi (agent framework) - AI Wiki:项目历史、Earendil 收购与设计背景。
- DeepWiki: Built-in Tools:内置工具与执行架构的源码级整理。
