Harness 的边界:Agent、Workflow 与承载层的分工

3 分钟阅读
作者 Solazah Team

模型之外的一切工程构成 harness。厘清它与 agent、workflow 的边界,是决定「这个需求该怎么做」的第一步。

这是《Agent Harness 工程》系列的第一章。我们做桌面 agent(Solazah)做了一年, 沉淀下来的体会是:真正耗掉时间的从来不是 agent 本身,而是承载它的那一层。 这个系列讨论的就是那一层。

本章的范围是概念边界:harness 承载什么、不承载什么,以及一个具体需求该用确定性代码、 用 workflow 还是用 agent。

一、三层概念模型

术语先对齐。三个词描述的不是同一维度的事物,混用会让架构讨论失焦。

Agent 指由模型动态决定控制流的系统。Anthropic 在 Building Effective Agents (2024-12-19)给出的分界很清晰:workflow 是「LLM 与工具沿预定义代码路径被编排」的系统, agent 则是「LLM 动态决定自身流程与工具使用」的系统。差别不在于是否调用了模型, 而在于下一步做什么由谁决定

Workflow 指路径预先写定的编排。同一篇文章列举了五种模式:prompt chaining(串行分解)、 routing(分类后分流)、parallelization(分为 sectioning 并行子任务与 voting 多次取信)、 orchestrator-workers(主控拆解后派发)、evaluator-optimizer(生成与评判迭代)。 其中 orchestrator-workers 适用于「无法预判需要哪些子任务」的场景, evaluator-optimizer 则要求存在清晰的评价标准——没有标准,迭代就是空转。

Harness 指模型之外的一切工程。OpenAI 在 2026-02 的 Harness Engineering 中把它立为 prompt → context → harness 的第三阶段;Anthropic 的 Managed Agents(2026-04) 把运行时进一步拆成三层:Session(容器之外的持久事件日志)、Harness(无状态编排)、 Sandbox(隔离的执行环境)。

关键在于第三个词与前两个不在同一层:agent 与 workflow 是控制流的两种形态, harness 是承载这两种形态的工程层。一个系统可以没有 agent,但只要它调用模型完成任务, 就一定有 harness——区别只在于它是被显式设计的,还是散落在各处的胶水代码。

Anthropic 把最小构件称为 Augmented LLM:被检索、工具、记忆增强的模型, 它自行生成查询、选择工具、决定保留什么。这个构件的三项增强——检索、工具、记忆—— 恰好都由 harness 提供。模型负责决策,harness 负责让决策可以被执行。

二、边界一:什么时候才该用 agent

OpenAI 在 A Practical Guide to Building Agents(2025-04)给出三条判据, 满足其一才考虑 agent:

  1. 复杂决策——需要细腻判断与例外处理,规则难以穷举
  2. 难以维护的规则——规则集臃肿到更新代价高且容易出错
  3. 重度依赖非结构化数据——输入本身就需要理解而非匹配

原文同时写明:否则确定性方案可能已经足够。Anthropic 的表述更直接—— agentic 系统「用延迟与成本换取任务表现」,动手之前应当先问, 单次模型调用配合检索与示例是不是已经够用。

这条约束在实践中很容易被跳过。以我们的产品为例,同一个应用里三种形态并存:

命令系统是纯确定性的。用户按下快捷键、输入几个字、回车打开某个应用或某个插件页面—— 这条路径上没有任何模型参与。搜索应用不需要判断力,需要的是索引和排序。 把它做成 agent 只会带来延迟、成本和不确定性,没有任何收益。

智能助理是 agent。用户说「把这个目录里的发票按月份分好,文件名改成日期加金额」, 需要多少步、先读哪个文件、遇到格式异常怎么处理,都无法预先写定。这符合第一条与第三条判据。

定时任务是 workflow 包 agent。触发是确定性的(到点执行),但执行体本身是一个完整的 agent 回合。外层不需要模型,内层需要——这是最常见的组合形态,也最容易被误判为「整体是 agent」。

判据的价值在于:它把「要不要用 agent」从架构偏好变成了对需求性质的判断。

三、边界二:Harness 承载什么

一旦决定用 agent,harness 的职责范围就确定了:模型不做的事,全部由它做。

