Agent工程三层架构:Harness、Loop与Graph生产实战解析 先说个事去年我接了一个内部的Agent项目需求听起来特别简单“让AI自动把工单分类、答复、升级。”原型一周就跑通了但真到了上线阶段麻烦全冒出来了模型偶尔不按约定输出、某个工具插件一崩整个进程直接挂掉、多条件分支越堆越乱、并发一高内存里的状态互相污染。折腾了三个月我最大的收获不是“调prompt”而是把Agent拆成了三层来设计——Harness、Loop、Graph。这篇文章不是教科书式的概念解释而是我在这三层架构里的真实设计取舍、生产实战和踩坑记录希望给正在从Demo往生产冲的团队一点参考。这三个词怎么理解Harness是模型与外部世界之间的“承载层”负责工具接入、插件管理、权限和日志Loop是Agent自己的思考与执行闭环负责“推理、行动、观察”的循环Graph则是把零散步骤编排成生产级流程的“导航图”负责任务分支、并行、人工审核和状态流转。它们不是互相替代的关系而是从内核到外围层层嵌套。今天我会把每一层为什么存在、怎么设计、生产里容易踩哪些坑全部讲清楚。1. 为什么 Agent 工程需要三层架构1.1 从 Demo 到生产之间到底缺了什么很多团队做Agent的第一步是拿一个大模型API把工具函数列表塞进Prompt里让模型自己决定调用。Demo阶段确实够用因为数据量小、使用者少、失败可以重来。但一旦要接真实业务问题的密度会瞬间上来。工具调用没有强校验模型传错参数下游系统直接收到脏数据权限边界模糊一个带有“删除”能力的接口暴露给模型稍有不慎就是生产事故所有状态堆在进程内存里多轮对话一多上下文互相污染没有全链路日志出了故障只能靠聊天记录去猜更别提并发场景下的资源竞争和限流问题。本质上模型只是一个“路由决策器”它负责判断下一步做什么但模型本身不负责工具执行、状态存储、安全管控和错误恢复。这些能力必须由外部系统来提供。这个外部系统就是工程化要补的课也是三层架构出现的原因。把Harness、Loop、Graph想清楚等于把Agent从“玩具脚本”升级成“可运维服务”。1.2 Harness、Loop、Graph 怎么分工在早期我也混淆过这几个层次。LangGraph到底是不是替代LangChainAgent和Loop是不是一回事后来我自己总结了一张表层核心职责典型问题Harness承载运行环境工具注册、插件、上下文、安全、可观测性模型如何安全地使用外部工具日志和权限在哪做Loop决策闭环推理、行动、观察、记忆更新、终止判断Agent如何持续自主执行一个多步任务Graph流程编排节点、条件分支、并行、人工审批多Agent、多步骤任务如何被编排成可运维的流程打一个比方Graph是地图Loop是引擎Harness是车身和安全带。地图规划路径引擎持续驱动车身提供接口和防护。地图不负责烧油引擎不负责转弯车身不负责决定去哪但一辆能跑长途的车三个部分缺一不可。这个递进关系特别重要Graph的每个节点里往往运行着一个LoopLoop每一步工具调用最终都要落到Harness管理的插件上。所以三层是嵌套的不是平行的。2. Harness让模型与外部世界安全对接的承载层2.1 Harness 的本质模型是大脑Harness 是身体“Harness”这个词的直译是“马具、缰绳”放在Agent工程里非常形象。大模型本身只负责概率计算它原生不具备调用外部API、读取数据库、执行代码、操作文件的能力这些动作都需要通过工具来“授权”。Harness就是那个管理“授权”和“执行”的中间层。最近开源社区涌现了一批名字里带Harness的项目比如DeepSeek Harness、Harness Anything、Hermes Agent虽然形态各不相同但做的事情高度相似把模型接入可插拔的工具环境配好技能插件、上下文管理和外部服务连接对外暴露稳定接口。这个现象背后的信号是行业已经意识到光有强大的模型远远不够Agent产品真正需要的是工程化封装。没有Hands再聪明的大脑也只是纸上谈兵。Harness就是那双“手”同时还要兜住出错的风险。2.2 Harness 核心能力清单我在设计Harness时通常会按五个维度验收工具注册与契约校验。每个工具必须声明输入输出JSON Schema模型发起调用前先做参数校验参数错误直接把校验结果返回给模型让模型自己修正而不是把错误参数发到下游服务。插件隔离与生命周期管理。插件要能独立加载、独立失败、独立更新。插件加载失败不应该拖垮主进程更不应该让整个服务重启。这一条看起来基础但很多框架默认都没有做好。上下文与状态持久化。Harness需要提供“工作记忆”的存储接口比如session state、conversation_id对应的中间结果要能落到Redis或PostgreSQL而不是全塞在进程内存里。安全沙箱和权限控制。任何能执行代码的工具必须跑在隔离环境里对外部API的访问要有凭证管理和资源配额防止模型把密钥泄露给用户也防止某个工具把资源耗尽。可观测性。每次模型调用、工具调用、状态变更都要输出结构化日志并且携带同一个trace_id方便后续链路分析。2.3 生产级 Harness 落地要避开的坑插件系统最容易翻车的点是路径解析和依赖隔离。我们曾经遇到过“harness failed to load plugins”的问题查了一整天最后发现是容器挂载目录和插件默认目录错位了。建议不要靠自动扫描目录找插件而是用“显式插件清单启动完整性校验”。比如一个插件清单文件里面写明每个插件的入口路径和版本号启动时逐个加载并打印日志。这样哪个插件没加载、哪个版本不对一看日志就知道。上下文管理也是重灾区。很多Harness会把全部历史消息不加区分地塞给模型真实业务里一个用户会话可能跨越好几个小时历史记录上万字不截断、不摘要模型性能会急剧下降。后来我们加了一个上下文管理层按照“窗口滑动核心信息摘要引用来源压缩”来做每一轮发给模型的上下文都会经过裁剪。我自己的最大教训是Harness层千万不要和业务逻辑耦合。有一段时间我们图省事把很多业务helper函数直接塞进Harness结果工具命名空间越来越乱模型经常调错函数。后来把Harness收敛成纯基础设施层只暴露通用能力业务逻辑全部放到Graph节点和Loop的Prompt策略里混乱局面才控制住。3. LoopAgent 的思考引擎与执行闭环3.1 经典 Agentic Loop 的原理Loop是Agent的“内心戏”核心。最基本的模式是ReActReasoning根据当前状态和工具结果判断下一步→ Acting调用工具或给出中间回复→ Observing读取工具返回结果并更新状态然后回到Reasoning形成闭合循环。在ReAct之上还有两个常用变体。Plan-Execute模式会先规划若干步骤再逐步执行执行完可以重新规划Reflexion模式会把每次失败的原因写进“反思笔记”在后续循环中主动避免同类错误。这些变体本质上都是在管理同一个Loop目标、步骤、证据、输出。为什么Loop而不是一次生成因为真实世界的信息是不完备的。让Agent查一个订单状态它必须先调API看到一个结果才能决定要不要再调另一个API。多步决策天然是序列化的必须通过循环逐步逼近答案。没有Loop所谓Agent只是一个“带工具的聊天机器人”做不到真正的自主任务。3.2 状态与记忆在循环中的位置Loop运行时要维护几类状态目标状态原始任务、完成标准、硬性约束。执行状态已经做过的步骤、正在执行的工具、剩余步数预算。记忆状态短期记忆当前对话上下文、长期记忆向量库、知识库、用户画像。最容易被忽视的是退出条件。我见过太多Agent变成复读机模型觉得结果没达到预期就反复调用同一个工具直到耗尽token。所以在Loop设计里必须显式声明退出条件任务完成、达到最大步数、用户中断、预算耗尽以及“活锁检测”——连续几轮结果没有变化就自动终止。3.3 循环工程的经验超时、重试、收敛判断“Loop Engineering”这个词最近圈内提得多大意是别指望大模型自己会把循环跑好你要用参数和机制设计来“驯服”它。我给出一个可参考的默认配置loop: max_steps: 10 timeout_seconds: 120 retry_policy: max_retries: 2 backoff_factor: 1.5 exit_conditions: - task_complete - max_steps_reached - user_interrupt - no_progress这些参数不是拍脑袋定的要结合工具延迟和业务容忍度。比如我们的搜索工具单次返回2到3秒10步意味着最坏30秒在线客服场景根本接受不了。所以还加了“响应时间预算”快到时限时强制收束让模型给出“当前已获取的信息下一步建议”而不是继续死磕。强烈建议在Loop内置重复动作检测。如果模型连续三步调用同一个工具且参数完全一致这几乎就是死循环直接终止并切换到备用路径。这个小机制在生产里救回了很多故障工单。4. Graph把循环编织成生产级流程4.1 为什么需要 Graph 编排单个Loop能完成一个窄任务比如查天气、写一段代码。但是生产系统很少有单一目标你先要判断用户意图再决定走“自助查询”还是“人工客服”查询过程中还可能并行访问订单库和知识库最后可能还要生成工单并通知仓库。这种多节点、多分支、带并发、带人工介入的流程用脚本或链式调用写很快会变成意大利面条。Graph把流程变成节点边的有向图。节点代表“干一件事”边代表“条件转移”。显式建模后每个节点都可以单独测试、单独部署、单独加人工审批。更关键的是生产环境里你可以只替换某个节点做灰度不用把整个业务流程都重发一遍。4.2 Graph 节点的类型与设计模式按我的经验生产Graph里常用的节点类型有入口节点接收用户请求格式化输入。LLM决策节点让模型判断意图、打分、选择分支。工具节点调用Harness暴露的工具。子图节点嵌套调用另一个Graph实现模块复用。人工审批节点暂停流程等人在界面里确认。聚合节点把并行分支的结果合并交给下一环节。终止节点整理输出、写日志、释放资源。边除了基本的前序到后继还应该支持条件边和超时边。比如“意图退款”走A分支“意图投诉”走B分支某个节点超过30秒没有返回就自动走降级分支。这样整个图是活的而不是一条固定的流水线。4.3 Graph 与 Loop 如何配合这里要专门回答一个常见误区开始用Graph后是不是就不需要Loop了当然不是。Graph里哪怕一个“意图判断”节点底层也要跑一个小循环让模型反复读取上下文、调用必要工具才能产出可靠决策。Graph给的是骨架Loop给的是血肉。拿“补全客户信息”节点举例这个节点内部就是一个Agent Loop它可能需要依次查询历史工单、帮助文档、CRM系统才能把信息补齐。这个Loop的运行状态要能通过节点上报给GraphGraph再根据结果决定下一步走“自动处理”还是“人工审核”。所以Graph和Loop是上下层关系Graph调度Loop干活。Graph的Checkpoint机制尤其重要。它把每个Loop执行到哪一步、拿到了什么中间结果都保存下来进程崩溃或者机器重启还能从最近的检查点恢复而不是全部推倒重来。4.4 生产实践中的 Graph 设计要点第一图一定要先画出来再写代码。哪怕用白板画也要把节点和转移条件列全。画图的过程会把你不清楚的边界分支暴露出来。很多项目为了炫技直接上代码结果图是写完了逻辑漏洞一测一个准。第二Graph的配置要当成运维资产来管理。结构说明放到单独的JSON或YAML文件里配合Checkpoint做持久化。别把图定义硬编码到代码里否则改一个分支要发一次版太痛苦。第三状态变量的作用域要显式声明。每个节点输出什么、哪些字段会被下游读取、哪些临时变量在节点结束时应该标记删除这些不做好Graph跑久了会产生“记忆污染”——上游的脏数据顺着边传到下游排查难度成倍增加。第四千万别一上来就建大图。我踩过坑最初50个节点画到一张图里还没上线就已经没人敢改了。后来改成“入口大图若干子图”按业务域拆解独立演进每次改动只影响一个子图风险小得多。5. 生产实践全解析从零搭一个“工单分类 Agent”理论讲多了得回到具体工程。我拿自己维护的一个项目做例子企业内部的用户反馈工单自动分类与自动回复系统。这个场景几乎覆盖了前面讲的全部要点意图判断、外部系统查询、多轮确认、失败转人工。5.1 参考架构与技术选型技术上我们用Python FastAPI对外暴露接口内部严格按三层组织Harness层负责连接“工单系统API、知识库检索API、用户信息API”统一鉴权和工具Schema校验。每个外部系统对应一个插件目录采用插件方式隔离。Loop层维护一个“分析型Loop”模型在循环里不断追问这个反馈的真实意图是什么需要查哪些数据当前信息是否足够是否需要生成回复草稿每步循环都记录中间结论。Graph层最外层Graph有四个节点意图识别、信息查询、回复生成、人工升级节点之间用条件边连接。目录结构大致是agent-service/ harness/ plugins/ crm_plugin/ kb_plugin/ ticket_plugin/ runtime.py schema.py loop/ core.py memory.py termination.py graph/ nodes/ edges/ state.py config/ settings.yaml这个结构最大的好处是Harness层改插件不影响LoopLoop改策略不影响GraphGraph改流程不影响底层工具。每个层都有清晰的边界。5.2 核心配置示例我们的settings.yaml简化后大致是harness: tool_timeout_seconds: 10 max_tool_result_chars: 4000 plugin_manifest: [crm, kb, ticket] loop: max_steps: 8 timeout: 60 enable_reflection: true graph: nodes: intent: { llm_model: qwen-max } query_info: { timeout: 30, retry: 1 } draft_reply: { llm_model: qwen-max } human_review: { enabled: true, timeout: 3600 } edges: - from: intent to: query_info condition: intent.confidence 0.6 - from: query_info to: draft_reply condition: query_info.success - from: draft_reply to: human_review condition: draft_reply.score 0.7这里几个参数的意图说一下。max_tool_result_chars限制工具返回的最大字符数防止一段超长文本把上下文占满超出的直接截断enable_reflection让模型在每两步之间自我总结“我现在确定了什么、还不知道什么”能显著提高收敛质量human_review不是永远不触发低评分回复必须转人工这是生产底线。5.3 并发与稳定性Agent 怎么扛流量“AI Agent怎么扛并发”是群里被问烂的问题。我直接说实践结论核心是无状态化、资源隔离、全链路异步化。无状态化Agent实例本身不存状态所有session状态放到Redis或数据库。HTTP请求不带上下文只带session_id每次处理从持久层恢复状态这样任意实例都能处理任意请求水平扩展就是加副本。资源隔离LLM服务有QPS限制工具API也有。在Harness层做速率限制和预请求队列宁可让少数请求排队也不能把后端打爆。每个外部系统的配额分开统计避免一个高消耗任务拖垮其他任务。异步执行慢任务不要把HTTP请求线程占着。多步Agent跑完可能要好几十秒应该提交到消息队列客户端通过轮询或者WebSocket拿结果。这样Web worker不会因为一个Agent卡住而全部占满。幂等控制每次Agent执行分配唯一的execution_id工具调用把execution_id作为幂等键。这样网络重试不会造成重复扣费、重复发消息、重复建工单。这套组合拳下来我们线上入口能平稳扛住日均几百万次调用后端Agent worker根据LLM配额自动伸缩高峰期不会因为某一个模型限流而全站不可用。6. 常见故障与排查方案速查最后更新一部分生产里高频出现的故障。这些坑都是团队真实踩过的整理成速查表。6.1 故障现象与处理现象可能原因排查建议Agent执行被终止报“execution terminated due to error”插件抛未捕获异常、token超限、模型返回非法格式、外部API超时先看Harness层日志里的trace_id定位是哪一步给模型调用增加容错解析失败时自动纠偏一次Harness启动时提示“failed to load plugins”插件路径错误、依赖缺失、插件版本不兼容、入口文件缺失用显式插件清单启动时逐个加载并记录版本号检查容器workdir和挂载目录循环检测到“self referencing loop detected”Loop里把旧输出又当成新输入上下文发生自引用给状态打版本标记禁止覆盖已完成步骤在图编排上加环检测防止子图互相调用形成环并发上升后响应越来越慢同步占线程、LLM限流、数据库连接池不够压测时并发跑一轮全链路看瓶颈是模型调用还是工具API把同步改异步、增加连接池Graph状态漂移状态只存在内存里崩溃后丢失持久化Checkpoint重启时从最近节点恢复记录状态快照配合日志回放6.2 调试与观测的独家技巧没有好的观测手段排查就是猜谜。团队里一定要在Harness层做“三段式日志”入参日志模型收到的Prompt和工具列表、工具调用日志实际请求的URL、参数、消耗时长、结果日志模型最终输出。三个日志共享同一个request_id问题一查就能串起来。还要给Loop写“运行录像”。不是真录像而是把每一轮Reasoning的句子、选中的工具、返回的摘要、token消耗都落库。这样你搜一个session_id就能看到Agent在心里嘀咕了什么。很多“看起来乱跳”的问题一看运行记录就恍然大悟。最后一个小技巧在Graph层开发时准备一组可重复固定输入的测试夹具。固定一张工单、固定系统时间、固定模型seed再把外部API全部mock掉跑完对比输出差异。这样每次改Graph节点都能快速知道自己是否引入了回归。没有这套夹具生产回归基本靠运气。7. 工具链与框架选型自己造还是直接搭很多朋友问我在生产里是选现成框架还是自研。我的观点是先理解三层架构再选工具不然容易被框架绑架。7.1 开源生态现状现在能看到几个明显的趋势以LangGraph为代表的图编排工具把Graph状态、Checkpoint、条件边都做成了标准能力还有类似Snap Graph Builder这样的可视化流程构建器让非技术角色也能参与流程编辑更有一批围绕特定模型做的Harness工具本质上是把模型接入到可插拔工具环境里。这些工具形态各异但内在逻辑都越来越趋近于HarnessLoopGraph三层模型。如果你发现某个框架能把工具管理、循环控制、流程编排三者同时做好那它大概率是适合复杂项目的。如果只能做其中一层也不用排斥组合使用即可。7.2 选型的基本原则我给的参考原则小团队、单Agent、业务轻可以先只做HarnessLoopGraph用手写状态机甚至不用。别为了架构而架构。多Agent、强流程、多分支尽早引入Graph编排同时保留Harness层控制工具边界。对数据安全要求高Harness尽量自研因为插件隔离、权限管控、审计日志常常要跟公司安全体系深度绑定。希望灵活调试优先选支持Checkpoint、可视化、单节点调试的框架否则上生产后追问题会非常痛苦。框架只是手段不是目的。我见过有人用LangGraph把极其简单的事绕成一张大图也见过有人用一个手写循环把几十个条件分支写出一片“屎山”。核心还是你对三层架构的认知是否清晰。最后再分享一个我个人的体会如果你正在从零搭Agent我的建议是“先Harness、后Loop、再Graph”——先把工具接入和日志做好再调循环策略最后再考虑流程编排。不要一上来就画一张大图否则你大概率会在一周后推翻重来。Harness看起来最不性感但它恰恰是决定一个Agent项目能不能活过生产环境的关键。这篇文章没有涉及任何具体框架的快捷键操作但它想传递的思路很明确所有Agent工程问题最后都归结为如何让模型在一个受控、可观测、可恢复的世界里持续工作。你把这个想明白了工具选型不过是顺手的事。