企业把 Agent 接进生产,真正的阻力往往不在模型能力,而在三件事:它动手之前能不能拦一道人工审批;出了问题之后,能不能说清它当时「看到」了什么才做那个决定;以及这一轮运行有没有满足事先声明的治理要求。市面上的 Agent 框架,要么全自动不设刹车,要么把审批和观测都挂在厂商的云端控制面上——数据要出去,服务也跟着厂商走。OMA(Open Multi-Agent)要解决的就是这个:把这三件事做成运行时内置能力,全部落在你自己的环境里。

一个库,不是一个服务

判断写进第一句:OMA 是一个「库」,不是「平台」——它没有遥测、没有托管控制面,只有 npm 上的一个包和一行 npm create oma-app 的脚手架。

这意味着你的 key、你的模型、你的环境都归你自己。内置的 provider 适配器覆盖 Anthropic、OpenAI、Azure OpenAI、Bedrock、Gemini、Grok、NVIDIA、Copilot,也覆盖 DeepSeek、豆包、混元、MiniMax、MiMo、七牛,本地的 Ollama、vLLM、llama-server 走 baseURL 接。它的三条运行模式分别是:runAgent() 跑单个 agent,runTasks() 执行一条显式的任务流水线,runTeam() 从一个目标出发自动规划。先把最小的一步跑起来:

import { OpenMultiAgent } from '@open-multi-agent/core'

const oma = new OpenMultiAgent({ defaultProvider: 'openai', defaultModel: 'gpt-5.4' })

const team = oma.createTeam('research-team', {
  agents: [
    { name: 'researcher', systemPrompt: 'Find the relevant facts.' },
    { name: 'analyst', systemPrompt: 'Compare evidence and identify tradeoffs.' },
  ],
  sharedMemory: true,
})

const result = await oma.runTeam(team, 'Compare three approaches and recommend one.')

for (const task of result.tasks ?? []) {
  console.log(`[${task.status}] ${task.title} -> ${task.assignee ?? 'unassigned'}`, task.dependsOn)
}

注意这里没有声明任何任务图。runTeam() 里的 coordinator 在运行时把目标拆成带 assignee 和依赖的任务,调度器确定性执行,最后再写答案。coordinator 运行中途不会再被咨询,跑完的结果是能读回的数据。

持久化审批

判断写进第一句:durable approvals 的关键在于「durable」——审批不是一个同步回调,而是一份能跨进程重启延续的执行状态。

OMA 在四个边界上支持审批门:onPlanReady(计划就绪)、onApproval(回合边界)、onTaskDispatch(任务派发前)、onToolCall(工具调用前)。决策的返回值里,true 和 { action: 'allow' } 放行,false 和 { action: 'deny' } 拒绝,{ action: 'suspend' } 表示这个决定必须发生在当前回调生命周期之外——也就是把运行挂起,等人工来批。挂起之后,一个 FileStore 里存着不可变的审批请求和「先到先得」的决策:

import { decideApproval, FileStore, OpenMultiAgent } from '@open-multi-agent/core'

const store = new FileStore('./.oma/release-run.json')
const orchestrator = new OpenMultiAgent({
  onTaskDispatch: async (task) => {
    if (task.priority === 'critical') {
      return { action: 'suspend', reason: 'Critical release review' }
    }
    return true
  },
})

const suspended = await orchestrator.runTasks(team, tasks, { checkpoint: { store } })

if (suspended.status?.code === 'suspended') {
  for (const request of suspended.pendingApprovals ?? []) {
    // 把 request.content 与 request.requestHash 拿给审批人看
    await decideApproval(store, {
      requestId: request.id,
      requestHash: request.requestHash,
      decision: 'approve',
      reviewer: { id: currentUser.id, displayName: currentUser.name },
    })
  }
}

// 换一个新进程,重建同样的团队装配,用同一个 store 继续
const result = await new OpenMultiAgent({ onTaskDispatch: applicationDispatchPolicy })
  .restore(resumedTeam, { checkpoint: { store } })

这里有两个值得注意的设计。第一,审批请求带一个 SHA-256 的 requestHash,由审批范围、边界和待审内容做规范 JSON 哈希算出,审批人必须回传它核对过的这个 hash;hash 变了会报 APPROVAL_STALE_DECISION,并发或重复决策会报 APPROVAL_CONFLICT。第二,框架这一侧只有执行机制和持久化记录,审批 UI、通知、路由这些统统不提供——文档原话是「故意不在上面做一个审批产品」,集成方要自己提供 store、审批界面和恢复路径这三样。

可验证运行日志

判断写进第一句:运行日志(run journal)回答的是一个 checkpoint 和 trace 都答不了的问题——模型当时为什么看到这些内容。

journal 是 append-only 的事件流,默认关闭、开了才有开销。它记录每一轮有哪些消息进入对话、模型实际看到了哪些 block、哪些工具跑了、上下文策略把什么替换成了什么、计划与任务状态怎么流转、checkpoint 落在哪。落盘用 JsonlRunJournal,一个事件一行 JSONL;验证用 verifyRun():

import { verifyRun, JsonlRunJournal } from '@open-multi-agent/core'

const result = await verifyRun(new JsonlRunJournal('./.oma/run.jsonl'))
if (!result.ok) {
  for (const failure of result.failures) console.error(failure.code, failure.detail)
}

verifyRun() 检查三件事:序列单调性、sourceEventSeqs 的引用完整性、以及每个请求 block 的内容哈希能不能被它引用的那个事件「逐字节」复现出来。最后一层是关键——如果某个上下文策略偷偷重写了对话,它照样会「命名」之前的事件,只有要求被命名的事件真的能复现出这块内容,未记录的重写才会暴露。要记住它的边界:这检测的是「漂移」不是「篡改」。journal 没有哈希链、没有签名、没有 WORM 存储,能改写文件的人照样能改事件再重算哈希。它是一条审计线索,不是对抗存储管理员的密码学证据。

治理底线

最后一个能力叫 governance floor:声明必需的角色和它们的执行顺序,跑完之后检查实际运行有没有达标。这里有个反直觉的点,文档特意强调——一次「成功」的 run 仍然可能没有满足治理要求,所以应用必须单独检查结果里的 governanceConclusion,不能拿 run 成功当合规通过。这三样拼起来,就是「组织可以拥有、审批、审计」这三个词各自落地的位置。

踩坑

一是挂起依赖 checkpoint 和带原子 compareAndSet 的 store,进程内测试可以用 InMemoryStore,跨进程审批要么等挂起的写入方退出,要么换一个跨写入方原子的数据库 store。二是 verifyRun() 面向测试、CI 门禁和事后复盘,不是热路径,别把它挂到每次请求上。三是它和遥测(trace)是两条独立的记录,丢 trace 不影响 journal,反之亦然——别指望用一个替代另一个。

值不值得用

如果你的场景是「个人随手跑个 Agent 玩」,OMA 的审批和审计这套对你是过剩的,全自动框架更顺手。它的目标用户是那些要拿 Agent 干正经事、又必须有人签字、必须能复盘的组织——尤其是要求数据不出境、模型自持的团队。代价是要自己搭审批界面和恢复路径,这部分是明确的集成工作量。但对「可审批、可审计」有硬要求的场景,这恰恰是把判断权留在自己手里的那个选择。