# 代理操作的按会话审批与按调用审批

AI 代理不需要不受限制的访问权限才能发挥作用。它只需要完成当前任务所需的权限，在一个说得清楚的时间范围内使用，并且在人类判断下一次调用会改变风险的地方设置决策点。这就是按会话审批和按调用审批之间的实际区别。

我见过团队犯两种相反的错误。一种是为每次无害的查询都审批，最后让人们养成不读提示、直接点击警告的习惯。另一种是给编程代理一个长期会话，然后当循环创建五十张工单、触发多次部署，或者导出远超预期的数据时感到意外。这两种失败都不是来自什么罕见漏洞，而是审批边界放错了位置。

核心关键词 **按会话审批与按调用审批** 描述的是一个需要三个输入的选择：任务运行多久、凭据拥有多少权限，以及一次合法请求被重复执行后能造成什么。HTTP 方法、代理声称的计划，以及开发者正在旁观这几个信号，都不如这三点可靠。

## 审批是允许在明确边界内采取行动

按会话审批会授予一个已识别的代理进程权限，让它在本次运行期间使用某个凭据。按调用审批则要求每次使用该凭据时都重新作出决定。它们回答的是不同问题，把两者当成可以互换的方案，结果要么是盲目信任，要么是毫无价值的阻碍。

会话决定表达的是：「我确认这个进程，接受这次范围有限的运行，并认为这个凭据能执行的操作在本次运行中重复进行也足够安全。」对于一个在调查错误时检查几条问题记录的代理，这是合理的决定。对于一个只要自己的推理认为下一次变更有帮助，就能修改生产环境的代理，这个决定就很糟糕。

调用决定表达的是：「我现在接受这次对这个凭据的确切使用。」它有意更慢。提示应该出现在这样一个节点：人可以看懂后果，也可以拒绝，而不至于丢掉整个任务。如果提示没有提供有意义的选择，审批设计就有问题。如果提示出现在不可逆操作之前，多花这一秒通常很划算。

不要把这和身份验证混为一谈。身份验证告诉本地系统谁可以解锁凭据存储。授权回答的是某次代理运行是否可以使用特定凭据。按调用控制增加了第三个问题：在此时此刻，这次使用是否值得一次新的人工决定。

在普通编程任务中，这个区别很重要。代理可能使用一个 API 令牌读取构建状态，再使用另一个令牌触发发布。同一个进程可以足够可信地检查前者，但使用后者时仍然需要明确决定。进程身份不会抹平它能访问的每个端点所带来的风险。

一个有用的审批边界有四个特点：

- 人可以说清代理正在做什么工作。
- 凭据权限范围与这项工作匹配，而不是覆盖代理所有可能的任务。
- 工作或已识别的进程结束时，审批也随之结束。
- 人可以描述代理重复执行允许操作时最坏的合理结果。

第四个特点比大多数检查清单更能发现糟糕的设计。如果答案是「它只会再发出一次无害请求」，按会话审批可能合适。如果答案包含资金、客户沟通、生产状态、删除、权限变化或大规模导出，就应让人工决定尽量靠近每次操作。

## 任务时长会改变会话承诺的含义

当会话很短、只服务于一个任务，并且绑定到任务完成后就退出的单个进程时，它最安全。一个悄悄持续到无关工作的会话，只是换了个更好听的名字，实质上仍是长期权限。

持续时间会影响风险，因为代理完成第一个预期操作后并不会停止推理。它可能重试、追查新发现的子任务、检查另一个代码库，或者执行从文件或工单中读到的错误指令。进程存活得越久，你最初的判断模型就越不可靠。运行十分钟来检查失败测试，目的容易理解。运行整个下午的进程会积累上下文、改变目标，也会增加遇到恶意或误导性输入的机会。

尽可能使用任务边界，而不是时钟。进程退出是诚实的结束条件：获批的代理已经不在运行。固定超时是备用控制，不是等价的控制。到了十五分钟，代理可能仍在执行原来的工作，也可能已经有另一个工具继承了同样的权限。仅凭时间无法判断是哪一种。

