跳转到内容

外部智能体

OMA 可以编排以本地进程运行的外部智能体,与它由 LLM 驱动的智能体并肩工作。内置两种后端类型:

  • process 为每次智能体运行启动一个通用的本地命令,通过 stdin 或参数发送 prompt,并把 stdout/stderr/退出状态映射成一个正常的智能体结果。
  • acp 通过 Agent Client Protocol (ACP) 驱动一个编码智能体——这是一个 JSON-RPC-over-stdio 标准,由 Gemini CLI、Claude Code、Codex 等实现。

外部智能体是一等的团队成员:它处于同一个任务 DAG 中,写入同一份共享内存,向其下游依赖级联失败,并返回与任何 LLM 智能体相同的结果形状。最能说明问题的形态是一个混合团队——一个 LLM 规划器分解目标,一个外部编码智能体编写代码,一个 LLM 审查器审计 diff——全部在一次 runTeam / runTasks 调用中完成。

backend 而非模型来声明一个智能体。团队的其他一切都保持不变:

import { OpenMultiAgent } from '@open-multi-agent/core'
const oma = new OpenMultiAgent({ defaultModel: 'claude-sonnet-4-6', defaultProvider: 'anthropic' })
const team = oma.createTeam('hybrid-dev', {
name: 'hybrid-dev',
agents: [
{ name: 'planner', systemPrompt: 'Break the task into a short plan. Do not write code.' },
{
name: 'coder',
systemPrompt: 'Writes and edits code by running an external coding CLI.',
backend: {
kind: 'process',
command: 'node',
args: ['scripts/code-agent.js'],
cwd: process.cwd(),
},
},
{ name: 'reviewer', systemPrompt: 'Review the change and summarize risks. Do not edit files.' },
],
sharedMemory: true,
})
const result = await oma.runTeam(team, 'Add a slugify() utility with tests, then review it.')

协调器根据 coder 的名册描述把编码工作路由给它;子进程执行文件编辑;reviewer 随后从共享内存读取结果。

一个可运行的 process 版本见 examples/integrations/external-agent-process.ts。 一个可运行的 ACP 版本见 examples/integrations/external-agent-acp.ts

process 后端没有额外依赖。它使用 Node 内置的子进程 API,并启动你所配置的任何本地命令。

ACP 支持需要一个可选的 peer 依赖,它是惰性加载的,因此绝不会影响不使用 ACP 的使用方:

Terminal window
npm install @agentclientprotocol/sdk

你还需要一个支持 ACP 的智能体。设置后端的 command / args 来启动它——任何 ACP 智能体都可以。常见选择:

智能体command / args说明
Claude Codenpx -y @agentclientprotocol/claude-agent-acp官方 Claude Agent SDK 适配器(Claude Code 没有原生 ACP)。通过 ANTHROPIC_API_KEY 认证。
Gemini CLIgemini --acp原生 ACP。注意:据报道 Google 正在停用免费层的 Gemini CLI(及其 --experimental-acp 标志)——依赖它之前请先确认其可用性。
Codexcodex-acp (or codex --experimental-acp)实验性的 ACP 支持。

本指南中的 ACP 示例使用 Claude Code,它契合 OMA 以 Anthropic 为中心的默认配置,且整个团队只需一个密钥(ANTHROPIC_API_KEY)。

AgentConfig.backend 接受一个 ExternalAgentBackendConfig 可辨识联合类型:

字段类型默认值含义
kind'process' | 'acp'后端判别式。
commandstring要启动的可执行文件('npx''gemini'、…)。
argsstring[][]传给 command 的参数。
envRecord<string,string>额外的环境变量,合并覆盖到 process.env 之上。
cwdstringprocess.cwd()子进程的工作目录。
input'stdin' | 'argument' | 'none''stdin'process:如何把 prompt 传给命令。
permission'auto-approve' | 'reject' | fn'auto-approve'acp:如何回应权限提示(见下)。

当设置了 backend 时,LLM 专属的字段(modelprovideradapter、采样、tools、上下文策略)都不适用——外部智能体运行它自己的循环,model 变为可选。智能体的 systemPrompt 是例外:它仍然会塑造外部智能体,因为 OMA——缺少任何 ACP 系统 prompt 字段——会把它前置到智能体的第一个 prompt 之前(每个会话一次),此外还会像对每个智能体那样用它为协调器的路由做引导。

对于 process,OMA 每次运行都启动一个全新的子进程。对于从 stdin 读取 prompt 的命令,使用 input: 'stdin';当命令期望把 prompt 作为最后一个参数时,使用 input: 'argument';对于从文件或环境推导其工作内容的固定适配器,使用 input: 'none'

ACP 智能体会请求客户端批准敏感的工具调用(编辑文件、运行命令)。因为 OMA 在 DAG 内自主运行智能体,默认值是 'auto-approve'(在提供该选项时选择最小权限的 allow_once,否则选择 allow_always)。按需收紧:

backend: {
kind: 'acp',
command: 'npx',
args: ['-y', '@agentclientprotocol/claude-agent-acp'],
// Reject everything…
permission: 'reject',
// …or decide per request.
permission: (req) => req.kind !== 'delete' && !req.title.includes('rm -rf'),
}