上下文的组装与调度。模型只看到一个 token 序列,序列里放什么、按什么顺序放、 什么时候压缩、什么时候丢弃,都是 harness 的决策。这是 harness 里最消耗设计精力的一块。

工具的注册与执行。工具定义如何进入请求、调用如何路由到实现、结果如何回到上下文、 失败如何表达。Anthropic 在 Writing effective tools for AI agents(2025-09-11)里 点出这层的特殊性:传统 API 是两个确定性系统之间的契约,而 agent 工具面对的是 会误判、会幻觉、会误解工具用途的调用方,因此软件设计的既有原则需要重写。

循环的终止。Agent Loop 必须有退出条件,OpenAI 列出四种: final-output 工具被调用、模型返回不含工具调用的响应、发生错误、达到最大轮数。 前三种由运行过程自然产生,第四种是产品决策而非技术参数——它回答的是 「这一轮允许跑多久」。我们的实现把这个上限设为 2000 个执行步, 并把它放在前端而非主进程,因为它跟着会话走,将来要做成用户可配置项也在那一层。 主进程只保留同名默认值兜底。撞到上限不是崩溃:已完成的工具调用都已落库,续一轮就能接着做。

状态与恢复。长任务需要在中断后继续,这要求状态可持久化、执行可重放。 这里有一个反直觉的约束:恢复不是从中断点精确续跑,而是重放,因此工作流必须确定且幂等—— 任何有副作用的步骤都会被再执行一次。

验证。Anthropic 的 Claude Agent SDK 把 agent 循环概括为 gather context → take action → verify work → repeat。第三步经常被省略, 而它恰恰是 harness 最该提供的能力——给 agent 一个它自己能跑的检查。

四、三条实施原则

Anthropic 在同一篇文章里给出三条原则,它们约束的都是 harness 而非模型:

Simplicity:保持设计简单。Agent 的每一层抽象都会增加调试成本, 而 agent 的故障本来就难以复现。

Transparency:显式展示规划步骤。用户看不到 agent 在想什么, 就无法在它走偏时介入。用户全程在场的桌面场景里,这一条尤其致命。

ACI(Agent-Computer Interface):像打磨提示词一样打磨工具接口。 具体手法包括给模型足够的 token 思考、让格式贴近模型在训练数据中见过的形态, 以及 poka-yoke 防错设计——用接口约束消除错误的可能性, 比如强制要求绝对路径,而不是在文档里叮嘱模型注意相对路径。

第三条最容易被低估。工具的参数设计、返回结构、错误文案, 决定的不是「模型能不能用对」,而是「模型用错之后能不能自己纠正」。

五、争议:要不要用框架

这是 harness 层唯一仍在争论的大问题,双方都有生产证据。

反对方。Anthropic 建议直接调用模型 API,理由是多数模式只需要几行代码, 而框架「往往引入额外的抽象层,遮蔽底层的提示词与响应」, 如果要用框架,必须理解其底层代码。Octomind 在生产环境使用 LangChain 十二个月后将其移除, 给出的具体痛点是:他们需要按业务逻辑与 agent 状态动态调整可用工具, 而框架不提供在运行中观察或控制 agent 状态的手段。 HumanLayer 的 12-Factor Agents 主张好的 agent「大部分只是软件」, 并强调它是设计与评审清单,不是运行时。

支持方。Harrison Chase 的回应区分了两件被混为一谈的事: 「agent 抽象」与「编排基础设施」。他主张真正的难点是 「确保每一步 LLM 拿到恰当的上下文」,而编排框架解决的正是这个; 多数所谓框架只是一组 agent 抽象,两者不该混淆。

收敛点是:拒绝 agent 抽象,接受编排与持久化基础设施。前者遮蔽你最需要看见的东西 (提示词、消息序列、工具定义),后者提供你不该自己重写的东西(检查点、重放、中断恢复)。

需要提醒的是,2026 年有大量宣称「这场争论已经结束」的文章来自厂商营销页面与内容农场, 其结论与一手材料多处冲突。判断框架选型时,应当回到 Anthropic、Octomind、LangChain 这几方的原文,而不是二手综述。

我们的选择

我们用框架:deepagents,它建立在 LangGraph 之上。

