发布时间:2026/7/24 2:38:18
Agent 工程思考:从 ReAct 到 Agent Harness 作者vivo 互联网项目团队- Ding Junjie从 ReAct 出发文章讨论 Agent 工程如何从“模型循环”走向 Harness通过前后端共享的 State Schema、运行事实和 UI 边界让模型行为变成可交互、可恢复、可控制、可追溯的产品能力。1分钟看图掌握核心要点大模型不是马是大脑而且是一颗刚刚觉醒的大脑。一、Agent 不止是 modelloop早期我理解的Agent 工程可以被写成一段伪代码whilenot done: reason act observe用户输入一句话模型思考一下决定调用工具。工具返回结果模型再思考再决定下一步。这也是 ReAct 的基本形态。Thought、Action、Observation 交替出现模型在生成内容的过程中调用工具再把工具结果放回下一步推理。早期Agent概念刚出我做了一个 demo 这个循环完全够用了。命令行里输出 token中间插入 tool call再把 observation 塞回 prompt最后模型给出结论。但最近开始深入去做Agent 产品过程中疯狂调研codex、lobehub、goose、opencode、PI、Flue等优秀Agent产品发现远远不止这段伪代码所表达的。真正的产品还会遇到一组运行时问题用户刷新页面之后刚才的工具审批还在吗工具执行到一半后端进程重启了下一次从哪里恢复子 Agent 在后台跑主线程要显示什么生成了一个 artifact内容本身不塞进上下文那它的引用、状态、归属在哪里用户点了 stop哪些东西应该取消哪些东西应该保留ReAct 不回答这些问题。ReAct 解释的是模型怎么思考和行动。Agent 产品还需要一层工程系统把模型做过的事落成可恢复、可控制、可展示、可验证的软件事实。下面我把这层系统叫做 Agent Harness。二、ReAct 的解释边界ReAct 的最小单元是Thought - Action - Observation这个抽象用来描述模型行为模型先想再行动再观察结果。到了工程系统里单位会换成 event、state、checkpoint、control。同样一次工具调用放在真实的Agent产品工程里大概会拆成这些事件run.started message.created assistant.text.delta tool.call.created tool.approval_required tool.call.running tool.call.completed artifact.created run.finished这里需要先区分 Observation 的身份。在 ReAct 里Observation 是给模型看的。工具返回了什么就把这段结果塞回上下文让模型继续想。这个层面上它当然可以是一段文本。但产品系统不能只停在这里。同一次工具调用用户关心它还在不在跑前端展示关心该不该显示审批按钮存储层关心能不能恢复artifact 面板关心这个结果属于哪次运行。这些消费方需要同一组可以被系统引用的事实。如果 Observation 只剩文本这些事实就没有权威来源。前端展示要从文本猜状态后端要靠临时字段补状态adapter 要把旧数据翻译成新 UI。问题会从运行时边界转移到多处推导逻辑的一致性。所以 ReAct 解释的是执行微循环模型看到什么下一步做什么。它没有定义产品系统里的事实边界哪些事情已经发生哪些状态可以恢复哪些动作可以控制哪些结果可以检查。这里说的 Agent Harness先落在一个具体职责上为 Agent 产品定义事实协议。三、事实从哪里来最近看了很多开源高star的项目会发现他们的整体设计都会解释一件事模型做出的动作怎么变成软件系统里的事实一种做法是让 ReAct loop 原样跑完外面再写一层 UI adapter。它读 message读 observation读 tool result尽量拼出 isBusy、pending-Approval、artifactRefs。这种做法改动小模型继续想工具继续跑前端也能先画出来。问题是这些事实只在事后出现。等 adapter 看到 observation 时审批可能只是一句话artifact 可能只是模型提到过的一个路径stop 也只剩一个按钮状态。系统还可以继续补字段、补判断、补同步逻辑但这些逻辑都在追认已经发生过的事。如果说Agent Harness model 那么Harness中最需要搞清楚的问题绝对不是skill怎么安装mcp怎么加载记忆是如何设计。而是更加工程的底气事实应该在哪里产生。当 tool call 需要审批runtime 应该直接产生 tool.approval_required。当文件或文档被生成runtime 应该写出 artifact.created 和可定位的 ref。用户点 stopcontrol 应该回到对应的 run而不是让组件自己把按钮置灰。所以 Harness 必须在运行路径上。tool call 开始、等待审批、执行完成、生成 artifact、写入 checkpoint这些节点都应该由 runtime 产生 event 和 state。用户的 approve、stop、resume也应该进入 runtime 的 control而不是停在组件自己的状态里。一个 Agent Harness 至少要回答这些问题现在谁在运行 运行卡在哪里 哪个状态可以恢复 哪个动作需要用户审批 哪个结果可以被检查 哪个 artifact 属于哪次运行 哪个子 Agent 是谁派出去的 用户可以发送哪些命令 刷新、重连、进程重启之后系统如何回到同一个现场如果这些问题没有被 Harness 统一回答实现里仍然要找地方放它们前端组件、工具回调、消息渲染、数据库字段、临时缓存或者某个“先这样”的判断。判断标准可以直接写出来同一个运行事实不应该从多个来源拼出来。pendingApproval、artifactRef、canStop 这类状态应该有明确归属。它们要么是 runtime state要么是从 runtime state 派生的 view不应该同时散在 message 文本、工具结果和前端本地状态里。问题到这里下一步就要设计系统怎么记、怎么算、怎么控制。四、从 Loop 到协议一个能产品化的 Agent 系统数据流应该更像这样runtime event - agent.state - agent.view - UI user action - agent.control - runtime event这里有三个词。state 是事实。它应该由 runtime 和明确的业务边界生产。比如messages activeRun checkpoint pendingApproval todos subagents artifactRefs workspaceContext这些状态影响任务能不能继续、能不能恢复、用户能不能检查结果。它们不属于前端展示缓存而属于 Agent 的运行状态。view 是派生。比如isBusy canStop waitingForFirstToken approvalBanner toolBadges subagentGroups messageProjection这些东西应该从 state 算出来。activeRun 存在所以可以显示 busy。pendingApproval 存在所以显示审批条。run 已经开始但第一个 assistant part 还没有出现所以显示 first-token waiting。control 是命令。比如invoke(input, stateSnapshot) resume(approvalDecision) stop(runId) updateState(patch) reload(threadId)control 只负责发命令不顺手改展示状态。用户点批准前端发 resume。审批条什么时候消失取决于 runtime 是否继续执行并写回新的 state。UI 只从新的 state 派生出来。边界在这里runtime 负责写事实UI 负责读事实。Agent Harness 把这条边界固定成协议。五、State Schema 定义事实边界开发一个Agent时不管是work Agent还是业务垂类Agent都应该先设计好state schema 只有这个清晰了Agent产品的定位工程的架构就清晰了。如果先设计 prompt、tool、模型选择最后才整理状态很多运行事实会被迫挂在 message、工具结果或前端缓存上。只要这个 Agent 要进入用户工作流就应该提前问哪些事实必须恢复 哪些事实必须跨端一致 哪些事实只是 view 哪些事实是用户现场 哪些事实可以从 messages 推导 哪些事实必须成为一等状态审批在 UI 上是按钮在 runtime 里是可恢复暂停点。如果模型要执行一个危险命令系统不能只在前端弹一个 modal。因为用户刷新页面之后这个 modal 会丢。后端也不知道自己停在哪里。可以把审批写成 stateagent.state.pendingApproval { id, runId, turnId, toolCallId, toolName, arguments, policy }用户点击批准agent.control.resume({ approvalId, decision: allow })runtime 从 checkpoint 继续继续之后再写回新的 state。前端只消费 state。artifact 的内容本体不一定要进 state。一个文档、一张图、一个大 JSON、一个外部系统连接可能属于文件系统、数据库或对象存储。但 artifact 的引用、状态、归属应该进 stateartifactRef: id type title status ownerRunId createdByToolCallId contentRef这样消息列表、右侧面板、历史记录、恢复流程都能通过同一个引用定位 artifact。内容可以懒加载引用必须是事实。子 Agent 也不应该只出现在文本里。子 Agent 的运行关系也应该进入 state。如果主 Agent 只是输出一句Started subagent abc123前端想画子任务面板就只能从文本里抠 ID。后续要做状态同步、跳转、恢复、错误展示时这个 ID 仍然没有明确归属。子 Agent 至少应该有运行事实subagent: id parentRunId parentTurnId title status startedAt completedAt resultRef error前端再从 subagent state 派生分组、徽标、进度文案、跳转目标。state 的判断标准可以直接写成一句话影响恢复、审批、继续执行、跨端一致、审计和可检查结果的东西应该进入 state。只改变展示方式的东西留在 view。六、UI 只能消费事实不能补写事实UI 可以负责渲染、交互、布局、流式展示和 view state。runtime fact 不属于 UI。pendingApproval、artifactRef、activeRun 这类事实应该由 runtime 写入 state。UI 的位置在 state 下游从 state 派生 view再把 view 渲染成可操作界面。agent.state.pendingApproval - agent.view.approvalBanner - UI: 批准 / 拒绝按钮如果 runtime 没有写入 pendingApprovalUI 不应该从 message 文本创建这个事实message: Need approval to run shell command - UI 判断这句话像审批请求 - UI 本地创建 pendingApproval - UI 显示批准 / 拒绝按钮这条路径的问题很具体刷新之后这个 approval 还在吗后端知道自己停在哪个 tool call 吗用户点批准时前端要把决定发给哪个 run边界规则是runtime 写入 factUI 消费 fact。七、系统要记得发生过什么到这里Harness 的含义可以再落一下。它不是给 UI 多加一层封装而是把 Agent 运行中的关键事实放进系统协议里模型发起了哪个 tool call当前卡在哪个审批哪个 run 产生了 artifact用户的 stop 要终止哪次运行。Agent 的运行不会总是顺着一条完整的同步调用走完。页面会刷新进程会重启工具调用会等待审批用户可能点 stop子 Agent 也可能在另一个执行上下文里结束。这时问题就不是 UI 怎么画而是这些事实有没有稳定归属能不能被恢复、继续和追溯。可以把这个要求写成可检查的行为刷新页面后pendingApproval 仍然存在且指向同一个 toolCall 进程重启后能从 checkpoint resume 到同一个 run/turn 用户 stop 后activeRun 终止且后端不会继续执行后续 tool call artifactRef 存在时内容可被定位、可追溯到 ownerRunId / toolCallId 子 Agent 完成后parent turn 能拿到 resultRef 并展示归属这组检查最后落到同一个问题运行事实有没有明确归属。pendingApproval、artifactRef、activeRun 这些东西必须由 runtime 生成并持久化UI 只能从 state 派生 view不能替系统补事实。所以 ReAct 和 Harness 的分工也会变得清楚ReAct 解释模型怎样一步步决定下一步。Harness 保证这些步骤在软件系统里发生过、能恢复、可控制、可审计。八、最后Agent 产品的难点不止是写出一个会调用工具的循环。那个循环让模型“能动”但用户真正依赖的是系统层面的确定性刷新不丢现场、重启能恢复、该停就停、结果可定位、责任可追溯。这就是 Agent Harness 的价值把一次次“模型行为”落成一组可引用、可恢复、可控制的软件事实。一句话总结ReAct 让模型动起来Harness 让这件事在产品里可被信任。

