Skip to content
learnspace
Go back

omp 多 Agent 协作:让子 agent 真正并行干活

上一篇讲了 Skill——把工作流固化成可复用知识。但 Skill 解决的是”怎么做”,不是”谁来做”。当任务变复杂,单 agent 会撞到 context window 上限、工具调用串行瓶颈、子任务互相踩文件这些问题。

这就是多 agent 系统要解的题。

用户视角:怎么让多 agent 干活

先讲最实际的——你(用户)怎么触发多 agent

方式一:直接说,让 agent 自己决定

最简单的方式:你只管描述任务,agent 自己判断要不要 spawn 子 agent

你:帮我重构 src/auth/ 目录,同时更新测试和文档。

agent 看到”同时”,会自动 spawn 多个子 agent 并行干活。你不需要关心内部怎么调度。

方式二:显式要求并行

如果你想强调并行,直接说:

你:并行调查 src/auth/、src/api/、src/utils/ 三个目录的结构,然后汇总。

agent 会 spawn 三个 explore agent 并行调查。

八种内置 Agent

omp 内置了 8 种 agent,每种有明确的分工:

Agent干什么能改文件吗用什么模型
task通用任务✅ 能pi/task
explore快速探索代码工具级只读pi/smol
plan架构规划⚠️ 带 bash,靠 prompt 约束pi/slow
designerUI/UX 设计✅ 能pi/designer
reviewer代码审查⚠️ 带 bash,靠 prompt 约束pi/slow
librarian查文档/库⚠️ 带 bash,靠 prompt 约束pi/smol
tester写测试✅ 能pi/task
sonic快速小任务✅ 能pi/smol

关键区别:只有 explore工具层面硬约束只读——它的工具列表里根本没有 editwritebash,物理上无法修改文件。

planreviewerlibrarian 虽然带 bash,但靠 prompt 约束”不主动改文件”。如果你对安全性要求很高,用 explore 最保险。

什么时候用哪个?

实战场景

场景一:大范围重构

需求:把项目里所有 var 改成 const/let

你:把 src/ 目录下所有 .ts 文件里的 var 声明改成 const 或 let,同时更新相关测试。

agent 会:

  1. spawn explore agent 调查哪些文件用了 var
  2. spawn 多个 task agent 并行修改不同子目录
  3. spawn tester agent 更新测试

场景二:新功能开发

需求:给博客加一个评论系统。

你:给博客加评论系统,需要:
1. 后端 API(src/api/comments.ts)
2. 前端组件(src/components/Comments.astro)
3. 数据库 schema(prisma/schema.prisma)
4. 测试
并行开发,最后集成。

agent 会 spawn 多个 task agent 并行开发各部分。

场景三:代码审查

需求:审查最近的改动。

你:审查 src/auth/ 目录的代码质量,找出潜在问题。

agent 会 spawn reviewer agent,它只读代码、报告问题,不会修改任何文件。

场景四:文档研究

需求:查一个第三方库怎么用。

你:查一下 zod 库的 discriminated unions 怎么用,给几个例子。

agent 会 spawn librarian agent 去查文档、搜示例。

场景五:多视角审稿

需求:审查一篇博客文章,从不同角度找问题。

这是多 agent 的高级用法——让多个 agent 从不同视角评估同一份内容,通过分歧暴露盲点

审稿 Prompt(可直接复制使用)

请 spawn 4 个 reviewer agent,从不同角度审阅这篇文章。
文章路径:src/content/posts/xxx.md
tasks:
- id: editor
role: 专业编辑
assignment: |
你是资深编辑,专注于:
- 文章结构是否清晰(引言→正文→结论)
- 段落过渡是否自然
- 语言是否简洁,有没有冗余表达
输出:评分(1-10) + 3个优点 + 3个改进点 + 具体建议
- id: reader
role: 目标读者
assignment: |
你是这篇文章的目标读者,专注于:
- 读完能否理解核心概念
- 能否照着文章实际操作
- 哪些地方看不懂需要更多解释
输出:评分(1-10) + 3个优点 + 3个改进点 + 具体建议
- id: tech
role: 技术审稿人
assignment: |
你是技术专家,专注于:
- 技术概念是否准确
- 代码示例是否正确、可运行
- 术语使用是否一致
输出:评分(1-10) + 3个优点 + 3个改进点 + 具体建议
- id: seo
role: SEO 专家
assignment: |
你专注于内容传播,专注于:
- 标题是否吸引人
- 是否适合搜索引擎和社交分享
- 段落长度是否利于快速浏览
输出:评分(1-10) + 3个优点 + 3个改进点 + 具体建议
最后汇总:
1. 一致认为的问题(必须改)
2. 有分歧的问题(需要判断)
3. 优先级排序

