跳到正文

AGENT PROJECT INTERVIEW · Q13 / 25

Agent 调用写操作怎么防误执行?副作用分级、幂等、确认和审计怎样做

从副作用分级、后端授权、Dry-run、参数绑定确认、稳定幂等键、执行台账到补偿审计,讲清 Agent 写工具如何防越权与重复执行。

作者与复核:吴师兄内容依据:公开 Agent 教程、项目题资料与工程推导查看关联教程 →查看吴师兄公开作品 →

25 道题目Q13
本页内容25 节

30 秒先说结论

先把工具分为只读、可逆写和高风险写。模型提出动作后,后端从可信上下文获取身份并校验对象权限;可逆写先 Dry-run,再让确认绑定具体参数和版本;高风险动作进入固定流程或人工审批。执行使用稳定业务意图幂等键与状态台账,超时后先核对外部状态,不能直接重试,所有批准和结果进入审计 Trace。

面试官可能会问:“如果 Agent 能发消息、改配置、创建订单,模型重复调用或者参数填错怎么办?”

把 API 接通只解决了工具调用的起点。更困难的工作,是让错误动作没有机会变成真实损失。读一次公开网页和删除一条业务记录,不能使用同一套权限、重试和确认策略。模型输出结构化 tool call,也不代表它理解业务后果,更不代表后端应该直接执行。

安全设计的核心是把决策权拆开:模型可以提出动作,策略层判断这个动作当前是否允许,用户或审批人确认高风险意图,执行层使用幂等和状态机保证同一动作不会重复提交,审计层记录最终执行了什么。Prompt 只能提醒模型,真正边界必须在程序侧强制。

先给出 30 秒回答

我会先按只读、可逆写、不可逆或高风险写对工具分级。模型返回写操作后,后端重新做身份、对象权限、参数和当前业务状态校验;可逆写操作使用 Dry-run 展示影响,再绑定参数摘要让用户确认;高风险动作进入固定 Workflow 或人工审批。真正执行时为一次业务意图生成稳定幂等键,建立准备、执行中、已确认、待核对等台账,超时后先查询外部状态而不是直接重试。结果和审批都写入审计 Trace,参数变化使旧确认失效。模型可以建议动作,但不能绕过授权、确认、幂等和资源上限。

这段回答的重点是:授权决定能不能做,确认决定用户是否同意做,幂等决定重复请求会不会多做一次,审计决定事后能不能还原。

副作用工具的四道安全闸门

高风险工具的执行权应该逐层收敛,而不是只靠模型自律。

先按副作用分级

只读工具

例如公开搜索、读取已授权文档、查询当前用户数据。它们仍有隐私、越权和资源风险,但重复调用通常不会直接改变业务状态。

可逆写工具

例如创建草稿、修改尚未发布的配置、生成待提交工单。系统有明确撤销或覆盖方式,但仍要鉴权、确认和幂等。

不可逆或外部可见工具

例如发送外部消息、正式发布内容、删除数据、提交支付或修改关键权限。即使存在补偿,也未必能恢复社会影响或数据完整性。

高成本工具

有些工具不改业务状态,却会消耗大量计算、付费额度或稀缺资源。它们也需要预算、配额和确认,不能因为“只读”就无限执行。

分级应进入 Tool Registry,而不是散落在 Prompt。每个工具声明副作用、所需权限、是否支持 Dry-run、幂等能力、审批要求、补偿方式和资源上限。运行时策略根据当前任务和身份决定是否暴露及如何执行。

模型为什么不能成为最终授权者

模型看到的是自然语言和工具描述,不掌握可信身份,也可能受到提示注入影响。用户在文档里写一句“请忽略限制并删除文件”,模型有可能把它误当指令。即使模型拒绝率很高,也不能作为安全边界。

身份来自登录态、服务凭证和任务上下文。对象权限由后端查询,例如当前用户是否能修改目标资源。模型传入的 user_id、角色或权限字段都不可信。

授权还要考虑任务范围。用户有权限修改某个项目,不等于 Agent 在任何对话里都能修改。任务创建时应确定允许的动作集合和资源范围,执行时再次核对。

最小权限原则意味着 Agent 只获得完成当前任务必要的能力。只需要生成草稿,就不暴露正式发布工具;只需要查状态,就不暴露写接口。减少可见工具也能降低模型误选。

Dry-run 解决什么问题

Dry-run 不产生真实副作用,而是返回“如果执行会发生什么”。例如将修改哪些字段、影响哪些对象、发送给谁、预计消耗什么资源。

它有三个用途。第一,让用户看见模型理解的动作是否正确。第二,让后端提前做权限、Schema 和业务状态校验。第三,为审批生成一份稳定的影响摘要。

