PiAgent 系列 7:pi-subagents 工作流编排

上篇介绍了如何自定义 agent 以及 pi-subagents 的三个设计约束:systemPromptMode: replace、子 agent 不能自由嵌套、以及 contact_supervisor 反向通道。这些约束决定了 pi-subagents 的编排风格,多 agent 协作主要靠文件交接,复杂流程由父 session 显式编排。本文在此基础上,介绍两种核心编排模式:Parallel 并行与 Chain 链式,以及工作流的保存、复用、管理和诊断。

Parallel:并行编排

Parallel 是最简单的编排形式:多个 agent 同时跑,互不干扰。

基础并行

/parallel \
  reviewer "审查安全性" \
  -> reviewer "审查性能" \
  -> reviewer "审查可维护性"

三个 reviewer 同时开始,互不干扰。所有结果汇总后一条消息返回主会话。

共享任务

/parallel scout researcher -- 深度分析支付模块

scout 扫代码 + researcher 线上搜,同一个任务,两种角度,并行完成。

差异化配置

/parallel \
  reviewer[model=deepseek-v4-pro,skills=security] "审查安全性" \
  -> reviewer[model=deepseek-v4-flash] "审查代码风格"

同一个 agent 类型,不同模型和技能承担不同子任务。

并行结果的传递

并行步骤的子 agent 结果按以下格式汇总,用分隔线区分:

=== Parallel Task 1 (reviewer) ===
...审查结果...

=== Parallel Task 2 (reviewer) ===
...审查结果...

如果 parallel 是 chain 里的一步,汇总文本会作为整步的 {previous} 传给下一步。

并行适合彼此独立的任务;一旦任务之间存在先后依赖,比如必须先分析、再计划、最后实施,就要用到 Chain。

Chain:流水线与文件协同

Chain 是 pi-subagents 中设计最精巧的部分。同一个 chain 可以用三种形式表达,分别适合临时执行、长期复用和动态生成任务:

方式 格式 适用场景
命令 /chain 一行命令,-> 连接 临时跑,快速试
.chain.md 文件 Markdown,## agent 标题 + 配置行 保存复用,长期维护
.chain.json 文件 JSON,chain 数组 动态扇出(任务数量不固定时)

三种写法都对应同一套执行模型:命令最直观,.chain.md 适合沉淀为可复用的工作流,.chain.json 支持 expand 动态扇出,这是前两种做不到的。

下面先用命令行讲解核心概念,再介绍内联并行组和动态扇出,最后讲保存复用。

为什么用文件而非上下文传递?

由于子 agent 使用 systemPromptMode: replace,它不会主动维护 Pi 的上下文。如果把前一个 agent 的完整输出直接内联进下一个 agent 的 task,上下文会快速膨胀,假设 scout 生成的 context.md 有 4000 token,planner 生成的 plan.md 有 3000 token,每次都内联,到 worker 时前两步输出已经占了 7000 token,很容易撞上上下文墙。

用文件交接的好处:

文件流转示意

scout
  │
  │  输出 → context.md
  ▼
planner
  │
  │  读取 context.md
  │  输出 → plan.md
  ▼
worker
  │
  │  读取 context.md + plan.md
  │  实施
  ▼
reviewer
  │
  │  读取 plan.md
  ▼

这三个文件在链路中的角色:

文件 产出者 消费者 内容
context.md scout, context-builder planner, worker 入口点、核心类型、数据流、风险、外部依赖
plan.md planner worker, reviewer 分步计划、涉及文件、验证方法
progress.md worker(自动维护) reviewer 当前进度:完成了啥、还没做啥、阻塞在哪

基础用法

/chain scout "扫描 auth 模块" -> planner "出方案" -> worker "实施"

每一步默认可以通过 {previous} 拿到上一步的完整输出。但如果上一步产出了文件,更推荐用 reads 显式读取,避免上下文膨胀:

/chain \
  scout[as=ctx,output=ctx.md] "分析 auth 的数据流和入口点" \
  -> planner[reads=ctx.md,as=plan,output=plan.md] "基于 {outputs.ctx} 制定重构计划" \
  -> worker[reads="ctx.md+plan.md"] "按 plan 实施,验证后汇报"

可用变量:

变量 含义
{task} chain 的原始 task
{previous} 上一步(或上次并行组)的完整输出
{outputs.ctx} 名为 ctx 的步骤的输出
{chain_dir} chain 的临时工作目录

内联并行组

Chain 中的一步可以是一个并行组,用 () 包裹,| 分隔:

/chain \
  scout "扫描项目" \
  -> (reviewer "审查安全性" | reviewer "审查性能" | reviewer "审查架构") \
  -> worker "修复所有审查发现的问题"

执行顺序:scout 先跑完 → 三个 reviewer 同时开始 → 全部完成 → 三份审查结果汇总为一步 → worker 拿到汇总结果开始修复。

并行组支持三个选项:

(revA "task1" | revB "task2" | revC "task3")[concurrency=2,failFast,worktree]
选项 效果
concurrency=2 同时最多跑 2 个,第三个排队等待
failFast 任意一个子 agent 失败就立刻停止全组
worktree 每个子 agent 在独立 git worktree 中运行,文件互不污染

