跳转到正文

多 Agent 分工 ​

完整场景为版本发布准备度评审:目标拆分 → Agent 分工 → 并行或串行分析 → 收集结果 → 汇总。流程读取实际资料文件,保存版本化的专职 Agent 结果,并生成带依据的评审报告。评审任务完成不等于版本可以发布;本例不执行发布操作。

可运行调用 ​

复制 examples/patterns/multi-agent、examples/_shared/tools/multi-agent、examples/_shared/tools/storage、examples/_shared/tools/evidence.ts 与 examples/_shared/tools/execution/files.ts 到消费者项目,安装 Core tarball 和 storage/dependencies/package.json 指定的 Redis 依赖。使用 Node 24、ditto.yaml、模型凭证和真实 Redis(DITTO_WORKER_CONTEXT_REDIS_URL)。

ts
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { loadRuntimeConfigFile } from "@codesoul-co/ditto/runtime";
import { createDemo } from "./examples/_shared/tools/multi-agent/adapters.ts";
import { openMultiAgent } from "./examples/patterns/multi-agent/cli.ts";
import { runMultiAgent } from "./examples/patterns/multi-agent/index.ts";

const config = loadRuntimeConfigFile("ditto.yaml", process.env);
const provider =
  process.env.EXAMPLE_MULTI_AGENT_PROVIDER ?? config.model?.provider;
if (!provider || !config.providers[provider])
  throw new Error("Configure provider");
const model = config.providers[provider].model ?? config.model?.model;
if (!model) throw new Error("Configure model");
const directory = await mkdtemp(join(tmpdir(), "ditto-team-example-"));
try {
  const request = await createDemo(directory, { mode: "parallel" });
  const app = await openMultiAgent(directory, request, config);
  try {
    const result = await runMultiAgent(app.runtime, {
      request,
      model: { provider, model },
      // Optional models: { engineering: { provider, model }, ... }
      // Keys: planner, engineering, operations, synthesis.
    });
    console.log(JSON.stringify(result));
  } finally {
    await app.close();
  }
} finally {
  // Use a persistent directory and omit cleanup to retain the report.
  await rm(directory, { recursive: true, force: true });
}

Agent 与流程组装 ​

mermaid
flowchart TD
  L[Main Loop: request and durable budgets] --> P[Planner Agent: decomposition]
  P --> V[Validate agents and dependencies]
  V --> E[Engineering Agent: scoped evidence and Context]
  V --> O[Operations Agent: scoped evidence and Context]
  E --> SE[Persist and validate engineering handoff]
  O --> SO[Persist and validate operations handoff]
  SE --> J[Collect verified results and failures]
  SO --> J
  J --> S[Synthesis Agent]
  S --> C[Check coverage, lineage and readiness]
  C --> R[Publish actual review report]

runMultiAgent(runtime,input,options) 只调用一次 runtime.loop(runMultiAgentLoop, ...)。主 Loop 通过 graphStep 组合阶段 Graph;Graph 只包含公开 Worker 节点,不嵌套子图、不直接执行 Worker、不在外部串联多个 runtime.run。应用侧 Agent 具有职责、任务、限定工具/资料、独立 Context 和可配置模型,共享 Runtime 基础设施,并非独立操作系统进程或独立认证主体。无需增加 Core 私有接口。

Agent职责输入和可用资料
planner拆分三项可执行任务并确定依赖目标、执行模式和固定 Agent 注册表,不读取原始业务资料
engineering分析测试与严重缺陷team_read_engineering、工程事实、独立 Redis scope
operations分析回滚与值班准备team_read_operations、运维事实;串行时接收显式工程交接结果
synthesis汇总并保留阻塞项和缺口经校验且具有内容摘要 ID 的结果,不直接读取原始资料

规划 Agent 在限定注册表内生成任务目标,不任意创建 Agent。校验要求工程、运维、汇总各出现一次,且只能使用批准的依赖关系;未知 Agent、重复 ID、循环和意外依赖都会在执行前停止。并行模式下工程和运维互不依赖,实际模型请求同时执行,Runtime 与 Infer 并发均配置为 4。串行模式下运维依赖工程成功结果,接收其完整交接。两种模式都先收集结果再汇总;前置任务失败时后续依赖标记 blocked,独立成功结果仍保留。

Input.model 为默认模型,Input.models 可按 planner、engineering、operations、synthesis 配置已注册模型。真实验收使用同一 provider/model 的独立调用,并验证按角色显式配置的路径,不声称已经完成跨供应商验收。改变模型配置不会重新执行已保存的阶段。

阶段公开节点 / API契约
加载与恢复MEMORY.GET、CONTEXT.LOAD、INTERACTION.ACT.TOOL任务身份、权限和来源摘要
拆分 / 汇总CONTEXT.LOAD → INFER.REASONING.SAMPLE校验后的计划 / 绑定结果的汇总
限定资料INTERACTION.ACT.TOOL每个专职 Agent 使用固定读取工具,不接受任意路径或其他角色参数
专职执行分支CONTEXT.LOAD → INFER.REASONING.SAMPLE → MEMORY.WRITE独立上下文,每个分支在汇合前保存自己的模型结果
校验与收集Interaction 调用 team_save、team_result角色、任务、版本、准备度、精确引用及依赖结果 ID
交付team_publish 与 Memory 写入核验结果、覆盖范围和缺口,写入真实报告