相关新闻

2026/7/24 2:38:18

论文查重工具评测与AI智能改写技术解析

1. 论文查重工具现状与核心需求解析在学术写作和毕业季高峰期,论文查重服务已成为学生群体的刚需。根据2023年高校学术规范调查报告显示,超过87%的本科生在论文提交前会进行至少3次查重检测。面对市场上数十种查重工具,学生群体普遍面临三个核…

2026/7/24 2:33:18

YOLO26与ACmix注意力机制融合优化目标检测

1. YOLO26与注意力机制融合的背景与价值目标检测领域近年来最显著的突破之一,就是注意力机制与卷积神经网络的深度融合。作为YOLO系列的最新迭代,YOLO26在保持实时检测优势的同时,通过引入ACmix这类混合注意力模块,实现了特征提取…

2026/7/24 2:33:18

5.10华为OD机试真题 新系统 - 美观的灯笼 (JavaPyCC++JsGo)

美观的灯笼 2026 华为OD机试真题 5月10日华为OD上机新系统考试真题 100 分题型 点击查看华为 OD 机试真题完整目录:2026最新华为OD机试新系统卷 双机位C卷 真题题库目录|全覆盖题库 逐点算法考点详解 题目描述 春节将至,工人要在古镇老街…

2026/7/24 4:08:22