worktree 特别适合多个 reviewer 同时做代码改动的场景,正常的并行会互相覆盖文件,worktree 让每个 reviewer 在独立的 worktree 上操作,互不影响。

动态扇出

当任务数量不固定时,比如 scout 发现了 7 个需要重构的文件,用 .chain.json 做数据驱动的扇出:

{
  "name": "dynamic-review",
  "chain": [
    {
      "agent": "scout",
      "task": "找出需要重构的文件,返回 {\"items\":[{\"path\":\"...\",\"reason\":\"...\"}]}",
      "as": "targets"
    },
    {
      "expand": {
        "from": { "output": "targets", "path": "/items" },
        "item": "f",
        "maxItems": 8
      },
      "parallel": {
        "agent": "reviewer",
        "task": "审查 {f.path},重构原因:{f.reason}"
      },
      "collect": { "as": "reviews" },
      "concurrency": 4
    },
    {
      "agent": "worker",
      "task": "综合 {outputs.reviews} 修复所有问题"
    }
  ]
}

scout 返回结构化列表 → expand 按列表项动态生成 N 个 reviewer → collect 收集结果命名为 reviews → worker 合成修复。maxItems 硬限制生成数量,防止任务数量失控。

保存与复用

编排好的链路可以存为 .chain.md,后续一句命令调用,这既是 chain 的第三种表达方式,也是复用工作流的推荐做法。

存放优先级:

优先级 路径
项目(推荐) .pi/chains/*.chain.md
用户 ~/.pi/agent/chains/*.chain.md

每个 ## agent-name 是一个步骤。标题后可以接 config 行:

---
name: review-flow
description: 审查并修复的完整工作流
---

## scout
phase: Context
label: 扫描代码
as: context
output: context.md

分析代码中的 {task}

## planner
phase: Planning
label: 制定计划
reads: context.md
as: plan
output: plan.md

基于 {outputs.context} 制定实施计划

## worker
phase: Implementation
label: 实施
reads: context.md, plan.md

按计划实施 {task}

步骤级字段说明:

字段 说明
phase 步骤分组名(进度展示用)
label 可读的步骤名
as 命名输出,后续 {outputs.name} 引用
output 输出写入的文件
reads 预读文件
model 覆盖模型
skills 覆盖技能
progress 开启进度追踪

执行:

/run-chain review-flow -- 重构用户认证

也支持自然语言:「Run the review chain on this branch.」

编排定义好之后,接下来就是运行时的管理与诊断。

Agent 的管理与诊断

日常使用中有几个命令比较常用:

命令 作用
/subagents-doctor 诊断配置是否正常
/subagents-models [agent] 查看各 agent 当前使用的模型映射
/subagents-fleet 查看所有前台/后台运行中的子 agent
/subagent-cost 汇总父 + 所有子 agent 的 token 和费用

除了命令,也可以用工具调用管理 agent 定义:

# 列出所有可用 agent
Show me the available subagents.

# 禁用某个内置 agent
subagent({ action: "disable", agent: "context-builder" })

# 恢复
subagent({ action: "enable", agent: "context-builder" })

disable/enable 本质上是在 settings.json 写入/删除 agentOverrides 中的 disabled 字段,持久生效。

启动前预览

默认行为是直接启动。如果想先审查要跑的配置再放行,可以加上 clarify: true:

subagent({ agent: "worker", task: "重构 auth", clarify: true })

会弹出 TUI 界面,供你预览和编辑,选模型、调 thinking、改 task、切换前台/后台。Enter 确认执行,Esc 取消。适合第一次跑复杂编排时先确认一遍。

补充能力

除了编排与诊断,pi-subagents 还有两个值得知道的补充能力:给子 agent 注入专属扩展,以及为角色开启持久记忆。

子 Agent 专属扩展

subagentOnlyExtensions 字段允许注册只在子 agent session 里加载的扩展,主 session 不受影响。适合给某个角色注入专属工具而不污染全局:

subagentOnlyExtensions: ./tools/child-only-audit.ts

持久记忆

可以为角色配置独立的持久化记忆文件,子 agent 每次启动时会加载之前积累的角色笔记:

memory:
  scope: project          # project(跟项目走)或 user(跨项目共享)
  path: security-reviewer # 文件名,存储在 agent-memory/ 目录下

项目级存储在 .pi/agent-memory/security-reviewer/MEMORY.md,用户级在 ~/.pi/agent/agent-memory/security-reviewer/MEMORY.md。有写入工具的 agent 会被提示"可以追加记录",只读 agent 只能看到历史记录。

总结

主题 要点
Parallel 多个 agent 同时跑,适合彼此独立的子任务
Chain 多步骤流水线,靠文件交接传递上下文
内联并行组 Chain 中的一步可以是并行组,支持并发数、failFast、worktree
动态扇出 .chain.json + expand 适合任务数量不固定的场景
保存复用 .chain.md 存到项目或用户目录,用 /run-chain 调用
管理诊断 /subagents-doctor、-models、-fleet、-cost
补充能力 subagentOnlyExtensions 与 memory

至此,pi-subagents 的进阶内容就介绍完了:上一篇讲单个 agent 怎么定制和它的底层约束,本篇讲多个 agent 怎么编排、管理和复用。把这两篇结合起来,你就可以根据项目需求定制专属角色,并把它们组装成稳定、可复用的工作流。