AI Agent生产环境稳定之道:Harness工程核心机制与实践

发布时间:2026/10/7 6:00:14
AI Agent生产环境稳定之道:Harness工程核心机制与实践 这两年做 AI Agent 的人不少但真正敢把 Agent 放进生产环境常驻服务的很少。原因不是模型不够聪明而是太不稳定——同一个 prompt上一秒还能正确调用函数下一秒就给你抛一个不存在的参数名上一轮还在正常遍历数据这一轮就自己进入死循环不肯出来。我见过太多项目死在 Demo 展示完之后死在用户真的开始用的那天。所谓Harness 工程指的就是围绕 Agent 建起来的那套“支架”执行流编排、约束护栏、并发治理、可观测回溯。它决定了你是造出了一个能稳定干活的系统还是造出了一个碰运气的玩具。这篇文章不聊模型训练也不聊提示词玄学只聊把一个 AI Agent 真正跑稳、跑久、跑扛得住并发的工程机制以及我这几年落地 Agent 服务时踩过的坑。1. 先聊清楚Agent 为什么总是Demo 战神、生产躺平1.1 LLM 的不确定性不是 bug是出厂设定做后端出身的人刚开始碰 Agent最容易犯的一个错误是把大模型当成一个“参数稍多一点的函数”。你给它一个输入它应该返回一个确定性的输出。但实际上大模型的输出是一个概率分布里的抽样结果同一个请求发十次十次都可能不一样。它不是传统软件里的确定性组件它的“随机性”是刻在机制里的。我举个非常常见的例子。你要求模型“只输出 JSON”大部分时候它确实输出合法 JSON但偶尔会在 JSON 前面多一行解释偶尔会把字符串值里的引号转义得乱七八糟偶尔会直接丢一个字段。单独看每一次失败都像是个偶然事故但把 100 次请求拉在一起看你会发现失败率稳定在某个数值附近。这就是概率系统的特征它不是“坏没坏”的问题而是“坏的概率有多高”的问题。这就带来一个本质矛盾Agent 的整个执行链路是由这些概率组件拼接起来的。如果链路上有 10 个环节每个环节的失败率是 5%那么整条链路一次跑通的概率大概是 0.95 的 10 次方也就是 60% 左右。这就是为什么本地写个 Demo 什么事都没有一上生产、一接真实数据、一跑多轮问题就像雨后春笋一样往外冒。换一个更强的模型可以把这个失败率往下压一点但压不到零也解决不了链路累积的问题。1.2 稳定性问题的本质是工程问题经常有朋友问我有没有哪个模型比较稳推荐一下我的回答是模型对稳定性的贡献最多占三成剩下七成在工程侧。你想想一个真实的 Agent 任务通常长什么样——用户抛来一句话Agent 要拆解意图、查数据库、调外部 API、整理结果、再回复。中间要经历多次模型生成、多次工具调用、多次状态更新。这里面每一个环节都可能出问题外部 API 超时了、上游返回的数据格式变了、模型在第五步的时候忘了最初的目标、上下文太长被截断了、并发一上来 API 开始限流……这些问题里除了第一个和第二个算是外部依赖的锅其余全部可以通过工程手段解决。把锅甩给模型是掩盖了自己的 harness 没做好。所以我在团队里一直强调一句话“稳定是设计出来的不是调出来的。” 所谓设计就是在模型输出和最终结果之间塞进足够多的确定性约束和兜底逻辑。让模型只负责它擅长的事——理解和生成——至于流程控制、状态保存、参数校验、重试策略全部由 harness 层来承担。1.3 Harness 工程到底是什么Harness 这个词字面意思是“马具”后来被借用到计算机领域泛指“让被承载的对象能安全、可控地运行起来的那套外部支撑系统”。放在 AI Agent 场景下Harness 工程就是一切“在模型生成之外、但决定模型生成能否安全可重复地完成任务”的部分。你可以这么理解大模型是发动机Harness 是车身、底盘、转向和刹车。一辆只有一个发动机的车也能跑但你会开它上高速吗Harness 工程至少包含这几个层面执行流Agent 的任务步骤怎么编排是链式、分支还是循环终止条件是什么约束护栏模型的输出怎么校验工具调用怎么授权资源消耗怎么控制并发治理多个用户同时发起任务时怎么排队、限流、防雪崩可观测与恢复跑挂了能不能查链路、能不能断点续跑、能不能人工接管。后面几章我就按这四个层面逐个拆开讲。每一层我都尽量给出可以直接照抄的设计思路和代码骨架。注意一点我在文章里引用的工具和代码只是“一种可行的实现”核心是它的机制不是工具本身。2. Harness 的第一层把失控的对话流变成受控的执行流2.1 线性链的问题一个坏节点毁掉整条链最早做 Agent 的时候很多人包括我都用过一种“一条大循环走天下”的写法。一个 while 循环把全部历史消息塞给模型问它下一步要调用哪个工具然后执行工具把结果追加进历史再让模型看一遍。代码写起来非常爽十几行就完事Demo 跑起来也像模像样。但一上真实任务就露馅了。最典型的是错误累积第三步调用工具的时候返回了一个异常结果这个结果被放进历史消息第四步模型基于这个脏数据继续推理方向就跑偏了越走越远。你想回滚到第三步重试做不到因为历史里全是拼接起来的长字符串你没法精准定位“某一步”的状态。另一个问题是循环不可控模型只要认为自己需要再确认一次就真的再确认一次十分钟过去它还能再确认一次。这个问题的本质是你让模型承担了“控制流”的职责但控制流恰恰是代码最擅长、模型最不擅长的事。模型擅长的是理解语义、生成文本而不是做一个可靠的状态机。2.2 图编排把“模型决定全程”降级为“模型决定当前一步”后来我切换到图编排思路用 LangGraph 这类工具或者干脆自己写一个轻量级的 DAG 执行器。核心思想很简单把整个任务拆成若干节点每个节点是一个确定性的执行单元——可以是调用模型可以是执行工具也可以是读写状态。节点之间的边代表转移关系什么时候走哪条边可以由模型决定也可以由代码里的条件判断决定。举个例子一个客服 Agent 的流程可以拆成这样意图识别节点把用户输入分类是咨询、投诉还是查询订单信息收集节点检查还缺哪些关键信息缺就反问用户工具调用节点查订单、查库存、查物流生成回复节点基于收集到的结构化数据生成最终回答。在这个结构里模型的职责被收缩到“当前节点我该做什么选择”。它不需要盯着前 20 轮对话去猜自己进行到哪一步了因为“进行到哪一步”这件事由执行器里面的游标决定。这就是从“失控对话流”到“受控执行流”的关键一步。我自己画过一个对比表列一下两种模型跑起来的行为差别维度单循环塞历史图编排 显式状态中间状态隐含在消息串里不可访问存在结构化 State 里随时可读可写错误定位只能整条链路重试定位到具体节点单节点重试循环控制靠模型自觉硬性 step 上限 超时熔断并发能力上下文越长越慢容易互相挤占每个节点独立可调度可观测性翻日志全靠 grep每个节点有独立的输入、输出、耗时如果你不想引入重型框架自己用代码实现一个 GraphRunner 也不难核心就是一张邻接表加上一个状态对象。我建议团队里的新人都自己手写过一遍写完再去看 LangGraph很快就能理解它的设计动机。2.3 循环、条件路由与终止条件无限循环是头号杀手图编排只是把流程从“一团麻”变成了“一张网”但网如果没有出口就是个陷阱。Agent 在真实环境里跑死最常见的症状不是报错而是不结束。模型觉得自己还要再调一次工具、再确认一下用户意图于是永远走不出循环。我处理这类问题的标准动作有三个全部在 Harness 层做不依赖模型自觉最大步数限制每个 session 最多执行 N 个节点到点强制终止。N 需要根据任务类型调我一般先给一个宽松值比如 20稳定后再收紧到 12。时间预算整个 Agent 任务配置一个 wall-clock 超时比如 120 秒。这个用 asyncio.wait_for 或者一个简单的 deadline 判断就能实现。循环逃生门检测到同一节点被执行超过阈值比如 3 次就不允许模型再选同一分支而是强制走另一条边比如“问用户澄清”或者“转人工”。这里有个细节终止条件不能只写在 prompt 里。你写“如果任务完成请输出 END”模型大概率会把这句话当成耳边风。真正靠谱的终止是一段硬代码steps 计数到顶、总耗时超限、状态里的最终标志位被置位。三选一哪个先到都算终止。2.4 显式状态机解决模型“失忆”问题我常说 Agent 是个“聪明的金鱼”——单轮理解能力很强但多轮之后非常容易忘记前面说过的话。你让它分三步完成任务第一步得到的中间结果到了第三步就被它忘得一干二净。这不是模型能力不够而是对话历史变长之后注意力和上下文都开始稀释。解决办法不是调 prompt而是把关键信息外置到一个显式的 State 对象里。比如一个“生成推广文案并发布”的 AgentState 里应该有这样的字段user_input用户原始需求永远不被覆盖product_info工具查到的商品信息做成结构化字段draft当前生成的文案草稿published是否已发布的布尔标记attempts各节点的执行次数记录。每次模型生成前我们从 State 里把必要的字段拼成简短的输入上下文每次模型生成后我们把结果解析出来回写到 State。这样即使模型在第五步忘记了第一步的需求代码仍然可以从State.user_input里把原始需求拿出来拼进第五步的 prompt 里。让模型做“实时翻译”让代码做“永久记忆”这是 Agent 稳定的第一个基础。3. Harness 的第二层约束与护栏把自由裁量权关进笼子3.1 结构化输出别让模型自由填空模型在 Agent 里的作用无非两件事从文本里抽取信息从选项里做决策。这两件事都涉及到模型往状态里写数据。如果放任模型自由输出它什么格式都能给你写出来JSON 带注释、YAML 缩进错误、Markdown 里嵌表格…… 这不是刁难你是它的抽样机制决定的。所以我在 Harness 里永远要求模型只能输出符合预定义 Schema 的结构化内容并且要过校验器校验失败宁可重试也不能放行。现在主流模型都支持 function calling / 结构化输出模式你可以声明一个工具参数是个严格的 JSON Schema模型只能按这个 Schema 给参数。用 pydantic 写的话代码类似这样from pydantic import BaseModel, Field from typing import Literal class OrderLookupResult(BaseModel): order_id: str Field(description订单号) status: Literal[pending, paid, shipped, cancelled] items: list[str] Field(default_factorylist) total_amount: float Field(ge0, description总金额必须大于等于0)配合模型的结构化输出模式让模型直接产出符合这个模型的 JSON再用 pydantic 校验解析。解析失败时不要盲目重试同一 prompt而要带上详细错误信息让模型修正。一个我在实战里反复验证过的经验是把 Schema 定义得越严模型的合规率越高。很多人担心 Schema 太严会让模型束手束脚实际上它反而帮模型省了力气——它不需要去猜格式和边界。3.2 Tool 调用的沙箱边界权限最小化Agent 的另一大不稳定来源是工具调用失控。模型看到你给它接了搜索引擎工具、数据库工具、发邮件工具它就有可能在某个奇怪的时刻去调用它们。不是它坏而是它对“哪些调用在业务上是合理的”缺乏边界感。我的做法是一套三层护栏白名单工具清单在环境变量或配置中心里显式声明模型只能调用白名单内的工具。新增工具必须走 code review不允许模型在对话里“发明”工具。参数校验每个工具入口都有一层 validate 函数对模型传进来的参数做类型、范围、枚举检查。比如get_order(order_id)必须校验 order_id 是合法字符串send_email(to, content)必须校验 email 格式。模型传进来的参数再怎么花里胡哨都要先在代码层面对齐。敏感操作二次确认对于写操作、支付操作、删除操作这类高风险动作Harness 里专门设置一个pending_confirmation状态必须用户明确确认后才真正执行。有个朋友问我这些校验原本调用方系统里也有Agent 层再做一遍是不是重复了我的回答是必须重复。因为传统系统的调用方是经过认证的 SDK而 Agent 的调用方是一个“有无限创造力的概率模型”。它可以绕过正常业务流程用各种你没想到的方式触发危险操作。把校验放在 Agent 和工具之间等于在上游再装一道闸门。3.3 预算与配额token、步骤数、耗时三本账一个跑在生产环境的 Agent最怕的不是单次贵而是失控累积。我管它叫“三本账”必须同时盯住账本监控点止损线超线处理Token 账单次任务累计 token按任务类型配置比如 50k触发上下文压缩或终止步数账节点执行总次数默认 20 步强制终止返回部分结果时间账任务墙钟耗时默认 120 秒异步任务进后台同步请求先返回这里特别想说 token。Token 不是只算“模型生成的那几个字”备份里至少有三个地方在偷偷消耗后面第 4 章会展开。现在先说结论每个 Agent 任务启动时都应该初始化一个 Budget 对象把三本账记在里面。预算在代码里不是装饰品是硬拦路虎——if budget.exceeded: raise TerminatedByBudget。我见过最可惜的事故一个用户让 Agent 批量处理 100 个文件Agent 处理到第 63 个时上下文爆炸token 烧掉几十美元进度还全丢了。如果有步数账和 token 账在第 50 个文件时就该触发分流或者存档根本不会走到爆炸那一步。3.4 失败兜底在 Harness 层兜底而不是在 prompt 层祈祷护栏的另一面是兜底。模型输出非法 JSON 怎么办工具调用超时怎么办方案是“重试 降级 默认值”三级递进。最容易被忽略的是第三级“默认值”。很多业务场景其实是可以接受默认值的比如查库存失败时返回“库存紧张”而不是报错。你要给每个可能失败的节点定义一个“失败时的安全默认行为”。在这儿我给一段处理模型 JSON 输出失败的实用例子def safe_extract_json(raw: str) - dict | None: # 第一级直接解析 try: return json.loads(raw) except json.JSONDecodeError: pass # 第二级剥掉模型常见的 markdown 围栏 cleaned re.sub(r^(?:json)?|$, , raw.strip(), flagsre.MULTILINE) try: return json.loads(cleaned) except json.JSONDecodeError: pass # 第三级返回兜底空结构由上层决定是否重试 return None这段代码看着简单但在生产里帮我少接了不少报警。因为模型输出非法 JSON 是常态事件不能每次失败都让链路回滚。让 harness 消化掉这层不确定性用户无感知体验才会好。4. Harness 的第三层并发、排队与资源抖动的工程治理4.1 并发场景下最先崩的往往是“人肉调参”很多 Agent 项目最初都是单线程跑通的。一个 FastAPI 接口收到请求就开一个协程跑 Agent循环里调模型、调工具。本地测试时并发一两路毫无压力。但是一旦放上生产用户量一起来最先崩的往往不是模型 API而是你身边那些“人肉调参”的隐性瓶颈数据库连接池被占满、外部 API 因为并发太高被限流、日志系统被撑爆。我以前接手过一个 Agent 服务某次高峰期突然大面积超时。查了半天发现是 Agent 每跑一步都往 MySQL 里写一段对话历史连接池只有 10 个连接而 Agent 的多步执行全是长事务一个用户的任务就攥着一个连接不放。并发 20 个用户连接池直接打满后续请求全在排队。这种问题跟模型一点关系都没有纯粹是 harness 层没有治理并发。4.2 控制并发信号量、队列与背压生产环境的 Agent 服务不能“来一个请求就开一个执行流”。要有明确的并发预算。我现在的标准做法是三重控制入口限流API 层用固定速率限制超出的请求直接返回 429让客户端退避重试执行并发限制用一个asyncio.Semaphore控制同时在跑的 Agent 任务数量。比如模型 API 配额允许 20 路并发我就把信号量设成 15留 5 路余量给其他服务队列与背压如果任务量大就把请求放进队列用 worker 池消费。队列有长度上限满了直接丢弃或降级而不是无限堆积导致所有任务一起超时。一个简单的信号量控制代码from asyncio import Semaphore class AgentExecutor: def __init__(self, max_concurrency: int 15): self._sem Semaphore(max_concurrency) async def run(self, task_id: str): async with self._sem: # 拿不到信号量就排队天然限流 try: await self._execute_agent(task_id) except Exception: # 进入重试或降级分支 ...这段代码看着简单但很多人没有意识到对并发做控制本质上是在保护下游而不是保护自己。下游的数据库、第三方 API、甚至模型 API 都有配额如果你让 Agent 像脱缰野马一样往上冲一定会吃到 429 或超时。4.3 Token 会从三个地方偷偷流走把并发控制在合理范围之后还要盯住每个任务的 token 消耗。我发现大部分团队根本没有 token 成本预算直到月底账单来了才傻眼。token 会从三个地方偷偷流走第一是上下文累积。模型每走一步工具返回结果、中间推理、最终回答都会被追加进历史。一个二十步的任务越到后面 prompt 越长单次调用的 token 消耗是指数级的。第二是工具返回的原始数据。模型查了一个数据库返回了 1000 行Agent 直接把整个原始结果塞回上下文一轮对话就把预算烧掉大半。第三是失败重试。一次输出非法 JSON重试三次每次都是全量重发历史多出来的开销比正常情况下还大。我的应对策略是三个字压缩、截断、摘要。工具返回的数据永远不原样进上下文而是先做字段裁剪只保留跟当前任务相关的字段历史消息超过一定长度就启动摘要节点让模型把前面的内容压缩成几条要点失败重试则使用局部重试把出错的节点单独拎出来把最小上下文喂回去。这三招都做足token 开销能降一半以上。4.4 优雅降级与重试语义最后是重试。很多工程师把重试做成“一个 while 循环失败了就再试一次”。但在 Agent 场景盲目重试是灾难。我给你画一个重试决策的框架先判断失败类型再决定动作。失败类型举例重试策略瞬时网络错误上游 API 连接超时指数退避重试最多 3 次上游限流429 Too Many Requests退避时间拉长建议等 Retry-After模型逻辑错误输出不符合 Schema、幻觉参数不重试回到前一个节点换分支工具业务错误资源不存在、无权限不重试直接走降级默认值不可恢复错误状态损坏、预算超限终止任务通知人工这里有个重要的点重试只针对“幂等且瞬时”的失败。Agent 里的工具调用有的幂等查订单有的不幂等创建工单、发消息。对于非幂等操作重试前必须做去重用 request_id 之类的东西保证不会重复执行。没有这个意识一次网络抖动就能给你搞出两张重复工单。5. 可观测性没有 trace 的 Agent 项目不配叫稳定5.1 传统日志为什么不够用Agent 服务出了故障最让人崩溃的不是故障本身而是查不出故障在哪。普通后端服务排错很简单翻请求日志看哪个接口 500看堆栈。但 Agent 不一样一个用户请求会触发几十次模型调用和工具调用这些调用还分了支、循环、并行。你打开日志系统看到的是一堆散落的条目模型调用成功、工具返回数据、下一次模型调用又开始…… 没有关联没有上下文你根本拼不出它的完整执行轨迹。所以我强烈建议Agent 项目从第一天就做trace 埋点而不是等出了事故再补。每个节点执行时至少打出这样一条结构化事件{ session_id: sess_8f3a..., node: order_lookup, node_type: tool, status: ok, duration_ms: 812, input_keys: [order_id], output_summary: statusshipped, items2, llm_call_id: call_h7x2..., state_version: 17 }字段看起来多但这是排查问题的弹药。没有 session_id你没法把一个任务的所有步骤串起来没有 node你不知道挂在哪个环节没有 input/output summary你只能盲猜是数据问题还是模型问题。5.2 一次排查 45 分钟超时的完整链路我讲一个真实发生过的排查过程你就知道 trace 有多重要了。有段时间用户反馈一个任务“跑着跑着就没反应了”单看日志什么也看不出来因为接口 200 返回了只是返回的内容是个空壳。我打开 trace按 session_id 过滤很快就看到这个任务的执行轨迹意图识别 OK1.2 秒→ 查订单 OK2 秒→ 查物流 OK3.5 秒→ 开始生成回复 → 这一节点持续了 42 秒没结束。再点开这一个节点的输入发现模型收到的上下文里包含了一大段工具返回的物流轨迹明细其中有一段是超过 12MB 的 Base64 编码图片。工具节点把整个原始响应塞进了状态生成节点要把这团数据一起发给模型于是延迟爆炸。定位过程前后不到十分钟而之前没有 trace 时我们盲猜了两天先怀疑模型 API又怀疑网络最后才靠人肉翻日志找到真凶。这个案例说明两件事一是工具返回数据必须做大小封顶和内容裁剪二是 trace 系统必须能下钻到“某节点的输入具体是什么”。有了 trace排查成本可以降低一个数量级。5.3 状态快照与 session 恢复让 Agent 学会“失忆后接上”最后是可恢复性。一个长时间运行的 Agent 任务跑着跑着服务重启了、进程被杀掉了怎么办传统做法是任务作废让用户重来。但用户已经等了好几十分钟一句“请重新开始”是非常糟糕的体验。我的做法是把 Agent 的 State 做成可序列化的快照每一步执行完就把快照存进 Redis 或数据库。快照里包含当前节点位置、节点中间产物、已经执行的步骤列表、预算消耗情况。这样当进程重启后可以根据 session_id 把快照拉回来从最后一个成功执行的节点继续而不是从头再来。class SessionStore: def __init__(self, redis_client): self._redis redis_client async def save(self, session_id: str, state: dict): payload json.dumps(state, ensure_asciiFalse) await self._redis.setex(fagent:{session_id}, 3600, payload) async def load(self, session_id: str) - dict | None: payload await self._redis.get(fagent:{session_id}) return json.loads(payload) if payload else None这个机制还能派生出两个高级功能一个是人工接管出问题时把 state 里的 pending_action 置为“需要人工确认”管理员看完直接改状态再恢复执行另一个是重放调试把线上失败的 state 快照拉下来在本地基于同一份数据重放路径复现率几乎百分百。这比让用户“再操作一遍”高效得多。6. 落到实践一个稳定的 Agent 服务长什么样6.1 生产级的最小骨架前面五章讲的都是机制这一章把它们拼成一个可落地的服务骨架。我自己常用的一套组合是 FastAPI 做 API 层Redis 存状态和队列Celery 或 asyncio worker 跑任务配合一个自定义的轻量级 Graph 执行器。目录结构大概是这样的agent_service/ ├── api/ │ └── routes.py # FastAPI 路由入口限流 ├── core/ │ ├── graph.py # 图编排执行器 │ ├── state_store.py # Redis 状态快照 │ └── budget.py # token/step/time 预算 ├── nodes/ │ ├── intent.py # 各业务节点 │ ├── order_lookup.py │ └── ... ├── tools/ │ ├── registry.py # 工具注册和白名单 │ └── validators.py # 工具参数校验 └── observability/ └── tracer.py # trace 埋点接口层只做三件事校验入参、生成 session_id、把任务交给队列。真正的 Agent 执行是异步的前端用定时轮询或 WebSocket 拿结果。同步执行只适合短任务和内部联调生产环境一定要异步化不然一个 120 秒的任务会把整个服务阻塞住。执行器的核心循环我简写如下你可以看到前面提到的机制如何汇聚到一个run方法里async def run(self, session_id: str): state await self.store.load(session_id) while not self.is_terminated(state): node self.graph.next_node(state) try: async with self.sem: new_state await node.execute(state) except RetryableError: new_state await self.retry_with_backoff(node, state) except FatalError: new_state self.mark_failed(state, reasonfatal) state new_state state.steps 1 await self.store.save(session_id, state) self.tracer.record_node(node, state) return state这里每一步之后做状态持久化既是为了恢复也是为了让外部可以随时查看进度。is_terminated里面同时检查state.steps max_steps、state.elapsed max_time、state.budget.exhausted以及业务终结标志。这套循环朴实无华但我在几个项目里跑了大半年很少再遇到“跑飞”的问题。6.2 几个反直觉的实战经验骨架讲完了最后分享几个反直觉的实战经验这些都不是文档里会写的东西模型越大不一定越稳。很多人默认强模型更稳但实际测试中大模型在简单任务上有时会“多想一步”反而产生多余输出。同一个 Schema 约束下小模型在受限分支上的合规率不一定差。关键是把任务拆到位把 Schema 定清楚。最稳的 Agentprompt 往往非常短。如果你的单个节点 prompt 超过 800 字大概率是没拆好。prompt 越长模型行为越发散越难测。我习惯把 prompt 压缩到“任务背景 State 关键字段 当前目标”其余信息统统走结构化状态传入。“把失败重试 3 次”在 Agent 里不是好策略。模型输出不合规重试多少次都可能不合规。得回到 harness 层换分支、换 Schema、或降级。重试只留给网络瞬时故障。稳定性预算要花在 harness 上而不是花在调 prompt 上。花两个星期微调 prompt 把成功率从 85% 提到 90%不如花两天加一层校验和重试把成功率直接拉到 99%。前者是碰运气后者是确定性工程。6.3 给新手的落地路径如果你是从零开始搭一个 Agent 服务我建议按这个顺序渐进不要一上来就上全套先线性 人工 review用一个简单的顺序流程把主链路跑通每个节点输出先存下来人眼看。这个阶段的目标是让正确逻辑成立。再加图编排与状态把线性流程升级为图加入分支和显式 State让错误可以定位、状态可以回滚。再加约束护栏结构化输出、工具校验、预算控制从这一步开始你的 Agent 才真正具备“上生产”的资格。最后加可观测与并发治理加 trace、快照、限流队列把剩下那 20% 的挺过境况问题解决掉。6.4 一点个人体会老实说我自己刚开始做 Agent 时也在 prompt 上耗了很久总觉得“提示词写得不对”后来才慢慢悟明白真正让 Agent 稳定下来的从来不是那句魔法咒语般的 prompt而是你给它搭的那套工程支架。支架搭好了模型哪怕偶尔发点小脾气整个系统也能兜得住支架不牢再聪明的模型也会在真实世界的噪音里翻车。这也是我把本文标题定为“Harness 工程”的原因——它可能没有模型迭代那么性感却是决定 Agent 项目能不能从 Demo 走到生产的隐形地基。希望这套从执行流、约束护栏、并发治理到可观测恢复的框架能帮你少踩几个我踩过的坑。