Code Agent 是否应在执行工具调用前校验 LLM 输出?

作者:袖梨 2026-09-16

Code Agent 应在执行工具调用前校验 LLM 输出,而且校验不能停留在“JSON 能解析”。模型输出是不可信输入:字段类型可能错误,路径可能越界,SQL 可能写数据,HTTP 请求可能访问未授权端点,shell 命令可能扩大影响范围。可靠链路需要依次完成语法解析、schema 校验、语义与策略检查、必要审批,再让受限执行环境完成操作。

为什么提示词不能充当安全边界

系统提示可以告诉模型只读数据库、只修改工作区或不要删除文件,但模型可能误解需求、产生格式错误,也可能被仓库内容中的提示注入影响。即使模型大多数时候遵守规则,偶发一次危险调用也足以造成不可逆后果。

提示词适合引导行为和减少无效尝试,真正的边界必须由确定性代码执行。社区讨论中的核心区分很准确:结构化输出不等于已经验证的输出。一个 JSON 对象完全符合 schema,其中的 command 仍可能是危险命令。

第一层是解析与 schema 校验

工具网关首先确认模型确实调用已注册工具,参数能解析为预期格式。schema 应拒绝未知字段、缺失必填项、错误类型、空字符串和超出范围的数字,并给数组数量、文本长度与枚举值设置上限。

例如 edit 工具可以要求 path 为字符串、edits 至少一项、每项具有非空 oldText 与 newText;搜索工具可以限制 maxResults;超时只能落在合理区间。错误应返回字段级诊断,让模型修正调用,而不是把异常参数传给底层库。

schema 解决“形状是否正确”,不解决“操作是否允许”。合法 path 仍可能是工作区外绝对路径,合法 SQL 字符串仍可能包含 DELETE,合法 URL 仍可能指向内网元数据服务。

第二层是工具名与能力允许列表

模型只能调用当前任务明确暴露的工具。服务端应从注册表解析工具名,而不是根据模型提供的模块名动态 import 或执行任意函数。只读模式可以只暴露 read、search 和 status;实现任务再按需要开放 edit、test 或受限 shell。

能力应遵循最小权限。一个负责总结文档的 Agent 不需要数据库写权限,代码审查 Agent 也不需要部署接口。工具越少,模型误调用和提示注入可利用的表面积越小。

文件路径需要规范化后再判断

文件工具不能只检查字符串是否以工作区路径开头。应先把相对路径基于固定根目录解析,折叠点号段,处理大小写和分隔符,再检查最终规范路径是否位于允许根内。还要考虑符号链接、junction 和 reparse point,防止表面在工作区内的路径跳到外部。

创建、读取、修改、删除和移动可以使用不同策略。移动操作同时校验源与目标;递归操作设置文件数量和总字节上限;敏感文件模式可要求额外确认。底层进程仍应以只能访问允许目录的身份运行,避免应用层校验遗漏。

SQL 为什么需要结构化解析

用正则判断 SQL 是否以 SELECT 开头并不可靠。注释、多语句、CTE、存储过程和数据库特有语法都可能绕过简单字符串检查。应使用对应方言的解析器生成 AST,拒绝非允许语句类型、多个 statement、危险函数和未授权表。

应用层验证之后,数据库连接本身还应使用只读账号,只授予允许 schema 和表的 SELECT 权限,并设置语句超时、行数及资源限制。这样即使解析器存在边界漏洞,数据库权限仍是最后一道防线。

HTTP 与 API 调用怎样限制

API 工具应允许固定主机、协议、端口、路径模板和 HTTP 方法。重定向后的目标也必须重新验证,DNS 解析要防止指向回环、链路本地或私有地址,除非这些地址明确属于任务范围。

请求体需要 schema 校验,认证凭据由工具注入,不允许模型直接提供或回显。创建、发送、发布、付款等外部副作用应等待审批,并使用幂等键防止模型重试产生重复操作。

shell 工具为何最难验证

shell 语言支持管道、重定向、变量展开、命令替换和子进程,静态判断完整影响范围非常困难。把命令按空格拆分再做黑名单既容易误报,也容易绕过。高风险场景应优先提供任务专用工具,而不是开放通用 shell。

必须提供 shell 时,可结合命令允许列表、固定工作目录、环境变量清理、资源限制、网络隔离和文件系统沙箱。写入、删除、权限修改和远程操作应显示完整命令并要求确认。即使策略判断为只读,也应在受限身份下执行。