依据与隔离 ​

默认资料为 50 项测试中 48 项通过、0 个严重缺陷,回滚和值班均就绪。因此工程结果必须为 blocked,运维为 ready,汇总不得抹去阻塞项。--ready 提供 50/50 测试通过的资料,最终为 ready。每份专职结果必须完整引用本角色两项事实的原文;适配器确定性校验分类与引文。汇总必须引用每份结果的准确摘要 ID,各 Agent 不重复,并列出全部缺失角色;有缺失则为 incomplete,无缺失但存在阻塞则为 blocked。

Context scope 包含租户、身份、任务和 Agent。模型只接收当前 working-set 消息,不注入另一角色的原始资料;串行交接会明确披露已验证的工程结果给运维 Agent。模型使用 INFER.REASONING.SAMPLE,不进行不受限的自主工具调用;可信控制器根据已验证计划绑定允许的工具。这是应用资料边界,不是操作系统隔离,也不用于隔离不可信插件。Memory 使用任务命名空间下的角色/尝试键,协调者可读取全部结果完成汇总。

请求、任务描述和资料均作为数据处理。确定性检查证明对象范围、结构化结论、原文引用和交接关系;自然语言解释仍是模型判断,结构校验不能证明每句话都正确。适配器和业务资料放在 _shared/tools/multi-agent,不向 Core 添加领域依赖。

失败、持久化与预算 ​

专职模型失败或结果无效时保存尝试,并按 maxAgentAttempts(1–3)重试,下一次输入包含之前的错误码。成功 Agent 不因其他 Agent 失败而重跑。重试耗尽后明确保留失败;有至少一个成功结果且预算允许时,继续汇总并列出缺失项。无效计划返回 needs-human;无效汇总保留专职结果但不形成已接受的综合结论。存储和权限故障显式抛出,不伪装成业务结果。

maxModelCalls(1–10)由规划、专职、重试和汇总共享;调用前先保存预算,并行分发前统一预留。进程终止可能消耗额度但未保存结果,每个并行分支独立的 Memory 保存节点可保留已完成部分。deadlineSeconds(1–3600)包含暂停时间,在新增模型调用前检查,不是强制终止正在运行请求的超时;Options.signal 用于取消执行。主 Loop 每次调用还受 1024 个 Graph 的上限约束。

Context 使用真实 Redis,缺失或过期时从持久样本及任务数据重建所需上下文;Redis/Memory 不可用时显式失败,不退化到内存。Memory 使用 memory.sqlite,业务输入和产物是独立文件。本例验证 SQLite,不代表已经验证 PostgreSQL/MySQL;其他存储通过公开 Memory 适配器接入。

stopAfter: "plan" | "specialists" | "report" 返回检查点。以同一目录和请求重新进入、移除 stopAfter 即可继续,每个目录只运行一个 Agent 执行者。completed、partial、needs-human 报告是终态快照;重放时验证保存产物,不新增模型调用。修改任务、资料或预算需要新任务。发布冲突不覆盖原文件,解决冲突后可重试;交接和交付前核验结果摘要,来源或结果变化显式失败。

产物包括 request.json、sources.json、policy.json、memory.sqlite、results/<hash>.json、output/report.json 和 output/report.md。Markdown 展示准备度、失败/缺失 Agent 和原文依据,JSON 保留计划、尝试、错误、交接 ID、汇总和预算。流程不进行生产部署、发信或外部系统写入。本地策略是可信控制器接入示例,不是身份认证;部署时保护目录并从认证会话注入身份。

运行与验收 ​

sh
export DITTO_WORKER_CONTEXT_REDIS_URL=redis://127.0.0.1:6379
npm run example:multi-agent -- --provider deepseek --mode parallel
npm run example:multi-agent -- --provider deepseek --mode serial
npm run example:multi-agent -- --provider deepseek --ready
npm run example:multi-agent -- --provider deepseek --stop-after specialists
npm run example:multi-agent -- --provider deepseek --directory .examples-multi-agent-tasks/cli-XXXXXX
npm run check:examples:multi-agent:package -- --provider deepseek

包验收在仓库外安装真实 npm tarball,以无路径别名的严格类型配置执行,阻断源码/私有导入,检查静默导入并运行上述文档调用。任务验收核对实际模型调用重叠与串行顺序、限定提示输入、交接关系、实际报告、重试/部分失败、无效计划/角色/引用、预算、Redis 过期/故障、Memory 故障、篡改、取消、进程终止及发布重试。模型输出替换明确标记为故障注入,正常场景使用未修改的真实模型输出。

Ditto · @codesoul-co/ditto · Node.js 24+