首页
/ pi 子代理体系实战:代码评审专员子代理(reviewer)的定义、加载与运行原理

pi 子代理体系实战:代码评审专员子代理(reviewer)的定义、加载与运行原理

2026-09-06 16:55:35作者:田桥桑Industrious

本文以 pi 编码代理仓库中 subagent 示例扩展的 reviewer.md 为核心,完整拆解一个“代码评审专员”子代理的 Markdown 定义文件——frontmatter 各字段如何被解析、系统提示词的约束设计意图,并结合 agents.tsindex.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-L306inheritsDispatchConfig 逻辑)。对比样本中 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);
  • namedescription必填字段:不是字符串的文件会被直接跳过(agents.ts#L90-L92),且单个坏文件不会影响同目录下其他代理的发现——这是刻意的容错设计(源码注释见 agents.ts#L49-L51);
  • frontmatter 之后的整个正文(即本例第 8 行起的提示词)被原样保存为 systemPromptagents.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 diffgit loggit show 这类纯只读命令,并显式禁止改文件、跑构建。这是“硬限制(工具白名单)+ 软约束(提示词)”双层防御的典型案例。

评审策略(三步法)

  1. git diff 查看最近变更(如适用)——先缩小评审范围;
  2. 读取被修改的文件——带着上下文看改动;
  3. 检查 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.tsdiscoverAgentsagents.ts#L128-L147):

位置 加载条件
~/.pi/agent/agents/*.md(用户级) 默认加载(scope 为 userboth
.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 最终都汇聚到 runSingleAgentindex.ts#L272)。以单代理模式 { agent: "reviewer", task: "..." } 为例,运行时的完整流程:

  1. 构建命令行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 白名单的运行时落点。
  2. 系统提示词走临时文件:reviewer.md 的正文不是拼进命令行的,而是先写入系统临时目录下的 prompt-<代理名>.md(文件权限 0o600,经文件变更队列串行写入),再以 --append-system-prompt 引用(index.ts#L239-L247index.ts#L334-L339);进程退出后 finally 块负责清理该临时文件与目录(index.ts#L426-L439)。

  3. 解析子进程事件流:父进程按行读取 stdout,message_end 事件携带完整消息(累积进 messages 并更新 usage:input/output/cacheRead/cacheWrite/cost/turns),tool_result_end 事件用于把工具结果也纳入消息序列,每次更新都会触发 onUpdate 向 TUI 推送流式进度(index.ts#L353-L388)。最终输出即取最后一条 assistant 消息的文本(getFinalOutputindex.ts#L170-L180)——这正是 reviewer 按契约输出的那份 Markdown 评审报告。

  4. 失败判定与错误语义isFailedResult 把“退出码非 0”“stopReason 为 error 或 aborted”都视为失败(index.ts#L182-L184);单代理模式失败时返回 isError: true 并附 stderr/错误信息;chain 模式在首个失败步骤处停止并报告失败步号;并行模式则逐任务返回诊断(含子进程提前退出时的 stderr)。中断(Ctrl+C)通过 AbortSignal 对子进程先发 SIGTERM、5 秒后 SIGKILL(index.ts#L410-L420)。

  5. 并行输出截断:并行模式下每个任务回传给父模型的内容按 50 KB(PER_TASK_OUTPUT_CAP)截断,完整结果保留在工具详情里(index.ts#L193-L202);并行上限 8 任务、并发 4(MAX_PARALLEL_TASKS/MAX_CONCURRENCYindex.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 与扩展源码中可以提炼出编写子代理定义文件的实践清单:

  1. name + description 必填,description 写给主模型看,是委派决策依据;
  2. 工具白名单最小化:评审代理去掉 write/edit,仅保留 read/grep/find/ls/bash;
  3. 对 bash 类高权限工具在提示词中显式收窄(只读命令清单 + “assume tool permissions are not perfectly enforceable” 的自我约束),弥补工具白名单对 shell 的覆盖盲区;
  4. 指定与任务匹配成本等级的 model,省略则继承父会话模型与思考等级;
  5. 规定结构化输出模板(固定段落 + “文件:行号”定位),保证链式工作流中 {previous} 交接的信息密度;
  6. 策略与工具集自洽:只允许 git 只读命令,策略就围绕变更集展开;
  7. 放在用户级目录可无条件使用;放项目级目录需调用方传 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)的基础。

登录后查看全文
热门项目推荐
相关项目推荐