Skip to content

United Workforce:让 AI Agent 像团队一样协作

作者:星月 | 2026-06-06

一句话介绍

United Workforce(uwf) 是一个无状态的工作流引擎,用 YAML 定义角色和路由图,让多个 AI Agent 像一个团队一样分工协作——规划、编码、审查、测试、提交,每一步都是确定性的状态机跳转,而不是一个 Agent 硬扛到底。

为什么需要 uwf?

单 Agent 模式有一个根本问题:当任务复杂到一定程度,一个 Agent 独自做所有事情时,质量会严重下降。 它既要写代码又要审查,既要测试又要部署,最终什么都做不好——就像一个人既当运动员又当裁判。

uwf 的解法是 分工(division of labor)

  • 把一个复杂任务拆成多个角色(Role),每个角色专注做一件事
  • 状态路由图(Graph) 定义角色之间怎么流转——谁做完了交给谁、失败了回退给谁
  • 每个角色由独立的 Agent 进程执行,互相看不到对方的内部状态,只通过结构化的输出(frontmatter)传递数据

这不是什么新思路——软件工程里的 CI/CD pipeline、代码审查流程,本质都是分工。uwf 只是把这个模式变成了 YAML 可定义、CLI 可执行、CAS 可追溯 的基础设施。

核心概念

Workflow:YAML 定义的状态机

一个 Workflow 就是一个 YAML 文件,包含两个核心部分:

角色定义(roles) —— 每个角色有自己的目标、能力、行动步骤和输出格式:

yaml
roles:
  planner:
    description: "分析 issue 并输出测试规格"
    goal: "你是一个规划 Agent,分析 Gitea issue 并产出 TDD 测试规格。"
    capabilities: [issue-analysis, planning]
    procedure: |
      1. 读取 issue 和所有评论
      2. 评估信息是否充分
      3. 产出详细的 TDD 测试规格
    output: "输出测试规格摘要,设置 $status 为 ready 或 insufficient_info。"
    frontmatter:      # JSON Schema —— 结构化输出的合约
      oneOf:
        - properties:
            $status: { const: "ready" }
            plan: { type: string }
          required: [$status, plan]
        - properties:
            $status: { const: "insufficient_info" }
            reason: { type: string }
          required: [$status, reason]

路由图(graph) —— 状态驱动的确定性跳转:

yaml
graph:
  $START:
    new: { role: planner, prompt: "分析 issue 并制定计划。" }
  planner:
    ready: { role: developer, prompt: "实现测试规格(CAS hash: {{{plan}}})。" }
    insufficient_info: { role: "$SUSPEND", prompt: "信息不足:{{{reason}}}" }
  developer:
    done: { role: reviewer, prompt: "审查分支 {{{branch}}} 的代码规范。" }
  reviewer:
    approved: { role: tester, prompt: "运行测试。" }
    rejected: { role: developer, prompt: "修复问题:{{{comments}}}" }
  tester:
    passed: { role: committer, prompt: "提交并推送。" }
    fix_code: { role: developer, prompt: "测试发现问题:{{{report}}}" }
  committer:
    committed: { role: "$END", prompt: "PR 已创建:{{{prUrl}}}" }

路由图里的 {{{field}}} 是 Mustache 模板——上一步的输出字段会自动填进下一步的 prompt。数据在角色之间流动,但每个角色只看到自己需要的信息。

Thread:一次工作流的执行

Thread 是 Workflow 的一次运行实例。它是一条 不可变的 CAS 链(immutable chain)——每一步执行的输入、输出、Agent 会话细节都保存在内容寻址存储(CAS)中,任何一步都可以回溯和 fork。

bash
uwf thread start solve-issue -p "修复登录重定向 bug"   # 创建 thread
uwf thread exec <thread-id>                            # 执行一步
uwf thread exec <thread-id> -c 10                      # 连续执行最多 10 步
uwf thread show <thread-id>                            # 查看状态
uwf step fork <step-hash>                              # 从某一步 fork 出新分支

三阶段引擎循环

每次 uwf thread exec 执行一个完整的循环:

Phase 1: MODERATOR(调度器)
  读取上一步的 $status → 查路由图 → 确定下一个角色
  ⚡ 纯状态机查表,零 LLM 开销

