去年 11 月,我交付给一个客户一个由 Claude 驱动的代理,它应该能分类入站支持工单、将其路由到合适的部门,并起草初稿回复。我花了三周时间来构建它。在测试环境中看起来棒极了。上线第一天,它幻觉出了一个不存在的退款政策,把 17 张工单路由到了错误的队列,还信心满满地告诉一个客户他们的订单会"周四"送达,而它根本无法获取配送数据。
所以。我学到了一些东西。
这篇文章讲的是我现在知道的东西,在我正确重建那个代理并上线了几个新的代理之后。不是理论。是我实际做过的决策、我用过的工具,以及我不会重复犯的错误。如果你是代理公司的老板或自由职业者,想要超越使用 Claude Agent SDK 的演示阶段,这篇文章就是为你写的。
---
Claude Agent SDK 实际是什么(以及不是什么)
首先要说的是:SDK 不是魔法。它是一种结构化的方式,用来让 Claude 访问工具、跨多轮管理对话上下文,以及编排一个决策循环。Claude 推理一项任务,决定是否调用工具,获得返回结果,再次推理,要么调用另一个工具,要么给出最终答案。
这个循环听起来很简单。确实很简单。复杂性完全在于你在它周围放了什么。
SDK 提供的是管道。你仍然要负责水压、管径,以及你是否记得在开始钻孔前关掉水闸。我见过代理公司老板把 SDK 交给一个初级开发者,期望在一个冲刺周期内得到成品,结果得到的东西从技术上讲能跑,但遇到任何不在happy path中的输入就会崩溃。
实践中的循环是什么样的
你将工具定义为 JSON schema。Claude 读取这些 schema,决定何时使用它们,传递结构化参数,你的代码执行实际逻辑。Claude 永远不会直接运行代码。它是在请求。你的系统在做工作。然后 Claude 获得结果并继续。
这种分离的重要性比大多数人意识到的要大。它意味着 Claude 总是一个编排器,而不是执行器。这种框架应该引导你做出的每一个架构决策。
---
设计 Claude 能真正使用的工具
大多数构建在这里失败。过去一年我审查过大约 15 个来自其他开发者的代理代码库,最常见的问题不是提示工程或模型选择。是工具设计不当。
"设计不当"在实践中是什么意思:
- 一个叫
process_data的工具做五件无关的事情,具体取决于你传递的参数 - 工具描述读起来像内部代码注释("用认证头调用 v2 端点")
- 参数叫
type或mode,接收任意字符串而不是枚举 - 返回值中没有错误信息,所以 Claude 不知道调用是否成功
2023年初,Seahawk有一个内容管道项目,我们构建了一个manage_content工具,它接受一个action参数:create、update、delete、publish、unpublish、archive。Claude经常选错action,因为仅从schema无法看出这些区别。我们把它拆成六个独立的工具。在我们的内部评估中,那个特定决策的准确率从约60%上升到94%。只改了一个地方。
我现在遵循的规则
- 一个工具,一个工作。如果你不能用一句话(不含"和")来描述工具的目的,就把它拆开。
- 尽可能使用枚举。别让Claude去猜字符串。
- 为Claude写描述,不是为人类开发者写。Claude不了解你的代码库。它只知道你告诉它的东西。
- 始终返回包含明确成功/失败字段的结构化数据。别让Claude从沉默中推断。
- 工具名称要动词开头。search_orders、create_draft、fetch_customer_record。不要orders、draft、customer。
Anthropic工具使用文档对schema结构有更深入的说明,值得仔细阅读,别只是扫一眼。
---
上下文管理是隐藏的成本
这是一个没人充分讨论的问题。token不是免费的,agent很能吃。
循环中的每一轮都包括完整的对话历史、所有工具schema、系统提示和工具结果。一个中等复杂度、包含十个工具和详细系统提示的agent,可能在用户输入任何内容之前就要消耗3000-4000个token。加上五六个工具调用及其结果,每个已解决的任务就要花15000-20000个token。按Claude目前的API定价,这在任何量级上都会迅速累积。
我现在对此追踪得很仔细。对于我发布的每个agent,我都在QA期间运行成本per-resolution的计算。如果超过我与客户事先约定的阈值,我就会回过头来收紧系统提示、减少工具schema,或者看看能否使用提示缓存来缓存静态上下文,这是Anthropic添加的功能,我现在在每个项目上都用。在缓存命中时,缓存合格的token成本约为标准输入费率的10%。对于一个每天重新运行相同系统提示数千次的繁忙agent,这绝不是舍入误差。
精简而不破坏功能
诱惑是写一个涵盖所有边界情况的丰富、详细的系统提示。别这样做。你添加的每一行都要在每一轮上花token。为常见情况写。在工具返回值中或在正确时刻注入的更短的上下文指令中处理边界情况。
一旦agent工作起来,我也会无情地删除工具描述。如果描述说"此工具搜索订单数据库并返回与查询匹配的订单列表,包括订单ID、客户名称、行项目、配送状态和时间戳",我会简化为"按查询字符串搜索订单。返回匹配的订单记录。"Claude足够聪明。如果返回schema正确地记录了这些字段,它不需要工具描述中的字段列表。
---
多agent编排:一个agent不够时
单agent系统在一定的复杂度天花板处就会失效。去年春天我在一个物业管理公司的项目上触及了这个天花板。该agent需要处理维护请求、与承包商沟通、更新Notion数据库、通过SendGrid发送模板邮件,以及从自定义日历API拉取可用性数据。七个工具,其中几个有子工作流。
一个agent试图协调所有这些事情变得不可靠。上下文变得混乱。Claude有时会在循环中途忘记它在处理哪个子任务。
解决方案事后看起来很明显:编排器加专家。一个顶级Claude agent处理意图分类和路由。专家子agent处理特定的领域(通信、日程安排、数据更新)并返回结构化结果。编排器永远看不到每个专家做了什么的内部细节。它只看到输出。
这个模式在Anthropic自己的多agent指导中有描述,紧密映射到你如何设计一个人类团队。项目经理不会亲自写每封邮件和更新每个电子表格。他们委派、等待确认,然后继续。
关于子agent设计的实用笔记
- 为每个子agent给予严格、具体的系统提示。不要有跨领域的指令。
- 子代理不应该拥有超过其领域所需的工具。工具臃肿对子代理的危害就像对主编排器的危害一样大。
- 显式传递上下文。不要假设子代理"知道"上游发生了什么。只发送它需要的信息,不要多。
---
优雅地处理失败(因为它们会发生)
生产代理会失败。它们会超时。外部API返回500错误。用户发送你从未预料过的输入。Claude有时会误读工具架构并传递格式错误的参数。
问题不在于你的代理是否会失败。问题在于它是否能安全地失败。
现在我在每个代理中都无一例外地内置了三个东西:
- 对所有外部工具调用进行重试逻辑,带有退避。不仅仅是速率限制错误。对任何非200的响应都要重试。
- 当代理在不超过N次工具调用的情况下未能解决任务时,设置一个回退路径。N的值各不相同,但我很少让它超过八。到那个点,说明有问题,应该让人工介入。
- 系统提示中明确的不确定性处理。我告诉Claude:如果你没有足够的信息来有信心地行动,就问一个澄清问题,而不是基于假设继续。
第三点拯救了我最初提到的工单分类代理。重建后的版本现在在不确定路由时会问一个澄清问题。用户不会介意。他们宁愿回答一个问题,也不想让他们的工单进入错误的队列。
---
评估:没有它们你无法上线
我没有对支持工单代理的第一个版本运行适当的评估。那才是真正的错误。其他一切都是这个错误的症状。
评估不必很花哨。我现在做的是在开始构建之前构建一套40-60个代表性输入,涵盖正常情况、边界情况和对抗性输入。在每次重大改变后,我都针对所有这些输入运行代理。我跟踪三个数字:任务完成率、工具调用准确率(它是否调用了正确的工具并使用了正确的参数)和幻觉率(它是否声称了未建立在工具结果基础上的东西)。
对于生产代理,我不会在任务完成率低于88%且高风险输出(如包含特定声明的客户面向消息,如日期、价格、政策)中对幻觉零容忍的情况下上线。
斯坦福大学的HELM基准测试框架值得查看,以获得评估设计的灵感,即使你不是在学术规模上运行。他们测试的类别很好地映射到真实的生产需求。
---
系统提示是承重的
在过去一年里我改变了对这个问题的看法。我曾经把系统提示当作设置文本,写一次就忘了。现在我把它当作项目中最重要的文件。
一个写得好的系统提示做四件事:
- 明确定义代理的身份和范围(它做什么,以及关键的,它明确不做什么)
- 设置语气和输出格式期望
- 主动处理最常见的失败模式("如果你找不到订单,明确说出来,而不是猜测")
- 建立升级标准
范围定义是大多数开发者跳过的。没有它,Claude会尽力帮助你未曾打算的方式。在物业管理代理上,第一个系统提示没有明确排除财务建议。一个租户问代理他们是否应该对费用提出异议。Claude有帮助地权衡了一下。这不是客户付钱的东西,也不是代理的构建目的。
一句话就解决了:"你无权提供关于财务纠纷、法律事项或租赁解释的建议。请直接指导用户联系办公室了解这些主题。"
为每个超出范围的域写上这句话。不要假设Claude会自己推断边界。
---
FAQ
Claude Agent SDK与直接使用Claude API有什么不同?
API提供单一的请求-响应。Agent SDK(以及Anthropic记录的代理模式)提供结构化循环,Claude可以做出多个决策、调用工具、接收结果,并在多个回合间继续推理。这更多是关于一种模式而不是独立软件包:工具定义、多轮上下文管理和编排逻辑。你在API周围构建脚手架以启用这种循环。
发布生产就绪代理的现实时间表是多少?
说实话,任何非平凡的东西需要四到六周。其中两周用于构建和连接工具。一周用于提示词工程和迭代。一到两周用于评估、边界情况处理和QA。任何承诺一周内交付生产代理的人,要么没有实际发过代理,要么是把演示包装成产品。
在多代理系统中应该为所有子代理都使用Claude,还是混合使用不同模型?
我在需要细致推理或输出质量对最终用户很重要的地方使用Claude。对于简单分类任务或高量低风险路由,较小且便宜的模型可以适用。但混合模型会增加集成开销并使调试变得更困难。先为所有任务使用Claude,然后根据真实生产数据显示某个较轻模型足够时再优化。
我如何防止代理偏离脚本?
三件事共同发挥作用:带有明确超出范围声明的严格系统提示、在物理层面防止某些操作的工具设计(不要给代理它不应该使用的工具),以及对任何面向客户内容的输出验证。你不能仅依赖系统提示。这需要纵深防御。
开发者在代理内存方面最大的错误是什么?
把上下文窗口当作无限的。但它不是。我看到大多数设计不良的代理失败都来自于充斥着无关历史的臃肿上下文,迫使Claude通过噪音进行推理。积极地修剪。在可能的地方进行总结。只保留代理真正需要完成当前任务的内容。
---
诚实的总结是这样的:SDK不是难点。难点始终是软件开发中的同样问题——清楚地思考范围、为失败而设计,以及在发布前测试。Claude是一个强大的推理层,但它不会弥补系统设计不当的缺陷。先把管道搞对。