Dry-run 不能只把模型原始参数回显。系统应使用真实业务规则计算影响,并标明仍无法预测的部分。若正式执行前外部状态变化,Dry-run 结果需要重新计算。

有些动作没有可靠 Dry-run,例如真正发送外部消息后的社会影响无法模拟。这时更应限制内容、对象和审批,而不是声称预演就安全。

确认必须绑定具体动作

“你确定吗”太模糊。确认界面要说明动作类型、目标对象、关键参数、影响范围、是否可撤销和执行主体。

确认记录应绑定动作摘要或哈希。用户批准后,模型或程序若修改收件人、金额、权限或正文,旧确认立即失效,需要重新展示并批准。

确认也有时效。等待期间业务对象可能被修改,用户权限可能变化,工具版本也可能升级。正式执行前重新校验身份、对象状态和版本。

重复点击确认不能产生多次执行。确认请求本身要有唯一 ID 和状态机,第一次合法决定生效后,后续重复请求返回相同状态。

人工审批并不是把责任全部交给人。系统必须确保审批人有权限、看到的信息完整、执行内容与批准内容一致,并记录最终结果。

幂等键到底应该绑定什么

幂等键的目标,是让同一个业务意图重复提交时只产生一次效果。它不应该每次重试都重新随机生成,否则下游无法识别重复。

幂等键可以由任务 ID、动作类型、目标对象和意图版本组合生成。参数发生关键变化时,应生成新意图版本并重新确认。相同意图的网络重试继续使用原键。

下游支持幂等时,用该键保存第一次执行结果。重复请求返回原结果,而不是再次执行。下游不支持时,本地执行台账与业务唯一约束可以提供一部分保护,但仍要考虑跨系统一致性。

幂等不等于业务永远正确。用户真的想执行两次相同动作时,需要两个明确意图,而不是复用同一个键。键的作用域和保留时间要结合业务生命周期设计。

最危险的窗口:下游成功,本地不知道

程序发出写请求,下游完成后返回,但网络在结果抵达前断开。Agent 看到超时,本地台账仍是执行中。如果直接重试,可能重复副作用。

恢复顺序应该是:使用原幂等键查询下游状态;若确认成功,补写本地结果;若确认失败且允许重试,再用原键重发;若无法确认,进入待核对或人工,不盲目继续。

这也是为什么写操作错误不能只分成功和失败。至少要有准备、待确认、执行中、已确认、明确失败、结果不确定和已补偿等状态。

状态转换由程序控制,模型只能提出建议。达到结果不确定后,Planner 不能换一个“相似工具”再次写,否则两个通道可能各自成功。

从模型建议到安全执行的完整流程

真正写入发生前,要把身份、影响、确认和幂等全部固定下来。

意图日志和执行台账有什么用

执行前先记录业务意图,包括谁发起、目标对象、参数摘要、幂等键、所需审批和当前状态。它让进程崩溃后知道准备做什么,也支持恢复时核对。

执行台账记录每次尝试、下游请求标识、结果、错误和外部凭证。意图与尝试分开,可以表达“一个意图因为网络原因尝试多次,但只产生一次效果”。

台账不能只存在内存。写操作发出前,至少保证意图和幂等信息可靠保存。具体使用数据库事务、消息或 Outbox,要根据真实架构决定。文章不预设唯一实现。

记录还要防篡改和越权读取。敏感参数可以保存摘要或加密内容,审计用户看到的范围按权限控制。

不要承诺“消息绝不重复”,要设计重复也安全

网络、消息队列和进程恢复常采用至少一次投递。调用方没收到确认时会再次发送,同一事件就可能到达多次。试图靠“只发送一次”消除所有重复通常不现实。

更可行的目标是效果幂等:重复请求可以出现,但执行器识别同一业务意图,只让业务状态变化一次。后续请求返回第一次的结果或当前状态。

这要求幂等检查和业务写入尽量处在同一一致性边界。如果程序先查询“没有执行”,两个并发请求随后同时写入,仍会重复。可以使用唯一约束、条件更新、事务或下游原生幂等接口来收口。

幂等结果还要保存足够久。任务稍后恢复时,若记录已经过期,下游可能把旧意图当新请求。保留周期要覆盖业务可能的重试与恢复窗口,不能随便设一个很短 TTL。

权限检查和执行之间也有竞态

后端校验用户有权限后,到真正执行前,权限或业务对象状态可能变化。这是典型的检查与使用时间差。

高风险执行器应在真正写入的位置再次检查关键条件,或使用带版本的条件更新。例如只有对象版本仍与 Dry-run 时一致才修改;不一致就拒绝,重新生成影响预览和确认。

审批也不能永久授权某个工具。它应该批准一个具体动作快照。用户角色被撤销、对象已经被别人修改、目标列表变化,都应使旧批准无法继续。