Phase 2: AGENT(执行者)
  启动外部 Agent CLI → 传入上下文和 prompt → Agent 自主完成任务
  🤖 这一步消耗 token

Phase 3: EXTRACT(提取器)
  从 Agent 输出中提取 frontmatter → 校验 JSON Schema → 保存到 CAS
  📋 保证输出结构合规

关键设计决策:Moderator 是确定性的状态机,不是 LLM。 路由逻辑不消耗 token,不会出现幻觉,行为 100% 可预测。LLM 只在 Agent 执行阶段被使用。

Agent Adapter:可插拔的执行后端

uwf 不绑定任何特定的 LLM 或 Agent 框架。Agent 是独立的 CLI 命令,通过标准协议与引擎交互:

Adapter包名后端
uwf-hermes@united-workforce/agent-hermesHermes Agent(ACP 协议)
uwf-builtin@united-workforce/agent-builtin直接调用 OpenAI 兼容 API
uwf-claude-code@united-workforce/agent-claude-codeClaude Code CLI
uwf-sumeru@united-workforce/agent-sumeruSumeru 实例(HTTP/SSE)
uwf-mock@united-workforce/agent-mock固定脚本回放(测试用)

其中 uwf-sumeru 是一个特别的 adapter——它不直接驱动某个 Agent CLI,而是把 prompt 发给一个 Sumeru 实例的 HTTP endpoint,由 Sumeru 统一管理 session 和会话记录。这让 uwf 的执行后端可以是「网络上某个节点的某个 agent」,而不必在本机安装。

你也可以用 @united-workforce/util-agent 提供的 createAgent 工厂快速构建自己的 adapter:

typescript
import { createAgent } from "@united-workforce/util-agent";

const main = createAgent({
  name: "my-agent",
  run: async (ctx) => {
    // ctx 包含 thread 历史、角色定义、edge prompt
    // 调用你的 LLM 后端,返回 frontmatter markdown
    return { output: rawMarkdown, detailHash, sessionId };
  },
  continue: async (sessionId, message, store) => {
    // 当 frontmatter 提取失败时,引擎会用纠正消息重试
    return { output: correctedMarkdown, detailHash, sessionId };
  },
});
main();

CAS:不可变的数据层

所有工件(Workflow 定义、Thread 步骤、Agent 会话细节)都存储在 内容寻址存储(Content-Addressable Store) 中:

  • 每个节点的 ID 是它内容的 XXH64 哈希(Crockford Base32 编码)
  • 数据一旦写入就不可变——天然支持审计追溯
  • Thread 的每一步都是一个 CAS 节点,通过 prev 字段链成一条链
  • 存储在本地文件系统(~/.ocas/),用 ocas CLI 可以直接读取

这意味着你可以精确地回答"这段代码是哪个 Agent 在第几步写的"——每一步的 Agent 输出、模型选择、完整的对话历史都有 hash 可查。

实战示例

示例 1:solve-issue —— TDD 驱动的 Issue 解决

这是我们日常开发中最常用的 workflow,完整实现了 规划 → 编码 → 审查 → 测试 → 提交 的闭环:

$START → planner → developer → reviewer → tester → committer → $END
                      ↑            │          │
                      └── rejected ┘          │
                      ↑                       │
                      └────── fix_code ───────┘
  • planner 读取 Gitea issue,产出 TDD 测试规格
  • developer 在 git worktree 中实现代码(先写测试,再写实现)
  • reviewer 检查代码规范(build、lint、类型检查)
  • tester 运行测试,验证每个场景是否覆盖
  • committer 提交代码、推送分支、创建 PR

如果 reviewer 拒绝,会回退给 developer 修改;如果 tester 发现代码问题,也会回退给 developer。这种循环会自动进行,直到所有关卡通过。

示例 2:debate —— 结构化辩论

两个角色互相反驳,直到一方认输:

yaml
graph:
  $START:
    new: { role: proponent, prompt: "提出你支持该命题的开场论点。" }
  proponent:
    speak: { role: opponent, prompt: "反驳对方论点:{{{argument}}}" }
    conceded: { role: host, prompt: "正方认输:{{{reason}}}。请总结辩论。" }
    final: { role: opponent, prompt: "正方终辩:{{{closing}}}。发表你的终辩。" }
  opponent:
    speak: { role: proponent, prompt: "反驳对方论点:{{{argument}}}" }
    conceded: { role: host, prompt: "反方认输:{{{reason}}}。请总结辩论。" }
    final: { role: host, prompt: "反方终辩:{{{closing}}}。辩论结束,请总结。" }
  host:
    done: { role: "$END", prompt: "总结完成。" }

这个例子展示了 uwf 的循环路由能力——两个角色交替辩论最多 3 轮,任何一方设置 $status: conceded 可提前认输,最终由 host 角色做总结裁决。

示例 3:analyze-topic —— 单角色分析

最简单的 workflow——一个角色,一步完成:

yaml
roles:
  analyst:
    goal: "你是一个研究分析师,擅长将复杂主题拆解为清晰的结构化摘要。"
    procedure: |
      1. 识别主要论题
      2. 列出 3-5 个关键观点
      3. 指出反对意见或注意事项
    frontmatter:
      type: object
      properties:
        $status: { const: "done" }
        thesis: { type: string }
        keyPoints: { type: array, items: { type: string } }
      required: [$status, thesis, keyPoints]
graph:
  $START:
    new: { role: analyst, prompt: "分析主题并产出结构化摘要。" }
  analyst:
    done: { role: "$END", prompt: "分析完成。" }

架构全景

packages/
├── protocol/          # 共享类型定义(WorkflowPayload、StepNodePayload 等)
├── util/              # 基础工具(Crockford Base32、ULID、日志、frontmatter 解析)
├── util-agent/        # Agent 框架(createAgent 工厂、上下文构建、提取管线)
├── agent-hermes/      # uwf-hermes CLI(Hermes Agent 适配器)
├── agent-builtin/     # uwf-builtin CLI(内置 LLM + 工具适配器)
├── agent-claude-code/ # uwf-claude-code CLI(Claude Code 适配器)
├── agent-sumeru/      # uwf-sumeru CLI(Sumeru 实例适配器,走 HTTP/SSE)
├── agent-mock/        # uwf-mock CLI(固定脚本回放,测试用)
├── eval/              # uwf-eval CLI(workflow 评测工具)
├── cli/               # uwf CLI(线程生命周期、工作流注册、状态机 Moderator)
└── dashboard/         # Web 可视化面板(私有,未发布)

依赖分层严格遵循 protocol → util → util-agent → agent/cli 的方向,下层不依赖上层。

快速开始

bash
# 安装
npm install -g @united-workforce/cli
npm install -g @united-workforce/agent-hermes  # 或 agent-builtin / agent-claude-code

# 配置
uwf setup --provider openrouter --api-key sk-or-xxx \
          --model anthropic/claude-sonnet-4 --agent uwf-hermes

# 运行
uwf thread start examples/solve-issue.yaml -p "修复登录重定向 bug"
uwf thread exec <thread-id> -c 10

设计哲学

uwf 的设计遵循几个核心原则:

  1. 无守护进程(No Daemon) —— 没有长运行的服务端。每次 uwf thread exec 是一个独立进程,跑完就退出。状态全在磁盘上(CAS + SQLite),用普通的 CLI 工具就能调试和检查。

  2. 确定性调度 + 非确定性执行 —— Moderator 是纯状态机(零 token 开销,100% 可预测),LLM 只在 Agent 阶段出场。这避免了"用 AI 调度 AI"的混乱。

  3. Schema 即合约 —— 每个角色的输出必须符合 JSON Schema。这是 Agent 和下游角色之间的类型化合约——不是可选的"建议格式",而是硬性校验。如果 Agent 输出不合规,引擎会自动用纠正消息让 Agent 重试。

  4. 内容寻址存储 —— 所有数据不可变、有 hash、可追溯。Thread 的每一步都是一个 CAS 节点。你可以从任意一步 fork 出新分支,也可以精确定位"这个 PR 是哪个 Agent、用哪个模型、在第几步生成的"。

  5. Agent 不可知(Agent Agnostic) —— 引擎不关心你用什么 Agent。Hermes、Claude Code、自研工具,只要能产出 frontmatter markdown,都能接入。

相关链接

Shazhou Studio