对于有边界的会话，在审批前写下工作单元。好的描述要具体：「检查失败的持续集成运行，并根据结果打开一条草稿评论。」糟糕的描述是「协助发布」。宽泛的语言会给代理留下空间，把小型诊断任务变成发布工作。

可以参考这些任务形态：

| 任务形态 | 按会话审批是否合适 | 原因 |
| --- | --- | --- |
| 在一次代理运行期间读取一组明确的构建日志 | 通常合适 | 进程会退出，数据集有边界，而且操作不应改变远程状态。 |
| 准备补丁时搜索内部文档 | 通常合适 | 凭据可以很窄，预期操作是重复读取。 |
| 处理生产告警 | 有条件合适 | 读取权限可以使用会话审批，任何变更性的恢复操作都需要单独决定。 |
| 执行迁移 | 通常不合适 | 代理可能发出许多改变状态的请求，重试还可能创建第二条迁移路径。 |
| 管理共享收件箱或客户账户 | 不合适 | 每次发送、编辑或导出都可能形成对外承诺，或暴露私人信息。 |

一种常见的捷径是因为人们讨厌中断，就给每个任务都批准会话。提示在低后果调用中频繁出现时，这种抱怨确实有道理。解决办法是缩小凭据范围，并把常规工作分组到真正有边界的会话中，而不是把一次长时间代理运行变成全权限窗口。

代理重启也要同样谨慎。对于启动命令的人来说，重启看起来可能是连续运行，但它实际上是新进程，可能加载不同的指令、代码或插件。重启后应请求新的会话授权。这不是官僚做法。原来的决定绑定的是特定的可执行权限和运行实例，而不是开发者对整个下午的模糊打算。

## 凭据敏感性首先取决于能力，而不是密钥类型

凭据之所以敏感，是因为它能造成、暴露或委托什么，而不是因为它有某个特定名称。只能读取一个公开构建产物的 API 密钥，可能比一个能把管理员带入私人工作区的令牌更不危险。可以访问部署主机的 SSH 密钥，与调用计费 API 的令牌有不同的失败模式，但两者都可能需要按调用控制。

应根据远程系统的实际权限对每个凭据分类。不要在没有检查 API 如何定义「读取」之前，就接受「读取令牌」这样的标签。有些服务把导出端点列为读取操作。另一些服务允许所谓的只读端点启动报告生成、消耗稀缺容量，或者返回代理根本不应该批量看到的数据。

我在选择审批级别前会问四个问题：

1. 这个凭据能否改变本地机器之外的状态？
2. 它能否泄露不适合放进代理上下文或输出的信息？
3. 它能否直接或通过触发的工作流授予更多权限？
4. 调用者能否花钱、消耗配额，或形成合同上的承诺或声誉影响？

任何一个问题回答「能」都不一定强制要求按调用审批，但意味着按会话审批需要更窄的任务、更紧的权限范围和可信的回滚方案。如果有多个问题的答案都是「能」，每次都询问通常才是诚实的选择。

先用权限范围降低风险，再用审批作为第二层控制。只能读取一个代码库的令牌，比能读取组织内所有代码库的令牌更适合用来作会话决定。仅限一个预发布环境的凭据，比能操作生产环境的凭据更适合交给会话使用。代理已经获得权限后，人工审批无法修复一个宽得离谱的令牌。

SSH 需要特别对待，因为人们经常把它称为「只是 shell 访问」。Shell 访问实际上是一条通向庞大且不断变化的操作面的通道。真正的风险取决于账户、主机、网络可达性、可用命令、部署钩子，以及该账户能读取的文件。只能运行一条诊断命令的受限账户可能适合会话审批。部署账户、存放客户数据的主机，或能够改变访问控制的账户，在权限可以缩小时之前，都应放在按调用审批之后。

不要让凭据轮换掩盖这项分析。一个新生成但拥有广泛生产权限的密钥，仍然拥有广泛生产权限。在糟糕的运行后轮换它，可以限制未来的滥用，但无法撤销已经成功执行的远程调用。

## 重复会把可容忍的操作变成昂贵操作