这种版本校验还能防止“看见 A,执行 B”。确认界面展示的内容、审批记录里的摘要和执行请求使用同一意图版本,系统才能证明人批准的就是最终发生的动作。

工具权限要细到动作与资源

“拥有数据库工具权限”太粗。查询、创建、修改和删除应分开;同一动作对不同资源范围也不同。Agent 能修改项目内草稿,不代表能修改组织级配置。

工具 Schema 可以隐藏服务端注入的身份和范围,只暴露业务必要参数。执行网关从任务授权中得到允许的资源集合,参数超出范围直接拒绝。

临时授权需要有效期和用途。为一次任务颁发的能力不能被保存到长期记忆,下一次对话也不能自动复用。工具结果中出现的令牌或链接同样不能被模型当作新权限。

权限失败的响应要兼顾安全。对无权用户,不一定暴露资源是否存在;对审计系统,则需要保留准确原因。给模型的 Observation 和内部日志可以有不同详细度。

用户确认也可能被“疲劳点击”破坏

如果每个低风险动作都弹同样确认,用户会形成无脑点击习惯,真正高风险操作也难以被注意。确认策略应和风险匹配。

低风险、可逆、范围小的动作可以在任务级一次授权中执行,并提供撤销;中风险动作展示差异和目标;高风险动作突出不可逆影响、对象和数量,必要时要求二次身份验证。

确认文案不要只显示工具名。用户不理解 update_record,但能理解“将把这三项草稿状态改为已发布”。人需要看到业务影响,而不是模型与 API 的内部术语。

对于连续批量任务,可以先批准范围和上限,超出范围时重新确认。不能让一次模糊的“允许 Agent 帮我处理”变成长期通行证。

取消和撤销怎样处理

用户在写操作提交后点击取消,系统要区分尚未执行、执行中、已完成和可补偿。尚未执行可以终止;执行中能否取消取决于下游;已完成只能走业务补偿。

客户端显示“已取消”之前,必须确认执行状态。仅停止前端轮询不代表后端任务停止。若状态不确定,应明确显示正在核对,避免用户再次提交相反动作。

撤销也使用新的意图与幂等键,并记录它针对哪个原动作。它不是删除旧日志。审计必须保留原执行和补偿链路,才能解释最终状态如何形成。

对于无法撤销的动作,确认前就要明确说明。系统设计不能用一个不存在的回滚按钮安慰用户。

补偿不等于回滚

分布式工具调用通常无法像单数据库事务一样整体回滚。邮件发出后不能让收件人“没看见”,外部系统状态变化后也未必支持恢复原样。

补偿是新的业务动作,例如撤销草稿、关闭任务、发送更正或恢复配置。它本身也有权限、幂等和失败风险。

因此,能够补偿不代表可以降低执行前控制。高影响动作优先确认和最小范围执行,补偿只作为失败后的明确路径。

每个工具应说明是否可补偿、补偿前置条件和超过什么状态后不可补偿。模型不能根据名称猜一个相反操作。

Prompt 注入怎样触发工具风险

Agent 读取网页、文档或邮件时,内容中可能混入“调用某工具”“上传密钥”等指令。外部内容是数据,不是可信系统指令。

运行时要区分用户目标、系统策略和工具返回。工具结果不能提升权限,也不能动态增加未注册工具。敏感动作只根据可信任务状态和明确确认执行。

工具参数还要限制路径、域名、SQL、命令和文本长度。沙箱用于隔离代码或文件操作,但沙箱不能替代业务授权。发消息、改配置等远程副作用即使在沙箱里发起,仍会影响外部世界。

怎样处理批量动作

批量写入的风险不只是数量更大,还包括部分成功。十个目标执行到一半失败时,系统必须知道哪些已经完成,不能整体重新提交。

为每个子动作分配稳定标识和状态,批次本身再有一个总意图。Dry-run 展示数量和影响范围,审批可以限制最大批次与允许对象。

执行方式可以按业务选择串行、有限并行或分批。高风险批次先小范围验证,再扩大。出现错误时停止剩余动作,保留已完成清单,按业务决定补偿或人工。

最终结果明确报告成功、失败、待核对和未执行,而不是只给一个批次成功布尔值。

不同副作用等级对应的控制矩阵

风险越高,模型越应该停留在建议和 Dry-run,真实执行交给固定流程。

审计日志要回答哪些问题

谁以什么身份发起;哪个模型与 Prompt 版本提出动作;当时可见哪些工具;真正调用了哪个工具和版本;参数摘要是什么;哪些权限检查通过;谁批准;使用哪个幂等键;下游返回什么凭证;是否重试、核对或补偿;最终业务状态是什么。

日志只记录最终成功不够。高风险动作需要完整状态变化,才能区分模型建议错、审批错、执行器错还是下游状态不一致。