选它的理由只有一条:检查点、状态图、中断恢复这三样自己写不划算。不是写不出来, 而是它们的正确性藏在细节里——恢复是重放而非续跑,因此节点必须幂等; 并行工具调用的回执必须紧跟在发起它的消息之后,否则整条历史作废。 这些约束不会在设计阶段暴露,只会在生产环境里以「每轮请求都 400」的形式出现。

代价是你必须读它的源码

框架为工具调用的完整性提供了一个修复中间件,我们一度以为这道保障是完整的: 它逐个检查 tool_call 有没有对应的回执,缺了就补上一条取消说明。 但看它的判据就会发现,那是一次在后续全部消息里的存在性查找—— 只要能找到对应回执就算通过,中间隔了什么它不关心。

而我们有一个工具在返回时会往消息序列里追加一条图片消息, 于是并行批次里先返回的那个,把后返回的回执挤出了批次。 协议要求回执紧随发起它的消息之后,这样的历史一旦落进检查点, 之后每一轮请求都会被服务端拒绝——而修复中间件全程没有报警, 因为按它的判据,回执确实都在。

这不是框架的缺陷,是抽象的边界:它承诺的是「回执不缺失」,不是「消息序列合法」。 两者的差别只有读过那段实现才知道。同类的地方我们一共改了 12 处,历史上一度到过 17 处。

另一种形态是抽象遮蔽真实状态。框架的自动压缩只在模型档案带有上下文长度时才按比例触发, 否则退到一个固定的兜底值;而那份档案在绑定工具之后往往读不到。 结果是:百万上下文的模型,实际只用到 17%。它不报错、不影响功能, 只是对话比预期更早被压缩——从外部完全看不出来。

所以我们的结论是对收敛点加一个前提:接受编排基础设施的同时, 必须一并接受「要读它的源码、要给它打补丁」这一整套成本。 我们愿意付,是因为自己重写检查点与重放语义的成本更高、且更容易错在看不见的地方。 如果一个团队没有读框架源码的准备,那么 Anthropic 的建议——直接调 API—— 对它来说是更诚实的选择。框架不会因为流行就变得透明, 它只是把你的问题从「实现正确性」换成了「理解别人的正确性」。

六、判定表

把上面的判据合并成一张可以直接套用的表:

需求性质形态理由
路径固定、无需判断确定性代码模型只带来延迟、成本与不确定性
路径固定、单点需要理解单次模型调用不需要循环,也就不需要 agent
路径可枚举、分支有限Workflow五种模式覆盖绝大多数编排需求
需要细腻判断或例外处理Agent规则无法穷举
规则集臃肿到难以维护Agent维护成本已超过不确定性成本
重度依赖非结构化输入Agent输入本身需要理解
触发确定、执行需判断Workflow 包 Agent最常见的组合,外层不必是 agent

表的用法是自上而下匹配第一个成立的行,而不是自下而上寻找用 agent 的理由。

七、本章的结构,哪些会过时

这个系列的每一章都以同一个问题收尾。Anthropic 在 Managed Agents 里有一句值得反复引用的话: 「Harnesses encode assumptions that go stale as models improve.」 Harness 编码的是关于模型能力的假设,而这些假设会随模型进步而失效。

本章的内容里:

会过时的是「何时才该用 agent」的三条判据中的阈值部分。判据本身(复杂决策、 规则难维护、非结构化输入)是关于需求性质的,相对稳定;但「多复杂才算复杂」 会随模型能力持续下移——今天需要精心编排 workflow 的任务,明年可能单个 agent 回合就能完成。

不会过时的是分层本身。只要模型的输出是概率性的、执行是有副作用的, 就永远需要一层工程来承担上下文组装、工具执行、状态持久化与验证。 模型越强,harness 反而越需要把边界划清楚——因为能交给模型的事情越多, harness 里剩下的每一件就越是模型做不了的事。

下一章讨论控制流的承载:ReAct、Reflexion 这些推理范式分别要求 harness 提供什么能力, 以及它们被报告的收益究竟来自哪里。


本文的实践背景是 Solazah —— 一个 AI 驱动的启动器,无限的工具:solazah.com

Solazah Team

Solazah Team

我们在做 Solazah —— 一个 AI 驱动的启动器,无限的工具