PiAgent 系列 6:pi-subagents 自定义子智能体

上篇介绍了 pi-subagents 的概念、8 个内置角色、fork/fresh 机制与模型/技能继承。本文继续深入:如何定制 agent,以及 pi-subagents 为什么要这样设计——理解这些底层约束,是后续编排工作流的前提。

自定义 Agent

内置的 8 个角色已经覆盖了大多数场景,但实际项目中往往要微调:让 reviewer 用更强的模型、给 scout 关掉网络搜索、或者加一个只负责安全审计的专属角色。pi-subagents 提供了两类自定义方式:一类是通过配置项 agentOverrides 覆盖内置 agent 的元数据;另一类是通过 .md 文件创建或覆盖 agent 定义,同名文件会覆盖内置角色,新名字则作为补充角色。

通过配置覆盖:agentOverrides

agentOverrides 是 Pi settings 中 subagents 下的一个配置对象,写在项目 .pi/settings.json 或用户 ~/.pi/agent/settings.json 里。它用来覆盖内置 agent 的元数据,不需要新建 agent 文件。其特点是:不改 prompt,只调模型、thinking、默认上下文等配置。适合快速对齐不同项目的需求。

{
  "subagents": {
    "agentOverrides": {
      "reviewer": { "model": "deepseek-v4-pro", "thinking": "high", "defaultContext": "fork" },
      "scout": { "model": "deepseek-v4-flash" },
      "researcher": { "disabled": true }
    }
  }
}

disabled: true 隐藏不需要的内置 agent。subagents.disableBuiltins: true 一次性禁用所有内置 agent(如果只用自定义角色)。

通过 .md 文件创建或覆盖

在项目或用户目录创建 .md 文件即可定义 agent。如果文件名与内置 agent 同名,就会覆盖内置角色;如果取新名字,就会新增一个补充角色。

项目 .pi/agents/reviewer.md        ← 最高优先级(跟项目走,适合团队统一规范)
用户 ~/.pi/agent/agents/reviewer.md ← 次优先级(个人偏好,跨项目复用)
内置 reviewer.md                   ← 最低优先级

示例——为一个 Web 项目定制审查规则的 reviewer:

---
name: reviewer
description: 我的项目审查员
tools: read, grep, find, ls, bash, edit, write
model: deepseek-v4-pro
thinking: high
systemPromptMode: replace
inheritProjectContext: true
inheritSkills: false
defaultContext: fork
defaultReads: plan.md
skills: security-checklist
---

你是此项目的专属代码审查员。

审查规则:
1. 所有 SQL 必须用参数化查询,不得拼接字符串
2. API 返回格式必须统一为 { code, data, message }
3. 密钥、token、手机号、身份证不得出现在日志中
4. 新增接口必须有入参校验
5. 数据库迁移必须有回滚方案

同名覆盖示例已经展示了一个 Web 项目的专属 reviewer。如果要新增角色,则取一个不与内置 agent 重名的文件,比如 security-auditor.md——只盯安全,不看性能或风格,适合内置角色覆盖不到的垂直职责。

两种机制由浅入深:agentOverrides 适合做轻量参数调整,.md 文件适合做角色重写或新增角色。但无论哪种方式,好的 agent 设计都遵循一些共同规律。

设计一个好 Agent 的几个原则

基于 8 个内置 agent 的设计,可以总结出几条规律:

  1. 系统提示要窄不要宽。 写清楚"你不做什么"比"你能做什么"更重要。planner 明确说"do not make code changes",oracle 明确说"do not silently become a second decision-maker"这些是角色隔离的核心。

  2. 工具集给最少。 如果一个 agent 不需要 edit,就别给 edit。每个多余的工具都是一扇可能被误用的门。

  3. 用 systemPromptMode: replace。 除非有明确的理由(比如 delegate 需要完整 Pi 提示),否则都该用 replace。子 agent 是专注角色,不需要知道 Pi 怎么运作。下一节会深入解释为什么这是角色隔离的基石。

  4. 产出格式要固定。 worker 的输出模板(Implemented X. Changed files: Y…)不是啰嗦,固定格式让主 agent 能稳定解析结果,做出下一步决策。