一个请求单独看可以接受，但代理重复执行后仍可能变得不安全。应分类重复操作，而不只是查看提示中显示的第一个操作。

这正是团队过度依赖 HTTP 方法名称的地方。RFC 9110 规定，安全方法的意图是只读，包括 GET、HEAD、OPTIONS 和 TRACE。它也提醒说，如果服务器通过安全方法暴露不安全行为，客户端不能因此被追责，因为这种行为由资源所有者决定。这段表述很重要。GET 端点在语义上可能用于获取信息，但应用仍可能让它变得昂贵、暴露大规模导出、更新审计字段，或触发下游工作。方法名称可以帮助你开始调查，但不能代替调查。

人们也经常误用幂等性。一个请求具有幂等性，是指在服务器状态上重复它的预期效果与执行一次相同。这不表示重复没有危险。把标志设为 `true` 的 PUT 请求可能是幂等的，但仍然会启用生产功能。第一次删除后，DELETE 可能仍是幂等的，但它依然可能删除重要内容。GET 在协议意义上可能是安全的，但代理循环调用它仍可能耗尽速率限制。

在一次性账户或预发布环境中测试端点的重复行为。发送相同请求两次，检查远程状态和副作用，然后再问代理发送一百次会怎样。不要只看响应正文。还要检查发送的消息、排队的任务、创建的审计记录、消耗的配额、触发的 webhook，以及复制到其他位置的数据。

对于会创建对象的端点，如果服务支持幂等键，就使用它。这种请求形式可以防止网络重试在第一次响应丢失时创建第二个付款、工单或配置请求：

```http
POST /v1/provisioning-requests HTTP/1.1
Authorization: Bearer injected-by-gateway
Idempotency-Key: agent-run-8b2f1-request-17
Content-Type: application/json

{"environment":"staging","version":"2025.04.18"}
```

服务再次收到同一个幂等键时，应返回原来的结果。响应通常会带有相同的对象标识符和成功状态，而不是创建新对象。要在服务文档中确认这一行为，并亲自测试。幂等键可以减少重试造成的重复创建，但不会让不合适的部署变得合适，也不会阻止代理为每次错误尝试生成新键。

具有以下任一重复特征的操作适合按调用审批：

- 每次调用都会创建一个新对象，例如发票、账户、工单、消息或订单。
- 每次调用都会改变实时状态，而且之前的状态很难重建。
- 每次调用都可能再泄露一页、一个归档或另一位客户的数据。
- 每次调用都可能产生公开或面向客户的效果。
- 每次调用都可能触发花钱或占用有限容量的工作。

当远程一方认为重复调用后果很低、凭据权限范围很小，而且任务有清晰的结束条件时，会话可以容纳重复调用。证明这一点是团队的责任。「代理大概不会循环」不是端点的属性。

## 只读标签不能决定风险

即使读取权限不能修改远程记录，也可能产生隐私、运营和提示注入风险。尤其当代理可以总结、复制或利用读取内容决定下一步时，应把数据暴露视为会产生后果的操作。

假设代理有权搜索支持系统。对于只限于一张工单及其附件的任务，会话审批可能合理。同一个凭据如果能枚举所有工单、获取导出文件，或把私密客户对话拉入本地上下文，就很难再审批。端点可能全都使用 GET，但定义风险的是数据边界，而不是动词。

一个令人不安的问题是：代理本身是否被允许看到返回结果。凭据网关不把令牌交给代理，并不意味着每个结果都适合返回。响应中经常会泄露秘密：配置端点返回连接字符串，用户记录包含个人数据，命令输出包含环境变量，错误响应暴露内部路径或标识符。

只要某个结果可能暴露敏感类别的信息，或代理请求能够扩大自己的搜索范围，就应对读取操作使用按调用审批。这包括广泛搜索、导出、获取秘密、枚举账户，以及对内容不断变化的目录运行 `cat` 等命令。人应该有机会先看到目标，再决定是否把这些数据释放到本次运行中。