审批解决什么问题

审批让用户在有副作用的操作发生前看到目标、范围和预期变化。文件修改最好展示 diff;命令展示参数和工作目录;API 调用展示方法、目标和关键载荷;数据库写入展示受影响对象。

审批不是把所有安全责任转给用户。系统不能让用户在几秒内识别编码、路径穿越或复杂 shell 注入。机器可确定的规则应先自动校验,只把真正需要业务判断的决策交给人。

校验顺序为什么重要

推荐顺序是:解析模型输出;查找注册工具;schema 校验;规范化参数;执行工具特定策略;计算预览与影响范围;请求审批;在沙箱中执行;验证结果;记录审计事件。越便宜、越确定的拒绝应越早发生。

审批前构建预览时不能产生真实副作用。若预览需要读取文件或查询元数据,应使用只读能力。审批通过后还要防止检查时与使用时之间的竞态,例如写文件前比较内容哈希,数据库更新使用事务和版本条件。

失败反馈如何让模型自我修正

验证失败应返回结构化错误码、字段路径、原因和允许的恢复动作。path_outside_root、sql_not_read_only、unknown_tool、approval_denied 和 resource_limit 应是不同状态。模糊的“tool failed”会促使模型盲目重试或寻找绕过方式。

错误消息不应泄露敏感路径、凭据或内部策略细节。可以告诉模型应改用相对路径或拆分查询,但不必公开安全检测的所有实现规则。

执行后仍然需要验证

前置校验只能证明调用被允许,不能证明结果正确。edit 成功后要比较 diff 并运行测试;SQL 查询要检查行数与返回 schema;API 请求要验证状态码和响应对象;命令要检查退出码、超时和实际副作用。

工具还应防止重复执行。网络超时可能发生在服务端已经完成操作之后,Agent 重试会造成双重创建。幂等键、事务 ID 和操作状态查询能把不确定结果变成可恢复流程。

审计日志应记录什么

记录模型请求的工具名、经过脱敏的参数摘要、校验决策、审批主体、执行环境、开始结束时间、结果与错误码。文件修改保存 diff 或内容哈希,数据库和 API 操作保存业务对象 ID。

日志不能原样保存密钥、个人数据和完整敏感文件。应在进入持久化层前脱敏,并设置保留期限和访问控制。审计的目标是复盘决策,不是制造新的数据泄露面。

不同风险工具的最低防线

  • 读取文件:规范路径、限制根目录、限制大小并检测二进制。
  • 编辑文件:加唯一上下文、陈旧版本校验、diff 审批和原子写入。
  • SQL:AST 校验、单语句、对象允许列表、只读数据库账号和超时。
  • HTTP:主机与方法允许列表、重定向复检、凭据隔离和幂等键。
  • shell:最小暴露、沙箱、资源限制、危险操作审批和完整退出状态。
  • 外部消息:收件人确认、内容预览、速率限制和发送记录。

如何测试验证层

测试不能只有正常调用。应加入路径穿越、绝对路径、符号链接逃逸、未知字段、超长数组、SQL 注释与多语句、HTTP 重定向到内网、命令替换、超时和重复请求。每个拒绝都要确认底层工具根本没有执行。

还应做属性测试和模糊测试,覆盖解析器边界;做集成测试证明应用层遗漏时底层只读账号或沙箱仍能阻止操作。生产遥测关注拒绝原因、误报率和审批后失败率,而不是只追求工具调用成功率。

社区经验应怎样解读

Reddit 讨论中,有开发者描述了 schema、允许列表和破坏性操作审批三层做法,并建议 SQL 同时使用应用层解析与只读数据库账号。这些是合理工程模式,但属于参与者经验,不能据此声称所有生产团队都采用相同方案。

是否校验不应由流行程度决定,而应由风险模型决定。只要工具能改变用户数据、访问秘密或触发外部行为,原始模型输出直接进入执行器就缺少必要的信任边界。

结论

Code Agent 应在工具执行前校验 LLM 输出,但“校验”至少包括形状、权限、资源范围和业务影响。schema 阻止畸形参数,策略层判断是否允许,审批提供业务判断,沙箱与底层权限限制最坏影响。

没有任何单层能独立保证安全。可靠系统把模型当作会犯错的不可信规划器,把工具适配器当作执行边界,并在执行后验证真实结果。这样既能让 Agent 自动完成工作,也不会把自然语言承诺误当成确定性控制。

相关文章

精彩推荐