首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >读完「Harness 其实就是控制论」后,我对 Agent 工程的一些思考

读完「Harness 其实就是控制论」后,我对 Agent 工程的一些思考

作者头像
用户1174346
发布2026-07-13 19:36:28
发布2026-07-13 19:36:28
230
举报

模型负责产生可能,Harness 负责决定哪些可能可以发生。

最近一段时间,我一直在做 Agent 相关的开发和系统设计。随着实现逐渐从模型调用、Prompt 和工具接入,走向状态、权限、中断、记忆、并发与恢复,我对「Agent 工程到底在解决什么问题」也有了一些阶段性的感受。恰好最近读到碳基智的《Harness 其实就是控制论》,其中不少观点和开发过程中的思考产生了呼应,于是有了这篇文章。

这不是对 Harness Engineering 的完整定义,也不是一套已经被充分验证的方法论,只是我结合当前开发实践和阅读形成的一些个人理解。其中难免存在不成熟或值得讨论的地方,写下来主要是为了整理自己的思路。

读这篇文章时,我最直接的感受不是「又出现了一个新的 Agent 概念」,反而是松了一口气。过去一年,从 Prompt Engineering 到 Context Engineering,再到 Harness Engineering,Agent 领域的新词几乎按季度出现。每个新词都像是在宣布:之前关注的东西已经过时,又需要重新学习一套方法。

但这篇文章提醒我,名词虽然在变,工程面对的核心问题并没有变:如何让一个内部机制无法被完全解释、行为又不完全确定的系统,稳定地朝着人的目标运行。大模型恰好就是这样一个黑箱。没有人能准确解释某个 Token 为什么在此刻出现,也不能依靠一段足够长的 Prompt,穷尽模型可能发生的所有行为;真正能做的,是控制它看到的信息,限制它可以选择的动作,观察执行结果,并在偏离目标时及时纠正。

从这个角度看,System Prompt、上下文、结构化输出、工具权限、Eval、重试和人工审批,确实可以组成一套反馈控制系统。这个视角也让我重新审视了自己此前对通用 Agent 系统的设计,以及 Blades develop 分支提供的运行能力。最初我关注的仍然是模型能不能理解任务、选择工具、完成规划;但当问题进入状态、权限、中断、记忆、并发和恢复以后,真正困难的部分逐渐从「Agent 能做什么」变成了「谁拥有最终控制权」。

我当前更倾向于这样理解:

生产级 Agent 工程,不是试图消灭模型的不确定性,而是在不确定的智能外面,建立一个确定性的控制系统。

这套系统,就是我目前理解的 Harness。

真正的问题:Agent 系统的控制权在哪里

设计 Agent 系统时,人很容易把主要注意力放在模型身上:Agent 应该有什么人设,Prompt 应该怎么写,应该给它哪些工具,是否需要一个 Orchestrator,多个 Agent 应该怎样协作,模型能不能自己规划并完成任务。这些问题当然重要,但它们主要解决的是「Agent 能不能做」。

生产系统还必须回答另一组问题:Agent 为什么在此刻运行,谁允许它运行,它可以看到哪些信息、提出哪些动作,哪些动作能够真正改变外部状态,用户改变意图后旧任务是否应该继续,运行中断后系统从哪里恢复,Agent 产生的内容哪些可以成为系统事实,以及 Prompt、模型和工具升级后,历史行为还能否解释和复现。

这两组问题的区别,实际上就是智能执行面与确定性控制面的区别。智能执行面负责理解、生成、规划和提出候选动作;确定性控制面负责管理状态、校验权限、执行副作用、记录结果、发现偏差和恢复现场。模型可以说「下一步应该调用这个工具」,但这句话本身不是业务事实,真正的工具调用是否发生,仍然要由模型外部的系统决定。

生产级 Agent:智能执行面与确定性控制面

模型负责提出候选动作;状态机、权限、预算和工具网关决定动作能否真正进入外部系统。

换句话说:

