pi 子代理体系实战:代码评审专员子代理(reviewer)的定义、加载与运行原理
本文以 pi 编码代理仓库中 subagent 示例扩展的 reviewer.md 为核心,完整拆解一个“代码评审专员”子代理的 Markdown 定义文件——frontmatter 各字段如何被解析、系统提示词的约束设计意图,并结合 agents.ts 与 index.ts 的源码说明它如何被发现、校验、以及最终以独立 pi 子进程方式运行,帮助读者掌握“用声明式文件定义可委派子代理”的完整方法论。
一、reviewer 在 subagent 扩展中的定位
subagent 是 pi 编码代理(coding agent)的一个示例扩展,入口为 index.ts。它向会话注册了一个名为 subagent 的工具,核心能力是把任务委派给“专职子代理”:每个子代理在独立的 pi 进程和独立的上下文窗口中运行,主会话只拿到最终输出,避免子任务的过程信息污染主对话。据其 README,该扩展支持:
- 隔离上下文:每个子代理在单独的
pi进程中运行; - 流式输出:工具调用与进度实时可见,并行任务同时流式更新;
- 用量跟踪:逐代理展示轮次、token、成本与上下文用量;
- 中断支持:Ctrl+C 会传播到子代理子进程并将其终止。
扩展内置了四个示例子代理定义(位于 agents/ 目录),reviewer 是其中之一:
| Agent | 用途 | 模型 | 工具 |
|---|---|---|---|
scout |
快速代码库侦察 | Haiku | read, grep, find, ls, bash |
planner |
制定实现计划 | Sonnet | read, grep, find, ls |
reviewer |
代码评审 | Sonnet | read, grep, find, ls, bash |
worker |
通用全能力执行 | Sonnet | 全部默认工具 |
可以看到 reviewer 的定位非常明确:只读、专注质量与安全分析、不落地任何修改。它通常出现在“实现 → 评审 → 修订”这类流水线中,作为质量门禁角色。
二、reviewer.md 全文与逐字段解析
2.1 完整定义文件
reviewer.md 全文如下(YAML frontmatter + 系统提示词正文):
---
name: reviewer
description: Code review specialist for quality and security analysis
tools: read, grep, find, ls, bash
model: claude-sonnet-4-5
---
You are a senior code reviewer. Analyze code for quality, security, and maintainability.
Bash is for read-only commands only: `git diff`, `git log`, `git show`. Do NOT modify files or run builds.
Assume tool permissions are not perfectly enforceable; keep all bash usage strictly read-only.
Strategy:
1. Run `git diff` to see recent changes (if applicable)
2. Read the modified files
3. Check for bugs, security issues, code smells
Output format:
## Files Reviewed
- `path/to/file.ts` (lines X-Y)
## Critical (must fix)
- `file.ts:42` - Issue description
## Warnings (should fix)
- `file.ts:100` - Issue description
## Suggestions (consider)
- `file.ts:150` - Improvement idea
## Summary
Overall assessment in 2-3 sentences.
Be specific with file paths and line numbers.
2.2 frontmatter 字段:一个子代理的四要素
name: reviewer:代理唯一标识。子代理按名字被调用({ agent: "reviewer", task: "..." }),同名时项目级代理会覆盖用户级代理(见 3.2 节)。description: Code review specialist for quality and security analysis:给主模型看的“能力说明”。主模型在决定委派给谁时依赖这段描述判断该任务是否适合 reviewer。tools: read, grep, find, ls, bash:工具白名单。运行时会转换为子进程命令行参数--tools read,grep,find,ls,bash(见 index.ts#L307),从而在进程层面限制子代理可用的内建工具。注意这里没有 write/edit——reviewer 从工具集上就无法修改文件,这是“评审不改码”的第一道硬约束。model: claude-sonnet-4-5:指定子代理使用的模型。若省略该字段,子代理会继承发起会话当前激活的模型与思考等级(README 的 Agent Definitions 一节明确说明;实现见 index.ts#L301-L306 中inheritsDispatchConfig逻辑)。对比样本中 scout 用更快的 Haiku、reviewer/planner 用 Sonnet,体现“按任务复杂度选模型”的成本意识。
解析实现的细节(agents.ts):
- frontmatter 由 pi 内建的
parseFrontmatter用真正的 YAML 解析器读取(agents.ts#L88),因此tools写成字符串tools: read, bash或数组tools: [read, bash]都是合法 YAML,两种写法都被parseToolList接受并归一化为字符串数组(agents.ts#L53-L60); name与description是必填字段:不是字符串的文件会被直接跳过(agents.ts#L90-L92),且单个坏文件不会影响同目录下其他代理的发现——这是刻意的容错设计(源码注释见 agents.ts#L49-L51);- frontmatter 之后的整个正文(即本例第 8 行起的提示词)被原样保存为
systemPrompt(agents.ts#L99),运行时会作为子进程的附加系统提示注入(见第四节)。
2.3 系统提示词正文:角色、约束、策略与输出契约
正文虽然不长,但每一段都有明确的设计意图:
角色设定:“You are a senior code reviewer. Analyze code for quality, security, and maintainability.”——一句话锚定三重评审维度(质量/安全/可维护性),与 frontmatter 中 description 呼应。
Bash 只读约束(本文件最核心的安全设计):
Bash is for read-only commands only:
git diff,git log,git show. Do NOT modify files or run builds. Assume tool permissions are not perfectly enforceable; keep all bash usage strictly read-only.
第二句尤其值得注意:它默认“工具权限并不能被完美强制”。原因在于:--tools 白名单只能限制子进程可调用哪些内建工具,而 bash 工具一旦被授予,理论上仍可能执行任意 shell 命令(包括写操作)。因此提示词层面必须再做一道软约束,把 bash 用法严格限定为 git diff、git log、git show 这类纯只读命令,并显式禁止改文件、跑构建。这是“硬限制(工具白名单)+ 软约束(提示词)”双层防御的典型案例。
评审策略(三步法):
git diff查看最近变更(如适用)——先缩小评审范围;- 读取被修改的文件——带着上下文看改动;
- 检查 bug、安全问题、代码坏味道(code smells)。
这个策略与前面 bash 约束闭环:正因为只允许 git diff/log/show,reviewer 的评审工作流天然围绕“近期变更集”展开,而不做全库漫游(那是 scout 的职责)。
结构化输出契约:文件后半部分以模板形式规定输出必须包含四个段落——Files Reviewed(评审过的文件与行号范围)、Critical (must fix)、Warnings (should fix)、Suggestions (consider)、Summary(2-3 句总评),并以 file.ts:42 这类“文件:行号”格式定位问题,结尾强调 “Be specific with file paths and line numbers.”。
这套固定输出格式不是随意排版,而是为链式协作服务的:在 implement-and-review 工作流中,reviewer 的输出会整体填入下一步 worker 的 {previous} 占位符(index.ts#L556)。结构化、带精确行号的评审结论让 worker 无需重新理解代码即可直接按“Critical → Warnings”顺序落地修改。对照 scout.md 的 “Files Retrieved / Key Code / Architecture / Start Here” 与 planner.md 的 “Goal / Plan / Files to Modify” 模板,可以看出 pi 的子代理体系把“代理间交接格式”当作了规范级要素来设计。
三、加载机制:reviewer.md 如何被发现与校验
3.1 发现路径与 agentScope
代理发现逻辑在 agents.ts 的 discoverAgents(agents.ts#L128-L147):
| 位置 | 加载条件 |
|---|---|
~/.pi/agent/agents/*.md(用户级) |
默认加载(scope 为 user 或 both) |
.pi/agents/*.md(项目级,从 cwd 向上就近查找) |
仅当 agentScope: "project" 或 "both" |
agentScope 是 subagent 工具的参数,默认 "user";取 "both" 时同名代理以项目级覆盖用户级(源码中项目代理在 user 之后写入 agentMap,见 agents.ts#L137-L144)。项目级目录由 findNearestProjectAgentsDir 从当前目录逐级向上探测 .pi/agents 得到(agents.ts#L116-L126)。
3.2 每次调用重新发现
README 的 Limitations 一节指出:代理在每次工具调用时重新发现(“Agents discovered fresh on each invocation”),这意味着会话中途编辑 reviewer.md(例如调整输出格式或工具白名单)在下一次委派时立即生效,无需重启会话。
3.3 安全模型:为什么默认只加载用户级代理
README 的 Security Model 一节给出了关键背景:subagent 工具实际是用委派的系统提示词和工具/模型配置启动一个独立的 pi 子进程,而项目级代理(.pi/agents/*.md)属于“仓库可控的提示词”——攻击者只要控制仓库中的代理文件,就可能诱导子代理读文件、跑 bash 命令。因此:
- 默认只加载用户级代理;
- 要启用项目级代理需显式传
agentScope: "both"(或"project"),且 README 提醒“只在你信任的仓库中这么做”; - 交互式运行时,在未信任项目中执行项目级代理前会弹出确认提示;可传
confirmProjectAgents: false关闭该确认(对应实现见 index.ts#L520-L548)。
回到 reviewer 本身:它的提示词恰好示范了“即使 bash 可用,也要自我约束为只读”的写法,正是对上述“仓库可控提示词”风险的缓解模式——值得在自定义代理时直接借鉴。
四、运行时:reviewer 子进程是如何被拉起的
subagent 工具的 execute 最终都汇聚到 runSingleAgent(index.ts#L272)。以单代理模式 { agent: "reviewer", task: "..." } 为例,运行时的完整流程:
-
构建命令行(index.ts#L300-L341):
pi --mode json -p --no-session \ --model claude-sonnet-4-5 \ --tools read,grep,find,ls,bash \ --append-system-prompt <临时提示词文件> \ "Task: <委派的任务文本>"--mode json让子进程以 JSON 事件流输出,父进程据此逐行解析(见下文);-p为打印/非交互模式,--no-session不落会话文件;- 只有当 frontmatter 省略
model时才继承父会话模型与思考等级(--thinking); --tools参数即 frontmatter 白名单的运行时落点。
-
系统提示词走临时文件:reviewer.md 的正文不是拼进命令行的,而是先写入系统临时目录下的
prompt-<代理名>.md(文件权限0o600,经文件变更队列串行写入),再以--append-system-prompt引用(index.ts#L239-L247、index.ts#L334-L339);进程退出后finally块负责清理该临时文件与目录(index.ts#L426-L439)。 -
解析子进程事件流:父进程按行读取 stdout,
message_end事件携带完整消息(累积进messages并更新 usage:input/output/cacheRead/cacheWrite/cost/turns),tool_result_end事件用于把工具结果也纳入消息序列,每次更新都会触发onUpdate向 TUI 推送流式进度(index.ts#L353-L388)。最终输出即取最后一条 assistant 消息的文本(getFinalOutput,index.ts#L170-L180)——这正是 reviewer 按契约输出的那份 Markdown 评审报告。 -
失败判定与错误语义:
isFailedResult把“退出码非 0”“stopReason 为 error 或 aborted”都视为失败(index.ts#L182-L184);单代理模式失败时返回isError: true并附 stderr/错误信息;chain 模式在首个失败步骤处停止并报告失败步号;并行模式则逐任务返回诊断(含子进程提前退出时的 stderr)。中断(Ctrl+C)通过 AbortSignal 对子进程先发 SIGTERM、5 秒后 SIGKILL(index.ts#L410-L420)。 -
并行输出截断:并行模式下每个任务回传给父模型的内容按 50 KB(
PER_TASK_OUTPUT_CAP)截断,完整结果保留在工具详情里(index.ts#L193-L202);并行上限 8 任务、并发 4(MAX_PARALLEL_TASKS/MAX_CONCURRENCY,index.ts#L33-L34)。对 reviewer 这类输出通常不长的评审任务,截断影响很小,但长文件的逐行引用仍建议在提示词中引导它做摘要。
五、安装与调用方式
5.1 安装(软链接示例扩展)
按 README 的 Installation 一节,在仓库根目录执行:
# 链接扩展(必须放在带 index.ts 的子目录中)
mkdir -p ~/.pi/agent/extensions/subagent
ln -sf "$(pwd)/packages/coding-agent/examples/extensions/subagent/index.ts" ~/.pi/agent/extensions/subagent/index.ts
ln -sf "$(pwd)/packages/coding-agent/examples/extensions/subagent/agents.ts" ~/.pi/agent/extensions/subagent/agents.ts
# 链接代理定义(reviewer.md 等)
mkdir -p ~/.pi/agent/agents
for f in packages/coding-agent/examples/extensions/subagent/agents/*.md; do
ln -sf "$(pwd)/$f" ~/.pi/agent/agents/$(basename "$f")
done
# 链接工作流提示词模板
mkdir -p ~/.pi/agent/prompts
for f in packages/coding-agent/examples/extensions/subagent/prompts/*.md; do
ln -sf "$(pwd)/$f" ~/.pi/agent/prompts/$(basename "$f")
done
也可以用同样的 frontmatter 规范在 ~/.pi/agent/agents/(或受信任仓库的 .pi/agents/)下直接放置自己的 reviewer.md,无需改动扩展代码。
5.2 三种调用模式
subagent 工具参数的三种模式(SubagentParams 定义见 index.ts#L442-L469):
| 模式 | 参数形态 | 说明 |
|---|---|---|
| Single | { agent, task } |
一个代理一个任务 |
| Parallel | { tasks: [...] } |
多个任务并发(最多 8 个、并发 4) |
| Chain | { chain: [...] } |
顺序执行,任务文本支持 {previous} 占位符引用上一步输出 |
直接对话式用法示例(来自主模型对 subagent 工具的调用):
Use reviewer to audit the recent changes for security issues
5.3 工作流预设:implement-and-review(reviewer 的典型舞台)
implement-and-review.md 是一个工作流提示词模板,注册为 /implement-and-review 命令,流程为 worker → reviewer → worker:
1. First, use the "worker" agent to implement: $@
2. Then, use the "reviewer" agent to review the implementation from the previous step (use {previous} placeholder)
3. Finally, use the "worker" agent to apply the feedback from the review (use {previous} placeholder)
其正文要求模型用 chain 模式执行,{previous} 由 runSingleAgent 逐步替换为前一步最终输出(index.ts#L554-L556)。在这个流水线里,worker(全能力代理)负责改代码,reviewer 产出结构化评审,第二个 worker 按评审意见修订——三个代理各司其职,而主会话的上下文只承载两次“交接摘要”。同类预设还有 /implement(scout → planner → worker)与 /scout-and-plan(scout → planner),对照见 prompts/。
六、自定义评审代理的要点清单
从 reviewer.md 与扩展源码中可以提炼出编写子代理定义文件的实践清单:
- name + description 必填,description 写给主模型看,是委派决策依据;
- 工具白名单最小化:评审代理去掉 write/edit,仅保留 read/grep/find/ls/bash;
- 对 bash 类高权限工具在提示词中显式收窄(只读命令清单 + “assume tool permissions are not perfectly enforceable” 的自我约束),弥补工具白名单对 shell 的覆盖盲区;
- 指定与任务匹配成本等级的 model,省略则继承父会话模型与思考等级;
- 规定结构化输出模板(固定段落 + “文件:行号”定位),保证链式工作流中
{previous}交接的信息密度; - 策略与工具集自洽:只允许 git 只读命令,策略就围绕变更集展开;
- 放在用户级目录可无条件使用;放项目级目录需调用方传
agentScope: "both"/"project",并注意未信任项目的确认提示。
七、小结
reviewer.md 篇幅不长,却完整呈现了 pi 子代理体系的核心约定:一个 Markdown 文件 = 身份(name/description)+ 能力边界(tools/model)+ 行为契约(正文提示词)。frontmatter 由 agents.ts 解析与容错加载,正文经临时文件以 --append-system-prompt 注入独立 pi 子进程,工具白名单经 --tools 进程级生效,输出经 JSON 事件流回收并按 usage 统计归账。理解并复用这套“声明式代理 + 双层权限约束 + 结构化交接”的模式,是构建 scout/planner/reviewer/worker 这类多角色协作工作流(如 /implement-and-review)的基础。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00