对于常规读取，应限制请求形式。优先使用仅限某个项目、代码库、环境或 API 资源组的凭据。服务支持时，设置服务端分页上限。可能的话，给代理一个接受明确标识符的查询机制，而不是不受限制的搜索端点。这些选择会让每次允许的调用更小，因此也能减少审批提示。

事故响应中常见一种失败模式。代理先发出一个无害请求检查日志，随后在日志行中发现一个令牌，又在大型归档中搜索这个令牌的所有出现位置。在人的理解中，最初的会话审批覆盖的是故障排查，但凭据范围和查询形式却允许收集数据。操作员看不到活动列表中的变更，于是认为运行安全。真正敏感的行为是读取。

单独记录请求内容、使用的凭据，以及该调用是作为会话操作还是按调用操作获批。这份记录可以帮助调查人员区分代理被入侵和审批选择不当，也能暴露哪些凭据需要进一步缩小范围。只记录成功的变更，会让最难发现的读取失败消失。

## 让提示对应于人真正能作出的决定

当提示频繁到没人会读，或含糊到无法判断时，审批疲劳就是设计失败。按调用审批只有在每个提示都能让审核者了解足够的信息，从而接受或拒绝一个具体后果时，才真正有效。

有用的提示应说明调用进程、凭据或操作类别、目标位置和实际影响。「允许 API 请求」无法帮助任何人作出好决定。「已签名的代理进程请求使用发布凭据进行生产部署」就可以。对于敏感读取，提示应该说明数据集或目标，而不只是「GET 请求」。对于 SSH，应显示主机和命令，或显示有意义的命令类别。

不要通过隐藏目标位置来解决提示过载。开发者如果只根据友好的任务名称批准请求，就无法发现拼写错误、恶意指令，或已经改变方向的代理。提示需要足够具体，才能发现预期工作与实际操作之间的不匹配。

同时，也不要要求人们为每个常规请求解析原始 HTTP 正文。这样会产生形式主义审批。把重复且影响较低的调用放进有边界的会话，把按调用提示留给跨越真正决策边界的操作。人应该看到更少的提示，但剩下的每个提示都应该重要。

在每个凭据配置旁边写一条简短的审批说明。它不是政策语言，也不需要变成一套政策。例如：「仅限一个代码库的构建状态读取使用会话审批；每次生产发布都要审批。」这样的句子能让后续审查变得具体。如果团队无法写出一句话，将普通工作与有后果的操作分开，凭据可能就太宽了。

会话授权时显示的进程身份也值得关注。人应该批准可执行权限，而不只是容易复制或修改的命令行。已签名的父进程和未签名的辅助程序是不同的信任决定。面对陌生权限，正确做法是停止运行，确认它为何变化，并且只有在变化符合预期时才批准。因为任务紧急就点击，会教会整个组织接受冒充路径。

## 调整审批设置前先使用决策矩阵

一个小型矩阵可以避免团队根据个人对提示的容忍度争论。按后果评估操作；当分数指向两个方向时，选择更严格的级别。

| 问题 | 倾向按会话审批 | 倾向按调用审批 |
| --- | --- | --- |
| 运行会持续多久？ | 一个有边界的任务，进程退出时结束 | 长时间运行、重启、定时运行或定义含糊的工作 |
| 凭据可以访问什么？ | 一个范围窄的项目或环境 | 生产环境、多个租户、特权账户或广泛导出 |
| 一个请求会做什么？ | 获取有限的常规信息，或执行影响较低且可逆的更新 | 发送、删除、发布、配置、部署、改变权限或转移价值 |
| 重复会造成什么？ | 重复后果很小，且服务器能控制重复效果 | 每次调用都会增加成本、创建对象或扩大暴露范围 |
| 操作员能否撤销？ | 有清晰的回滚方式，不太可能丢失数据 | 回滚不完整、代价高或无法回滚 |

当表格给出混合答案时，应拆分工作流，而不是折中。给代理一个按会话审批、用于诊断的凭据，再给它一个按调用审批、用于修复的凭据。这样通常比反复审批读取，或为了避免变更审批而授予宽泛会话，更自然。

看一个具体例子。代理正在调查一次失败的部署。它需要读取构建日志，获取某个预发布环境的状态，并可能重启一个服务。