Prompt 描述期望行为,控制面定义允许发生的行为。

Blades 提供的是 Agent 执行内核

带着这个视角再看 Blades develop 分支,很多设计会变得非常清晰。Blades 的核心不是一个庞大的业务编排平台,而是一个事件驱动的 Agent 执行框架。

它定义了统一的 Agent 接口。Agent 接收输入事件流,返回输出事件流;一次运行不只是返回最终文本,还会产生模型增量、完整响应、工具开始、工具结束、Turn 结束、错误和完成等事件。这件事很重要,因为控制一个系统的前提,是系统状态必须能够被观察。

Blades 没有把 Agent 简化成一个黑盒式的「输入文本 → 等待 → 输出文本」,而是把运行过程展开成一条事件流。应用层不必理解模型内部发生了什么,也可以知道模型何时开始输出、调用了什么工具、工具是否失败、一次 Turn 为什么停止,以及本次运行消耗了多少 Token。从控制论的角度看,事件流就是 Harness 的传感器层。

在输入侧,Blades 区分了几类不同的控制信号:Prompt 用于开始一个新的 Turn,Steer 用于在步骤边界注入补充信息或修正,Abort 用于在步骤边界终止当前 Turn。这里需要特别说明:当前的 SteerAbort 主要在模型步骤或工具执行波结束后的边界被消费,并不等于可以在任意时刻立即抢占正在执行的模型流或工具调用。更强的即时中断,还需要 context.Context 取消、应用层运行状态和副作用治理共同完成。

这个细节反而很能说明 Harness Engineering 的特点:「支持打断」不是一个简单的布尔值,而是必须明确打断发生在哪个边界、正在进行的副作用如何处理、运行状态最终落在哪里。

Blades 内部的 Agent Loop 基本遵循「模型—工具—模型」的循环:模型产生工具调用,运行时执行工具,将工具结果写回 Session,然后再次构建上下文并调用模型。如果一次响应包含多个工具调用,当前实现会并发执行这一批 Tool Call。并行能力能够降低延迟,但同时也放大了副作用风险。并发读取多个信息源通常没有问题;如果工具涉及写库、发消息、扣费或修改外部状态,应用层仍然需要处理幂等、依赖顺序、冲突和部分成功。

如果把具体的 Go 实现压缩掉,Blades 的一次 Turn 大致可以写成下面这样:

代码语言:javascript
复制
开始 Turn:
  把用户输入写入 Session

  循环:
    Request  = 根据当前 Session 重新构建上下文
    Response = 调用模型,并持续输出流式事件

    如果模型没有请求工具:
      把 Response 写入 Session
      在步骤边界消费 Steer / Abort
      结束,或者带着 Steer 再运行一步

    如果模型请求了工具:
      发出 ToolStart
      执行这一批 Tool Call
      发出 ToolEnd
      把模型消息和工具结果写入 Session
      在步骤边界消费 Steer / Abort

      如果收到 Abort:结束当前 Turn
      否则:进入下一轮「模型—工具—模型」

结束 Turn:
  输出 StopReason、Usage 和 Action

在这段循环里,事件不只是日志,而是应用控制面的观测入口。AbortSteer 的消费位置也说明了一个重要边界:它们主要在一次模型步骤或一批工具执行完成后生效;如果需要立即取消正在运行的模型或工具,还要结合 Context 取消和应用层状态管理。

在工具真正执行之前,Policy 可以进行允许、拒绝、要求审批或修改参数等判断;Hook 则覆盖 Turn、模型调用和工具调用前后的生命周期,可用于观测、审计和扩展处理。不过,当前代码中的 Ask 仍然主要是一种策略语义:运行时会返回「需要审批」的工具错误,但完整的审批等待、状态持久化、批准后恢复执行,仍然需要应用层补齐。

省略并发调度以后,一次 Tool Call 更接近下面这条受控管道:

