[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fzSyenrYjQmKvCu4xc5R_69MuouFIOZ6PJeF6xRe95XU":3,"$fS3Ft78gtchj_N00LTrJEDA_8RB9PhVMzi7uZGQOCjMY":48},[4],{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":40,"status":41,"seoTitle":40,"seoDescription":40,"canonicalUrl":40,"isFeatured":42,"sno":43,"sortOrder":44,"publishedAt":45,"updatedAt":46,"createdAt":47},"bcd1e95f-e759-4a5a-8cdb-71f51c35f803","article","模型路由：为什么 AI 应用不该每个问题都调用最强模型","model-routing-quality-cost-latency","模型路由让简单请求走便宜模型，复杂或高风险任务再升级到强模型。本文解释规则路由、分类器路由和级联路由的差异，结合 RouteLLM 说明如何平衡质量、成本、延迟与风险，并给出评测和回滚清单。","## 为什么 AI 应用不该每个问题都调用最强模型\n\n一个产品通常同时面对三类请求：简单的分类和改写、中等难度的知识问答，以及需要长链路推理或复杂工具调用的任务。如果所有请求都交给最贵、最强的模型，质量可能不错，但成本和延迟会一起上升；如果全部交给小模型，简单任务很划算，难题却容易失败。\n\n模型路由（Model Routing）就是在请求进入主模型之前，先判断它适合哪一个模型。简单问题走便宜、快速的模型，困难问题才升级到更强的模型。它把“选哪个模型”从开发者写死的配置，变成了一个可以测量、调优和持续学习的系统决策。\n\n![RouteLLM 项目概念图](https:\u002F\u002Fopengraph.githubassets.com\u002F1\u002Flm-sys\u002FRouteLLM)\n\nRouteLLM 的[论文](https:\u002F\u002Farxiv.org\u002Fabs\u002F2406.18665)把问题表述成质量与成本之间的权衡，并提供了一个开源框架来训练和评估路由器。它的核心思想并不是“永远选小模型”，而是让小模型处理它擅长的请求，把强模型预算留给真正需要的地方。\n\n## 路由和负载均衡不是一回事\n\n负载均衡只关心“把请求平均分到哪台机器”，例如两台相同模型服务器各处理一半流量。\n\n模型路由关心的是“这个请求需要什么能力”：\n\n- 翻译、摘要、格式转换可以走轻量模型。\n- 复杂代码修复、数学推理和多步骤规划可能需要强模型。\n- 企业内部某类术语，可能应该路由到专门微调过的模型。\n\n所以路由器评估的不只是流量，还包括任务类型、复杂度、领域、上下文长度、用户等级和失败代价。\n\n## 三种常见路由方式\n\n### 规则路由：最容易上线\n\n可以先用明确规则：包含代码块就走代码模型，超过某个上下文长度就走长上下文模型，涉及付款就走经过安全评估的模型。\n\n规则简单、可解释、容易审计，但它通常只能看到表面特征。一个短问题也可能很难，一个很长的请求也可能只是重复文本。\n\n### 分类器路由：学习“谁更适合回答”\n\n分类器可以根据历史请求、人工偏好或评测结果，预测不同模型在当前问题上的胜率。RouteLLM 的思路就是用偏好数据训练路由器，在强模型和弱模型之间做选择。\n\n这里最重要的不是预测“这个问题难不难”，而是预测“强模型相对于弱模型能带来多少额外收益”。如果两个模型都能答对，就没有必要为了保险升级。\n\n### 级联路由：先便宜，失败再升级\n\n级联先调用小模型，再用规则、校验器或评审模型判断是否需要升级。例如结构化输出校验失败、答案缺少引用、置信度不足时，再把原问题交给强模型。\n\n它比单次路由更稳，但最坏情况下会付出两次调用的成本。对于不可接受错误的场景，级联通常比一次性押注路由器更容易解释。\n\n## 路由器到底应该看哪些信号\n\n最容易想到的信号是输入长度，但它只能说明上下文大，不代表任务难。更有用的信号通常来自四个方向：\n\n1. **任务能力**：是否需要代码、数学、翻译、视觉或长文档理解。\n2. **任务风险**：回答错了是“改写不自然”，还是会触发付款、删数据或对外发信。\n3. **结构约束**：是否要求严格 JSON、引用证据、固定字段或可执行工具参数。\n4. **业务预算**：用户等级、实时性要求、剩余配额和当前模型可用性。\n\n这些信号应当组合使用。例如，一个 100 字的“帮我修改退款金额并提交”并不长，却有明显副作用；一个 50 页的会议纪要摘要可能很长，但只需要稳定的长上下文模型，不一定需要最强推理模型。\n\n可以把决策结果理解成一个“质量—成本前沿”：在满足任务质量门槛的前提下，选择成本最低的模型；只有当便宜模型无法达到门槛时，才升级。这个原则比追求一个固定的“最强模型胜率”更适合生产系统。\n\n## 级联中的质量门槛怎么做\n\n质量门槛不能只依赖模型自己说“我有信心”。更可靠的是组合多个可验证信号：\n\n- JSON 能否通过 Schema 校验。\n- 答案是否覆盖问题里的必答字段。\n- 引用是否真的支持对应结论。\n- 工具参数是否通过类型、权限和业务规则检查。\n- 轻量评审器是否发现明显矛盾或遗漏。\n\n例如客服 Agent 先用小模型生成答案，再检查引用和退款金额。如果引用缺失，就升级到强模型；如果金额与订单 API 不一致，则直接停止自动回复。这种设计把“升级”从模糊的主观判断变成了可测试的状态机。\n\n注意质量门槛也会制造额外调用。一个评审器如果和强模型一样昂贵，路由系统就可能变成“先调用路由器，再调用评审器，再调用主模型”。因此第一层优先使用确定性校验，只有无法用规则判断的质量问题才调用评审模型。\n\n```mermaid\nflowchart TD\n    Q[\"用户请求\"] --> R[\"路由器：任务、复杂度、风险\"]\n    R --> S{\"小模型足够吗?\"}\n    S -->|是| M1[\"轻量模型\"]\n    S -->|否| M2[\"强模型或领域模型\"]\n    M1 --> V{\"通过校验或质量门槛?\"}\n    V -->|是| O[\"返回结果\"]\n    V -->|否| U[\"升级到强模型\"]\n    U --> O\n    M2 --> O\n```\n\n## 一个可落地的路由策略\n\n假设你在做一个企业知识助手，可以先定义四个等级：\n\n- **L0**：改写、分类、提取字段，使用小模型。\n- **L1**：单文档问答，使用成本较低的通用模型。\n- **L2**：跨文档比较、需要引用的问答，使用更强模型或检索级联。\n- **L3**：涉及审批、代码修改或高风险判断，使用强模型，并要求人工确认。\n\n路由器先根据请求类型和风险选择候选级别，再由质量门槛决定是否升级。这样“模型强弱”不是唯一维度，权限和失败代价也进入了决策。\n\n可以把升级条件写得很具体：\n\n- JSON Schema 校验失败。\n- 必须引用资料但没有找到证据。\n- 工具参数缺字段或类型错误。\n- 评测器判断答案没有覆盖问题中的关键约束。\n- 用户请求涉及不可逆副作用。\n\n这些条件比“感觉模型答得不自信”更容易测试。\n\n## 路由器本身也有成本\n\n如果每次请求都先调用一个昂贵的路由模型，节省下来的钱可能被路由器吃掉。路由器应该足够快、足够便宜，最好能复用已有输入特征，或使用规则与轻量分类器做第一层筛选。\n\n此外，模型能力会变化。今天的小模型可能在摘要上很好，下一次版本升级后却改变了格式习惯；供应商价格、限流和延迟也可能调整。因此路由策略不能只在上线前评估一次。\n\n## 上线要像发布一个模型一样谨慎\n\n路由器本身也会产生回归。一个新路由器可能把更多请求送进便宜模型，账单下降了，但复杂问题成功率也下降；或者路由判断准确，却因为额外网络往返让 P95 延迟变差。\n\n比较稳的发布方式是分阶段进行：\n\n1. **离线回放**：用脱敏后的真实请求和人工质量标签比较不同策略。\n2. **影子模式**：新路由器参与判断，但不改变真实模型，只记录它会怎么选。\n3. **小流量灰度**：按租户或请求类型逐步放量，监控升级率、质量和尾延迟。\n4. **自动回滚**：当高风险任务错误率、结构化失败率或人工投诉超过阈值时，切回固定模型。\n\n路由日志至少要记录最终选择、候选模型、路由理由类别、是否升级和结果质量。不要记录一段让模型自由生成的“解释”作为唯一审计依据；真正可审计的是输入特征、规则版本、阈值和最终决策。\n\n模型更换时还要重新校准。旧模型上的“0.5 阈值”没有理由在新模型上继续成立，尤其当价格、上下文能力、工具遵循能力和输出格式发生变化时。\n\n## 如何正确评估路由效果\n\n不要只看平均成本。至少要维护一个包含真实流量分布的评测集，并同时比较：\n\n1. **质量**：任务成功率、人工偏好、结构化校验、引用正确率。\n2. **成本**：平均输入输出 Token、模型调用次数、升级比例。\n3. **延迟**：P50、P95，以及升级请求的尾延迟。\n4. **安全**：高风险任务是否被正确升级，是否出现越权调用。\n5. **稳定性**：路由器换模型、换领域、换用户群后是否退化。\n\nRouteLLM 官方仓库也强调，路由阈值应使用与真实请求相近的数据进行校准，而不能直接照搬公开数据集上的阈值。因为同一个阈值，在客服、代码助手和内容审核场景里的含义完全不同。可以参考其[开源实现和评测说明](https:\u002F\u002Fgithub.com\u002Flm-sys\u002FRouteLLM)。\n\n## 常见误区\n\n**误区一：按 Token 长度判断难度。** 长文本不一定难，短问题也可能需要复杂推理。\n\n**误区二：只追求最省钱。** 如果升级率很低但错误率明显上升，节省的是账单，损失的是用户信任。\n\n**误区三：用模型评模型却不做人工抽样。** 自动评审可以扩展覆盖面，但自身也会有偏差，关键业务仍需要人工复核。\n\n**误区四：把路由器当成永久真理。** 模型、价格、流量和用户目标都会变，路由策略必须和评测、观测、回滚一起建设。\n\n**误区五：忽略失败后的用户体验。** 路由升级失败时，不能只返回“模型错误”。应该告诉用户正在重试、请求人工处理，或明确哪些部分已经完成。路由系统是产品流程的一部分，不是藏在 API 网关后面的黑盒。\n\n## 什么时候值得采用\n\n当你只有一个低流量原型时，固定使用一个模型更简单。模型路由真正有价值的信号通常是：调用量已经上升、不同任务能力差异明显、模型账单开始影响业务，或者你需要把小模型与领域模型组合起来。\n\n推荐的最小落地顺序是：先记录真实请求与质量结果，再用规则做第一版路由；确认成本和质量边界后，再训练或接入分类器；最后为高风险流程加入级联、人工确认和自动回滚。\n\n## 结语：把模型选择变成产品策略\n\n模型路由不是简单的“省钱开关”，而是一套质量、成本、延迟和风险之间的决策系统。最好的路由器不会让所有请求都走小模型，而是让每个请求得到“足够完成任务”的能力。\n\n**落地清单：**\n\n- 是否知道不同任务分别需要什么能力？\n- 是否有真实请求组成的路由评测集？\n- 是否定义了升级条件和高风险任务的硬规则？\n- 是否把路由延迟和调用成本纳入总账？\n- 是否能在质量退化时快速切回固定模型？\n\n## 一手资料\n\n- [RouteLLM 论文](https:\u002F\u002Farxiv.org\u002Fabs\u002F2406.18665)\n- [RouteLLM 开源框架](https:\u002F\u002Fgithub.com\u002Flm-sys\u002FRouteLLM)\n- [RouteLLM 的阈值校准说明](https:\u002F\u002Fgithub.com\u002Flm-sys\u002FRouteLLM#threshold-calibration)","\u002Fuploads\u002F2026-08-05\u002Ff959361f-b807-496f-8287-3e2a843e0f65.jpg",[],[],"Foundit AI","https:\u002F\u002Ffoundit.cn","f39339b1-aaa6-4e86-b0c2-a6e6a21113b5",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"88d2bc27-0e0f-468a-b907-2991cb97b87b","人工智能","ai",{"id":28,"name":29,"slug":30},"0848beb4-db26-4fb8-b391-f852a11be192","AI编程","ai-coding",{"id":32,"name":33,"slug":34},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":36,"name":37,"slug":38},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse","资料来源",null,"published",false,66,0,"2026-08-05T00:00:00.000Z","2026-08-05T03:14:40.243Z","2026-08-05T02:13:46.501Z",[49,79,97],{"id":50,"type":6,"title":51,"slug":52,"summary":53,"body":54,"coverUrl":55,"productScreenshots":56,"productLinks":57,"authorName":58,"authorUrl":59,"authorSubject":16,"category":60,"tags":65,"sourceLabel":40,"sourceName":40,"sourceUrl":40,"status":41,"seoTitle":40,"seoDescription":40,"canonicalUrl":40,"isFeatured":74,"sno":75,"sortOrder":44,"publishedAt":76,"updatedAt":77,"createdAt":78},"7f4dc034-e104-4542-bea6-1148e984189e","构建高效的智能体","building-effective-agents","最成功的效果并没有使用复杂的框架或专门的库。相反，它们是用简单、可组合的模式构建出来的。","过去一年，我们与数十个跨行业、正在构建大语言模型（LLM）智能体的团队开展了合作。我们发现，最成功的效果并没有使用复杂的框架或专门的库。相反，它们是用简单、可组合的模式构建出来的。\n\n在这篇文章中，我们分享从服务客户和自行构建智能体的过程中学到的经验，并为开发者提供关于构建高效智能体的实用建议。\n\n## 什么是智能体？\n\n\"Agent\"（智能体）可以用几种方式来定义。一些客户将智能体定义为完全自主的系统，它们在较长时间内独立运行，使用各种工具来完成复杂任务。另一些客户则用这个词来描述遵循预定义工作流的、更具规定性的实现。在 Anthropic，我们将所有这些变体都归类为**智能体系统**（agentic systems），但在架构上明确区分**工作流**（workflows）和**智能体**（agents）：\n\n- **工作流**是通过预定义代码路径来编排 LLM 和工具的系统。\n- **智能体**，则相反，是 LLM 动态主导自身流程和工具使用、并对如何完成任务保持控制的系统。\n\n下面，我们将详细探讨这两类智能体系统。在附录 1（\"实践中的智能体\"）中，我们描述了客户发现这类系统特别有价值的两个领域。\n\n## 何时（以及何时不）使用智能体\n\n在用 LLM 构建应用时，我们建议尽可能寻找最简单的解决方案，仅在确有需要时再增加复杂度。这可能意味着根本不需要构建智能体系统。智能体系统常常以更高的延迟和成本为代价换取更好的任务表现，你应该想清楚这种权衡在何时是值得的。\n\n当确实需要更高复杂度时，工作流为定义良好的任务提供可预测性和一致性；而当需要大规模的灵活性和模型驱动的决策时，智能体是更好的选择。不过，对许多应用而言，用检索和上下文示例来优化单一的 LLM 调用通常就已足够。\n\n## 何时以及如何使用框架\n\n有许多框架让构建智能体系统变得更容易，包括：\n\n- [Claude Agent SDK](https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fagent-sdk\u002Foverview)；\n- [AWS 的 Strands Agents SDK](https:\u002F\u002Fstrandsagents.com\u002Flatest\u002F)；\n- [Rivet](https:\u002F\u002Frivet.ironcladapp.com\u002F)，一个拖拽式的 GUI LLM 工作流构建器；以及\n- [Vellum](https:\u002F\u002Fwww.vellum.ai\u002F)，另一个用于构建和测试复杂工作流的 GUI 工具。\n\n这些框架通过简化调用 LLM、定义和解析工具、将调用串联起来等标准底层任务，让你轻松上手。然而，它们常常制造额外的抽象层，掩盖了底层的提示词与响应，使其更难调试。它们还容易让人产生\"加复杂度\"的冲动，而其实更简单的设置就足够了。\n\n我们建议开发者先用 LLM API 直接上手：许多模式只需几行代码就能实现。如果你确实使用框架，请确保理解其底层代码。对\"引擎盖下\"是什么的错误假设，是客户出错的一大常见来源。\n\n查看我们的 [cookbook](https:\u002F\u002Fplatform.claude.com\u002Fcookbook\u002Fpatterns-agents-basic-workflows) 获取一些示例实现。\n\n## 构建模块、工作流与智能体\n\n在本节，我们将探讨在生产中见过的智能体系统常见模式。我们从基础的构建模块——增强型 LLM——开始，逐步提升复杂度，从简单的组合式工作流一直到自主智能体。\n\n### 构建模块：增强型 LLM\n\n智能体系统的基础构建模块，是叠加了检索、工具、记忆等增强能力的 LLM。我们当前的模型能够主动使用这些能力——生成自己的搜索查询、选择合适的工具、并决定保留哪些信息。\n\n![The augmented LLM](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002Fd3083d3f40bb2b6f477901cc9a240738d3dd1371-2401x1000.png)\n\n*图：增强型 LLM*\n\n我们建议把实现的重点放在两个关键方面：让这些能力贴合你的具体用例，并确保它们为你的 LLM 提供简单易用、文档完善的接口。尽管实现这些增强有多种方式，其中一种途径是通过我们近期发布的 [Model Context Protocol](https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fmodel-context-protocol)（模型上下文协议），它让开发者只需一个简单的 [客户端实现](https:\u002F\u002Fmodelcontextprotocol.io\u002Ftutorials\u002Fbuilding-a-client#building-mcp-clients)，就能与不断增长的第三方工具生态集成。\n\n本文余下部分，我们假设每次 LLM 调用都能访问这些增强能力。\n\n### 工作流：提示词链（Prompt chaining）\n\n提示词链将任务分解为一系列步骤，每一次 LLM 调用处理上一次的输出。你可以在任意中间步骤上添加程序化检查（见下图中的\"gate\"门槛），确保流程仍在正轨上。\n\n![The prompt chaining workflow](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F7418719e3dab222dccb379b8879e1dc08ad34c78-2401x1000.png)\n\n*图：提示词链工作流*\n\n**何时使用此工作流：** 当任务能够被轻松、干净地拆解为固定的子任务时，这个工作流最理想。其主要目标是通过让每次 LLM 调用都成为更简单的任务，以延迟换取更高的准确率。\n\n**提示词链有用的例子：**\n\n- 生成营销文案，再将其翻译成另一种语言。\n- 先写文档大纲，检查大纲是否满足某些标准，再基于大纲撰写文档。\n\n### 工作流：路由（Routing）\n\n路由对输入进行分类，并将其导向专门的后续任务。这一工作流实现了关注点分离，并能构建更具针对性的提示词。没有它，针对某一类输入的优化可能会损害对其他输入的表现。\n\n![The routing workflow](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F5c0c0e9fe4def0b584c04d37849941da55e5e71c-2401x1000.png)\n\n*图：路由工作流*\n\n**何时使用此工作流：** 当任务复杂、且存在最好分别处理的明显类别，同时分类可由 LLM 或更传统的分类模型\u002F算法准确完成时，路由表现良好。\n\n**路由有用的例子：**\n\n- 将不同类型的客服查询（一般问题、退款请求、技术支持）导向不同的下游流程、提示词和工具。\n- 将简单\u002F常见的问题路由给更小、更具成本效益的模型（如 Claude Haiku 4.5），而将困难\u002F少见的问题路由给能力更强的模型（如 Claude Sonnet 4.5），以优化最佳性能。\n\n### 工作流：并行化（Parallelization）\n\nLLM 有时可以同时对一项任务工作，并将其输出以编程方式聚合。并行化这一工作流体现为两个关键变体：\n\n- **分块（Sectioning）**：将任务拆分为并行运行的独立子任务。\n- **投票（Voting）**：多次运行同一任务以获得多样化输出。\n\n![The parallelization workflow](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F406bb032ca007fd1624f261af717d70e6ca86286-2401x1000.png)\n\n*图：并行化工作流*\n\n**何时使用此工作流：** 当拆分的子任务可以并行以提速，或需要多个视角\u002F多次尝试以获得更高置信度的结果时，并行化很有效。对于带有多个考量的复杂任务，当每个考量由单独的 LLM 调用处理、从而能对每一具体方面聚焦注意力时，LLM 通常表现更好。\n\n**并行化有用的例子：**\n\n- **分块**：\n  - 实现护栏：一个模型实例处理用户查询，另一个实例筛查其中的不当内容或请求。这往往比让同一次 LLM 调用同时处理护栏和核心响应表现更好。\n  - 自动化评估（evals）以评测 LLM 性能，其中每次 LLM 调用评估模型在给定提示下表现的不同方面。\n- **投票**：\n  - 审查一段代码是否存在漏洞，由多个不同提示词审查并在发现问题时标记代码。\n  - 评估某段内容是否不当，由多个提示词评估不同方面，或要求不同的投票阈值来平衡误报与漏报。\n\n### 工作流：编排者—工作者（Orchestrator-workers）\n\n在编排者—工作者工作流中，一个中心 LLM 动态拆分任务，将其委派给工作者 LLM，并综合它们的结果。\n\n![The orchestrator-workers workflow](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F8985fc683fae4780fb34eab1365ab78c7e51bc8e-2401x1000.png)\n\n*图：编排者—工作者工作流*\n\n**何时使用此工作流：** 这个工作流非常适合你无法预知所需子任务（例如在编程中，需要改动的文件数量以及每个文件改动的性质很可能取决于具体任务）的复杂任务。尽管在形态上相似，它与并行化的关键区别在于其灵活性——子任务并非预定义，而是由编排者根据具体输入动态决定。\n\n**编排者—工作者有用的例子：**\n\n- 每次都对多个文件进行复杂改动的编程产品。\n- 涉及从多个来源收集并分析信息以寻找可能相关内容的搜索任务。\n\n### 工作流：评估者—优化器（Evaluator-optimizer）\n\n在评估者—优化器工作流中，一个 LLM 调用生成响应，另一个则在一个循环中提供评估与反馈。\n\n![The evaluator-optimizer workflow](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F14f51e6406ccb29e695da48b17017e899a6119c7-2401x1000.png)\n\n*图：评估者—优化器工作流*\n\n**何时使用此工作流：** 当我们拥有清晰的评估标准，且迭代式精炼能带来可衡量价值时，这个工作流特别有效。两个适配良好的标志是：第一，当人类阐明反馈时，LLM 的响应能得到明显改善；第二，LLM 自身能够提供这样的反馈。这类似于人类作者在产出精修文档时可能经历的迭代写作过程。\n\n**评估者—优化器有用的例子：**\n\n- 文学翻译，其中存在译者 LLM 起初可能捕捉不到的细微差别，但评估者 LLM 能提供有用的批评。\n- 需要多轮搜索与分析以收集全面信息的复杂搜索任务，由评估者决定是否值得进一步搜索。\n\n### 智能体（Agents）\n\n随着 LLM 在关键能力上的成熟——理解复杂输入、进行推理与规划、可靠地使用工具、并从错误中恢复——智能体正在生产中涌现。智能体以来自人类用户的指令或交互式讨论开始工作。一旦任务明确，智能体便独立规划与运行，并可能返回人类处获取更多信息或判断。在执行过程中，智能体在每一步都从环境获得\"真实情况\"（ground truth，如工具调用结果或代码执行）以评估进展，这一点至关重要。智能体随后可在检查点，或遇到阻碍时暂停以征询人类反馈。任务通常于完成时终止，但加入停止条件（如最大迭代次数）以保持控制也很常见。\n\n智能体能处理复杂的任务，但它们的实现往往直截了当。它们通常只是 LLM 在一个循环中根据环境反馈使用工具。因此，清晰而审慎地设计工具集及其文档至关重要。我们在附录 2（\"对你的工具做提示词工程\"）中详述工具开发的最佳实践。\n\n![Autonomous agent](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F58d9f10c985c4eb5d53798dea315f7bb5ab6249e-2401x1000.png)\n\n*图：自主智能体*\n\n**何时使用智能体：** 智能体可用于难以或无法预测所需步骤数量、且无法硬编码固定路径的开放式问题。LLM 可能会运行很多轮，你必须对其决策有一定程度的信任。智能体的自主性使其非常适合在可信环境中扩展任务。\n\n智能体的自主本质意味着更高的成本，以及错误累积的潜在风险。我们建议在沙箱环境中进行充分测试，并配置恰当的护栏。\n\n**智能体有用的例子：**\n\n以下例子来自我们自己的实现：\n\n- 一个用于解决 [SWE-bench 任务](https:\u002F\u002Fwww.anthropic.com\u002Fresearch\u002Fswe-bench-sonnet) 的编程智能体，这些任务涉及基于任务描述对许多文件进行编辑；\n- 我们的 [\"computer use\"（计算机使用）参考实现](https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fanthropic-quickstarts\u002Ftree\u002Fmain\u002Fcomputer-use-demo)，其中 Claude 使用计算机来完成任务。\n\n![High-level flow of a coding agent](https:\u002F\u002Fwww-cdn.anthropic.com\u002Fimages\u002F4zrzovbb\u002Fwebsite\u002F4b9a1f4eb63d5962a6e1746ac26bbc857cf3474f-2400x1666.png)\n\n*图：编程智能体的高层流程*\n\n## 组合与定制这些模式\n\n这些构建模块并非规定性的。它们是开发者可以按需塑造和组合以适应不同用例的常见模式。与任何 LLM 功能一样，成功的关键在于衡量性能并迭代实现。重申一遍：你应当*只在*复杂度能明显改善结果时，才考虑增加它。\n\n## 总结\n\n在 LLM 领域的成功，不在于构建最复杂的系统，而在于为你的需求构建*合适的*系统。从简单的提示词开始，用全面的评估优化它们，并仅在更简单的方案力有不逮时，才加入多步智能体系统。\n\n在实现智能体时，我们力求遵循三条核心原则：\n\n1. 在智能体的设计中保持**简洁**（simplicity）。\n2. 通过显式展示智能体的规划步骤来优先保证**透明**（transparency）。\n3. 通过彻底的工具**文档与测试**，精心打造你的智能体—计算机接口（ACI）。\n\n框架能帮你快速起步，但当你走向生产时，不要犹豫去削减抽象层、用基础组件构建。遵循这些原则，你就能创建出不仅强大，而且可靠、可维护、并为其用户所信任的智能体。\n\n### 致谢\n\n由 Erik S. 和 Barry Zhang 撰写。这项工作借鉴了我们在 Anthropic 构建智能体的经验，以及客户分享的宝贵见解，我们对此深表感激。\n\n## 附录 1：实践中的智能体\n\n我们与客户的合作揭示了两个特别有前景的 AI 智能体应用，它们展示了上述模式的实际价值。两个应用都说明：对于既需要对话又需要行动、拥有清晰的成功标准、能启用反馈循环、并整合有意义的人工监督的任务，智能体创造的价值最大。\n\n### A. 客户支持\n\n客户支持将熟悉的聊天机器人界面与通过工具集成增强的能力结合起来。这对于更开放的智能体而言是天然契合的，因为：\n\n- 支持交互天然遵循对话流，同时需要访问外部信息与动作；\n- 可集成工具来获取客户数据、订单历史和知识库文章；\n- 诸如发放退款或更新工单等动作可以程序化地处理；并且\n- 成功与否可通过用户定义的解决结果清晰衡量。\n\n数家公司已通过基于用量的定价模式（仅对成功解决的结果收费）证明了这种方法的可行性，显示出对其智能体有效性的信心。\n\n### B. 编程智能体\n\n软件开发领域已展现出 LLM 功能的惊人潜力，其能力从代码补全演进到了自主解决问题。智能体特别有效，因为：\n\n- 代码解决方案可通过自动化测试验证；\n- 智能体可以用测试结果作为反馈对方案迭代；\n- 问题空间定义明确且结构化；并且\n- 输出质量可被客观衡量。\n\n在我们自己的实现中，智能体现在已能仅凭拉取请求的描述，在 [SWE-bench Verified](https:\u002F\u002Fwww.anthropic.com\u002Fresearch\u002Fswe-bench-sonnet) 基准上解决真实的 GitHub issue。然而，尽管自动化测试有助于验证功能，人工审查对于确保方案符合更广泛的系统需求仍然至关重要。\n\n## 附录 2：对你的工具做提示词工程\n\n无论你在构建哪种智能体系统，工具都可能是你智能体的重要组成部分。[工具](https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Ftool-use-ga)通过在我们的 API 中指定其确切结构与定义，让 Claude 能与外部服务和 API 交互。当 Claude 响应时，如果它打算调用某个工具，会在 API 响应中包含一个 [tool use block](https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fbuild-with-claude\u002Ftool-use#example-api-response-with-a-tool-use-content-block)（工具使用块）。工具的定义与规范，应当像你的总体提示词一样，得到同等程度的提示词工程关注。在这篇简短的附录中，我们描述如何对你的工具做提示词工程。\n\n同一动作常常有几种指定方式。例如，你可以写一段 diff（差异）来指定文件编辑，也可以重写整个文件。对于结构化输出，你可以把代码返回在 markdown 内或 JSON 内。在软件工程中，这类差异只是表面性的，可以无损地互相转换。然而，某些格式对 LLM 来说远比其他格式更难书写。写 diff 需要在写出新代码前，先在块头（chunk header）中知道有多少行在改动。在 JSON 内写代码（相比 markdown）需要对换行和引号做额外的转义。\n\n我们关于决定工具格式的建议如下：\n\n- 给模型足够的 token 让它在\"走进死胡同\"之前先\"思考\"。\n- 让格式贴近模型在互联网文本中自然见到的样子。\n- 确保没有格式上的\"开销\"，例如必须精确数出成千上万行代码，或对其写的任何代码做字符串转义。\n\n一条经验法则是：想想在人机界面（HCI）上要投入多少精力，并计划投入同样多的精力来创建良好的*智能体*—计算机界面（ACI）。以下是一些如何做到的想法：\n\n- 设身处地为模型着想。基于描述和参数，它的用法是否一目了然，还是你也需要仔细思考？如果是后者，那么对模型大概也一样。一个好的工具定义通常包含示例用法、边界情况、输入格式要求，以及与其他工具的清晰界限。\n- 如何修改参数名或描述，让事情更一目了然？把这当作为你团队里初级开发者写一份出色的文档字符串（docstring）。在使用许多相似工具时，这尤其重要。\n- 测试模型如何使用你的工具：在我们的 [workbench](https:\u002F\u002Fconsole.anthropic.com\u002Fworkbench) 中运行许多示例输入，看看模型会犯什么错，并迭代改进。\n- 对你的工具做 [Poka-yoke](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPoka-yoke)（防呆）设计。修改参数，使其更难出错。\n\n在为 [SWE-bench](https:\u002F\u002Fwww.anthropic.com\u002Fresearch\u002Fswe-bench-sonnet) 构建智能体时，我们实际上在优化工具上花的时间比优化总体提示词还多。例如，我们发现，在智能体移出根目录后，模型会对使用相对文件路径的工具犯错。为修复此问题，我们将工具改为始终要求绝对文件路径——结果发现模型完美地使用了这一方法。\n","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-17\u002F826eb252-ac2b-4588-9d03-5138802a0d8b.jpg",[],[],"Anthropic","https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fbuilding-effective-agents",{"id":61,"name":62,"slug":63,"description":64},"c523f1c9-338c-4618-add9-9ce67a39b2a0","研究","research","研究成果与启发",[66,67,68,72,73],{"id":28,"name":29,"slug":30},{"id":24,"name":25,"slug":26},{"id":69,"name":70,"slug":71},"a2ccffe0-49b2-458b-baf6-a83a1b20443d","大语言模型","llm",{"id":36,"name":37,"slug":38},{"id":32,"name":33,"slug":34},true,2,"2024-12-19T00:00:00.000Z","2026-07-17T02:51:57.538Z","2026-07-17T02:51:58.572Z",{"id":80,"type":6,"title":81,"slug":82,"summary":83,"body":84,"coverUrl":85,"productScreenshots":86,"productLinks":87,"authorName":14,"authorUrl":15,"authorSubject":16,"category":88,"tags":89,"sourceLabel":39,"sourceName":40,"sourceUrl":40,"status":41,"seoTitle":40,"seoDescription":40,"canonicalUrl":40,"isFeatured":42,"sno":93,"sortOrder":44,"publishedAt":94,"updatedAt":95,"createdAt":96},"525e9d4d-50ba-48c4-be55-4810590d714b","AI Agent 可观测性：如何知道它到底在哪一步出错","genai-agent-observability-with-opentelemetry","Agent 的一次回答可能经过多次模型调用、检索、工具执行和重试。本文从日志、指标与 Trace 的分工讲起，介绍 OpenTelemetry 的 GenAI 语义约定、失败排查方法、敏感内容采集边界，以及如何把 AI 运行变成可解释的执行链路。","## 当 Agent 答错时，先别急着换模型\n\n一个 Agent 花了 45 秒才回答一个简单问题，原因可能完全不同：模型本身慢、检索服务慢、工具重试了三次、上下文被塞得太长，或者多个步骤串行执行导致整体延迟被放大。\n\n如果系统只有一条“请求失败”日志，你无法知道问题发生在哪里。AI 应用的可观测性，不能只记录最终答案，而要记录一次 Agent 运行中发生过的模型调用、工具调用、检索、重试和输出。\n\n![OpenTelemetry 标志](https:\u002F\u002Fopentelemetry.io\u002Fimg\u002Flogos\u002Fopentelemetry-horizontal-color.png)\n\nOpenTelemetry（简称 OTel）正在为 GenAI 场景补充语义约定（Semantic Conventions），把“模型名称”“输入输出 Token”“工具调用”和“Agent 工作流”等信息用统一字段记录。OpenTelemetry 的[官方实践文章](https:\u002F\u002Fopentelemetry.io\u002Fblog\u002F2026\u002Fgenai-observability\u002F)展示了如何把一次 LLM 调用放进普通服务的 Trace 中。\n\n## 日志、指标和 Trace 各自回答什么\n\n三种信号不是互相替代的：\n\n- **日志**回答“某一刻发生了什么”，适合记录错误详情和业务事件。\n- **指标**回答“整体趋势怎样”，适合看延迟、Token 消耗、错误率和调用量。\n- **Trace**回答“一次请求经过了哪些步骤”，适合定位 Agent 的链路瓶颈。\n\n对传统 Web 请求来说，一条 Trace 可能是“网关 → API → 数据库”。对 Agent 来说，它更像：\n\n```text\n用户请求\n  └─ Agent 工作流\n      ├─ LLM：判断是否需要检索\n      ├─ Retriever：查询知识库\n      ├─ LLM：生成工具参数\n      ├─ Tool：调用订单 API\n      ├─ LLM：整理结果\n      └─ 最终回答\n```\n\n没有这条树状链路，工程师只能靠猜。\n\n## GenAI 语义约定记录了什么\n\n具体字段仍处于演进中，但常见信息包括：\n\n- 请求使用的模型与服务商。\n- 输入 Token、输出 Token 和调用持续时间。\n- 模型停止原因，例如正常结束或发起工具调用。\n- Agent、Workflow、Session 和工具的标识。\n- 检索、工具执行和模型调用之间的父子关系。\n\n例如，一次慢请求可以被拆成：模型调用 1.2 秒，向量检索 0.4 秒，订单 API 8 秒，模型总结 1.1 秒。你不必猜“是不是模型变慢了”，因为 Trace 会直接显示大部分时间花在订单 API 上。\n\n```mermaid\nflowchart TD\n    Q[\"用户请求\"] --> T[\"Agent Trace\"]\n    T --> L1[\"LLM：理解意图\"]\n    L1 --> R[\"检索或工具调用\"]\n    R --> L2[\"LLM：生成下一步\"]\n    L2 --> C{\"成功完成?\"}\n    C -->|否| E[\"记录错误与重试原因\"]\n    C -->|是| M[\"记录结果、Token 与耗时\"]\n    E --> F[\"返回或进入受限重试\"]\n    M --> F\n```\n\n## 一次失败应该怎样排查\n\n假设用户投诉：“客服 Agent 这次答非所问。”可以按下面顺序看 Trace：\n\n### 先看输入是否正确\n\n检查系统指令、用户问题、历史摘要和检索片段是否真的进入了模型上下文。很多所谓“模型幻觉”，根源是检索为空、字段被截断，或者把旧版本政策混进了当前请求。\n\n### 再看工具是否返回正确\n\n工具调用成功不代表业务结果正确。HTTP 状态码是 200，不等于订单查询返回了正确用户的数据。Trace 里应记录工具名称、版本、参数摘要、耗时和错误类型；对于敏感值，只记录哈希、字段名或脱敏后的摘要。\n\n### 最后看模型是否正确使用上下文\n\n如果上下文里有正确资料，模型仍然选错工具或忽略约束，才更像提示设计、模型能力或路由策略的问题。此时可以把同一个 Trace 送进离线评测，比较不同模型、提示模板和工具描述。\n\n## 一条 Agent Trace 应该长什么样\n\n不要把所有信息都塞到一个巨大的 Span 里。更容易排查的结构，是为一次用户任务建立根 Span，再按执行层级嵌套：\n\n```text\nagent.run\n├── retrieval.query\n├── gen_ai.chat\n│   └── tool.call\n├── tool.execute\n└── gen_ai.chat\n```\n\n每个 Span 记录“这个步骤做了什么”和“花了多少时间”，而不是默认保存全部内容。模型 Span 可以记录模型名、响应状态、输入输出 Token 和结束原因；检索 Span 可以记录索引名、Top-K、过滤条件摘要和命中文档 ID；工具 Span 可以记录工具版本、参数校验结果、外部响应码和重试次数。\n\n把字段分成低基数和高基数也很重要。模型名、操作类型和错误类别适合做指标标签；完整用户问题、订单号和工具参数不适合直接作为指标标签，否则时间序列数量会爆炸。高基数信息应该放在受控的日志或事件里，并设置访问权限。\n\n## 从代码到 Trace：先包住边界，再追求完整\n\n第一版 instrumentation 不需要覆盖整个 Agent 框架。可以先包住三个边界：\n\n```python\nwith tracer.start_as_current_span(\"agent.run\") as run:\n    result = call_model(messages)\n    record_model_usage(run, result.usage)\n\n    with tracer.start_as_current_span(\"tool.execute\") as tool_span:\n        tool_span.set_attribute(\"tool.name\", tool_name)\n        tool_result = execute_tool(args)\n\n    final = call_model(messages + [tool_result])\n```\n\n关键不是这段代码本身，而是让每次模型调用和工具调用都继承同一个 Trace 上下文。否则你会得到一堆互相孤立的请求记录，仍然无法回答“这次回答经过了哪个工具”。\n\n接下来再补齐重试、检索和人工接管。每加一类信号，都应该配一个排查问题：它能不能帮助定位慢、错、贵或不安全？如果不能，就不要为了“字段齐全”增加采集复杂度。\n\n## 内容采集是双刃剑\n\n记录完整 Prompt 和模型输出，对调试非常有帮助；但这些内容也可能包含个人信息、商业机密、访问令牌和用户输入的恶意指令。\n\nOpenTelemetry 的 GenAI 指南特别强调，默认可以只记录模型名、Token 和耗时，只有明确开启内容采集时才保存完整消息、工具参数和工具结果。生产环境建议分层：\n\n- 默认记录元数据，不记录原文。\n- 调试租户或抽样请求才采集内容。\n- 对邮箱、手机号、订单号和密钥做脱敏。\n- 限制 Trace 的保存时间和访问角色。\n- 严禁把完整 Prompt 直接打进普通应用日志。\n\n可观测性本身也必须经过威胁建模，否则为了排查 AI 问题，反而建立了一个更大的数据泄露面。\n\n一种实用的内容策略是“默认摘要、按需取原文”：Trace 默认只保存消息长度、哈希、敏感字段数量和版本号；当用户授权调试时，再从加密的短期存储中关联原文。这样既能判断“上下文是否变长、是否发生了重试”，也不会让每个监控面板都暴露完整对话。\n\n如果确实需要记录工具结果，应优先保存经过裁剪的结构化摘要。例如只保存 HTTP 状态、返回字段集合和结果条数，不保存完整客户资料。对于安全事件，还可以保存触发规则和脱敏后的攻击片段，让安全团队能复盘，不让普通业务角色看到原始隐私数据。\n\n## 指标应该如何设计\n\n至少需要四类指标：\n\n1. **延迟**：首 Token 延迟、完整响应延迟、工具调用延迟。\n2. **消耗**：输入输出 Token、缓存命中、模型调用次数。\n3. **可靠性**：超时、解析失败、工具失败、重试次数和人工接管率。\n4. **质量代理指标**：引用覆盖率、结构化输出校验率、拒答率和离线评测分数。\n\n不要把“Token 越少越好”当成唯一目标。压缩上下文可能降低成本，却也可能删掉回答所需的证据。正确的做法是同时看质量、延迟和成本，按用户任务分组，而不是只看全局平均数。\n\n这些指标还需要和“请求类型”绑定。客服问答、代码生成、文档摘要和事务执行的正常范围不同，混在一起看会把异常平均掉。建议至少按 Agent、任务类型、模型版本和租户分组，并同时看 P50 与 P95。平均延迟正常，不代表最慢的那 5% 用户没有一直卡住。\n\n成本归因也不要只用一个总金额。可以把一次任务的成本拆成模型成本、检索成本、工具调用成本和重试成本。这样当账单上升时，你才能判断应该缩短上下文、调整模型路由、修复工具超时，还是限制某一类 Agent 的最大步数。\n\n## 与传统 OTel 的关系\n\nGenAI 语义约定不是一套新的监控后端，也不是要求你换掉现有的 Jaeger、Prometheus 或 OTLP Collector。它更像是一组让不同厂商“说同一种字段语言”的约定。\n\n因此，落地可以从现有链路开始：给每次 Agent 运行创建一个根 Span，把模型调用和工具调用作为子 Span，再把 Token、模型版本和错误原因写入标准属性。这样未来更换可观测性后端时，数据仍然能迁移。\n\n不过要注意，语义约定仍在快速发展，字段的稳定级别可能变化。建议把属性名集中封装在自己的 instrumentation 层，不要在几十个业务文件里散落字符串。\n\n## 从观测到自动修复\n\n可观测性最终不只是给人看，还可以成为控制回路：\n\n- 工具连续超时，自动降低该工具的并发并切换备用路径。\n- 输入 Token 接近预算，先压缩历史，再决定是否升级模型。\n- 结构化输出连续校验失败，暂停自动执行，转人工处理。\n- 某个模型版本的错误率显著上升，按流量比例回滚到上一版本。\n\n但自动修复必须有边界。不要让 Agent 根据自己记录的 Trace 无限调整权限、提示词或工具列表。观测数据应该进入经过审核的策略层，由明确的阈值、审批和回滚机制控制变更。\n\n## 结语：从“答案错了”走向“哪一步错了”\n\nAI Agent 的可观测性不是给日志加几个 Token 字段，而是把一次非确定性运行还原成可解释的执行链路。工程团队真正需要的不是知道“模型很慢”，而是知道“哪一个模型调用、哪一次检索、哪一个工具、哪一次重试造成了这次慢”。\n\n建议先选一个高价值流程，建立最小 Trace：请求 ID、Agent ID、模型名、输入输出 Token、工具名、耗时和错误类型。等链路稳定后，再逐步加入内容采集、评测结果和成本归因。\n\n**落地清单：**\n\n- 是否能看到一次 Agent 运行的完整步骤树？\n- 是否能区分模型慢、工具慢和重试造成的慢？\n- 是否记录了模型版本、提示版本和工具版本？\n- 是否默认关闭敏感内容采集？\n- 是否把 Trace 与离线评测样本关联起来？\n\n## 一手资料\n\n- [OpenTelemetry GenAI 可观测性实践](https:\u002F\u002Fopentelemetry.io\u002Fblog\u002F2026\u002Fgenai-observability\u002F)\n- [OpenTelemetry GenAI 属性与语义约定](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fsemconv\u002Fregistry\u002Fattributes\u002Fgen-ai\u002F)\n- [OpenTelemetry 语义约定总览](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fsemconv\u002F)","\u002Fuploads\u002F2026-08-05\u002F19586c04-7c5c-483a-8cdf-0860e7a03918.jpg",[],[],{"id":18,"name":19,"slug":20,"description":21},[90,91,92],{"id":28,"name":29,"slug":30},{"id":32,"name":33,"slug":34},{"id":36,"name":37,"slug":38},64,"2026-07-31T00:00:00.000Z","2026-08-05T04:11:43.185Z","2026-08-05T02:13:45.344Z",{"id":98,"type":6,"title":99,"slug":100,"summary":101,"body":102,"coverUrl":103,"productScreenshots":104,"productLinks":105,"authorName":14,"authorUrl":15,"authorSubject":16,"category":106,"tags":107,"sourceLabel":39,"sourceName":40,"sourceUrl":40,"status":41,"seoTitle":40,"seoDescription":40,"canonicalUrl":40,"isFeatured":42,"sno":111,"sortOrder":44,"publishedAt":112,"updatedAt":113,"createdAt":114},"03ca8001-f2c1-4b68-9a9a-1d2225483c68","Durable Execution：如何让长任务 Agent 崩溃后接着工作","durable-execution-for-long-running-agents","长任务 Agent 会遇到进程崩溃、网络故障、工具超时和人工等待。本文用 Workflow、Activity 与 Event History 拆解 Durable Execution，解释它与普通重试的区别、幂等副作用的边界，以及如何设计可暂停、恢复和审计的 Agent 工作流。","## Agent 最难的不是“会思考”，而是“不会丢进度”\n\n一个 Agent 要完成“调研供应商、比较报价、提交审批”这样的任务，往往需要十几个步骤。模型调用可能超时，工具服务可能暂时不可用，执行进程可能在第八步重启，用户也可能隔几个小时才回来确认。\n\n如果系统只把整个过程写成一段普通函数，失败后通常只能从头再来。这不仅浪费时间和模型调用，还可能重复扣款、重复发邮件或重复创建订单。\n\nDurable Execution（持久化执行）提供了另一种思路：把长任务写成可恢复的工作流，持续保存每一步的状态和结果。进程挂掉后，系统从最近一次完成的位置继续，而不是把 Agent 当成一次性请求重新启动。\n\n![Temporal 工作流项目概念图](https:\u002F\u002Fopengraph.githubassets.com\u002F1\u002Ftemporalio\u002Ftemporal)\n\nGoogle 的 Gemini 官方示例使用 Temporal 构建可恢复的 Agent 循环：模型调用和工具调用作为可重试的活动执行，工作流负责组织顺序和状态。[Temporal 官方文档](https:\u002F\u002Fdocs.temporal.io\u002F)把这种能力概括为让应用在崩溃、网络故障或基础设施中断后从原位置恢复。\n\n## 重试不等于持久化执行\n\n最简单的重试是：请求失败后，再调用一次同一个函数。\n\n但长任务通常有多个步骤：\n\n```text\n读取客户资料 → 查询库存 → 生成报价 → 请求审批 → 创建订单 → 发送通知\n```\n\n如果“创建订单”之后通知服务超时，系统无法判断订单到底创建成功没有。此时直接重试，可能得到两个订单；不重试，用户又可能永远收不到通知。\n\n持久化执行关注的不是“把异常捕获住”，而是把工作流历史、每一步的输入输出和重试状态保存下来。系统可以知道哪些步骤已经完成，哪些步骤还没有拿到确定结果。\n\n不过，持久化执行也不会自动把外部世界变成 exactly-once。数据库写入、付款、发邮件等外部副作用仍然需要幂等键、去重表或业务状态机配合。它解决的是“执行进度可恢复”，不是“所有外部系统天然只执行一次”。\n\n## 三个核心概念\n\n### Workflow：稳定的流程骨架\n\nWorkflow 描述任务的顺序、分支、等待和超时。例如：先并行查询三个供应商，等用户选择后再发起审批。它应该尽量保持确定性，因为系统可能会根据历史事件重放 Workflow 代码。\n\n### Activity：可以失败的具体动作\n\nActivity 承担模型调用、HTTP 请求、数据库读写、文件处理等不稳定工作。它们可以单独设置超时、重试策略和并发限制，也可以记录调用结果。\n\n### Event History：可重放的执行历史\n\n每完成一步，系统都会留下事件。恢复时，Workflow 根据历史跳过已完成的 Activity，重新计算下一步应该做什么。对 Agent 来说，这相当于把“上下文”从一段容易丢失的内存，变成可审计的执行记录。\n\n```mermaid\nflowchart TD\n    Q[\"用户提交长任务\"] --> W[\"启动持久化 Workflow\"]\n    W --> A1[\"Activity：读取资料\"]\n    A1 --> A2[\"Activity：调用模型与工具\"]\n    A2 --> H{\"需要人工确认?\"}\n    H -->|是| P[\"等待外部信号\"]\n    P --> A3[\"Activity：执行副作用\"]\n    H -->|否| A3\n    A3 --> C[\"记录完成事件\"]\n    C --> D[\"返回结果\"]\n    A2 -. \"进程崩溃或网络失败\" .-> R[\"从最近事件恢复并重试\"]\n    R --> A2\n```\n\n## Agent 为什么特别需要这个能力\n\n传统 CRUD 请求通常几百毫秒到几秒就结束，失败后重新请求的代价有限。Agent 任务则经常包含：\n\n- 多轮模型调用，且每轮可能选择不同工具。\n- 长时间等待人工审批、第三方回调或定时条件。\n- 需要跨越多个服务，任何一个依赖都可能短暂失败。\n- 不能重复执行的外部副作用。\n\n例如“整理一批合同并生成风险清单”可以分成：上传文件、解析文本、并行抽取条款、合并结果、人工复核、生成报告。解析到第六份文件时进程崩溃，如果前五份结果已经被保存，系统就不该从第一份重新开始。\n\n## Agent 工作流应该怎样拆\n\n一个实用原则是：**模型负责做判断，Workflow 负责保存进度，Activity 负责接触外部世界。**\n\n可以把 Agent 循环写成下面的逻辑：\n\n```python\nwhile not task_done:\n    decision = await call_model(state)\n    if decision.kind == \"tool_call\":\n        result = await run_tool_activity(decision.tool, decision.args)\n        state = update_state(state, result)\n    elif decision.kind == \"needs_human\":\n        await wait_for_signal()\n    else:\n        return decision.answer\n```\n\n这里的 `call_model` 和 `run_tool_activity` 不应被当成普通内存函数。模型请求应有超时、重试和版本记录；工具调用应有幂等键、权限检查和结果快照；`state` 应能在任务恢复后重新获得。\n\n对于高风险动作，最好把“决定要做”和“真正执行”拆成两步：先生成待确认计划，再由用户或策略引擎发出批准信号。这样 Agent 可以长时间等待，而不需要占用一个一直在线的 HTTP 请求。\n\n## 重放为什么要求 Workflow 保持确定\n\n持久化引擎恢复任务时，可能会重放 Workflow 代码，让它重新读取历史事件并走到当前节点。因此 Workflow 里不应该直接调用随机数、当前时间、网络请求或 LLM。否则同一份历史在第二次计算时得到不同分支，系统就无法判断哪些 Activity 已经执行过。\n\n正确的拆法是：Workflow 只负责调度，外部世界交给 Activity。当前时间可以由引擎提供一个可重放的时间值；随机 ID 可以在 Workflow 外生成后作为输入；模型调用必须作为 Activity 保存请求和结果。伪代码看起来相似，但责任边界不同：\n\n```python\n@workflow\nasync def order_workflow(request):\n    plan = await execute_activity(make_plan, request)\n    await workflow.wait_condition(lambda: workflow_state.approved)\n    result = await execute_activity(create_order, plan)\n    await execute_activity(send_notification, result)\n    return result\n```\n\n这里的 `make_plan`、`create_order` 和 `send_notification` 都可能失败，但 Workflow 本身只在事件历史上推进。尤其是 `send_notification`，不能因为它超时就假设“肯定没发出去”；它需要一个业务侧的幂等键，例如 `workflow_id + step_name`，让重复尝试最终只产生一条通知。\n\n## 幂等、副作用与“结果未知”\n\n工程上最危险的不是明确失败，而是**结果未知**：客户端发出创建订单请求，连接在服务端返回之前断开。此时 Agent 无法仅靠异常判断订单是否存在。\n\n常见处理方式是把副作用设计成三段：\n\n1. 生成全局幂等键，并把它写入请求。\n2. 服务端在事务中记录“幂等键 → 业务结果”。\n3. 重试前先用幂等键查询；如果已有结果，直接复用，不再创建新副作用。\n\n邮件、支付、工单、仓储扣减都可以采用类似模式。若第三方 API 不支持幂等键，就要在自己的系统里增加状态表或中间层，至少能够区分“尚未执行”“执行中”“已确认成功”和“需要人工核查”。\n\n这也是为什么 Durable Execution 不能单独解决一致性问题：它能可靠地恢复你的流程，却无法替你修改银行、邮件服务或供应商系统的语义。\n\n## 人工确认其实是工作流的一部分\n\n很多 Agent Demo 把人工确认做成一个同步接口：模型问“要不要继续”，用户必须立刻回答。生产系统更常见的情况是用户关掉页面，第二天才点批准。\n\n持久化 Workflow 可以把等待设计成显式状态：\n\n```text\n准备计划 → 等待审批 → 已批准 \u002F 已拒绝 \u002F 已过期\n```\n\n用户批准时发送一个带有 `workflow_id`、审批人、审批时间和审批版本的信号。执行前再次检查计划是否被修改、权限是否仍然有效、价格或库存是否过期。这样“用户点过同意”不会被误当成对任何未来状态都永久授权。\n\n还可以设置补偿动作。例如订单已创建但通知失败，补偿动作不是删除订单，而是把通知标记为待补发；如果支付已扣款但库存预留失败，则进入人工处理队列，而不是让 Agent 自己随意退款。\n\n## 重试策略不能一刀切\n\n不同错误应该使用不同策略：\n\n- **网络暂时不可用**：指数退避后重试。\n- **限流**：尊重服务端的 Retry-After，并降低并发。\n- **参数错误**：先让 Agent 修正参数，不要盲目重复。\n- **权限错误**：暂停并请求用户授权。\n- **副作用结果未知**：先查询业务状态，再决定是否重试。\n\n模型调用通常可以重试，但重试也可能产生不同答案。若下游依赖结构化输出，恢复时应保存原始响应、解析结果和模型版本，避免同一任务在重放中悄悄换成另一种决策。\n\n建议把每次重试都记录成一个可查询的事件，而不是只在应用日志里写一行“retry”。至少保留：步骤名、尝试次数、错误类别、等待时长、依赖版本和最终结果。这样可以回答两个很实际的问题：一次任务失败是依赖偶发抖动，还是某个工具从根本上不稳定；以及重试成功到底为平均延迟和成本增加了多少。\n\n版本升级也要谨慎。Workflow 可能持续运行数天，旧任务的历史需要由旧代码解释，新任务才使用新逻辑。实际落地时要为流程定义做版本兼容或迁移策略，不要直接修改一个正在执行的分支含义。\n\n## 什么时候不值得上 Durable Execution\n\n它不是所有 Agent 的默认基础设施。一次性问答、无副作用的摘要、几秒内完成的简单分类，普通请求加超时和日志就够了。\n\n引入工作流平台会增加服务部署、事件存储、版本迁移和运维成本。只有当任务真的跨步骤、跨时间、跨服务，且失败恢复的价值高于基础设施成本时，才值得采用。\n\n## 落地清单\n\n- 把每一步标成“可重试”“不可重试”或“需要人工确认”。\n- 为所有外部副作用设计幂等键和状态查询接口。\n- 把模型调用、工具调用、解析和业务写入拆成可观测的 Activity。\n- 记录模型版本、提示模板版本、工具参数和返回摘要。\n- 为 Workflow 设置总时限、单步时限和最大重试次数。\n- 设计暂停、恢复、取消和人工接管，而不只是成功路径。\n\n持久化执行的核心价值，可以用一句话概括：Agent 不再是一段“运行时可能忘记一切”的循环，而是一条可以暂停、恢复、审计和接管的业务流程。\n\n## 一手资料\n\n- [Temporal 官方文档](https:\u002F\u002Fdocs.temporal.io\u002F)\n- [Gemini + Temporal 的 Durable AI Agent 示例](https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Ftemporal-example?hl=en)\n- [Temporal Durable Execution 介绍](https:\u002F\u002Ftemporal.io\u002Fhow-it-works)","\u002Fuploads\u002F2026-08-05\u002F6ea439e7-4d7e-46cc-ace8-efc556719f28.jpg",[],[],{"id":18,"name":19,"slug":20,"description":21},[108,109,110],{"id":24,"name":25,"slug":26},{"id":36,"name":37,"slug":38},{"id":32,"name":33,"slug":34},65,"2026-08-04T00:00:00.000Z","2026-08-05T03:15:43.428Z","2026-08-05T02:13:44.156Z"]