这些原则的共同目标是把角色边界做实:子 agent 越专注,主 agent 越容易编排。

下面这个速查表汇总了 agent 文件里可用的 Frontmatter 字段,供写自定义 agent 时参考。

Frontmatter 字段速查

字段 说明
name agent 名,同名覆盖内置
description 给 LLM 看的描述
tools 工具白名单。省略则继承全部。subagent 可声明以允许子 agent 内再调子 agent
model 默认模型
fallbackModels 主模型失败时的备用(如配额耗尽、超时、认证失败)
thinking off / minimal / low / medium / high / xhigh / max
systemPromptMode replace(替换 Pi 提示)或 append(追加)
inheritProjectContext 是否继承 AGENTS.md
inheritSkills 是否继承 Pi 技能列表
defaultContext fork 或 fresh
skills 显式指定的技能列表
defaultReads 启动前自动读的文件
defaultProgress 是否维护 progress.md
completionGuard false 可跳过实现完成检查(给只用 bash 的验证类 agent 用)

设计约束

在学编排之前,有必要先把三个底层约束理解清楚,它们决定了你能怎么编排、不能怎么编排,以及为什么 chain 必须靠文件交接。

systemPromptMode: replace——角色隔离的基石

delegate 以外的所有内置 agent 都用 systemPromptMode: replace。子 agent 拿到的是一个完全替换掉 Pi 默认系统提示的 prompt。

它不知道自己在一个叫 Pi 的工具里,不知道 Pi 怎么运作,不知道 Pi 有哪些自定义扩展。它只知道我是 scout/worker/reviewer,我有这些工具可以做这些事。这比其他 agent 框架常见的「追加一条角色指令」要激进得多,换来的是更强的角色边界。

这种隔离直接决定了编排方式:子 agent 拿不到 Pi 主提示,所以不会主动读文件、不会主动建上下文、不会自我纠正偏离的任务,只能靠你给的 task 和文件引用来工作。这就是 Chain 需要显式文件流转、而不是简单把上一步输出塞进下一步提示的根本原因。

由于 replace,子 agent 看不到 Pi 的默认基础系统提示(以及你在其中写的全局规则)。但 AGENTS.md 不受影响——内置 agent 全部设了 inheritProjectContext: true,项目指令仍然会注入。如果需要子 agent 也带上 Pi 基础系统提示,只能用 systemPromptMode: append(只有 delegate 这么干)。

子 Agent 原则上不能再调子 Agent

子 session 的系统提示明确说「你不是父编排者,不能提议或运行子 agent」。默认不注册 subagent 工具。即使某个 agent 显式声明了 tools: subagent,拿到的也是受限版本,只能执行父 agent 分配的扇出任务,不能自由创建 agent。全局默认最多允许 2 层嵌套(主 session → 子 agent → 子子 agent),maxSubagentDepth 可以收紧,但不能放宽。单个 agent 还可以设更紧的 maxSubagentDepth 限制自己的孩子。

设计意图: 避免树状嵌套爆炸。如果允许子 agent 自由建子 agent,一个审查任务可能不知不觉套三层,token 消耗失控。

contact_supervisor:子 Agent 的反向通道

当 worker 在实施中遇到计划没覆盖、但又必须拍板的决策时,它不会猜测,也不会擅自决定——而是通过 contact_supervisor 联系父 session。流程如下:

worker: contact_supervisor(reason="need_decision", message="需要确认:API 返回格式用 snake_case 还是 camelCase?")
主会话回复: 用 camelCase,跟现有风格一致
worker: 收到回复,继续执行

在 Pi 主会话中,你会收到一条 supervisor 消息,确认或回复后 worker 才会继续。

这是一个受控的升级通道。子 agent 的系统提示强调:不要把它当作常规完成汇报的通道,只在被阻塞或需要决策时才用。 reason 有三个选项:need_decision(阻塞性决策)、interview_request(结构化输入)、progress_update(非阻塞更新)。

为什么要先理解这些

这三个约束共同解释了 pi-subagents 的编排风格:

理解了这个设计前提,下一篇就可以放心地进入编排本身:如何并行运行多个 agent,如何用 Chain 串联它们,以及如何保存和复用这些工作流。