代码语言:javascript
复制
执行 Tool Call:
  call = BeforeTool(call)
  decision = Policy.Check(call.tool, call.input)

  如果 decision == Deny:
    返回「策略拒绝」

  如果 decision == Ask:
    返回「需要审批」
    // 当前只表达策略语义,不会自动挂起等待审批

  如果 decision == Modify:
    确认工具身份没有被替换
    使用修改后的参数继续

  如果 decision == Allow:
    result = Tool.Handle(call.input)

  result = AfterTool(call, result)
  发出 ToolEnd(result)
  返回标准化的 Tool Result

Policy 负责决定「能不能做、用什么参数做」,Hook 负责在模型和工具生命周期前后提供观测与扩展点。两者共同构成执行内核里的控制闸门,但完整的审批流、审计持久化和恢复机制,仍然属于应用控制面。

Session、Prompt Builder、Context Builder 和 Compactor 共同决定了每一步模型实际能看到什么。Session 提供消息和状态抽象;每次模型调用之前,Context Builder 都会重新读取消息、构建 System Prompt、加入当前工具集合,并在超过 Token 阈值时执行上下文压缩。这说明上下文并不是一段静态 Prompt,而是一个每一步都可以重新计算的控制面。

Blades 还提供 routing、sequential、parallel、loop 等 Flow,也允许把一个 Agent 包装成另一个 Agent 可以调用的 Tool。这些能力解决了 Agent 的组合问题,让不同 Agent 可以被路由、串联、并行或循环执行,但组合不等于治理。这些 Flow 本身并不天然提供持久化工作流、分布式 lease、业务事务、幂等或故障恢复;Blades 自带的 Session 实现也主要是内存形态,它提供了可以扩展的抽象,但不代表生产级持久化和重放已经自动完成。

因此,我目前更愿意把 Blades 定位为「事件驱动的 Agent 执行内核」:

Blades 在完整 Harness 中的位置

Blades 解决 Agent 如何运行;应用控制面继续补齐状态、权限、版本、持久化、审计和恢复。

Blades 解决 Agent 如何运行;应用系统还要决定为什么运行、是否允许运行,以及运行结果如何成为业务状态。

Orchestrator 也在控制回路之内

在多 Agent 系统里,引入 Orchestrator 是一个很自然的选择。它可以理解当前目标,判断下一步该由哪个 Agent 执行,也可以把复杂任务拆成多个步骤。在 Blades 中,Agent 可以被包装成 Tool,模型还可以在一次响应中提出多个工具调用,这些能力都很适合表达 Agent Loop 和多 Agent 协作。

但我不认为一个 Agent 只要被命名为 Orchestrator,就天然成为了系统最终的控制器。只要 Orchestrator 仍然由 LLM 驱动,它就仍然具有模型固有的不确定性:可能选错 Agent,构造错误参数,重复调用工具,陷入循环,或者在不合适的时机继续执行。

因此,我当前的设计倾向是让 Orchestrator 负责提出结构化动作,例如调用哪个 Agent、调用哪个工具、等待更多输入、结束当前回合,或者将任务移交给其他执行者。这些动作仍然只是候选决策,不能直接等同于业务事实。它们需要经过模型外部的确定性校验:当前状态是否允许、发起者是否有权限、工具是否在授权集合中、参数是否符合 Schema、是否超过步数和成本预算、是否已经执行过、是否需要人工审批,以及失败后能否安全重试。

所以在我目前的理解中,真正的控制器不是某一个 Orchestrator Agent,而是由状态机、运行时、策略系统、工具网关、事件存储和人工审批共同组成的控制面。Orchestrator 提供智能决策,控制面保留最终裁决权。

Orchestrator 动作的安全执行流程

Orchestrator 的输出只是候选动作;状态、权限、参数、幂等和审批共同构成模型外部的确定性控制链。

Agent 最危险的能力,是把错误升级为状态