该回调收到一个最小化的、与 SDK 无关的 { title, kind, optionKinds },返回 true 表示批准 / false 表示拒绝。

安全。 与 OMA 的文件系统工具沙箱不同,外部后端直接访问 cwd——它们是拥有你的权限的本地子进程。把 cwd 限定在一个你信任该后端的项目里。ACP 后端可以用 permission 来 把关协议层的权限提示;process 后端没有协议级的 权限提示,因此要约束所配置的 command、args、env 和 cwd。

两个内置后端都实现了与 AgentRunner 已经实现的相同的 AgentBackend 接口(run + stream)。因此,池、调度器、任务队列、共享内存和预算聚合都可以像对待 LLM 智能体一样对待外部智能体,无需任何特例。

process 后端为每次运行启动一个全新的子进程。它拼接所配置的 systemPrompt 和用户 prompt,把结果传给命令,并按如下方式映射进程的结果:

进程结果映射为
stdout + 退出码 0成功;stdout 成为 result.output
stderr + 退出码 0成功;stderr 被忽略,除非进程把它写入了 stdout
退出码 / 信号任务失败;stderr 经脱敏处理后包含在错误输出中
调用方中止取消;子进程被杀掉
无 token 信号tokenUsage{0, 0}

对于简单的本地 CLI、脚本,或不需要长生命周期智能体协议的适配器,使用这个后端。

OMA 担任 ACP 客户端角色。在某个智能体的第一次运行时,它启动子进程,把它的 stdio 组织为以换行分隔的 JSON-RPC,执行 initialize,并在 cwd 中打开一个 session/new。随后每次 agent.run(prompt) 发送一个 session/prompt 回合,并将 session/update 通知汇入一个正常的智能体结果:

ACP update / stop映射为
agent_message_chunk (text)流式的 text 增量 + 结果的 output
tool_call / tool_call_updateresult.toolCalls 中的条目
usage_update (used)result.tokenUsage(见下方注意事项)
stop end_turn成功
stop max_tokens / max_turn_requests成功,带 budgetExceeded(提前停止)
stop refusal任务失败(级联到下游依赖)
stop cancelled返回部分输出(来自一次中止)

ACP 报告的是单个上下文 token数字(usage_update.used——“当前在上下文中的 token”),而非输入/输出的拆分,且它在一个会话中是累计的,不是每回合的增量。因为 OMA 在一个智能体的各回合间复用同一个会话,它把每回合的用量记录为自上次读数以来的增量,并存为 tokenUsage.input_tokensoutput_tokens: 0)——这样跨回合求和会收敛到最新的数字,而非重复计数。那个总量会聚合进本次运行并遵守 maxTokenBudget。一个不发出任何 usage_update 的智能体会报告 {0, 0},因此不受预算门控——请按 LLM 智能体来设定预算,或用 ACP 智能体自己的 --max-* 标志来约束它。

大多数用户只会接触 backend。若要直接构造一个后端,从对应的子路径导入:

import { createAcpBackend } from '@open-multi-agent/core/acp'
import { createProcessBackend } from '@open-multi-agent/core/process'
const processBackend = createProcessBackend({ command: 'node', args: ['agent.js'] })
const processResult = await processBackend.run([{ role: 'user', content: [{ type: 'text', text: 'summarize' }] }])
const backend = createAcpBackend({ command: 'npx', args: ['-y', '@agentclientprotocol/claude-agent-acp'] })
const result = await backend.run([{ role: 'user', content: [{ type: 'text', text: 'refactor foo.ts' }] }])
await backend.dispose() // close the connection and kill the subprocess

本次发布尚未做到的(附上真实用例开一个 issue,可推动其中任何一项提前实现):

  • 仅客户端角色。 OMA 驱动外部智能体;它不会把 OMA 智能体作为一个 ACP 智能体暴露给编辑器。
  • 不代理 fs/* 智能体在 cwd 内自行进行文件系统访问;OMA 尚未通过它的沙箱代理 ACP 文件操作。需要客户端来提供文件的智能体不受支持。
  • Process 后端是无状态的。 它每次运行启动一个子进程,并把 stdout 映射为输出。当你需要会话、结构化的工具事件或协议级的权限提示时,使用 ACP 或自定义后端。
  • 没有基于成本的预算。 预算是基于 token 的;usage_update.cost 会被忽略。
  • ACP 子进程的生命周期。 一个被编排的 ACP 智能体的子进程会一直存活到进程退出(runTeam / runTasks 中没有按智能体的销毁钩子)。当你需要显式拆除时,使用编程式 API + dispose()
// 直接联系

把 Open Multi-Agent 用进真实业务

联系框架作者本人,帮你梳理 AI 落地目标、让 AI 真正与业务结合

可提供的工程服务
S-01

AI Agent 定制开发

业务梳理、Agent 设计、Prompt 评估、生产部署、私有化与持续支持。

S-02

多智能体系统集成

多 Agent 架构编排、RAG、CRM / ERP / API 对接、性能与稳定性调优。

S-03

企业 AI 咨询

AI 场景评估、技术选型、POC、ROI 估算与落地路线规划。