如果令牌只访问这个项目，而且进程会在诊断结束后退出，日志和状态调用可以使用按会话审批。重启应使用另一个按调用审批的凭据，因为它会改变运行状态。即使重启服务通常是安全的，重复重启也可能中断正在进行的工作、掩盖根本原因并触发自动恢复循环。代理发现重启是合理修复方案，并不会让它变成常规操作。

现在改变一个细节：状态 API 可以查询所有生产环境，日志读取可以获取未脱敏的客户负载。按会话审批不再适合这个诊断凭据。团队应先缩小访问范围。把同一个宽泛凭据放到按调用审批之后，确实能限制一种失败，但如果数据选择器仍不受约束，审核者无法可靠地评估每次读取请求。

这就是为什么为每个代理设置一个统一审批级别是糟糕的模型。审批应属于操作通道和凭据范围。只要边界画得有意，一个代理运行可以安全地同时使用两种级别。

## 审计记录能解释错误决定，但无法撤销它

防篡改记录可以帮助你调查代理运行、撤销活动会话，并确认代理是否重复了某个操作。但它无法阻止远程服务接受已经批准的调用。

保留两种活动视图。会话记录回答谁在运行、运行何时开始、拥有什么进程权限，以及是否有人撤销了它。调用记录回答代理使用了哪条凭据路径、联系了什么目标，以及调用是由会话授权还是新的审批允许的。两者都需要。只有会话列表无法证明哪个操作造成了问题，而没有进程上下文的一堆调用也无法说明是谁发起了它们。

让审计完整性可以测试，而不要只停留在口号上。如果有人修改、删除或重新排列存储序列中的记录，哈希链日志应无法通过验证。测试很简单：验证一份已知正确的副本，在副本中修改一个字节，再次验证。验证器应报告链不再有效，而原始记录仍应通过验证。在测试夹具中完成这项操作，绝不要编辑生产审计存储。

Sallyport 从一个写入隔离、加密并采用哈希链的审计日志中生成 Sessions 和 Activity 日志；`sp audit verify` 可以在离线状态下直接对密文检查哈希链，无需保险库密钥。当检查记录的人不应获得保险库保护的凭据或操作负载时，这种分离很有用。

日志也会暴露一种常见的审批错误：把会话当成停止观察的理由。检查调用数量异常多、联系了新目标、运行时间远超任务描述，或使用了不属于平时类别的凭据的运行。你不需要规则引擎才能发现这些模式。每周由人抽查少量运行，就能在权限范围扩张变成日常习惯之前发现它。

代理行为不当时，在改变配置前保存进程身份、任务输入、会话记录、调用顺序和远程服务日志。然后提出一个比「代理是否被入侵」更具体的问题：该操作是否在凭据权限范围内？审批级别是否符合重复风险？提示是否提供了足够信息让人拒绝？授权后进程是否发生变化？这些答案会导向修复措施，笼统禁止自主运行不会。

## 从狭窄范围开始，胜过设置宽泛例外

先选择一个可以不含糊地描述影响的工作流，再把最可能造成损害的凭据交给按调用审批。在几次真实运行后，再考虑把常规部分移入有边界的会话。

对于基于 Mac 的代理设置，Sallyport 会把 API 和 SSH 凭据保存在加密保险库中，并执行操作，而不是把秘密传给代理。这能减少凭据暴露，但你仍必须同样谨慎地选择审批边界，因为远程操作依然真实存在。

第一次配置应该让开发者稍微觉得不方便，而不是让人失去判断。如果每次运行都会为构建状态读取产生一长串提示，就需要改进权限范围或任务分组。如果代理只获批一次，就能在一小时内修改生产环境，会话范围就太宽了。在让人退出决策环节之前，先调整凭据和任务边界。

用操作语言写下下一次审批选择：这个签名进程针对这个任务，可以在退出前执行这些影响较低的调用；另一个凭据的每次使用都需要重新决定，因为它可能改变我们无法轻易撤销的内容。这句话能给审核者一个在压力下也能使用的标准。更含糊的说法最终都会变成永久例外。