《Harness 其实就是控制论》讨论了 Agent 为什么会「越跑越蠢」:模型在早期步骤里产生一个错误,这个错误被写回上下文;下一轮模型把它当成事实继续推理,又产生更大的错误。错误不断进入工作记忆,最终形成正反馈。

在实际工程里,错误传播的范围不只限于上下文。它还可能进入长期记忆、用户画像、任务状态、Agent 之间的消息、Orchestrator 的后续计划、工具产生的外部副作用、自动生成的 Few-shot 样本,甚至后续版本的 Prompt。

因此,我当前有一个比较强烈的判断:

Agent 最危险的能力,不是生成错误,而是把错误升级为状态。

错误输出如何升级为系统状态

错误一旦未经校验进入上下文、记忆或任务状态,就可能在后续推理中持续放大;独立校验负责切断这条正反馈链。

模型生成一段不准确的文字,影响可能只停留在当前响应;但如果这段文字未经校验就进入长期记忆、业务数据库或下一个 Agent 的输入,它就从「一次错误输出」变成了「系统事实」。这也是为什么通用 Agent 系统必须区分不同性质的数据:正式消息是可以被用户看到和回放的事实,Agent Event 是运行过程中的可观测记录,Thinking 不应自动成为下一轮事实,Tool Result 是外部工具返回的原始结果,而模型对 Tool Result 的解释仍然只是模型输出。

长期记忆同样不能由聊天 Agent 随意写入。它至少需要经过提取、来源校验、去重、合并和过期治理;运行摘要可以帮助压缩上下文,但不能覆盖权威业务状态。系统恢复时,也不能只读取模型上一次留下的总结,然后让它「接着想」,而应从持久化消息、运行状态、工具结果和版本配置中重新构建上下文。这本质上是在切断错误形成正反馈的传播路径。

把控制论变成可执行的工程规则

控制论提供了理解 Agent 系统的视角,但要进入生产环境,还需要把这个视角转化为可以实现和验证的工程规则。

上下文控制:不是越多越好

上下文越多,不代表控制能力越强。无关信息、过期信息和未经验证的信息,同样会扩大模型的输出空间。上下文工程真正需要解决的是:当前这一次决策,模型应该看到哪些足以完成任务、又不会扩大无关不确定性的信息?

一个通用 Agent 系统至少要区分当前用户输入、最近对话、已确认的业务状态、与当前目标相关的记忆、授权工具、运行预算,以及不同来源信息的可信等级。长期记忆首先是一个写入治理问题,然后才是检索问题;如果写入阶段没有来源、置信度、有效期和权限控制,那么召回做得越好,错误传播得可能越快。

副作用控制:模型调用工具不等于工具应当执行

工具是 Agent 从「生成内容」走向「改变世界」的边界。因此,Tool Call 必须经过权限校验、参数校验、幂等控制、超时控制和审计,高风险动作还需要人工审批或更严格的业务规则。Policy 可以决定一类工具调用是否允许,Hook 可以观察和处理执行过程;但审批等待、分布式幂等、跨工具事务和补偿逻辑,仍然属于应用控制面。

失败控制:每种失败模式都要有对应传感器

Prompt 很难覆盖所有失败模式。模型可能产生幻觉、格式错误、工具越权、重复执行、无限循环、错误记忆和过长输出,也可能在用户意图已经变化以后继续执行旧任务。生产级 Harness 不能只有一条「失败后重新 Prompt」的反馈链,每一种重要失败模式都需要对应的观测信号和控制机制。

失败模式

观测信号

控制机制

结果状态

输出格式错误

Schema 校验失败

修正或有限重试

retryable

工具越权

Policy 拒绝

阻止执行并记录

denied

重复副作用

幂等键冲突

返回既有结果

succeeded

Agent 循环

步数、Token、时间超限

Budget 中止

exhausted

错误记忆

来源或置信度不足

拒绝写入

discarded

并发运行冲突

lease 冲突

等待或放弃本轮

waiting

用户改变意图

新输入或取消信号

中止旧 Run、重新规划

interrupted

