本节课没有语音摘要。
屏幕 1:到本模块结束时你将能够做什么
模块 4 方向介绍 · 2 分钟 到本模块结束时你将能够做什么
你已经构建了能工作的代理。本模块是关于证明它们在生产流量下继续工作。
在过去两个模块中,你连接了工具使用循环,构建了具有规划和记忆的代理,并用钩子和 MCP 服务器打包了 Claude Code 工作流。这些代理能运行。生产提出的开放问题是不同的:当一个你从未测试过的边界情况到达时,当速率限制达到峰值时,当获取的网页携带隐藏指令时,系统是否能坚持还是会悄然失败?本模块将"在我的机器上能工作"变成一个你可以在审查中为之辩护的系统。这项工作分为五件你将能够做的事情。
到本模块结束时,你将能够: 1 编写一个评估套件,在部署前定义 Claude 功能的"完成"含义,选择适合任务的评分方法,并根据人工标记的案例校准 LLM-as-judge 评分,使结果是你可以为之辩护的。 2 构建一个测试和追踪层,在单元、功能、集成和端到端级别捕获回归。 3 通过区分可重试错误和终端错误,创建一个对生产故障有弹性的应用。 4 通过对每个调用进行仪表化并仅在任务需要时才使用并行代理,保持系统在其成本、延迟和可靠性预算内,包括当工作分散在多个协调代理中时。 5 通过防御提示注入、越狱、不受信任的输入、作用域身份、暴露的秘密和数据边界,为集成辩护,使部署能通过安全或合规审查。
本模块适合已经构建了能工作的东西,现在必须证明一旦有更多人依赖它们就能继续工作的开发者。你是实用的、代码优先的、面向模式的。本模块假设你从前两个模块连接的工具使用循环、构建的具有规划和记忆的代理,以及打包的 Claude Code 工作流能工作,不会重新审视它。它是关于决定功能在生产流量下是否能坚持的工程决策:你如何衡量它是正确的,你如何测试和追踪它,你如何处理生产抛出的开发从未显示的故障,你如何保持它在成本和延迟预算内,以及你如何针对不受信任的输入和安全审查为它辩护。
"本模块中的构建"
本模块中的一切都围绕一个反复出现的差距构建:开发隐藏了生产揭示的故障。在开发中,该功能在你尝试的少数几次中返回了正确的答案,每个调用都成功了,因为流量从未达到限制,语料库适合窗口,代理读取的唯一内容是你写的内容。在生产中,同一系统遇到没有人测试过的输入形状、峰值时的速率限制、太大而无法加载的语料库,以及携带针对代理的指令的获取页面。故障几乎从不是运行的代码中的错误。它是一个从未做出的决定:成功从未被写下来作为一个分级集合,可重试情况从未被给予一条路径,预算从未被仪表化,操作边界从未被强制执行。本模块中的工作是在故障在生产中出现之前在纸上做出每一个决定,并在构建的其余部分读取的设计文档中捕获它们。你添加的每一层,评估、测试和追踪、故障路径、成本预算和安全边界,都关闭了开发到生产差距变成悄然生产故障的一种方式。
教育内容的免责声明/通知
我们构建了这个开发者课程模块 4:生产工程、评估和安全,以帮助你用 Claude 完成真实工作。将其视为教育内容。它不构成法律、财务或其他专业建议,因此请根据你自己的情况调整你学到的内容。我们的产品和服务发展迅速,因此某些内容可能包含错误或已过时;记住在 Anthropic 的网站或文档上验证。课程中使用的示例和场景是说明性的,通常是虚构的。如果课程材料提到一家公司或产品,这并不意味着 Anthropic 认可它们,它们认可 Anthropic,或者我们有关联。另请注意,你对 Anthropic 产品和服务的使用受我们的条款、政策和文档的约束;如果本课程中的任何内容与它们冲突,它们占优先地位。
屏幕 2:在你发货前定义完成:评估和校准的评判者
教学 评估与评判者 · 20 分钟 在你发货前定义完成:评估和校准的评判者 你的成功指标很简单:代码正确工作。你在前面模块中构建的代理和工具在你手动尝试时正确回答。差距是"我尝试了几次,看起来是对的"不是你可以追踪的信号。
生产硬化需要的第一件事是一种方法,将这种直觉变成一个可衡量的数字,当提示、工具或模型改变时你可以追踪。这就是评估给你的,本模块的其余部分都依赖于它。
编写说明什么是完成、安全和可负担的设计文档 在你编写任何生产代码之前,写下你将要构建什么以及你将如何知道它是正确的。设计文档是那个书面记录。它是一个短文件,通常是单个 markdown 页面,说明功能的成功标准、系统必须存活的故障、系统必须保持在内的成本和延迟,以及系统必须防御的信任边界。它是实现之前的规划步骤,存在是为了让你定义什么是正确的,而不是稍后为模型产生的任何东西辩护。
文档首先出现的原因是本模块中的每个生产层都基于它。成功标准成为你的评估被评分的案例。你列出的故障成为你的错误处理必须覆盖的可重试和终端案例。成本和延迟数字成为你对其进行仪表化的预算和你拒绝优化以下的底线。信任边界成为你视为数据的输入和你用钩子门控的操作。在构建之前一次性写下这四个决定,是保持各层彼此一致而不是每一层解决不同问题的原因。
一个有用的设计文档包含四个决定,每个都说得足够具体,以至于有人可以根据它检查构建的系统:
1成功标准命名功能必须产生什么。用足够具体的术语说明代表性案例的输出以进行评分,因为"总结线程"这样的模糊目标无法检查,而"列出每个操作项及其所有者的两句摘要"可以。这些标准是你的评估集从中构建的,所以首先写下它们是使评估成为可能的原因。 2故障处理命名系统必须存活的故障以及它对每个故障做什么。列出生产将抛出的错误,将每个标记为可重试或终端,并说出当故障无法恢复时用户得到什么。在纸上做出这个决定是什么阻止第一个真实速率限制响应成为你发现你没有错误路径的时刻。 3成本和延迟预算命名系统必须保持在内的上限和它无法交易的可靠性底线。在确定架构之前设置硬成本和延迟预算。写下每请求预算、每月成本上限和延迟目标,以及设计必须保持的最小可靠性。在构建之前设置这些数字是什么让你在写一行代码之前根据预算检查架构。 4信任边界命名哪些输入不受信任以及系统被允许做什么。写下代理读取的哪些内容是其他人可以写的,以及功能完成其工作所需的最小操作和访问集。在纸上命名边界是什么将最小权限变成你可以用钩子强制执行的设计决定,而不是你稍后记得添加的设置。
如果你构建一个代理编码工具,这个文档也是你在它写任何东西之前提交的。首先规划工作并将结果捕获为书面工件,然后根据它实现。给定明确成功标准和明确约束的工具做出更少的假设并产生你可以根据你已经同意的文档检查的代码。本模块依次教授这四个决定中的每一个,累积任务在最后要求你同时针对所有四个硬化系统。
评估是定义功能在发货前必须做什么的测试集 评估的工作方式就像温度计一样。它不会让患者更健康。它只是给你一个你可以信任的数字。在你有一个之前,"完成"是一种感觉。之后,它是固定案例集上的一个分数。 你收集一组输入案例。对于每一个,你写下你期望的行为。你在每个案例上运行功能并根据该预期行为评分输出。案例、期望和分数的集合是评估。"完成"在几次手动尝试后停止成为一种感觉,变成一个分数。你在功能之前写评估,因为它强制你在实现开始之前定义成功。否则,你可能会发现自己稍后为模型产生的任何输出辩护。
管道很小,每次都需要相同的框架:加载案例数据集,通过功能运行每个案例,评分每个结果,并平均分数。最小版本只有几个函数。第一个在一个案例上运行功能,第二个评分该输出,第三个循环遍历数据集并平均。
分数本身既不是固有的好也不是坏。第一次尝试评分二或三分之十是正常的。重要的是当你改变提示、工具或模型时数字是否增加。一次改变其中一个,所以你知道哪个导致了改进。评估是使那个改变可衡量的工具,而不是仅仅感觉不同。
将评分方法与输出形状匹配 评分者是将输出变成可衡量信号的部分,通常是一到十之间的数字。有三种方式产生那个信号,选择错误的是评估工作被浪费的地方。
1精确或字符串匹配在输出有一个正确形式时有效。必须返回一个标签的分类器,或必须返回已知值的函数,可以逐字符检查。它是最便宜的评分者和最脆弱的:任何可接受的开放式答案的释义都会失败。它对任何可以用多种方式表述的输出都是错误的工具。 2代码评分检查在函数可以验证输出时有效。有效的 JSON、可解析的 Python、范围内的数字、包含必需字段的响应:这些都是你可以写的检查,返回通过或失败。输出不必匹配固定字符串,只需满足规则。这个方法捕获字符串匹配会错过的格式和语法故障,以及人类会发现手动检查很乏味的故障。 3LLM-as-judge 适用于质量重要但无法通过模式匹配评估的开放式输出。你给第二个模型输出和一个评分标准,它返回一个带推理的分数。这是唯一能扩展"这个摘要是否忠实?"或"这个答案是否遵循了指令?"这样的问题的方法,因为没有代码规则捕获那些。它也是最昂贵和最嘈杂的,所以在代码检查就足够的时候使用它会增加成本和方差而没有收益。
代码评分者通常只是一个解析尝试。如果输出解析为所需格式,它评分很好,而如果它抛出错误,它评分为零。这足以廉价地捕获整个格式故障类。
比较同一输出在每个方法下如何评分通常会使正确选择变得清晰。想象一个应该返回一个地区三个首都作为 JSON 数组的功能。一次运行以不同的顺序返回数组而不是你的参考字符串。精确匹配评分为零,因为字符不对齐,即使答案是正确的。一个解析 JSON 并检查成员资格的代码评分者评分很好,因为所有三个城市都存在且结构有效。
现在想象功能应该返回一个段落的建议理由。代码评分者可以确认它是一个非空字符串,这里几乎毫无价值,精确匹配是无望的,因为没有两个好的理由措辞相同。只有评判者可以说理由是否忠实和完整。方法遵循输出结构:一个正确形式采用匹配,结构规则采用代码检查,开放式质量采用评判者。还有一个成本维度表格没有充分强调。精确匹配和代码检查在本地运行,每个案例的成本实际上为零,所以你可以在每次改变时运行数千个。
评判者是每个案例的第二个模型调用,所以一个由评判者评分的千案例评估是每次运行时的一千个额外 API 调用。这对于定期完整评估是合理的,但对于紧密内循环是浪费的。许多团队用代码在每次提交时评分格式和结构,并为较慢的计划质量通过保留评判者。将评分者与任务匹配部分是关于信号,部分是关于你能多频繁地运行它。
你可以在构建时保持打开的评分者选择表 下面列出的三种方法中,评判者是你必须构建和调整的唯一方法,所以它在这里得到自己的处理。
任务类型|评分方法|它捕获什么|它在哪里不可靠 ---|---|---|--- 单个正确标签或值|精确或字符串匹配|当恰好有一个正确答案时的错误答案,零歧义和接近零成本。|对每个有效的释义或重新排序都失败,所以它对任何开放式的东西都是错误的。 结构化或代码输出|代码评分检查|无效的 JSON、不可解析的代码、超出范围的数字和缺失的必需字段。|对内容是否好说不了什么,只是它是否格式良好。 开放式质量|LLM-as-judge|忠实性、指令遵循、完整性和没有代码规则表达的语气。|嘈杂和昂贵,产生一个看起来有信心的数字,在校准之前毫无意义。
构建和校准评判者,使其分数是可辩护的 评判者是由清晰评分标准指导的第二个模型调用。使其可用的是要求它提供优势、劣势和推理以及分数,而不是仅返回分数。没有那个,模型倾向于一个安全的中间数字,通常在六左右,无论输出的实际质量如何。首先要求评判者提供推理是什么将分数锚定到具体的东西。
大多数人跳过校准,这是什么使评判者不可信直到他们做。从一组人类已经标记的案例开始,在相同案例上运行评判者,并衡量评判者与人类的一致程度。一个与人类标签不一致一半时间的评判者产生一个看起来严格但提供没有价值的数字。在依赖分数之前衡量一致性是什么将评判者从猜测变成你可以为之辩护的证据。如果一致性低,你修复评分标准:收紧每个分数的含义,添加一个好答案和坏答案的例子,并重新衡量。
覆盖比完美更重要 一个更大的评估集,具有稍微更嘈杂的自动评分,通常比一个小的手工评分案例集揭示更多。评估的要点是提供足够的覆盖来捕获回归,而不是创建完美的评分标准。二十个包括不规则和边界输入的案例将捕获三个精心选择的案例从不会执行的中断。当你需要更多案例时,你可以让 Claude 从一个小的、标记的起始集生成额外的。然后你可以抽查生成的案例,使集合保持诚实。覆盖是捕获边界案例的东西,覆盖来自体积。
把三个部分放在一起,工作流是一个循环:设定目标,写初始提示,运行评估,读取它失败的地方,应用一个提示工程改变,并再次运行评估。你重复最后两个步骤直到分数保持在你需要的地方。评估是告诉你改变是否有帮助而不仅仅是感觉不同的工具。
使循环工作的策略是一次改变一个组件。如果你重写提示、添加两个例子并在一次通过中切换模型,分数移动,你学到了关于哪个改变导致它的什么。移动一个杠杆,重新运行,读取每个案例的结果,并仅在分数上升时保留改变。这个方法对于单次迭代来说较慢,但对于功能的生命周期来说快得多,因为它教你什么驱动分数。每个案例的分解与平均值一样重要。一个稳定的平均值可以隐藏一个修复了三个案例并破坏了三个其他案例的改变。每个案例的视图立即显示那个,而平均值隐藏它。
一个低分数是要采取行动的信息。当一个案例失败时,重要的问题不是它是否失败,而是为什么。格式化故障指向提示的输出指令。检索内容上的事实故障指向检索步骤。仅在长输入上出现的故障指向上下文处理。评估告诉你一个案例失败,每个案例的输出告诉你类别,这是什么将下一次迭代变成有针对性的修复而不是猜测。
处理得很好|将"看起来是对的"变成一个你可以为之辩护并一次移动一个深思熟虑改变的追踪分数。 增加成本或复杂性|编写案例和校准评判者是任何功能发货前的真实前期工作。 使用不同的方法|对于单个固定格式输出,代码检查单独就足够了。完全跳过评判者。
屏幕 3:通过的演示和未通过的边界案例
观看 评估与评判者 7 分钟
通过的演示和未通过的边界案例
设置 你看着代理正确回答了大约十二次,所以你得出结论它已完成。问题是那十二次尝试都使用了看起来像你构建它时想到的输入。
事后分析:功能通过了它拥有的每个检查,仍然提取了错误的值 一个团队发货了一个从客户消息中提取结构化字段的功能。在启动前,他们通过大约十二个示例消息运行它,读取输出,同意它们看起来是对的,并进入部署。功能有输入验证:它确认每个消息是非空文本,检查日期字段返回填充,并拒绝返回格式错误或不可能日期的提取。两周后它似乎按预期工作。
然后一个客户发送了一个在一个句子中放置两个日期的消息:"我在 3 月 3 日下了订单,但直到 4 月 12 日才收到。"功能提取了 4 月 12 日作为订单日期。每个验证检查都通过了,因为两个日期都格式良好且字段返回填充。验证确认一个值是正确的形状。它无法确认值是正确的。下游逻辑作用于错误的日期,一批记录被错误地更新。
审查发现模型或提示中没有错误。功能从未根据包含两个日期的消息进行衡量,因为没有人将该案例的预期行为定义为分级示例。十二个手动检查都使用了单日期消息,这是构建者想象的输入。没有保留集,所以没有信号表明两日期输入存在于人口中。
缺失的分级集是根本原因。某个行为改变,最可能是一个提示改变命名要提取哪个日期,纠正了输出。评估没有修复提取;它检测了故障,将预期行为记录为可检查案例,并防止了对每个未来改变的相同回归。两日期消息成为该集中的案例一。
在客户这样做之前找到像这样的输入的一种方法:要求模型枚举可能破坏当前实现的边界案例。一个句子中的两个日期、没有日期、相对日期如"下周二"。将合理的变成分级案例,具有人工检查的预期输出。这是与评估构建部分相同的案例生成移动,在启动前应用而不是之后。
为什么这破裂了 成功由印象而不是分级集判断。评估是显示故障和防止回归的东西。提示是改变输出的东西。在发货前将预期行为写下来作为分级案例,并使用模型帮助你找到你没有想到测试的边界输入。
屏幕 4:为总结功能完成部分评估
检查点 评估与评判者 · 9 分钟 为总结功能完成部分评估 这个评估有两个差距。对于数据集,识别每个输入案例应该产生的具体输出。对于评判者提示,将每个分数段与其含义匹配。将每个答案卡从银行拖到下面的其行。
dataset. json
judge_prompt. txt
提交 暂时跳过
屏幕 5:测试和追踪
教学 测试与追踪 · 14 分钟 测试和追踪 你刚才构建的评估告诉你好看起来像什么作为一个数字。它不告诉你故障发生在哪里,也不阻止通过的评估隐藏工作流中某处的中断。
一个分级目标需要下面的测试和追踪层:隔离每个故障类型的测试,以及显示哪个步骤产生坏结果的追踪。
各种测试级别,每个捕获其他级别错过的故障 测试仅在你知道它识别哪个故障时有用。四个级别分割工作,大多数悄然生产中断住在一个特定级别:
单元测试隔离一个函数,例如解析器或工具包装器,并单独检查它。它告诉你一个部分表现,但关于部分如何组合在一起什么都不说。 功能测试检查一个 Claude 调用对给定输入返回预期形状:正确的字段、正确的类型、可解析的响应。它验证调用而不是围绕它的系统。 集成测试练习两个组件之间的交接,例如,检索结果被传递到模型调用中。这是大多数悄然故障隐藏的地方,因为每一侧可以通过自己的测试,而它们之间的交接是破裂的。 端到端测试运行整个流程,就像用户会做的那样,从输入到输出。它捕获仅在所有东西一起运行时出现的中断,代价是运行最慢和最难定位。
追踪:找到故障的来源 测试告诉你故障存在,但它们不告诉你哪个步骤导致了它。这是追踪添加的。
追踪记录运行的每个步骤:提示、工具调用、中间输出和时序。当一个案例失败时,追踪让你看到哪个步骤产生了坏结果。没有追踪,一个失败的评估告诉你有问题但不告诉你它在哪里失败。这是五分钟修复和一天手动追踪工作流之间的区别。追踪读起来像运行的时间线,失败的步骤通常在你能看到中间输出后变得明显。
追踪将"案例失败"变成"步骤四:解析器在模型未返回的字段上引发了 KeyError。"这也是什么使改变可审查的:你可以显示移动的步骤而不仅仅是下降的分数。
在两种方法之间路由,所以你仅在需要时为迭代付费 你不必为所有东西选择一个策略。一个便宜的分类步骤可以将单事实查询发送到获取一次路径,将多部分问题发送到跨轮搜索路径。这允许你仅在查询需要时才花费迭代。将所有东西默认为迭代搜索会在单个获取会回答的问题上膨胀成本和延迟,而将所有东西默认为静态索引在需要多个通过的问题上给出浅答案。路由器是一个小模型调用,读取查询并选择路径。
那个分类调用成本远低于在单个检索会回答的查询上运行迭代搜索。路由器在你的流量混合时赚取其成本:一些查询是简单查询,一些需要多个通过。如果每个查询都是相同形状,跳过路由器并硬编码适合的路径。
你可以在构建时保持打开的参考
级别|它隔离什么|它无法捕获什么 ---|---|--- 单元|一个函数,例如解析器或工具包装器,单独。|关于组件如何组合在一起的任何东西。 功能|一个 Claude 调用对输入返回预期形状。|围绕该单个调用的系统中的故障。 集成|两个组件之间的接缝,例如检索到模型。|仅在端到端出现的整个流程行为。 端到端|整个流程,就像用户会运行的那样,输入到输出。|确切的中断在哪里,因为它仅看到最终结果。 检索选择|在稳定语料库中为单事实查询获取一个固定集一次。|多步问题和变化的语料库,需要跨轮搜索。
处理得很好|将故障定位到一个步骤并将每个测试与它可以看到的中断匹配。 增加成本或复杂性|追踪和四个测试级别是你构建和维护的基础设施。 使用不同的方法|对于稳定语料库中的单事实查询,获取一次检索胜过迭代搜索。
屏幕 6:部分通过了,接缝破裂了
观看 测试与追踪 8 分钟
部分通过了,接缝破裂了
设置 你单独测试了提示和解析器。两个都通过了,所以你信任了整个流程。
追踪摘录:绿色单元和功能运行,红色端到端运行在交接处 来自评估运行的追踪显示解析器单元测试通过和模型调用功能测试通过。每个在单独测试时返回预期形状。端到端运行失败。向下读取追踪,故障发生在检索结果被传递到模型调用的交接处。
每一侧单独是正确的。检索函数返回块字典列表,提示构建器被写成期望纯字符串。这导致上下文到达格式错误,模型从自己的记忆而不是检索的政策回答。两个组件之间的交接从未被执行,因为没有测试覆盖那个接缝。这是集成级别存在的故障。单元测试无法识别它,因为单元本身工作。功能测试无法识别它,因为调用在格式良好的输入上工作。只有用真实检索数据驱动检索到模型交接的测试可以在用户这样做之前提出不匹配。
为什么这破裂了 检索步骤和提示构建器之间的格式合约从未被定义。一个返回字典列表,另一个期望纯字符串,没有什么强制它们之间的边界。
如何防止它 添加一个集成测试,用真实检索数据驱动两个组件一起。单元测试无法捕获这个,因为每个组件单独工作。只有练习交接的测试才能在用户这样做之前显示不匹配。
屏幕 7:诊断故障属于哪个测试级别
检查点 测试与追踪 · 10 分钟 诊断故障属于哪个测试级别 现在尝试。读取下面的追踪,其中端到端测试失败,而每个单元测试都通过。识别中断在哪里,命名机制,并从显示的三个选项中选择有针对性的修复和会捕获它的测试级别。
选项 A · 修复解析器
选项 B · 修复提示措辞
选项 C · 对齐交接 + 添加集成测试
A 修复解析器(dateutil. parse 已通过其单元测试) B 修复提示措辞("仔细回答并引用政策") C 对齐交接并在 retrieve() -> build_prompt() 上添加集成测试
提交 暂时跳过
屏幕 8:存活生产故障:工具错误
教学 故障处理 · 12 分钟 存活生产故障:工具错误 你的测试现在告诉你故障存在,追踪告诉你它发生在哪里。下一个问题是系统在实时流量中故障发生的那一刻做什么。
生产引入了原型从未看到的故障。弹性系统和脆弱系统之间的区别是你是否提前决定了每种故障如何处理。
每个故障从一个问题开始:它是可重试还是终端? 测试是一个单一问题:等待并尝试完全相同的请求再次会合理地工作吗?如果是,它是可重试的。如果不是,它是终端的。速率限制随时间清除;格式错误的请求会相同地失败直到请求本身被修复。
生产流量产生开发从未显示的故障:速率限制响应、超时、格式错误的工具结果和瞬间网络错误。任何故障的第一个决定是稍后尝试是否可能成功。如果是,故障是可重试的。如果不是,重试仅浪费时间和预算,使其成为终端的。速率限制响应或临时服务器过载是可重试的,因为相同的请求可能在一刻后通过。格式错误的请求或身份验证故障是终端的,因为重试相同的坏请求改变什么。在 Anthropic API 上,状态代码告诉你桶。429 意味着你达到了速率限制,529 意味着服务临时过载,两个都是可重试的。400 意味着坏请求,401 意味着身份验证故障,两个都是终端的。5xx 范围内的服务器错误,包括 500 内部错误和 504 超时,也是可重试的,因为它们是通常在重试时解决的 Anthropic 端故障。
这个单一区别之所以承载这么多权重是因为它决定了等待是否有帮助。可重试错误是一个其中原因是瞬间的:服务暂时超过容量,连接断开,或你暂时超过了每分钟限制。时间单独解决它,所以稍后尝试可能成功。终端错误是一个其中原因在请求本身:格式错误的主体、过期的密钥、不存在的模型名称。时间改变什么,因为每个请求会产生相同的错误。重试终端错误浪费重试预算并隐藏实际问题在相同故障的墙后。每个不必要的重试消耗重试预算并增加延迟,可重试故障流程中其他地方可能需要的。正确分类保留重试预算用于需要它的故障。
一些状态坐在线上,值得指出。超时通常是可重试的,因为工作可能仅仅花费了比客户愿意等待更长的时间。重复超时在昂贵请求上是一个信号来修复请求本身,而不是重试它。来自服务的 500 是可重试的,因为它是一个通常清除的服务端故障。403 是终端的,因为它是重试无法修复的权限问题。当你不确定时,安全的默认是将错误视为终端并提出它。错误分类为终端失败大声并被修复。错误分类为可重试锤击服务并隐藏真实问题在重试的墙后。
SDK 已经重试一些故障,所以在你自己写之前知道它覆盖什么 在你手动构建重试循环之前,检查 SDK 为你做什么。Anthropic 客户端库自动重试瞬间故障,具有渐进重试延迟,最多可配置尝试次数。知道这个的要点是避免在 SDK 已经运行的重试之上添加你自己的重试。两个重试循环围绕相同调用相乘对速率限制的尝试而不是限制它们。决定重试住在哪里:要么让 SDK 处理瞬间案例并为应用特定的回退保留你自己的代码,要么关闭 SDK 重试并拥有完整路径。在相同故障上运行两个层重试,而不是其中任何一个知道另一个,是要避免的模式。
API 也在每个响应上返回速率限制头,告诉你多少限制保留以及何时重置。最有用的是 retry-after,一个 429 或 529 响应包括告诉你在再次尝试之前要等多长时间。尊重那个值比用退避单独猜测更精确,因为服务告诉你确切何时容量返回。后面这个模块中的纠正重试代码首先读取 retry-after 并仅在头不存在时回退到指数退避。当头存在时将其视为权威等待时间,当它不存在时将你自己的退避视为回退。具体的头名称和限制值是版本固定的,所以在构建时根据参考层确认它们。
工具错误必须明确返回给 Claude 而不是丢弃 当你的代码运行一个工具且那个工具失败时,结果应该返回给 Claude,is_error 明确设置为 true。它不应该作为悄然空结果返回。返回错误后,模型可以反应:尝试不同的方法、要求澄清或停止。一个丢弃自己的错误并返回什么都不返回的工具产生一个下游自信但错误的答案。这是因为模型将空结果视为有效数据并继续在其上推理。一个可见的故障远比建立在缺失数据上的自信但不正确的答案更容易捕获。
设置 is_error 后,模型知道工具失败并可以反应。没有它,模型将空结果视为有效数据并在假前提上继续。
错误处理决定表你可以在构建时保持打开
错误类型|可重试或快速失败|退避策略|回退行为 ---|---|---|--- 速率限制 (429)|可重试|指数退避带抖动,尊重 retry-after,限制尝试。|在上限后,提出清晰错误或路由到缓存或更简单结果。 过载 (529)|可重试|退避;529 反映 Anthropic 端负载,所以它不是速率限制信号。|如果持续,故障转移到回退路径或返回优雅错误。 坏请求 (400)|快速失败|无重试。相同请求会再次失败。|修复或拒绝输入并将错误显示给调用者。 工具结果错误|取决于工具|仅在基础原因是瞬间时重试。|返回错误标志给 Claude,使模型可以反应,从不沉默它。 拒绝 (200, stop_reason: "refusal")|快速失败|无重试。模型做了内容决定,不是瞬间错误。|将拒绝提出给调用者。记录它。不要悄然重试或将其视为有效输出。
处理得很好|通过按名称处理每个故障类型,保持一个坏响应不会级联到停机。 增加成本或复杂性|每个故障路径是你在快乐路径之上写、测试和维护的代码。 使用不同的方法|不要重试终端错误。重试 400 仅浪费重试预算。
屏幕 9:在开发中从未失败的调用
观看 故障处理 6 分钟
在开发中从未失败的调用
设置 在开发中,你调用端点几十次,它每次都干净地返回,所以没有明显的理由写错误路径。那是陷阱。开发流量是低体积,在稳定连接上运行,很少达到导致调用失败的条件:速率限制、超时、瞬间网络断开或格式错误的响应在负载下。当你手动测试时这些都不出现,所以处理它们的代码从不被写。调用在生产中首次失败,故障显示为未处理异常而不是可恢复错误。
轶事:第一个速率限制响应使整个请求崩溃 一个开发者构建一个面向客户的功能,在循环中调用 API。每个开发运行返回成功,因为开发流量从未接近速率限制。代码被写成没有任何错误处理,因为到现在为止,什么都没有在那里失败。
功能发货了。在第一个流量峰值,API 返回了速率限制响应,未处理的错误被提出,整个请求失败而不是等待一刻并再次尝试。对用户来说,看起来功能根本就坏了。开发者的第一本能是在紧密循环中添加立即重试。这使它更糟:每个即时重试计为对相同限制的另一个请求,加深它。真实修复是来自教学屏幕的区别。速率限制响应是可重试的,所以它需要指数退避,限制尝试次数,以及一个尊重 retry-after 值的重试,当响应包括一个时。开发从未产生故障,所以会知道如何处理一个的路径从未被写。
为什么这破裂了 一个可重试故障遇到了没有错误路径的代码,然后遇到了加深限制的锤击重试。对故障进行排序为可重试,然后用上限退避,在流量为你找到差距之前。
屏幕 10:修复破裂的错误和重试路径
检查点 故障处理 · 8 分钟 修复破裂的错误和重试路径 下面的块有一个缺陷。识别它并写纠正版本。
显示给学习者的破裂代码
与模型答案比较 暂时跳过
屏幕 11:生产中的模型选择
教学 模型选择 · 10 分钟 生产中的模型选择 前面的屏幕在模型被选择后保持系统在其成本预算内。这个屏幕处理设置那个预算的选择:哪个 Claude 模型运行工作负载。
成本管理在模型内优化支出。模型选择决定优化工作的基线。
模型族及其能力层级 Claude 是一个模型族,在成本、延迟和能力之间进行权衡:Fable 是最具能力的,用于最苛刻的推理、编码和代理工作;Opus 处理 Sonnet 信封上方的苛刻工作;Sonnet 是大多数生产工作负载的平衡默认值;Haiku 为适合其信封的任务构建以实现速度和成本效率。相同的提示在任何一个上运行,所以模型选择是你按工作负载设置的杠杆,可以在不重写应用的情况下改变。在构建时根据 platform. claude. com 确认当前阵容和模型 ID。
延迟、成本和质量权衡 升级模型层级以更高的每令牌成本和通常更高的延迟为代价交换质量。降级模型层级以较低成本和速度为代价购买质量下降的风险。更高层级的模型如果它以比较低层级模型更少的令牌达到结论,也可以更快和更便宜地处理请求。错误的成本属于那个计算:在较低层级模型上节省几美元一天不是一个合理的权衡,如果质量下降引入了具有显著下游成本的错误。没有全局正确的选择,仅有任务在质量标准下的正确选择。纪律是使权衡可衡量而不是默认到最具能力的模型。这是生产中最常见和最昂贵的模型选择错误。默认是从 Sonnet 开始,仅当评估显示 Sonnet 错过质量栏时才移动到 Opus,仅当评估显示质量下降对任务可接受时才移动到 Haiku。
路由:默认模型加上任务信号上的覆盖 系统不必为所有东西使用一个模型。一个常见的生产模式是一个默认模型加上覆盖:将大部分流量路由到平衡默认值,并根据从请求读取的便宜信号(例如任务类型、输入长度或难度分类)将特定请求类型发送到更大或更小的模型。这是用于检索的相同路由想法,应用于模型选择:你仅在需要它的请求上为更具能力的模型付费。当每个请求都是相同形状时,跳过路由器并固定一个模型。
何时升级以及何时降级 当评估显示当前模型在你的流量包含的最难案例上失败且错误答案的成本很高时升级一个层级。当评估显示较便宜的模型在大部分流量上保持质量栏,释放预算和延迟时降级一个层级。在两个方向上评估是工具:模型改变在对你的案例的衡量分数上被提升。这是为什么你之前构建的评估也是模型决定的门。
处理得很好|将每个工作负载与最便宜的模型匹配,该模型在评估上衡量的质量栏上保持,而不是假设。 增加成本或复杂性|路由添加分类步骤和第二个模型路径来维护。 使用不同的方法|对于一个质量栏的统一流量,固定单个模型并跳过路由器。
屏幕 12:选择模型并命名决定约束
检查点 模型选择 · 2 分钟 选择模型并命名决定约束 对于每个场景,选择模型层级(Opus、Sonnet 或 Haiku)并识别驱动决定的一个约束。
场景 1. 一个高体积分类步骤每天标记数百万条短消息;评估显示 Haiku 保持质量栏。哪个选择最好? A Opus,决定约束是模糊消息上的推理深度 B Sonnet,决定约束是在体积上平衡质量和速度 C Haiku,决定约束是体积成本,因为评估确认质量栏仍然保持 D Opus,决定约束是数百万请求的一致性
场景 2. 一个多步代理规划一个依赖重构,其中错误的早期步骤是昂贵的;评估显示 Sonnet 错过最难案例上的栏。哪个选择最好? A Sonnet,决定约束是长代理运行上的成本效率 B Opus,决定约束是错误答案成本很高的硬推理上的质量 C Haiku,决定约束是许多顺序步骤上的速度 D Sonnet,决定约束是依赖步骤上的延迟
场景 3. 混合流量:大多数请求是简单查询,一些是复杂综合。哪个方法最好? A 为所有东西使用 Opus,决定约束是保证复杂请求上的质量 B 为所有东西使用 Haiku,决定约束是最小化所有流量的成本 C 为所有东西使用 Sonnet,决定约束是混合需求的单个平衡模型 D 路由:Sonnet(或 Haiku)默认,复杂请求上的 Opus 覆盖,决定约束是流量混合
提交 暂时跳过
屏幕 13:在代理间保持成本、延迟和可靠性在预算内
教学 成本与编排 · 29 分钟 在代理间保持成本、延迟和可靠性在预算内 一个从故障恢复的系统仍然必须是可负担和快速的,或者它不会存活与真实账单的接触。
上一个屏幕的重试预算和回退保持它可靠。这个屏幕对其进行仪表化和预算,然后处理最快乘以成本的模式:在多个协调代理间分配工作。
成本和延迟在开发中是不可见的,但在生产中是决定性的 在开发中,你运行一把调用,从不看账单。在生产中,相同的调用以体积运行,而成本和延迟成为约束。Claude 系统的可观测性意味着对每个调用仪表化三个指标:令牌使用(输入和输出令牌)、延迟和错误率。对每个调用有三个指标,你可以看到哪个步骤是昂贵或慢的,而不是从总月账单猜测。从一开始对每个调用进行仪表化。将可观测性视为稍后步骤意味着账单在解释之前到达。在代码中,它是围绕调用的薄包装器,记录 API 已经返回的使用。
一旦每个调用记录这三个指标,成本或延迟问题停止成为发票上的谜团,变成你可以排序的行。
影响预算的杠杆 成本或延迟问题几乎总是追踪到几个可衡量的组件之一。在调整之前识别杠杆是什么保持优化不是猜测。为每个杠杆选择标签以查看它如何移动成本或延迟。
模型选择 提示与上下文大小 工具调用数量 流式与批处理 带工具使用的流式处理
任务的模型选择:选择一个更小、更快的模型来削减更复杂的成本和延迟。为需要它的步骤保留最具能力的模型,并将更简单的工作路由到其他地方。 提示和上下文大小:提示中的每个令牌都对成本有贡献。修剪上下文和删除不必要的工具输出直接减少每个调用成本。这是从第一个模块应用于操作成本的上下文工程工作。 工具调用数量:每个调用添加成本和延迟。进行比需要更多调用的流程是不必要支出的常见和可衡量来源,一旦你对调用进行仪表化就变得可见。 流式与批处理输出,以及重复上下文的提示缓存:流式改变单个响应对用户的感觉方式,在准备好时返回第一个令牌而不是等待完整响应。对于面向用户的功能,这很重要:在 300ms 开始到达的响应感觉比在两秒后以单个块交付相同内容的响应更快,即使总生成时间相同。提示缓存在其自己的部分中覆盖。 带工具使用的流式处理需要额外处理。在非流式调用中,完整响应作为单个对象到达,tool_use 块直接可访问。在流式调用中,响应作为服务器发送事件序列到达,tool_use 块在多个增量事件中累积,然后才完整。在不考虑这个的情况下消费流产生部分工具输入和悄然下游故障。
模式是按索引累积增量直到流关闭,然后从完成的块重建工具调用:
tool_use 块在流关闭且完整 input_json 被累积之前不安全地作用。作用于部分块产生格式错误的工具输入。相同的可重试对终端故障处理从故障屏幕应用这里:一个在响应中间断开的流是瞬间故障,整个请求应该被重试,不是部分输出被传递下游。
提示缓存:重用已在稳定前缀上完成的工作 在模型生成任何东西之前,它处理你的输入:它将提示分解为令牌并构建它需要参与它们的内部表示。在普通请求上,那个处理工作在响应返回后被丢弃。当你的下一个请求重复相同内容时,相同的处理从头开始再次运行。移除那个重复工作的杠杆是提示缓存。
提示缓存存储处理工作用于内容的一个拉伸,所以稍后请求可以读取它回来而不是重新计算它。第一个请求将工作写到缓存,后续请求发送相同内容到标记点读取缓存而不是重新处理。缓存写以高于基础输入令牌的溢价计费,5 分钟 TTL 为 1. 25 倍,1 小时为 2 倍,而缓存读成本是标准输入的一个分数(0. 1 倍),所以经济学仅在读超过写时工作。这也是为什么缓存适合稳定、频繁重用的前缀:更多请求命中相同缓存内容,跨批处理的混合成本和延迟越低。
缓存可以自动或用明确的断点设置。在自动模式中,你在请求的顶级添加单个缓存标志,系统在对话增长时管理断点,这是大多数用例的推荐起点。用明确的断点,你在特定内容块上放置 cache_control 标记,模型缓存所有工作直到并包括那个点。任何一种方式,最后一个断点后的内容被正常处理。最值得缓存的组件是请求间保持相同的:长系统提示和大工具模式是通常的候选,因为它们很少改变,而用户消息每次改变。
三个属性决定缓存是否帮助给定工作负载:
1缓存内容必须相同。缓存在精确前缀上匹配,所以断点前的任何改变,即使添加单个词如"请",使缓存无效并强制完整重新处理。这是为什么缓存适合稳定内容并反对必须反映实时状态的任何东西,因为每个请求改变的内容从不产生缓存命中。 2相同内容必须重现并很快重现。默认缓存生命周期是五分钟,在每次命中时刷新。一小时生命周期在额外成本下可用。节省仅在相同前缀在那个窗口内再次发送时到达。一个前缀每分钟重用几次付出,而一个每小时重用一次不在默认 TTL 下,因为缓存在下一个请求到达之前已过期。 3缓存前缀必须足够长以清除最小值。有一个缓存的最小长度阈值,它因模型而异。较短的提示无论多么稳定都看不到好处。较长和更稳定的前缀,缓存重用的处理工作越多,这是为什么缓存在携带长、固定系统提示的高体积系统上最有效。
有一个权衡要针对节省权衡。缓存假设缓存内容在稍后请求上仍然正确。如果前缀需要反映可以改变的数据,缓存保持一个版本,可能对稍后请求过时,只要它活着。那是你的用例必须能够容忍的一致性窗口。对于固定系统提示和稳定工具模式,没有什么会过时,这是为什么那些是安全和高价值的缓存地方。
批处理 API:用延迟交换更低的账单 一些工作不需要立即答案。一个通宵分类运行、一个大数据集上的回填或一个计划报告都可以等待。对于那种工作,消息批处理 API 异步处理请求,作为交换它每个请求的成本低于一次一个进行的相同调用。成本削减足够显著,它是任何非紧急、高体积任务的决定杠杆。当前折扣是版本固定的,所以在构建时根据参考层确认它。
权衡是延迟用于成本。你提交一个批处理,结果在异步完成窗口内返回而不是立即。批处理对任何用户等待的东西是错误的工具,对任何由计划驱动的东西是正确的工具。决定镜像流式处理相反:流式处理优化单个响应对循环中用户的感觉方式,而批处理优化没有用户等待的工作的账单。两个杠杆从不竞争相同的请求,因为请求要么是面向用户的,要么不是。
批处理和提示缓存在非紧急工作重用相同上下文跨许多请求时复合。批处理折扣降低每个请求的成本,缓存降低每个内的重复前缀的成本,所以携带长固定系统提示的计划工作从两个中受益。那个组合正是本模块后面的成本和编排检查点要求你识别的。
多代理编排作为深思熟虑的权衡 在编排者-工作者模式中,一个主导代理将任务分解为子任务并委托给多个并行工作的子代理,每个有自己的上下文窗口。一旦分配完成,它们编译它们的结果。在代码中,结构由规划、并行扇出和综合组成。
这真的帮助大任务可以分成独立部分。例如,跨许多单独来源的研究,因为子代理可以同时探索而不是一个接一个。
保持这个的方式是作为一个招聘决定。五个研究者比一个完成一个广泛调查更快,但你支付五个薪水。你仅在工作真的分成人们可以做而不互相等待的部分时雇用一个团队。
Anthropic 自己的研究系统使用这个模式并报告了定义权衡的发现。在 Anthropic 内部研究评估上,一个多代理设置,Claude Opus 4 作为主导和 Claude Sonnet 4 子代理显示了对单个代理 Claude Opus 4 基线的实质改进,在内部评估上。成本大约是正常聊天交互令牌的十五倍,因为每个子代理对其自己的上下文花费自己的令牌。
模式对紧密耦合的任务也不那么有效,例如编码,其中每个步骤取决于前面部分且无法并行探索。Anthropic 的分析发现令牌使用占大多数性能方差。架构主要工作是因为它购买更多并行计算。
仅在任务真的需要并行探索时使用它。一个具有好上下文的单个代理以成本的一个分数处理大多数工作。乘数也在某个东西表现不当时复合。一个失控的子代理或一个超大工具结果可以在请求完成之前推远超过十五倍基线。
一个粗略的成本估计使权衡具体。假设一个单个代理在大约一万令牌中回答一个研究问题。编排者-工作者版本旋转一个主导和四个子代理,每个读取其自己的来源片在其自己的上下文中。主导然后综合它们的返回。Anthropic 报告五个上下文加综合通过使用大约十五倍令牌数。所以,相同的问题成本在大约一百五十万令牌的顺序。
如果问题是一个单个查询打扮成研究,你为什么都不需要支付乘数,因为四个五个上下文做工作任务从不需要。数字既不是固有的大也不是小。其值完全取决于任务是否需要额外的代理。
有一个控制维度成本估计不捕获。跨代理分散工作乘以故障可以发生的地方,所以每个子代理需要相同的可重试对终端处理、相同的退避和相同的回退纪律从故障屏幕,独立应用。一个单个子代理达到速率限制且没有退避可以在主导等待从不来的返回时停滞整个编译步骤。编排模式不替换故障处理工作,它乘以它,这是另一个原因仅在并行探索值得那个添加表面积时使用它。一个模型选择细节也在这里帮助:考虑使用更具能力的模型作为主导代理和较便宜的模型用于子代理,所以你不是在每个并行上下文支付顶级费率。这在保留协调质量重要的地方时减少成本乘数。
可靠性有一个你在其内调整成本的底线 成本仅是预算的一半。另一半是可靠性,它建立一个基线,成本不应该低于。
最便宜的配置很少是最可靠的。首先通过定义基线开始,例如重试预算和延迟上限,然后在其上调整成本而不是下面。在可靠性底线下削减成本用悄然故障替换可见支出。在生产中,这通常是更糟的权衡,因为稍微更高的账单比不工作的系统更容易为之辩护。
可靠性底线的具体版本使纪律清晰。假设你决定面向用户的请求必须在四秒内完成,可能重试失败的依赖最多三次。那些约束定义底线。现在,每个成本优化必须满足这些要求。切换到一个更小、更便宜的模型是好的,如果它仍然适合延迟上限且不增加错误率足够以燃烧重试预算。将重试计数减少到两个以节省成本在一个慢依赖上如果它推动故障率超过底线允许的不可接受。在这种情况下,你会交换更低的成本用于更多失败的请求。
底线是什么保持优化诚实:它强制每个成本节省改变演示它没有悄然交换可靠性。它也提供一个清晰的边界,你不削减下面,无论节省看起来多么有吸引力。
顺序很重要,因为成本和可靠性创建相反的压力,成本通常更响亮。一个高账单每天显示在仪表板上并产生持续压力来减少支出。一个可靠性问题显示为偶然故障,容易作为噪声驳回直到它们累积成一个事件。如果你首先优化成本,第二个可靠性,更响亮的压力赢,你仅在跨越它后发现可靠性底线。首先设置底线反转那个:可靠性变成固定约束,成本变成你在其下优化的东西。来自早期部分的评估集是什么使底线可强制执行的:一个固定基线分数定义最小可接受可靠性在可检查形式中,所以任何成本节省改变,下降分数低于基线失败门在它发货之前。
你可以在构建时保持打开的可观测性和编排参考
指标|在哪里对其进行仪表化|单个代理对编排者-工作者 ---|---|--- 令牌成本|每个调用,按请求和按流程聚合。|单个代理每个步骤一次产生令牌成本。编排者-工作者乘以子代理数量的令牌消耗,在 Anthropic 报告的案例中大约 15 倍。那个乘数应用于输入和输出令牌,因为每个子代理接收自己的上下文并生成自己的输出。 延迟|每个调用,带追踪识别工作流中最慢的步骤。|并行子代理可以减少独立工作上的墙钟时间,但添加协调延迟来规划和编译。 错误率|每个调用和每个依赖。|更多代理意味着潜在故障点,每个子代理需要相同的重试和回退处理作为单个代理。
处理得很好|使支出和延迟每个调用可见,所以成本问题追踪到一个命名杠杆。 增加成本或复杂性|并行子代理乘以令牌成本,在报告的案例中大约 15 倍,在改进任何答案之前。 使用不同的方法|对于紧密耦合的工作,例如编码,一个具有好上下文的单个代理胜过扇出。
屏幕 14:并行扇出三倍了账单
观看 成本与编排 6 分钟
并行扇出三倍了账单
设置 你有一个运行缓慢的任务,所以你跨多个并行子代理分割它,推理同时完成的工作完成得更快。延迟下降了一点。然后账单到达了几倍高于单个代理版本,而答案质量几乎没有移动。
客户引用:"为什么我的编排者-工作者设置这么昂贵?" 一个开发者在内部频道发布:
开发者 "我的编排者-工作者设置工作,但账单三倍了,答案仅仅比单个代理版本稍好。我在为什么付费?"
一个高级开发者回复:
高级开发者 "每个子代理对其自己的上下文消耗自己的令牌。Anthropic 报告了其自己的多代理研究系统使用大约十五倍正常聊天的令牌,正是出于那个原因。那个乘数值得当任务分解成可以并行探索的独立部分时,如跨单独来源的研究。你的任务不那样分割。每个步骤取决于最后一个,所以子代理大多在互相等待。在这种情况下,你支付扇出成本而不获得并行好处。切换回一个具有好上下文的单个代理,成本下降到工作实际需要的。"
开发者将任务移回单个代理,保持相同上下文,账单下降,而答案质量保持。课程不是编排是坏的。它是令牌乘数仅在工作可以真的并行执行时购买东西。仅在任务需要并行探索时使用编排者-工作者。
为什么这破裂了 并行扇出被用在不分解成独立部分的任务上,所以每个子代理乘以令牌成本而不添加并行值。仅在任务需要并行探索时使用编排者-工作者。
屏幕 15:将每个任务与其代理类型和成本杠杆匹配
检查点 成本与编排 · 8 分钟 将每个任务与其代理类型和成本杠杆匹配 现在尝试。对于下面的四个场景,选择最好与其匹配的配置片段。每个片段用其代理类型和它使用的主要成本杠杆标记。
标记的配置片段 A orchestrator_worker(lead=LARGE, workers=SMALL, n=5) # lever: parallel split B single_agent(model=SMALL, batch=True, cache=True) # lever: Message Batches API (~50% cost reduction) + prompt caching C single_agent(model=SMALL, retrieval="fetch_once") # lever: model choice D single_agent(model=SMALL, stream=True) # lever: streaming
一个单事实查询对稳定参考语料库 A B C D
一个分成独立部分在一次探索的广泛研究问题 A B C D
一个用户面对的请求,其中回复应该感觉立即 A B C D
一个成本敏感、非紧急批处理工作 A B C D
提交 暂时跳过
屏幕 16:针对不受信任的输入和受管制审查保护集成
教学 安全 · 24 分钟 针对不受信任的输入和受管制审查保护集成
你现在拥有的可观测性和钩子机制做的不仅仅是保持预算。你在前面模块中用来强制项目规则的日志和 Claude Code 钩子也可以强制安全边界。
这个屏幕将那些机制应用于防御:保护代理免受它读取的内容的影响,并作用域它,所以它存活受管制审查。
提示注入:任何读取它没有写的内容的代理的核心威胁 模型读取其整个上下文的方式与你读页面的方式相同:它无法识别哪些句子你提供对哪些被嵌入的东西它从其他地方检索。一个伪造的笔记混入你的指令看起来像另一个命令。从机制开始。一个模型处理其上下文中的所有东西一起,作为一个令牌流。它没有内置边界,分离受信任从不受信任的数据。当代理获取网页、文档或工具结果时,隐藏在那个内容中的指令坐在与你自己的提示相同的上下文中。模型将这些视为命令。那是提示注入。考虑代理获取来总结的页面,包含,靠近底部,一行针对代理而不是读者。
防御直接遵循机制:将获取和用户提供的内容视为要检查的数据,从不作为要遵循的指令。信任你自己的用户不解决问题,因为敌对指令通常潜入代理检索的内容,而不是用户的提示。Anthropic 以两种方式解决这个,训练模型识别和拒绝注入的指令,并在不受信任的内容进入上下文时在其上运行分类器。Anthropic 对一个限制是明确的:没有读取不受信任内容的代理是完全免疫的。这是为什么应用也必须防御边界。
模型接收一个单一文本流。你的系统提示、用户的消息和内容都只是那个序列中的文本,没有结构标记说"这些令牌是受信任的,那些不是"。你可以通过用分隔符包装不受信任的内容并指示模型将其中的任何东西视为数据来减少风险。这有帮助,但它保持一个软边界,因为不受信任的内容可以包含模仿你的分隔符的文本或有说服力地论证成为例外。模型级训练和分类器提高栏,这是为什么当前模型抵抗许多注入一个未训练的会遵循的。但这些防御是概率性的,不保证。可靠的边界通常不在文本本身。它在代理因那个文本被允许做什么。这是为什么本屏幕的其余部分是关于访问和强制而不是关于更仔细地措辞提示。
威胁模型也比单个检索页面更广泛。代理读取的任何内容,其他人可以写,是一个向量:共享驱动中的文档、数据库记录、电子邮件的主体或工具返回的输出,其自己在其他地方获取。一个注入可以是间接的,植入代理稍后会读取的内容中,而不是在当前交互中。它也可以是隐藏的,放在白色文本、图像或页面的一个人不会滚动到的部分。存活所有这些变化的防御姿态是相同的:代理将它没有编写的任何东西视为数据。然后它约束和记录任何后果行动,无论那个数据说什么。防御单个提示的措辞不泛化。防御行动边界做。
越狱和提示注入是不同的威胁,但防御有相同的形状 越狱试图让模型忽略其自己的安全约束。提示注入试图劫持你的应用指令。它们是不同的目标,但分层防御有相同的方法:验证和约束到达模型的东西,并限制模型因此被允许做什么。仅防御提示而不防御行动使模型一旦被转向自由造成伤害。这是为什么行动边界的一侧与输入边界一样重要。上面的例子是无害的,如果代理没有可以写到那个路径的工具,这正是为什么行动边界是边界变成真实的地方。
安全设计身份和访问:最小权限、作用域秘密 行动边界从身份和访问构建,这是防御的下一层。一个生产代理以某个身份行动,那个身份应该仅携带任务需要的权限,意味着仍然让工作运行的最小权限集。秘密属于环境变量或秘密管理器,从不在提交的配置中。访问应该作用域,所以代理仅可以到达其任务需要的系统。一个细节容易错过:任何可以修改代理的身份验证配置的东西可以有效地以那个身份行动。保护那个配置与保护秘密本身一样重要。这建立在前面模块的身份验证模式上。那里,身份验证是关于获取代理连接。这里,它是关于限制连接的代理可以到达什么。
注意拒绝列表和狭窄写路径是什么限制爆炸半径,如果代理曾被转向:它根本无法到达注入想要的路径。
最小权限是一个设计原则,不是配置设置,因为它是即使每个其他防御失败时也保持的控制。为了论证起见,假设一个注入通过模型的训练、过去分类器,代理决定作用于敌对指令。接下来发生什么完全由代理的身份被允许做什么界定。如果那个身份可以写到任何地方并读取每个秘密,注入是一个事件。如果那个身份可以写到一个输出目录并仅读取它被给予的输入,相同的注入是一个拒绝的行动和一个日志条目。现实是没有系统可以消除被转向模型的可能性。什么决定结果的严重性是被转向代理可以做多少伤害,最小权限最小化这个。
这是为什么身份验证配置必须被保护的原因:任何可以扩大代理权限的东西也可以移除限制爆炸半径的控制。编辑代理的角色因此是一个特权行动,属于与秘密相同的保护后面。
秘密处理遵循相同的逻辑。一个在提交的配置中的秘密是一个永久暴露。它活在存储库历史中,所以即使在你从当前文件中移除它后,任何曾有过存储库读访问的人可能已有秘密的访问。从环境变量或托管秘密存储拉秘密保持它们出代码并让它们在不改变应用本身的情况下被轮换。这很重要,因为对泄露秘密的响应是轮换它,你无法轮换烤入你的源中的东西。模式很小,故障的爆炸半径很大。
基于钩子的护栏:强制,不是惯例 你在前面模块中使用的 Claude Code 钩子在代理生命周期的固定点运行你自己的检查。指向安全,一个钩子可以阻止接触受保护资源的工具调用,拒绝由不受信任的输入触发的行动,并记录每个特权行动用于审计。在受管制环境中重要的区别很简单:一个仅活在提示中的规则不被强制,而在工具执行前运行的钩子是一个强制的控制。
钩子在执行前阻止注入的写并记录被阻止的行动和每个允许的特权行动。作为结果,控制和其证据在审查者曾问之前存在。当多个钩子或规则应用于相同行动时,优先顺序是拒绝超过询问超过允许。单个拒绝规则阻止行动,无论多少允许规则也存在。那个顺序是什么使钩子一个真实边界而不是最好努力检查。
在审查停滞你之前为受管制行业作用域 一个金融或医疗保健客户早期问三件事:数据在哪里处理?访问如何被记录?管理员可以集中控制配置吗?在作用域期间命名数据驻留(数据在哪里处理)、审计日志和托管配置是什么保持集成不在安全审查中停滞。这些是预期问题,其缺席读作风险。提前提出它们将安全审查从阻止变成检查表。
一个模型特定约束提前命名:零数据保留 (ZDR) 资格因模型和平台而异,即使在现有 ZDR 协议下也不保证每个模型。截至本文撰写,不是所有当前模型都是 ZDR 合格的,较新或更高能力的模型可能还没有 ZDR 状态确认。在作用域时根据 Anthropic 信任中心确认每个模型的当前 ZDR 资格,在 Amazon Bedrock、Vertex AI 或 Microsoft Foundry 上确认每个平台下的数据保留。对于 ZDR 是要求的受管制客户,部署表面必须使用在作用域时确认 ZDR 合格的模型,这可能约束模型或平台选择。
三个问题中的每一个映射到具体的东西,要么存在于设计中,要么不存在。数据驻留是关于数据物理存储的地方:哪个区域处理请求、任何数据是否离开客户的边界,以及部署表面、直接 API 或云提供商的托管版本是否满足客户的约束。你通过知道你的部署路径回答这些问题,这直接连接到下一个模块的跨平台工作。
访问日志是审计线索,它直接映射到钩子产生的每个行动日志:每个特权行动、采取它的身份和结果。审查者不想要代理表现的承诺。他们想要他们可以检查的记录,钩子的审计日志提供那个记录。托管配置是关于管理员是否可以集中定义和控制规则,所以单个开发者无法悄然在他们自己的机器上扩大权限。它是锁定身份验证配置的组织版本。实际上,受管制审查是一个请求看到这三个能力。一个用它们在心中作用域的集成通过显示它已经拥有什么而不是在截止日期下仓促添加控制来通过。
安全是分层的,每层做不同的工作。模型的训练和分类器减少注入到达的频率。将获取内容视为数据减少到达的注入被作用的频率。最小权限和锁定配置界定成功行动可以到达什么。钩子在行动发生前强制那些边界并记录它们。受管制审查作用域使整个安排对必须签署它的人可理解。没有单个层足够。一个防御取决于一个控制失败关闭是一个错误离开事件,而一个分层防御在任何单个层被绕过时降级而不是崩溃。
操作系统级沙箱:剩余控制 钩子和最小权限角色是强制的控制,但它们共享一个依赖:它们必须明确覆盖它们保护的路径或端点。一个检查 write_file 的钩子不自动阻止对未审查端点的网络调用。操作系统级沙箱通过在进程级别隔离代理而不是规则级别来解决这个差距。文件系统隔离将代理限制到其工作目录,无论任何单个钩子允许什么;网络隔离将出站连接限制到一个命名的端点集,无论身份角色允许什么。因为隔离由操作系统而不是应用逻辑强制,它即使当钩子缺失、配置错误或被绕过时也保持。这是企业安全审查者首先问的控制,以及关闭"我们有钩子"和"我们有可辩护边界"之间差距的控制。配置通过 Claude Code 设置;完整文档在 code. claude. com。
你可以在构建时保持打开的防御检查表
威胁|它进入的地方|阻止它的控制|被记录的东西 ---|---|---|--- 提示注入|隐藏在获取页面、文档或工具结果中的指令。|将获取内容视为数据,加上一个钩子,拒绝由不受信任的输入触发的行动。|获取的来源、尝试的行动和块。 越狱|一个精心设计来绕过模型安全约束的用户提示。|输入验证加上模型被允许做什么的约束。|标记的提示和拒绝。 过度宽泛的访问|一个身份作用域比任务需要更宽。|最小权限身份、秘密在管理器中、锁定身份验证配置。|每个特权行动,带采取它的身份。 沙箱逃逸|一个被转向的代理试图文件系统或网络访问在其允许的边界外,包括没有钩子或权限规则明确覆盖的路径和端点。|操作系统级沙箱:文件系统隔离作用域到工作目录,网络隔离作用域到仅允许的端点。通过 Claude Code 设置配置;在 code. claude. com 上记录。当钩子或权限规则缺失时保持的控制。|每个在沙箱边界外的尝试访问,用触发它的工具调用和被拒绝的路径或端点记录。
处理得很好|通过默认将不受信任的输入视为敌对并用钩子和最小权限强制边界。 增加成本或复杂性|最小权限作用域、秘密管理和审计日志是部署审查就绪前的设置工作。 使用不同的方法|没有提示指令是安全控制。如果它必须保持,用钩子强制它,不是提示。
屏幕 17:获取的页面给了命令
观看 安全 8 分钟
获取的页面给了命令
设置 你的代理获取网页,可以写到单个文件路径。你的用户都是内部的,所以你决定了输入是受信任的,跳过了验证它获取的页面。推理感觉合理:如果你信任做请求的人,你信任请求。然后代理写了一个没有人要求的文件。
短成绩单:一个配对会话,其中获取的内容给了命令 两个开发者,在一个读网页并可以写到单个文件路径的代理上工作:
开发者 A "我们的用户是内部的,所以我没有费力验证代理获取的页面。风险是用户,我们信任他们。"
开发者 B "但指令不来自用户。它来自页面。拉起它写那个意外文件的运行。"
开发者 A "这里。用户要求它总结一个页面。页面有一行,靠近底部,告诉代理写其总结到不同的路径并忽略其前面的指令。所以,它遵循了那个指令。"
开发者 B "正确在那里。代理读取页面作为指令,不是作为数据。用户从未要求那个写。敌对指令通过代理获取的内容到达。"
代理将获取内容中的文本视为命令。修复是两侧的:将获取内容视为要检查的数据,并在写工具前放置一个钩子,拒绝由不受信任的输入触发的行动。这在工具运行前强制边界,而不是仅依赖提示。有了钩子,相同的注入行击拒绝的写和审计条目,而不是成功的数据泄露。
为什么这破裂了 不受信任的获取内容被视为指令。信任用户的信任没有帮助,因为注入通过内容到达。将获取内容视为数据并用钩子强制行动边界。
屏幕 18:为获取和写代理组装最小安全配置
检查点 安全 · 10 分钟 为获取和写代理组装最小安全配置
场景是一个获取不受信任网络内容并写到单个受保护路径的代理,同时在作用域身份下行动。为这个代理组装最小配置。写它必须包括的四个控制,并在一句话中解释每个强制什么。留出不属于的任何东西。
部分 1 · 生命周期事件上的钩子
部分 2 · 拒绝规则
部分 3 · 秘密参考
部分 4 · 审计日志行
与模型答案比较 暂时跳过
屏幕 19:累积生产硬化任务:找到三个缺陷并解释每个
累积 模块范围 · 7 分钟 累积生产硬化任务:找到三个缺陷并解释每个
到目前为止的一切都一次硬化了一层:评估、测试和追踪层、故障路径、成本和编排预算以及安全边界。真实生产故障很少一次一层到达。
这个任务在一个可运行的应用中放置三个缺陷,每个从不同的层组抽取,并要求你找到并修复所有三个。
现在尝试。下面的应用运行,但它包含三个植入的缺陷,每层一个。首先,将每个缺陷定位到其层。然后为每个写修复。你的目标是找到、修复和集成所有三个。
识别每个缺陷 上面的应用有三个缺陷,每层一个。对于每个缺陷:命名它属于的层,并写一句话描述它在运行时导致什么。
与模型答案比较 暂时跳过
屏幕 20:累积生产硬化任务:写纠正版本
累积 模块范围 · 8 分钟 累积生产硬化任务:写纠正版本
写应用的纠正版本。对于你识别的每个缺陷,显示修复的代码并命名它改变什么。
来自前面屏幕的应用(供参考)
与模型答案比较 暂时跳过(最终任务)
屏幕 21:关键要点
总结 模块 4 · 3 分钟 关键要点
1
在构建前设置标准。 一个评估将"完成"从感觉变成固定案例集上的分数。评分方法必须与输出匹配:当有一个正确形式时精确匹配,结构化输出的代码检查,开放式质量的评判者,你在信任它之前根据人工标记案例校准。你首先写评估,因为识别预期行为强制你在设计仍然可以改变时定义成功。
2
将测试与故障匹配,追踪所以你知道它发生在哪里。 单元、功能、集成和端到端测试每个捕获不同的中断,大多数悄然故障隐藏在两个通过的组件交接的集成接缝处。追踪显示哪个步骤产生了坏结果,这将一天的调查变成短修复。相同的直觉驱动检索选择:对单事实查询获取一次,当问题真的是多步时跨迭代搜索。
3
对每个故障排序,然后单独处理它们。 任何故障的第一个问题是等待和重试是否可能解决问题。可重试故障获得指数退避,有上限和重试预算,从不立即循环,仅加深问题。工具故障用错误标志设置返回给模型,不隐藏在空结果后面,模型错误地将其视为数据。每个重试无法修复的故障需要一个命名的回退。否则,未处理异常变成默认行为,这是一个坏响应如何使整个流程崩溃的方式。
4
每个调用衡量成本和延迟,仅在任务真的分割时扇出。 你无法预算你不衡量的东西,所以对每个调用仪表化令牌成本、延迟和错误率。然后调整一个选择的杠杆而不是从发票猜测。编排者-工作者模式乘以子代理数量的令牌成本,在 Anthropic 报告的案例中大约十五倍。它仅在分成独立并行部分的任务上赚取那个成本,不是紧密耦合的工作,单个代理可以以成本的一个分数处理。
5
将获取内容视为数据并用钩子强制边界。 一个模型读取其上下文中的所有东西一起,作为一个令牌流,没有受信任指令和不受信任数据之间的内置线。隐藏在获取内容中的指令可以影响代理的行为。信任你自己的用户没有帮助,因为注入通过代理读取的内容到达。检查不受信任的输入作为数据,将代理的身份作用域到最小权限,保持秘密出提交的配置,并用在工具运行前阻止和记录的钩子强制行动边界。那个边界是受管制审查可以控制和检查的。
接下来是什么 下一个模块将你现在可以构建的生产就绪系统变成可重用的加速器和贡献的知识产权。它覆盖如何将工作构建打包为参数化模板、MCP 服务器或便携式评估套件,通过维护者接受的频道贡献它回去,然后选择、版本固定和防御它在第一方 API、Amazon Bedrock 和 Google Vertex AI 上运行的地方,所以模型改变或驻留审查不会破坏生产。下一个模块覆盖本模块搁置的部署平台细节。
Anthropic 公开参考(时间敏感)
ID|来源|类型|用于 ---|---|---|--- S1|https://platform. claude. com/docsProduct 文档|评估工具和评分方法、测试级别、API 错误和状态代码、重试和退避指导、工具结果错误标志、可观测性和提示缓存、IAM 和提示注入防御。 S2|code. claude. com|产品文档|Claude Code 钩子生命周期事件(PreToolUse)和护栏模式。 S3|anthropic. com 和 Anthropic 多代理研究写作|工程和研究写作|编排者-工作者模式及其大约 15 倍令牌成本、代理搜索对 RAG 和 Claude Code 检索发现、提示注入防御。 S4|用 Claude API 构建(Skilljar)|Anthropic 课程|评估管道、代码和模型评分者、RAG 和检索机制、工作流模式、提示缓存。仅稳定概念材料。 S5|Claude Code 101 实际行动(Skilljar)|Anthropic 课程|Claude Code 钩子和从前面模块携带的配置。
你现在可以证明 Claude 功能在生产流量下保持。 评估、测试和追踪、故障处理、成本和编排纪律以及安全边界;每层关闭开发隐藏生产揭示的一种方式。
屏幕 22:本模块的关键术语
词汇表 关键术语 · 3 分钟 本模块的关键术语
按字母顺序。点击一个术语来展开其定义。
代理搜索|让模型发出自己的查询、读取结果并跨多个轮次精化,而不是一次获取固定的上下文集。它处理多步问题和变化的语料库,代价是更高的令牌和延迟成本,避免了维护索引的陈旧性和基础设施。 评估|一个输入案例、预期行为和分数的集合,定义功能在发货前必须做什么。运行评估产生一个保留集上的分数,这将"完成"从判断调用变成一个数字,当你改变提示、工具或模型时你可以追踪。 指数退避|一个重试策略,在尝试之间等待一个增长的间隔,最多到一个上限和固定数量的尝试,通常带随机抖动。它防止立即重试加深速率限制,并在响应提供一个时尊重 retry-after 值。 基于钩子的护栏|一个在 Claude Code 代理生命周期的固定点运行的检查,例如工具调用前的 PreToolUse,可以阻止一个行动并记录它。与提示指令不同,钩子是一个在受保护行动前运行的强制控制,这是受管制审查关心的区别。 集成测试|一个练习两个组件交接的测试,例如检索输出传递到模型调用。它捕获单元和功能测试错过的悄然故障,因为每个组件可以单独通过,而它们之间的交接是破裂的。 LLM-as-judge|一个评分方法,使用第二个模型调用带评分标准来评分没有代码规则可以检查的开放式输出。它返回一个带推理的分数,仅在你根据人工标记案例校准它并衡量一致性后才可信。 编排者-工作者模式|一个多代理形状,其中主导代理规划任务、生成并行工作的子代理,每个有自己的上下文,并编译它们的结果。它在分成独立部分的广泛任务上帮助,代价是在 Anthropic 报告的案例中大约十五倍的令牌成本。 提示注入|一个攻击,其中隐藏在代理获取的内容中的指令被视为命令,因为模型读取其整个上下文作为一个流,没有受信任指令和不受信任数据之间的内置边界。防御是将获取内容视为数据并在提示外强制行动边界。 可重试对终端错误|任何生产故障的第一个区别。一个可重试错误,例如速率限制或过载,可能在稍后尝试时成功,获得退避。一个终端错误,例如坏请求,会相同地再次失败,应该快速失败而不是浪费重试预算。
屏幕 23:恭喜!你已成功完成这个模块。
模块完成 开发者路径 · 2 分钟 恭喜!你已成功完成这个模块。
你现在可以证明 Claude 功能在生产流量下保持:一个定义"完成"的评估、一个定位中断的测试和追踪层、存活速率限制的故障处理、在规模下保持的成本和编排预算,以及存活受管制审查的安全边界。每层关闭开发隐藏生产揭示的一种方式。
0 个?检查点通过
M1
MSO 基础 令牌、上下文窗口、采样、模型层级、提示模式和 API 传输机制。
M2
生产级提示、代理与工具使用 生产就绪的提示、工具使用循环、流式处理、上下文和记忆管理,以及检查点代理循环。
M3
Claude Code、MCP 与集成 权限模式、持久项目上下文、插件打包和 MCP 集成,不泄露凭证。
M4
生产工程、评估和安全 证明系统在生产流量下保持并存活安全审查。
你在这里
M5
加速器和知识产权贡献 打包加速器、准备可验证的贡献、选择部署平台并标记信任边界。
接下来
审查模块 重新开始
模块完成已记录。
No flashcards for this lesson.
No quiz for this lesson yet.