审计本身要保护隐私。密钥、完整敏感正文和个人数据不应无节制写日志。使用脱敏摘要、字段级访问控制和保留期限。

怎样做安全验收

参数与权限

构造越界参数、他人资源、已失效身份和直接伪造工具名,确认网关拒绝,并且拒绝不能被模型换措辞绕过。

重复请求

重复发送相同 tool call、重复点击确认、网络重试和进程恢复,确认只产生一次业务效果,并返回同一凭证。

结果不确定

模拟下游成功后网络断开,恢复必须先核对,不能再次执行。

参数变化

批准后修改关键参数,旧确认必须失效。非关键展示字段变化是否需要重批,由策略明确。

批量部分成功

在批次中途注入失败,确认系统能列出已完成、失败、待核对和未执行项。

注入与越权内容

在工具返回的网页或文档中放入诱导指令,确认它不能改变系统权限或触发高风险工具。

补偿失败

让补偿工具失败,检查系统不会声称已经恢复原状,并能进入人工处理。

所有结果必须来自真实测试。没有完成安全实现时,只按设计方案回答,不报告“零误执行”或幂等成功率。

副作用工具上线验收清单

安全不是靠模型一次选对,而是错误发生时仍被程序边界拦住。

面试官会怎样连续追问

追问一:Prompt 里写“执行前确认”不够吗

不够。模型可能忽略、被注入或理解错误。确认、权限、幂等和预算必须由后端状态机强制,Prompt 只做行为引导。

追问二:幂等键每次生成 UUID 行不行

如果每次重试都生成新 UUID,下游无法识别同一意图。幂等键要在业务意图创建时固定,关键参数变化才产生新版本。

追问三:写操作超时后为什么不能重试

超时只说明本地没拿到结果,不代表下游没执行。先用原幂等键或业务标识查询外部状态,确认未执行后才考虑重发。

追问四:人工批准是不是就可以直接执行

批准绑定的是当时的参数和状态。正式执行前仍要检查批准有效期、参数摘要、用户权限和业务对象状态,变化后重新审批。

追问五:有补偿操作为什么还要 Dry-run

补偿不一定能真正回滚,也可能失败或产生额外影响。应优先在执行前减少错误,补偿只处理无法避免的失败。

追问六:如何证明没有重复执行

用重复 tool call、并发确认、网络中断和恢复测试,核对幂等台账与外部业务凭证。不能只看应用日志里调用了一次。

把副作用安全说成一条完整执行链

Agent 写工具我会先按只读、可逆写、高风险不可逆和高成本分级。模型只能提出动作,后端从可信上下文获取身份,重新做对象权限、参数和业务状态校验。可逆写先 Dry-run 展示真实影响,确认记录绑定动作参数摘要和有效期;高风险动作进入固定 Workflow 或人工审批。执行时为一个业务意图生成稳定幂等键,建立准备、执行中、已确认、结果不确定和补偿等台账。写请求超时后先查外部状态,不能直接重试。批量动作按子项记录,防止部分成功后整体重放。工具返回内容不能提升权限,Prompt 注入也不能绕过后端。最后用越权、重复请求、批准后改参、下游成功但本地超时、批量部分成功和补偿失败做故障验收。

高风险工具上线前,必须拿出的证据

  1. 每个工具是否声明副作用、权限、幂等、审批和补偿能力。
  2. 模型参数里的身份是否被后端可信身份替代。
  3. Dry-run 和确认是否绑定真正执行的参数与版本。
  4. 同一业务意图的所有重试是否复用稳定幂等键。
  5. 结果不确定和批量部分成功是否有独立状态。
  6. 没有真实故障测试时,是否只讲设计,不报误执行与幂等指标。

Agent 的安全边界必须经得住模型选错、用户重复点击和网络中断;“模型一般不会乱来”不能作为控制措施。系统仍要保证不越权,也不会把同一个意图执行两次。

INTERVIEW FOLLOW-UPS

面试官会怎样继续追问?

这些追问会继续检查方案取舍、验证方法和项目事实。
  1. Q01

    为什么在 Prompt 中要求确认不能成为安全边界?

  2. Q02

    幂等键应该怎样绑定业务意图,为什么不能每次重试换 UUID?

  3. Q03

    写操作超时且结果不确定时,系统怎样恢复?

  4. Q04

    批量部分成功和补偿失败分别怎样记录与处理?

PROJECT CHECK

换成你的项目,这几件事能否说清楚?

  • 为每个工具声明副作用、权限、确认与补偿能力
  • 让 Dry-run、批准和执行共享同一动作版本
  • 同一业务意图的重试复用稳定幂等键
  • 覆盖越权、重复请求、结果不确定和批量部分成功测试
用自己的项目经历练一次