基于MSP430与bq电量计的宽输入智能充电器设计实战

1. 项目概述与核心价值在嵌入式电源管理领域,设计一个既智能又可靠的电池充电器,尤其是在宽输入电压范围下,一直是个兼具挑战与价值的课题。传统的充电方案往往依赖于固定的充电曲线或简单的模拟反馈,难以适应电池老化、温度变化等…

2026/7/24 4:08:22

TRF796x RFID读写器芯片:从寄存器配置到直接模式实战详解

1. 项目概述与芯片定位在嵌入式硬件开发领域,尤其是物联网和自动识别应用中,RFID(射频识别)技术因其非接触、快速识别的特性,始终占据着重要地位。而在这个技术栈里,读写器芯片的性能与易用性,直…

2026/7/24 4:08:22

基于PyTorch的中医舌诊AI系统开发实践

1. 项目背景与核心价值舌诊作为中医四诊中的重要环节,通过观察舌质、舌苔的变化来判断人体健康状况已有上千年历史。传统舌诊高度依赖医师经验,存在主观性强、标准化程度低的问题。我在三甲医院实习期间亲眼目睹老中医们为了一张舌象照片的判读争论不休—…

2026/7/24 4:08:22

PPL-Factory:基于任务与预算感知的智能数据选择框架实践

