ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

生产级AI Agent三层架构:Harness、Loop与Graph实战拆解

生产级AI Agent三层架构:Harness、Loop与Graph实战拆解 这两年 AI Agent 被聊得都快起茧了但真上手搭过生产级 Agent 的人都知道从“能跑通的 Demo”到“敢放在线上跑的工程”中间隔着一条巨大的鸿沟。我最近重构一个基于大模型的自动化服务把旧代码彻底推倒重来最大的转折就是把项目从单体 Agent 脚本拆成了 Harness、Loop、Graph 三层架构Harness 管好边界和装备Loop 管好执行节奏Graph 管好流程路径。这篇文章我想用一线踩坑的实际视角把这三层拆开讲透——它们各自解决什么问题、在项目里长什么样、怎么选型、怎么协作、上线遇到坑该怎么排查。内容覆盖从基础的 Agent 开发思路到生产环境的高并发、安全、可观测性适合正在做 Agent 项目开发的同学也适合刚入坑想少走弯路的初学者。1. 为什么 Agent 工程需要 “三层拆解”——先从需求闹剧说起1.1 单体 Agent 的“三宗罪”先说我之前那个失败版本。当时项目是个聚合多个内部系统的自动化助手需求听起来不复杂用户用自然语言提需求Agent 调用数据接口、查数据库、生成报告。我当时图省事写了一个单体 Python 脚本模型调用、工具分发、会话历史全塞在一个主循环里。Demo 阶段表现惊艳领导看了都觉得很厉害结果一上多人试用就原形毕露。第一个痛点是上下文失控。会话一开始还好聊了几十轮之后每次请求要把所有历史消息原封不动拼接进 prompt上下文长度动不动就几万 token又慢又贵。最夸张的一次用户只是问了一句“昨天的单量呢”模型却在读一个 20 万字符的聊天记录响应延迟从 2 秒涨到 20 秒。到了这一步任何调优都救不回来因为问题出在架构上没有人负责管理上下文的生命周期。第二个痛点是工具调用逻辑和业务代码完全耦合。脚本里到处是“if 用户问天气 then 调天气 API”“if 用户要查订单 then 调订单服务”这种硬编码分支表面上是 Agent实际上是披着大模型外衣的规则引擎。新增一个工具得动主循环改一个工具的返回格式得连带改三处解析逻辑团队其他人根本不敢碰这段代码。更严重的是模型不知道该什么时候用什么工具工具描述对模型不可见只能靠人肉在 prompt 里写“你可以用以下工具但请自行判断”效果全看运气。第三个痛点是流程完全不可控。单体 Agent 的循环没有边界它可能在“查数据→生成报告→发现数据不对→再查一次”这个圈里反复绕十几遍既没有最大步数限制也没有目标完成度的校验器。有一次测试任务跑了 40 多分钟成本烧了几十块钱最后输出一份错得离谱的报告还一本正经地告诉我“已完成”。这种体验让我痛下决心Agent 不能只靠模型自律工程上必须有强约束。1.2 三层架构边界、节奏、路径后来重构时我把整个系统按职责拆成三个层面分别解决上面三类问题。Harness 层管“边界和装备”它定义 Agent 能做什么、不能做什么维护会话上下文、模型连接、工具插件、安全策略Loop 层管“节奏和推进”它负责多轮“思考→行动→观察”的执行循环控制终止时机、成本预算、上下文裁剪Graph 层管“路径和协作”它把多个 Agent 节点、工具节点、人工节点组织成一张有向图决定任务按什么顺序流转、出错往哪走、结果往哪传。我习惯用一个类比跟新同学解释这三层的关系Agent 可以想象成你新招的一名全能员工脑子里有大模型这样的聪明大脑但光有大脑没法干活。Harness 是这个员工的工位、工牌和公司规章制度——他只有在这个环境里才能刷卡进门、调用系统、知道权限边界Loop 是这个员工的日报和周会机制——他每干一件事都要汇报一次、被检查一下方向偏了立刻纠正Graph 是公司的 SOP 流程图——什么岗位先做什么、什么情况跟谁协作、最终怎么交付全部画清楚。没有这三层Agent 就像一个没有工位、没有汇报机制、没有流程指引的自由人聪明是很聪明但你完全不知道他会捅出什么篓子。拆完之后效果立竿见影。上下文由 Harness 统一管理有清理有压缩工具调用由 Harness 注册和鉴权新增工具就像插拔 U 盘一样简单循环由 Loop 兜底永远不会出现“无限烧钱”的恐怖场景复杂的业务流程由 Graph 编排哪个环节出错都能精确锁定。后面我所有的 Agent 项目都沿用这个三层结构再也没踩过第一版那种大坑。2. Harness 层Agent 的边界、装备与教练2.1 一句话说清楚 Harness 和 Agent 的区别“harness 和 agent 到底什么区别”这个问题被问过很多次我自己的定义是Agent 负责思考和决策Harness 负责支撑思考和决策的一切工程设施。然后我再往细了说清楚。Agent 的核心是“智能体”——它是一个由大模型、提示词、工具选择逻辑组成的推理单元它做的事情是“根据输入想下一步干嘛”。而 Harness 是给这个智能体套上的一层“工程外壳”模型连接怎么封装、API Key 怎么管理、系统提示词怎么加载、历史会话怎么保存、工具插件怎么注册、用户在哪个目录下执行、命令需要经过什么审批这些全归 Harness 管。换句话说Agent 是“大脑”Harness 是“身体外骨骼教练组”。“大脑”负责想“身体”负责让想法落地“教练组”负责制定战术边界。最近大家讨论热度很高的 DeepSeek Harness、Claude Code 里的 harness engineering本质上都是在做同一件事把某个模型包装成一个带固定技能包、行为约束、上下文管理能力的可部署工程体。你装一个 Harness相当于给模型配了一套可插拔的工具链和一套策略配置而不是每次从零拼接 prompt。我也在本地部署过这类 Harness 项目实际体验下来最大的收益不是模型变聪明了而是“可控性”上了一个台阶什么工具能用、什么行为被禁止、上下文怎么裁剪全部由配置文件说了算。这套思路放到任何 Agent 项目里都成立不管你是不是用现成的框架。2.2 Harness 的核心职责拆解我在项目里把 Harness 的职责拆成五块每块都有自己的代码边界和测试用例这里逐个说一下。第一块是模型接入与上下文管理。Harness 要向上层 Loop 暴露一个统一的模型调用接口不管是接 OpenAI、DeepSeek 还是本地部署的模型上层代码不用改。你需要维护一份系统级提示词把工具描述、安全规则、输出格式约束放在最前面会话历史单独存按策略做滚动裁剪还要做 token 预算控制——每次调用前估算即将发送的 token 数超了就先压缩再发。这块最容易犯的错是在代码里到处直接 import 模型 SDK导致后面换模型时改到怀疑人生。第二块是工具与插件体系。Agent 要调用外部能力必须经过 Harness 的工具注册中心。我给每个工具定义一份元信息工具名称、功能描述、参数 Schema、执行超时、失败重试策略、权限级别。模型看到的是这套元信息的文本描述Harness 负责把描述拼进 prompt模型输出包含工具调用指令时Harness 解析指令并按注册信息执行。这套设计带来的好处是新增工具零侵入——往注册表里加一条元数据、挂一个执行函数Agent 立刻就能用主循环一行不改。第三块是会话状态与运行时隔离。每个独立的用户会话必须有一个专属的状态容器里面存历史消息、中间变量、当前工作目录、剩余预算。容器之间物理隔离杜绝“用户 A 的上下文被用户 B 的请求读到”这种灾难。我在重构前就吃过这个亏后面细讲。状态容器要支持序列化方便持久化到 Redis 或数据库服务重启不丢会话。第四块是安全与权限边界。Harness 必须回答“模型能做什么、不能做什么”。我的做法是三层约束第一层是工具白名单模型只能调用注册过的工具第二层是命令沙箱所有系统命令必须经过安全检查危险命令直接拒绝第三层是数据脱敏进入模型的文本先过一遍敏感信息过滤器身份证号、手机号、公司机密自动打码。没有这三层Agent 就是一把没有保险栓的枪。第五块是审计与追踪。Harness 在每次模型调用、每次工具执行、每次状态变更时都写结构化日志记录时间戳、用户 ID、请求 ID、token 消耗、结果摘要。这些日志是后面排查问题、核算成本的唯一依据。曾有人问我审计日志有什么用我让他回忆一下被用户追责“Agent 为什么把我数据删了”的场面——没有日志你百口莫辩有日志你可以精确回放当时发生了什么。2.3 自研最小 Harness一个 Runtime 类就能跑起来如果你不想一上来就引入重型框架完全可以自研一个最小 Harness核心就一个类。我第一版的生产系统其实就是这么干的代码量不大但接口边界非常清晰。class AgentRuntime: def __init__(self, config_path: str): config load_yaml(config_path) self.model_client create_model_client(config[model]) self.tool_registry ToolRegistry(config[tools]) self.security SecurityPolicy(config[security]) self.sessions: dict[str, Session] {} def create_session(self, user_id: str) - Session: session Session(user_iduser_id) self.sessions[session.id] session return session def run_once(self, session: Session, user_input: str) - str: messages session.build_messages(user_input) messages self.security.sanitize(messages) response self.model_client.chat(messages, toolsself.tool_registry.descriptions()) if response.tool_calls: return self._execute_tool(response.tool_calls[0], session) session.append_message(user_input) session.append_message(response.text) return response.text def _execute_tool(self, call, session) - str: tool self.tool_registry.get(call.name) self.security.check_permission(session.user_id, tool.required_level) result tool.execute(**call.arguments) session.append_tool_result(call.id, result) return result这个 Runtime 的要点在于模型调用统一走model_client工具加载统一走tool_registry安全统一走security会话统一走session。往后的所有迭代都在这几个接口上做文章——比如model_client从单模型换成多模型路由tool_registry从静态注册改成动态热加载session加一层 Redis 持久化都不影响整体骨架。一个实操心得Harness 里的工具不是越多越好。我曾一度给 Agent 挂了 20 多个工具以为功能越全越强大结果模型经常在工具选择上纠结要么调用错工具要么连续试好几个才找到对的决策时延和错误率都明显上升。后来我把工具裁到 7 个每个工具的描述里写清楚“什么时候用、什么时候千万别用”准确率反而大幅提升。Harness 设计的第一原则是“最少够用”而不是“应有尽有”。3. Loop 层Agent 的执行引擎与自我进化循环3.1 为什么 Agent 必须有循环大模型本质上是一个“单步推理器”一次调用只能完成一步决策。但真实任务几乎没有一步就能搞定的查完数据要分析分析完要生成报告报告格式不对还得改改完可能发现数据口径错了又要重查。这中间每一步都需要模型基于上一步的结果重新推理所以 Agent 的实现形态天然是循环——业内经典的 ReAct 模式就是“思考→行动→观察”的循环模型先想下一步该做什么然后调用工具或输出文本系统把工具结果或执行结果返回给模型模型再接着想。没有显式循环的 Agent 只会是个聊天机器人问一句答一句无法推进多步骤任务。但这里说的循环不是while True那么草率——最近有个词叫 Loop Engineering讲的就是把“循环”本身工程化。工程化的意思是循环不能是隐形的每一步都要有清晰的输入输出、可观测的事件日志、可控的终止条件、可量化的成本指标。你看到 Agent 在循环里绕圈不能干瞪眼要能随时暂停、查看、干预、回退。所以 Loop 层在架构里不是一个“代码实现方式”而是一个需要精心设计的核心组件。我用一个类比帮团队理解Loop 就像开车时的导航。导航不是简单告诉你一条路线就完事它会实时监测你当前的位置如果偏离路线会提醒你掉头如果前方拥堵会帮你重新规划如果到达目的地会播报“到达”。Loop 的逻辑就是这个导航——它每转一圈都要校验“现在到哪了离目标还有多远要不要修正方向”。3.2 Loop 运行时的四个控制点终止、限流、裁剪、回退这里的四个控制点在代码上其实不复杂难的是想清楚每种情况下该怎么办。第一个控制点是终止条件。最基础的三层兜底必须有第一是“目标完成校验”模型自认为完成了还不够得有一个验证器——比如用校验表达式检查输出是否符合要求格式、是否包含必需字段第二是“最大迭代次数”任何循环都不能无限跑我一般根据任务复杂度设 8 到 20 步超过就强制结束并降级处理第三是“全局超时时间”整个 Agent 任务实时钟不能超过某阈值比如 5 分钟到时自动熔断。这套兜底组合起来才能彻底防止“无限烧钱”。第二个控制点是节奏与限流。Agent 循环里每一步都可能触发一次模型调用高并发时如果不做速率控制API 配额很快见底还会被服务商限流。我是在 Harness 层加一个令牌桶控制每秒最大模型请求数Loop 层拿到“被限流”的报错后做指数退避重试——第一次等 1 秒第二次等 2 秒第三次等 4 秒不是傻等是给上游恢复时间。同时每个会话配一个成本预算token 消耗超过预算就提前终止防止单个用户拖垮整个服务。第三个控制点是上下文裁剪。循环最直接的问题就是历史消息越积越多不裁剪的话第 10 轮的 prompt 可能比第 1 轮大 5 倍。我用的方法是组合策略滚动窗口只保留最近 8 轮消息更早的重要信息在每轮结束时由模型生成一句摘要存入状态容器工具返回的长文本只保留结构化摘要和关键字段原始数据落到外部存储。这样既能保住关键上下文又不让 prompt 无限膨胀。裁剪安排在每轮循环的“观察”阶段完成后执行属于一个独立的 Hook。第四个控制点是校验与回退。Loop 里非常容易出的一种情况是模型“自信犯错”——输出一堆看起来合理但实际错误的内容。我的做法是在 Loop 内嵌一个轻量验证器不一定要用大模型正则、JSON Schema、断言表达式基本够用。验证失败时把验证错误拼成一条提示语塞回给模型让它在此基础上修正最多重试 3 次连续失败则回退到上一个可靠的 checkpoint——也就是把会话恢复成第 N 轮开始之前的状态用追加保护性提示词的方式重新执行。这套机制看起来笨但真实生产环境拼的就是这份“笨功夫”。3.3 从普通 Loop 到反思型双循环Agent 自我进化的雏形单层 Loop 能解决“执行任务”但解决不了“任务方向有问题”。举个例子模型在第一轮决定用 A 方案查数据跑到第五轮发现 A 方案查出来的数据口径有偏差如果循环只顾埋头执行它会一直基于错误数据生成报告。要避免这种情况需要引入反思循环。我的做法是双循环结构——外层是工作循环负责按当前计划推进任务内层是反思循环每个阶段结束后触发一次。反思循环会让模型重新阅读已执行的历史回答三个问题当前结果离最终目标还有多远之前有没有走偏方向下一步用什么策略最优。然后把反思结果写回状态容器决定外层循环是“继续当前计划”“切换方案”还是“回退重做”。为了控制成本反思不能每次都触发。我在设计里只用两种触发方式一是节点的自然边界——比如数据拉取完成、报告生成完成之后二是异常信号——比如连续两次工具调用失败、模型输出被验证器拒绝。正常情况下一个 5 阶段的任务最多做 4 次反思不会无限碎步优化。实测下来双循环结构的任务成功率比单循环高不少尤其是在需求模糊、答案不唯一的开放型任务里。反思的本质不是让模型“变聪明”而是给它一个“回头看”的机制。人做事尚且需要复盘更别说 Agent 了。4. Graph 层把流程从“代码逻辑”升级为“可视化拓扑”4.1 为什么需要 Graph循环解决不了的协作问题Loop 层把单个 Agent 的能力放大了但真实业务几乎都是多角色、多阶段的流程。比如说做一个“智能周报助手”流程是接收用户需求→查询数据库→分析数据→生成初稿→人工确认→发送邮件。如果把这六步硬塞进一个大循环代码会变成一坨“面条”十几个 if 分支判断当前在哪个阶段每个分支里再嵌一个小循环下一个阶段依赖上一个阶段的局部变量整个流程几乎没法调试更没法可视化。Graph 层的核心价值就是把流程显式建模成一张图——节点是动作边是流转条件。这样做有四个直接收益。第一是可视化整个流程画出来产品经理都能看懂第二是可控性每个节点独立部署、独立测试改一个节点不影响其他节点第三是容错性每个节点可以配置自己的重试和异常分支失败不拖垮全流程第四是可复用性公共子流程可以封装成子图多张主图共享调用。之前有同事问我这个 Graph 不就是状态机加一点路由吗我说思路类似但 graph 化的表达力强太多了。状态机适合“状态少、迁移规则明确”的场景而 Agent 流程里充满了模型决策、人工审批、动态分支、并行分支这种不确定因素图的表达方式更能承载这种复杂度。拿“意图识别”举例模型输出可能是“查数据”“写报告”“发邮件”中的任意一个图上一个条件路由节点就能搞定状态机则要写满各种状态迁移矩阵。4.2 图的构建思路节点、边、条件路由与状态传递拆解一张真实验证过的流程图讲一下怎么构建。节点类型我一般分四类LLM 节点调度模型执行推理、工具节点执行具体操作、决策节点根据条件决定走向、人工节点人机回填等待审批或输入。边分为无条件边和条件边条件边挂在决策节点后面常见标签是 success、failed、retry、timeout、default。状态传递设计是最容易埋坑的地方。整张图共享一个 state 对象但每个节点只允许读写属于自己的 key 命名空间。比如data_fetch节点写入state[data]report_generate节点只读state[data]并写state[report]。严禁不加前缀直接读写顶层字段否则两个并发节点会互相覆盖数据。我自己就用过一个没做命名空间隔离的版本两个并行节点都把结果写到state[result]最后拿到的数据时而是 A 的时而是 B 的排查了一下午才定位。条件路由在我看来是整个 Graph 的“灵魂”。模型视角下LLM 节点输出一段结构化 JSON比如{next: data_fetch_subgraph, reason: user wants more detail}图的调度器解析这个字段决定下一步去哪个节点。这是最灵活也最自然的方式——让模型本身参与路径决策图只提供结构约束。同时在模型输出异常、JSON 解析失败的情况下路由必须兜底默认走到“澄清需求”节点或“告警并退出”节点绝不能让流程死掉。子图和并行也是常规需求。子图就是把一段流程封装成一个整体节点主图只看到它的输入输出接口适合“多轮对话澄清”“报表格式整理”这类会复用的流程并行节点则依赖 DAG 结构一个父节点可以同时发出多条边指向多个子节点子节点全部完成后聚合结果再进下一步。并行能显著提速但也要求每个并行分支天然独立不能读写同一份可变数据。4.3 主流 Graph 工具选型速览不用盲目追新做 Graph 层不一定要自研市面上已经有不少成熟的方案。我给一个非常主观的选型对比纯属个人使用经验。LangGraph 是语言模型图编排的代表——它的图结构就是可编程的 Python 对象节点是普通函数状态是显式类型特别适合已经在写 Agent 代码的团队。它跟 LangChain 生态无缝衔接能用最低成本把现有工具链包装成图节点。缺点是模型思维比较重团队需要花点时间理解它的 StateGraph 抽象另外生产级可观测性需要自己补。Temporal 是一个通用分布式工作流引擎——它把业务流程建模成持久化的工作流天然具备重试、超时、恢复、审计。Agent 的每一步可以作为 activity 提交到 Temporal让引擎负责长期运行和容错。适合节点事务要求很硬、流程可能要跑几小时的复杂系统杀鸡不必用牛刀团队如果没有分布式工作流的经验上手成本偏高。可视化图构建器也是一类选择——比如在社区里看到的 Snap Graph Builder 这类拖拽式工具可以让产品甚至业务同学直接画流程图再生成配置文件交给调度器执行。如果团队构成比较复合不想让流程定义全集中在开发手里这类工具值得试试。缺点是灵活度有限复杂条件路由、并行分支、动态子图往往不如代码写起来顺手。还有一个选择是自研轻量调度器。如果全公司就一个 Agent 产品、流程节点不超过几十个我真的推荐自研——需求看得见摸得着不用为一个图引入整套框架。自研的核心就三件套节点注册表、条件路由解析器、状态对象。上面说的那个最小 Harness 直接扩展即可。5. 三层协同从 Demo 到生产环境的完整实践5.1 一次完整任务的调用流程三层是怎么拧在一起的理论讲了这么多我用一个真实的“智能报表助手”场景把三层跑一遍看它们怎么协作。这个助手的任务逻辑是用户在后台输入“分析本月华东区订单量变化趋势”系统自动生成一份带图表的分析报告并发送到指定邮箱。系统启动后Harness 先干活从配置加载模型客户端、工具注册表、安全策略根据用户 ID 恢复或创建会话状态容器把可用工具描述组装进系统提示词。然后 Graph 上场按模板加载任务主图——主图的起点是“需求澄清”子图。在澄清子图内部Loop 开始运转模型向用户追问“华东区是指哪些省份本月要对比去年同期吗图表要什么格式”每收到一次回答Loop 把答案写回状态直到模型判定信息已充分决策节点将流程路由到“数据拉取”节点。数据拉取节点是个工具节点内部也跑着一个轻量 Loop调用数据库查询工具如果 SQL 执行超时Loop 会根据重试策略先重连数据库再重放查询如果结果为空Loop 会把“查询结果为空”的观察反馈给模型让它调整查询条件再来一次。数据到手后写入state[data]路由到“报告生成”节点。报告生成是 LLM 节点。它内部的 Loop 负责多轮润色生成初稿→验证器检查格式和指标是否齐全→不满足则带着校验错误返回模型修改→最多三遍。初稿合格后图走到人工节点——状态挂起等待负责人在后台点“同意”。这里必须强调人工节点在整个流程里起到闸门作用因为“给用户发邮件”这类副作用操作不应该由模型自行决定。审批通过最后一步是发送节点调用邮件工具完成投递整个 Graph 执行结束Harness 把最终状态持久化写完成审计日志。这条链路每一步都能指出它在三层架构中的位置Harness 始终在场提供会话、工具、安全、上下文Loop 散落在各个节点内部负责执行推进、低成本重试、校验回退Graph 纵览全局负责流程编排、条件路由、人工闸门、子图调度。只有三层同时工作这个程序才能稳定完成“从一句话到一个企业级交付物”的全过程。5.2 并发处理AI Agent 到底怎么扛并发“AI agent 怎么扛并发”是我被问到最多次的问题之一也是新手最容易想错的点。朴素实现是一个请求进来就 new 一个 Agent每个 Agent 内部串行跑循环结果就是同时来 10 个请求系统立刻卡死模型 API 被限流数据库连接爆掉整个服务雪崩。我总结下来的做法有五个关键点按重要性排序。第一模型调用必须过队列和限流。把模型请求投进消息队列消费端用令牌桶控制发往模型服务的速率情况再紧急也不能绕过限流直连 API——事实上绕过的那几次都是以 429 报错和线上故障收场。第二会话状态必须外置。每个 session 的状态容器不能只存在进程内存里要落 Redis否则服务一扩容缩容就全乱套用 Redis 还有一个好处是多实例可以按用户进行会话亲和同一个用户的请求始终打到同一实例省去状态同步的麻烦。第三任务尽量异步化。用户提交请求后立刻返回任务 ID真正的 Agent 执行放到任务队列慢慢跑前端轮询结果。用户其实不关心是不是实时同步返回他要的是体验不卡顿。第四工具调用全部走连接池。数据库连接、外部 HTTP 长连接、文件句柄统一复用不能每次调用都新建——高并发下新建连接的开销经常比工具本身还大。第五幂等设计。同一个任务必须能安全重试每个任务生成一个幂等键工具节点执行前先检查该键是否已处理过重复请求直接返回上次结果。没有幂等网络抖一下同一封邮件就可能发出去三次。并发压力下还有个容易忽略的点单个 Agent 实例不要独占线程。我习惯用一个信号量把并发 Agent 任务数限制到合理阈值比如机器核数的 1.5 倍剩余请求排队等待。排队看起来慢但比大家一起超时强得多。你在架构上永远要假定模型 API 的速度是瓶颈所有系统设计都要围绕“怎么在瓶颈不可突破的情况下最大化吞吐”。5.3 可观测性与安全生产环境下没人愿意踩的两个雷上线前最后一个环节是可观测性。我不止一次看到团队兴致勃勃把 Agent 服务推到生产结果出问题后完全不知道 Agent 内部发生了什么——模型怎么想的、调了哪个工具、为什么走了那条分支全是一团黑盒。所以我在 Loop 层每条执行路径都埋点结构化日志记录每一步的事件类型模型调用开始/结束、工具调用开始/结束、令牌消耗、延迟毫秒数、重试次数、路由跳转。每个事件都带 request_id 和 session_id用日志追踪一张“任务从下发到完成”的完整时间线。Graph 层则做节点级指标统计每个节点的成功率、平均执行时长、重试率、异常类型。这些数据接入监控后产品团队自己都能看报表理解 Agent 的行为模式。运行一两个星期你会惊讶于这些数据的价值——比如你会发现某个节点的失败率高得离谱但在此之前你甚至不知道它失败过。安全方面必须再强调一次。Harness 的白名单机制要卡在工具层不能卡在 prompt 层——prompt 只是对模型的“建议”白名单才是对系统的“强制”敏感数据进模型前要脱敏用户的手机号、身份证号这类字段在 Harness 里应该被替换成占位符外部命令执行要放进沙箱至少要做到命令白名单加参数黑名单最好直接用容器隔离。Graph 里的人工人节点一旦涉及付款、发信、删除、推送这些高影响操作一律强制等待人工确认。这些规则不会让系统变得更聪明但可以在 Agent“抽风”时保住你的业务和名声。6. 常见问题与排查经验实录6.1 高频问题速查表我把最近一年在 Agent 项目里带团队排查过的高频问题整理成一张速查表遇到相似情况可以直接对照着排查。问题现象大概率原因排查思路Harness 加载插件失败插件路径配置错、动态库缺依赖、权限不足先看插件扫描日志是否命中路径再用最小插件单独加载二分定位Model 调用报 429并发超过模型 API 限流阈值确认令牌桶参数、观察队列积压情况临时降级并发数Loop 停不下来终止条件写得太宽松模型判定“完成”标准过低加最大步数兜底打印每步目标校验结果强化验证器上下文令牌数暴涨Loop 里历史消息没有裁剪检查是否有滚动窗口和摘要压缩看当前会话保存的消息数量Graph 状态被覆盖节点读写共享 state 时没有命名空间隔离全图搜索顶层字段读写改成按节点前缀隔离模型不调用工具工具描述不清晰或系统提示词没有强调工具可用精简工具数量在描述里写明“什么时候必须用”生成报告格式错验证器太松或返回给模型的校验错误含糊把校验错误模板化给出错误字段和修正示例并发时串线Session 对象被全局化或不洁地共享每个请求创建独立运行时所有状态挂到 session 容器任务重试产生重复副作用没有幂等键重试把同一次操作执行了多次给任务和工具节点增加幂等键执行前先查去重表沙盒/环境异常消息发送失败沙箱配额用完或环境变量缺失检查沙箱资源限制确认环境变量加载路径这张表不是标准答案但它覆盖了我在生产环境真实踩过的绝大多数雷区。排查的原则是一致的不要在模型 prompt 上调来调去——大概率是工程层的问题先查 Harness 状态、Loop 终止条件、Graph 路由再回头谈模型行为。6.2 三个我踩过的坑写成避坑笔记第一个坑是 Harness 插件过度加载。我有段时间追求功能全面给 Agent 挂了 20 多个工具插件以为功能越多越好结果模型在每轮决策时都要从一大坨工具描述里挑经常挑错而且 prompt 被工具描述撑得非常长响应变得又慢又贵。后来我把工具数量砍到“最少够用”——只留任务链上真正需要的 7 个每个工具描述用一句话写清楚用途和触发条件效果立竿见影工具错误调用率降了大半。教训就是Harness 是给你定边界和减负的不是用来囤积工具的大仓库。第二个坑是 Graph 节点粒度过细。我一度迷信“节点要小要原子”把一次简单的周报任务拆成三十几个节点结果图看起来高大上实际上维护成本爆炸改一个字段要动五个节点排查问题要在节点跳转之间来回翻。后来我换成“阶段化粗粒度”按业务阶段分成 5 个大节点每个节点内部再定义自己的子流程能独立测试才是好节点图上的节点数以“人脑一眼看得过来”为上限。教训就是图的复杂度必须符合团队的可维护能力Graph 是给人看的不是给机器炫技的。第三个坑也是最严重的一个——并发状态串线。早期版本我用了一个全局字典保存 session本意是图方便结果线上同时跑 20 个任务时经常出现用户 A 的会话里混进用户 B 的消息问询时用户一头雾水我们排查了整整两天才定位到是共享数据结构的问题。改成“每个请求 new 一个运行时实例所有状态全部放进 session 对象”之后串线问题彻底消失。教训就是Agent 的并发安全没有捷径绝对不能依赖进程内的全局变量状态必须显式地跟 session 绑定。最后说点实在的这些架构做完之后我最大的感受是三层架构的核心价值不是“让 Agent 更聪明”而是“让 Agent 系统成为一个可以被运营、被审计、被改进的工程体”。模型能力长进是模型厂商的事我们能做的是把聪明大脑放对位置给它清晰的边界、可靠的循环、显式的流程然后盯着每一个环节的指标去优化。没有最好的架构只有最适合当前团队和业务复杂度的架构。如果你刚开始做 Agent先从一个最小 Harness 加一个单层 Loop 跑起来等真的遇到流程协作问题时再引入 Graph不用一步到位——但一定要在第一天就想好状态要隔离、循环要有终止、路径要能观察这三样是任何 Agent 工程的安全底色。
返回列表