这个模式的核心价值

不是让一个 agent 做所有判断,而是让多个 agent 从不同角度看,通过分歧暴露盲点

例如:

迭代改进

收到审稿结果后,可以让 omp 继续:

你:根据审稿结果,修改文章。优先处理一致认为的问题,
然后处理有分歧但你判断应该改的地方。

这就是多 agent 审稿的完整工作流

  1. 运行多视角审稿 prompt
  2. 查看一致问题和分歧点
  3. 让 omp 根据结果修改
  4. 如果需要,再跑一轮审稿验证改进效果

什么时候用多 agent

这是最重要的问题。多 agent 不是万能的,用错场景反而更慢。

✅ 适合多 agent 的场景

1. 独立子任务,无文件依赖

✅ 重构 auth.ts + 更新测试 + 更新文档
→ 三个 agent 各改各的文件,互不干扰

2. 大范围搜索

✅ "找出所有用了旧 API 的地方"
→ spawn 5 个 explore agent,每个搜一个子目录

3. 探索 + 执行分离

✅ "先调查代码库结构,然后实现功能"
→ explore agent 调查(只读,快速),task agent 执行(可写)

4. 多视角评估

✅ "从安全、性能、可维护性三个角度审查这段代码"
→ spawn 3 个 reviewer agent,不同角色,找分歧

❌ 不适合多 agent 的场景

1. 强依赖的串行任务

❌ "先改接口,再改实现,最后改测试"
→ 后一步依赖前一步,无法并行

2. 小任务

❌ "把这个变量名从 x 改成 count"
→ spawn agent 的开销比直接改还慢

3. 共享状态的任务

❌ "同时改 package.json 的依赖版本"
→ 两个 agent 改同一个文件,必然冲突

内部机制:agent 怎么调度子 agent

如果你好奇内部怎么工作,这里是简化的流程:

用户说"并行做 A、B、C"
主 agent 决定 spawn 子 agent
调用 task 工具,传入:
- agent: "task"(或 "explore" 等)
- assignment: 具体任务描述
omp 创建子 agent 进程
子 agent 独立执行,完成后 yield 结果
主 agent 收到结果,汇总

Batch 调用:一次 spawn 多个

普通调用一次 spawn 一个 agent:

task({ agent: "task", assignment: "重构 auth.ts" })

Batch 调用一次 spawn 多个,共享 context:

task({
agent: "task",
context: "目标:重构 auth 模块,使用 JWT 替代 session。约束:保持 API 兼容。",
tasks: [
{ id: "refactor", role: "Auth 重构专家", assignment: "重构 src/auth.ts" },
{ id: "tests", role: "测试工程师", assignment: "更新 auth 相关测试" },
{ id: "docs", role: "技术文档", assignment: "更新 API 文档" },
],
})

context 是共享背景——所有子 agent 都能看到。每个 task 的 assignment 是具体指令。

隔离执行:避免文件冲突

多个 agent 同时改文件会冲突。omp 的解决方案是 isolation worktree——每个 agent 在独立的工作区里工作,改完再合并。

注意isolated: true 需要先在 settings 里启用隔离模式:

{
"task.isolation.mode": "auto" // 默认是 "none",不启用隔离
}

可选的后端:autoapfsbtrfszfsreflinkoverlayfsprojfs

启用后,可以指定合并策略:

task({ agent: "task", assignment: "重构 auth.ts", isolated: true })

IRC:Agent 间通信

多 agent 运行时,它们之间可以发消息:

# 主 agent 给子 agent 发消息
irc({ op: "send", to: "AuthRefactor", message: "注意保持旧 API 兼容" });
# 子 agent 互相通信
irc({ op: "send", to: "TestWriter", message: "auth.ts 改完了,接口变了" });
# 查看有哪些 agent 可以联系
irc({ op: "list" });

什么时候用 IRC?当子 agent 之间有依赖关系时。比如 agent A 改完了接口,需要通知 agent B 更新测试。

自定义 Agent

内置 agent 够用,但有时你需要专门的 agent。

在项目里创建 .omp/agents/my-agent.md

---
name: my-agent
description: 专门处理数据库迁移的 agent
tools: read, grep, glob, write, edit, bash
spawns: "explore,task"
---
你是数据库迁移专家。
## 规则
- 先分析现有 schema
- 生成 migration 文件
- 更新 ORM 类型定义
- 跑测试验证
## 注意事项
- 不要破坏现有数据
- 生成回滚脚本

然后就能用了:

你:用 my-agent 给 users 表加一个 avatar 字段。

Agent 发现优先级

同名 agent 的优先级:

  1. 项目 .omp/agents/ (最高)
  2. 用户 ~/.omp/agent/agents/
  3. 内置 agent(最低)

你可以在项目里覆盖内置 agent 的行为。

性能陷阱

1. 过度并行

同时 spawn 10 个 agent 看起来很快,但:

2. Context 膨胀

每个子 agent 的输出都会回到主 agent 的 context。如果子 agent 输出很长,主 agent 的 context 会快速膨胀。

omp 的限制:每个子 agent 最大输出 500KB / 5000 行。超出会被截断。

3. 隔离开销

Worktree 隔离有成本:创建 worktree、克隆文件、合并结果。对于小任务,这个开销可能比任务本身还大。

源码视角:关键设计

如果你对实现细节感兴趣,这里是几个关键设计:

工具权限硬约束

packages/coding-agent/src/task/index.ts
export const READ_ONLY_TOOL_NAMES: ReadonlySet<string> = new Set([
"read", "grep", "glob", "web_search", "ast_grep",
"yield", "irc", "ask", "job", "todo",
// ...
]);
export function isReadOnlyAgent(agent: AgentDefinition): boolean {
return !!agent.tools?.length && agent.tools.every(tool => READ_ONLY_TOOL_NAMES.has(tool));
}

explore agent 的 tools 列表只有 read, grep, glob, web_search——全是只读工具。它根本拿不到 edit 工具。

planreviewerlibrarian 的 tools 列表里有 bash,所以 isReadOnlyAgent() 对它们返回 false。

Spawn 策略

// packages/coding-agent/src/task/spawn-policy.ts(简化)
export function resolveSpawnPolicy(parentSpawns): ResolvedSpawnPolicy {
if (parentSpawns === "*") {
return { enabled: true, defaultAgent: "task", allowedAgents: null };
}
const allowedAgents = parentSpawns.split(",").map(s => s.trim());
if (allowedAgents.length === 0) {
return { enabled: false };
}
return { enabled: true, defaultAgent: allowedAgents[0], allowedAgents };
}

agent 定义里的 spawns 字段控制谁能 spawn 谁:

并发控制

packages/coding-agent/src/task/parallel.ts
export async function mapWithConcurrencyLimit<T, R>(
items: T[],
concurrency: number,
fn: (item: T, index: number, signal: AbortSignal) => Promise<R>,
signal?: AbortSignal,
): Promise<ParallelResult<R>> {
const limit = Math.max(1, Math.min(concurrency, items.length));
// worker pool 模式,最多 limit 个并发
// 一个 worker 抛错,立刻取消其他 worker
}

默认并发上限 32。

下一步

多 agent 解决了”谁来做”的问题,但还有一个更深层的问题:agent 怎么记住之前学过什么?

下一篇讲 omp 的记忆系统——MnemoPi。它不只是”历史对话保存”,而是一个基于向量检索的知识库,让 agent 能从过去的经验里学习。


本文是「omp 编程工具使用探讨」专栏第 6 篇。文中的使用示例来自实际项目经验,源码片段来自 oh-my-pi 仓库。


Share this post:

Previous Post
Skill 工程化:从一次性 prompt 到可复用知识