1. 先搞清楚 PPL-Factory 到底解决什么实际问题如果你做过语言模型训练或微调,肯定遇到过数据选择的问题:面对海量候选数据,到底该选哪些、选多少才能让模型在特定任务上表现更好?PPL-Factory 的核心思路是把这个问题拆解成两个关…

2026/7/24 4:08:22

夸克网盘SVIP会员限时福利:365天免费兑换码领取攻略

这次我们来看一个夸克网盘SVIP超级会员的限时福利活动。根据标题信息,7月8日有365天会员兑换码可以免费领取,重点是解决网盘下载不限速的问题。如果你经常需要下载大文件或者备份重要资料,这个活动值得关注。夸克网盘作为常用的云存储服务&am…

2026/7/24 4:03:21

Stable Diffusion参数优化指南:避免AI图像生成的5大陷阱

1. AI图像生成中的关键参数陷阱第一次使用Stable Diffusion生成图片时,我兴奋地输入了"一只会飞的猫"这样的提示词,结果得到的却是一团难以辨认的像素怪物。这个惨痛教训让我意识到,AI图像生成不是简单的文字转图片魔法&#xff0c…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/24 0:03:10

不同品牌斜齿行星减速机如何替换?以PX与PAG系列为例

不同品牌斜齿行星减速机如何替换?以 PX 与 PAG 系列为例 一、系列对应不等于型号直接互换 PX 与 PAG 都属于斜齿、方法兰、输出轴式精密行星减速机,结构形式和应用方向具有对应关系。 原设备使用PX系列时,可以优先从PAG系列中寻找替换型号。但…

2026/7/24 0:03:10

jdk8 把list 扁平化成String 多个以逗号分隔

在 JDK 8 中&#xff0c;将 List 扁平化为以逗号分隔的 String&#xff0c;有几种非常简洁且高效的方法。&#x1f680; 推荐方案&#xff1a;使用 Collectors.joining()这是最标准的 Java 8 写法&#xff0c;适用于 List<String>。javaimport java.util.stream.Collecto…

2026/7/24 0:03:10

java 两个 long id 怎么合并成一个long id 并且不重复

“把两个 Long ID 合并成一个唯一的 Long ID&#xff0c;且保证不重复”这个需求&#xff0c;在 Java 里直接做数学上的“完美合并”是不可能的。因为两个 Long&#xff08;各 64 位&#xff09;要合并成一个 Long&#xff08;64 位&#xff09;&#xff0c;在信息论上是有损压…

2026/7/23 23:42:43

3个高效策略:快速掌握Axure中文界面配置

3个高效策略&#xff1a;快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…