失败必须能够被分类。系统要知道它是否可以重试、是否已经产生副作用、是否需要人工介入,以及应该恢复到哪个状态。只有这样,Agent 才真正具备「可恢复」,而不仅是「可以重新运行」。

演化控制:Prompt 也是需要发布的程序

在 Demo 阶段,直接修改 Prompt、模型参数和工具列表,然后重新启动服务,是很自然的做法。但在生产系统里,这些配置共同决定了 Agent 的行为,它们不是普通配置项,而是 Agent 的可执行定义。

因此,我当前倾向于把 Agent 拆成几个不同概念:Identity 表示长期稳定的 Agent 身份;Revision 表示某一版不可变的 Prompt、模型配置、策略和工具绑定;Deployment 表示当前身份正在使用哪个 Revision;Session 则固化实际使用的 Revision。这样做不是为了增加概念,而是为了回答几个基本问题:当前响应由哪一版 Agent 产生,新版本发布后旧会话是否受影响,出现问题后能否回滚,历史会话能否按照当时配置解释和重放,以及两次行为差异究竟来自模型随机性还是配置已经改变。

如果这些问题无法回答,Eval 和 A/B 测试也很难建立可靠结论。Prompt 修改不只是编辑一段字符串,而应当进入版本、发布、灰度、观测和回滚流程。

Demo Agent 与生产级 Agent 的对比

Demo 证明 Agent 能运行;生产系统还要证明它可控、可查、可停、可恢复。

我当前理解的 Harness

读完《Harness 其实就是控制论》,再回看 Blades 和自己对 Agent 系统的设计,我目前觉得:Harness 不是在模型外面随便包一层框架,也不等于 Eval 加重试。它真正做的是重新分配控制权。

模型适合负责理解模糊意图、生成候选方案、选择可能的工具、规划下一步和处理非结构化信息;确定性系统则负责管理状态、构建上下文、分配权限、执行副作用、记录事件、检测偏差、中止运行、控制版本和恢复现场。Blades 提供了事件驱动的 Agent Loop、工具运行时、Policy、Hook、Session、Compactor 和多 Agent Flow,让这些控制点有了统一的执行基础;应用层要做的,是在这些能力之上建立真正的生产控制面。

这可能也是 Agent 工程与传统软件工程一个很明显的差异:传统程序的确定性大多隐含在代码里,而 Agent 的不确定性迫使人把状态、边界、反馈和恢复机制全部显式地设计出来。

所以,我目前的理解是:

模型负责产生可能,Harness 负责决定哪些可能可以发生。

一个 Agent 能调用多少工具、能完成多复杂的任务,当然体现了它的能力;但一个系统能否解释它为什么运行、限制它可以做什么、发现它什么时候错了,并在失败后恢复,才真正决定它能不能进入生产。

Prompt Engineering、Context Engineering 和 Harness Engineering 也并不是彼此淘汰的三代技术。它们更像是视角不断向外扩展:从怎样表达意图,到怎样组织模型看到的信息,再到怎样让不确定的智能稳定地参与真实系统。

新名词还会继续出现,但工程面对的根本问题没有变。Harness 最朴素的含义,也许就是:不是让模型无所不能,而是让它的能力始终处于一个可观察、可约束、可纠偏、可恢复的系统之中。


参考资料

[1]

Harness 其实就是控制论: https://www.xiaohongshu.com/discovery/item/6a0ec5410000000038037228

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 kratos 开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 真正的问题:Agent 系统的控制权在哪里
  • Blades 提供的是 Agent 执行内核
  • Orchestrator 也在控制回路之内
  • Agent 最危险的能力,是把错误升级为状态
  • 把控制论变成可执行的工程规则
    • 上下文控制:不是越多越好
    • 副作用控制:模型调用工具不等于工具应当执行
    • 失败控制:每种失败模式都要有对应传感器
    • 演化控制:Prompt 也是需要发布的程序
  • 我当前理解的 Harness
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档