大多数团队在搭建生产级 AI Agent 时,都会直接引入 LangChain、LangGraph、CrewAI 或官方 SDK,把 loop、tools、memory 和 orchestration 一次性打包。这不是技术懒惰,而是生态在当时只提供了这种“全家桶”选项。

我起初也认为这很合理——快速验证、统一接口、社区示例丰富。可当系统进入长期运行、多租户、需要严格预算控制和人工审批的阶段后,问题就开始浮现:某个策略引擎不满足合规要求,想换却发现必须 fork 整个框架;审批 UI 死死绑在聊天界面上,想接 Slack 就得改核心代码;预算追踪和 trace 无法打通,只能事后补监控。

这些痛点不是个例,而是框架把 10 多个本应独立演进的职责强行绑定在一起的必然结果。

Harness 真正要做的 15 件事

把生产级 Agent Harness 剥开来看,它必须承担以下职责:

  • 接收客户端的 turn 请求并持久化
  • 为模型提供商解析并注入凭证
  • 查询模型能力(vision、tools、streaming、上下文窗口)
  • 驱动每轮状态机:provision → 流式生成 → 执行工具 → steering → 结束
  • 加载并提供技能定义(请求结构、错误码、使用说明)
  • 组装 system prompt(模式段落 + 身份前言 + 默认技能索引)
  • 将模型生成的 token 实时流回客户端
  • 工具调用前通过策略检查
  • 需要人工决策的调用暂停并路由回正确会话
  • 按 workspace 或 agent 维度追踪 LLM 花费
  • 工具调用前后执行 hook(日志、脱敏、自定义副作用)
  • 将会话持久化为可分支的树结构,支持 fork 与 resume
  • 上下文窗口即将溢出时进行压缩
  • 向 UI 推送事件流
  • 横跨所有步骤的统一 OpenTelemetry trace(很多框架在此缺失)

这些职责本身没有问题。问题出在:现有框架把它们做成了一个不可分割的发布单元。版本升级、策略替换、UI 定制、预算后端切换,任何一处改动都可能牵动全局。久而久之,团队要么忍受妥协,要么推倒重来。

iii 的不同选择:把 Harness 做成一组可替换的 Worker

iii 的核心判断是:Harness 不是一个东西,而是一组必须完成的工作。既然生态没有提供把这些工作优雅组合的 primitive,那就自己造一个。

他们的做法是:把上述职责拆成独立 Worker,所有 Worker 通过同一个引擎总线通信,只依赖一个原语——iii.trigger()。每个 Worker 可以独立发布、独立版本、独立替换,甚至用不同语言编写。

实际生产栈目前包含 11 个 Worker(加上 engine 本身):

  • harness meta(入口与 trace 包装)
  • turn-orchestrator(核心状态机与 prompt 组装)
  • provisioning(sandbox 启动、技能下载、默认 prompt 构建)
  • assistant_streaming(provider 流式调用与 channel 管理)
  • 各 provider worker(如 provider-anthropic、provider-kimi)
  • auth-credentials(凭证解析)
  • policy worker(权限检查)
  • approval-gate(人工审批持久化与唤醒)
  • llm-budget(花费记录)
  • hook-fanout(前后 hook 广播)
  • context-compaction(上下文压缩)
  • models-catalog(模型能力查询)

它们都注册到同一套 function id 和 trigger scope 上。引擎负责路由,Worker 只关心自己注册的那几个函数。

这带来了一个关键属性:替换任意一层不再需要改动其他层

单次 Turn 的真实执行路径

一个完整 turn 的协作顺序大致如下:

  1. 客户端通过 harness::trigger 发起请求,harness meta 负责注入 OpenTelemetry baggage(session_id、message_id),保证整条链路可追踪。
  2. run::start 落到 turn-orchestrator,持久化请求、初始化 TurnStateRecord 并返回。
  3. provisioning 启动 sandbox、下载默认技能、组装 system prompt(模式 + iii 身份前言 + 技能索引)。
  4. assistant_streaming 调用对应 provider worker,后者通过 auth-credentials 取凭证,流式把模型响应写入 channel。
  5. orchestrator 消费 channel,边产生边向 UI 推送 message_update
  6. 模型返回 tool call 后,进入 function_execute。所有调用必须经过 dispatchWithHookconsultBefore
  7. policy worker 在 5 秒超时内返回 allow / deny / needs_approval。
  8. needs_approval 的调用被挂起,等待 approval-gate worker 写入决策后,通过 turn::on_approval 单一 trigger 唤醒。
  9. 批次完成后,steering_check 决定是否继续下一轮,或调用 finishSession() 清理 sandbox 并结束。

整个过程中,任何 Worker 都可以被替换,而 orchestrator 感知不到区别——它只调用约定的 function id。

// 自定义 Policy Worker 示例(逻辑重构后)
import { iii } from '@iii/engine-sdk';

iii.registerFunction('policy::check_permissions', async (call) => {
  // 从 iii state 或外部 OPA/Cedar 加载规则
  const result = await evaluateCustomPolicy(call.function_id, call.args);
  
  return {
    decision: result.decision,      // allow | deny | needs_approval
    rule_id: result.ruleId,
    matched_constraint: result.constraint
  };
});

// 部署后执行:iii worker add your-org/custom-policy
// 引擎会自动把该 function id 路由到最新注册的 Worker

Thin 与 Thick 不再是架构二选一

传统框架把你锁定在某个位置:要么用 Anthropic 的 thin loop,要么用 LangGraph 的厚 DAG。

在 iii 模型里,thin 和 thick 只是你安装了多少 Worker 的区别。

  • Thin:只保留 turn-orchestrator + 一个 provider worker + 基础 auth + 最小 meta。适合内部研究型 Agent。
  • Thick:加上完整 policy、approval-gate、budget、hook-fanout、context-compaction,还可以再接 Slack 审批 Worker。适合面向客户的审计强场景。

切换只需要改 config.yaml 里的 worker 列表,合约(function id + wire schema)保持稳定。甚至 turn-orchestrator 内部把 FSM 从 11 个状态压缩到 7 个,其他 Worker 完全无感知。

这才是真正的“slider”——不是框架给你选好的固定挡位,而是你随时可以加减的连续调节。

从“用框架”到“拥有 primitive”的范式迁移

我后来意识到,框架时代的问题根源在于:它把本应是基础设施层的能力,做成了应用层的一次性选择

当 substrate(iii engine + worker 总线)把 credential、policy、approval、budget、trace 这些横切关注点都变成可独立替换的 Worker 时,“构建自己的 Harness”就从“fork 一个框架”变成了“在总线上多注册几个函数”。

这不是微优化,而是 Agent 基础设施的操作系统级重构。它让长期项目不再被迫在“忍受框架限制”和“全量重写”之间二选一。

如果你正在维护一个已经运行半年以上的 Agent 系统,问问自己:现在想换一个更严格的审批策略,或者把预算控制接进公司 FinOps 平台,代价到底有多大?

把 github.com/iii-hq/workers 克隆下来,关掉一个 Worker 再加一个自定义的,感受一下“替换”真正应该是什么样子。也许你会发现,真正的技术债,从来不是代码量,而是被打包在一起、无法单独演进的那些职责。

我是紫微AI,在做一个「人格操作系统(ZPF)」。后面会持续分享AI Agent和系统实验。感兴趣可以关注,我们下期见。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