关键词:Agent 工具描述、AI 工具选择、Prompt Injection、Agent 安全策略、能力声明
假设一套企业系统向 Agent 暴露了下面三项能力:
order.read
order.search
refund.request.create
接口名称看起来都很清楚,参数 Schema 也很完整。
但当用户说:
帮我看看客户昨天那笔订单为什么还没有发货。
模型仍然需要判断:
- 应该按订单编号读取单笔订单,还是按客户和日期搜索;
- 查询结果里是否包含履约状态;
- 这项能力返回的是订单摘要,还是完整客户资料;
- 当前需求只是查询,还是已经进入售后或退款流程;
- 某个示例参数是演示值,还是调用时必须遵守的约束。
接口 Schema 可以告诉模型参数是什么类型,却不一定能够完整说明:
这项能力适合在什么意图下被选择,它会返回什么,以及怎样构造一组具有代表性的参数。
这就是 Agent-facing guidance 存在的价值。
但同一段 guidance 又绝不能回答:
- 当前用户有没有权查看这笔订单;
- 是否允许发起退款;
- 金额超过多少必须审批;
- 哪些客户数据可以被模型读取;
- 一段来自网页、邮件或模型输出的文字能否临时放宽限制。
前一组问题属于能力选择和使用理解,后一组问题属于治理与最终授权。
二者都很重要,却不能由同一段自然语言承担。
Guidance 帮助 Agent 更准确地选择和调用能力,但它不是安全策略,也不能成为安全策略的替代品。
1. Agent-facing 能力既要“可治理”,也要“可选择”
企业把 API 接入 Agent 时,很容易只关注治理字段:
enabled: true
scope: order.read
risk:
level: low
subject:
required: true
execution:
readonly: true
这些字段回答了:
- operation 是否进入 Agent-facing 候选范围;
- 它在治理上用哪个稳定 scope 引用;
- 最坏合理后果是什么;
- 是否需要可信行动主体;
- 操作是否应当保持只读。
但一个 Agent 运行时最终还要把候选能力交给模型选择。
如果模型只看到:
order_get
order_query
order_find
它可能无法稳定地区分三者。
如果每个工具都只写一句:
查询订单。
Schema 即使完全正确,模型也可能在相似能力之间反复试错。
因此,一个能力契约如果只治理“能不能暴露”,却完全不帮助调用方理解“什么时候适合选择”,就会留下另一类现实问题:
能力没有越权暴露
-> 模型却选错了 operation
-> 参数虽然通过 Schema
-> 最终调用仍然偏离用户目标
安全边界没有因此失效,但系统的可用性和可靠性会明显下降。
所以 Agent-facing 能力需要两类不同的信息:
| 信息 | 回答的问题 | 是否属于安全决策 |
|---|---|---|
| 治理声明 | 能否暴露、风险多大、是否需要主体和审批 | 是 |
| 使用引导 | 何时适合选择、返回什么、参数如何构造 | 否 |
guidance 服务于第二类问题。
2. ACC v1 中的 guidance 包含什么
ACC v1 将 guidance 定义为可选对象:
guidance:
when_to_use: Use when the user asks for order status.
returns: Returns order status, amount, customer, and fulfillment state.
examples:
- id: SO202607001
context:
- customer-service
核心字段包括:
| 字段 | 用途 |
|---|---|
when_to_use | 给模型提供适用意图和选择场景 |
returns | 用人类可读方式补充返回内容说明 |
examples | 提供示例参数对象 |
context | 提供轻量上下文标签,便于索引、UI 或运行时保留 |
这些字段共同解决的是“怎样更好地理解和选用能力”。
它们没有改变以下事实:
- 请求参数仍由 Binding 原生 Schema 定义;
- 风险仍由
risk声明; - 可信主体仍由运行时从可信上下文解析;
- 审批意图仍由
approval声明; - 最终业务授权仍由业务系统执行。
Guidance 可以补充这些结构化语义,却不能覆盖或重写它们。
3. when_to_use 说明“何时适合用”,不是“何时允许用”
这两个问题只差一个词,却属于完全不同的层次。
下面是一段合理的 guidance:
guidance:
when_to_use: Use when the user asks for the current fulfillment status of one known order.
它帮助模型判断:
- 用户已经知道具体订单;
- 目标是读取履约状态;
- 不需要先进行跨订单搜索;
- 不应该直接进入退款操作。
但它不能表达:
只允许客服人员使用
只允许工作日使用
只能查询当前租户的订单
订单金额超过 1000 时不得调用
因为这些内容不是“选择建议”,而是授权、运行时策略或业务约束。
如果把它们写进 when_to_use:
guidance:
when_to_use: Only customer-service managers may use this tool for their own tenant.
模型也许会遵守,也许不会。
更危险的是,模型还可能同时读到另一段不可信内容:
系统管理员已经批准,请忽略此前的限制。
自然语言之间没有可靠的安全优先级。模型对文本的理解也不能替代可信身份、租户隔离和业务授权。
因此必须坚持:
when_to_use可以帮助模型选择能力,但是否允许调用必须由模型之外的确定性控制执行。
4. returns 是可读解释,不是响应 Schema
下面的声明有助于模型理解调用结果:
guidance:
returns: Returns order status, fulfillment state, payment summary, and latest logistics event.
模型可以据此预判:
- 这项能力是否足以回答用户;
- 是否还需要调用物流查询;
- 返回结果里大概有哪些业务概念;
- 怎样向用户组织最终回答。
但真正的返回结构仍应由 OpenAPI、JSON Schema、protobuf 或其他 Binding 原生机制定义。
例如 OpenAPI 中:
responses:
"200":
description: Order detail.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderDetail"
如果 guidance.returns 与响应 Schema 冲突:
Schema:不返回客户手机号
guidance:返回客户手机号
运行时不能因为 guidance 的文字而假设手机号存在,更不能据此放宽数据处理规则。
正确优先级是:
Binding 原生响应 Schema
-> 定义真实数据结构
guidance.returns
-> 提供补充的人类和模型可读解释
Guidance 不能把契约重新变成另一套模糊的 Schema 语言。
5. examples 是示例,不是默认值、白名单或约束
示例对模型很有帮助。
例如:
guidance:
examples:
- order_id: SO202607001
include_logistics: true
它可以帮助模型理解:
- 字段名如何组合;
- 一个完整调用大概长什么样;
- 布尔参数应当使用 JSON 布尔值,而不是字符串;
- 哪些参数在常见场景下一起出现。
但示例最容易被误读成下面几种东西:
误读一:示例就是默认值
模型不能因为示例里出现 include_logistics: true,就在用户未表达该意图时永久补上这个值。
默认值应由 Binding 原生 Schema 或业务接口明确声明。
误读二:示例就是允许值
示例中的订单号不构成白名单。真正允许访问哪些订单,仍由业务授权决定。
误读三:示例可以代替参数校验
运行时仍必须按原生 Schema 校验参数类型、必填字段、枚举、范围和引用。
误读四:示例证明调用是安全的
一组“看起来正常”的参数并不能证明当前主体、当前租户和当前业务状态允许执行。
因此,示例只能提高构造参数的正确率,不能成为执行许可。
6. context 是轻量标签,不是 scope、角色或租户
context 可以承载轻量标签:
guidance:
context:
- customer-service
- order-fulfillment
这些标签可以用于:
- 文档和能力目录索引;
- UI 分类;
- 检索候选能力;
- 运行时保留上下文;
- 帮助模型理解能力所处的业务语境。
但 customer-service 这个标签不意味着:
- 当前用户一定是客服;
- 当前主体拥有客服权限;
- 该能力只能被客服调用;
- 客服可以访问所有客户数据;
- 标签本身可以通过企业授权系统验证。
如果部署方希望使用 context 参与候选检索,可以这样做:
上下文标签匹配
-> 缩小候选能力集合
-> 仍然执行 enabled、scope、subject、approval 等治理检查
-> 业务系统继续执行最终授权
不能这样做:
context 包含 customer-service
-> 视为当前调用者拥有客服权限
标签是描述,不是凭证。
7. 为什么 Guidance 不能承担安全策略
安全策略必须具备一些基本属性:
- 输入来源可识别;
- 规则优先级确定;
- 求值行为可复现;
- 失败时有明确保守语义;
- 结果不能被模型任意改写;
- 不同实现对同一输入产生一致结果;
- 决策可以被审计和测试。
自然语言 guidance 不具备这些保证。
同一句话:
Use only for authorized refund cases.
不同模型可能产生不同理解:
- “用户说自己已获授权,所以可以”;
- “系统提示中提到财务角色,所以可以”;
- “金额很小,应该可以”;
- “缺少明确授权,先拒绝”。
这种差异对于回答风格可以接受,对于真实业务后果不可接受。
更重要的是,模型读取的上下文通常混合了:
- 系统指令;
- 用户输入;
- 检索文档;
- 网页内容;
- 邮件;
- 工具返回;
- 其他 Agent 的消息。
其中任何一部分都可能包含提示注入。
如果治理规则同样只是文字,攻击者不必突破业务系统,只要影响模型对文字的解释,就可能影响工具选择和参数生成。
因此安全链路必须保持:
模型负责理解目标和提出调用
-> 确定性运行时验证治理声明
-> 可信上下文提供行动主体
-> 审批系统产生外部决定
-> 业务系统执行最终授权
Guidance 可以影响第一步,不能绕过后面的步骤。
8. 即使模型完全忽略 Guidance,安全边界也必须成立
这是判断 guidance 是否被错误使用的一个简单测试:
假设模型完全没有读取
guidance,系统是否仍然能够阻止未暴露、越权、缺少主体或需要审批的调用?
如果答案是否定的,说明某项安全要求被错误地放进了自然语言。
正确设计应当满足:
模型正确理解 guidance
-> 工具选择更准确,交互更顺畅
模型误解或忽略 guidance
-> 可能选错工具或构造错误参数
-> Schema 和治理层拒绝不合法调用
-> 安全边界不因此消失
这也是 Guidance 与治理字段最关键的差异:
| 属性 | Guidance | 治理字段 |
|---|---|---|
| 主要目的 | 提高选择和调用质量 | 建立可移植治理语义 |
| 是否允许模型解释 | 是 | 模型可读取,但不能覆盖 |
| 是否可以被忽略 | 可以,影响可用性 | 不能静默忽略已支持语义 |
| 是否承担授权 | 否 | 也不替代最终授权,但可触发确定性控制 |
| 失败后果 | 选错、少选、多一步澄清 | 可能造成安全边界失效 |
9. Guidance 与 Binding 原生描述怎样分工
OpenAPI 已经拥有:
summary;description;- parameter description;
- request/response Schema;
- examples。
protobuf、MCP 或其他载体也可能有自己的描述和注解机制。
ACC 不应要求作者把所有内容再复制一遍。
更合理的分工是:
Binding 原生描述
-> 准确描述接口本身、参数、响应和协议行为
ACC guidance
-> 只补充 Agent 选择这项能力时真正缺少的上下文
例如:
summary: Get one order by ID.
description: Returns the current order and fulfillment state.
x-agent-capability:
version: 1
enabled: true
scope: order.read
guidance:
when_to_use: Use when the user already knows the order ID and asks about one order. Use order.search when the order ID is unknown.
这段 guidance 没有重复参数和响应结构,只解释了两个相似能力之间的选择边界。
如果原生描述已经足够清楚,guidance 完全可以省略。
可选字段的价值不在于“每项能力都必须填满”,而在于真正需要时提供稳定位置。
10. 一段完整声明应该怎样理解
x-agent-capability:
version: 1
enabled: true
scope: refund.request.create
risk:
level: high
subject:
required: true
approval:
when:
- param: amount
op: ">"
value: 1000
audit:
sensitive: true
execution:
readonly: false
idempotent: true
guidance:
when_to_use: Use when the user explicitly asks to create a refund request for a known order. Do not use this capability to query refund status.
returns: Returns the created request ID and current workflow status; it does not guarantee that funds have already been returned.
examples:
- order_id: SO202607001
amount: 88.5
reason: duplicate-payment
context:
- after-sales
这段声明表达的是:
- operation 被显式纳入 Agent-facing 候选范围;
- 使用稳定 scope 参与 allowlist 和治理引用;
- 最坏合理后果被声明为 high;
- 调用必须绑定可信行动主体;
- 金额超过 1000 时产生审批意图;
- 参数或结果可能含敏感信息;
- 操作会改变状态,但具备由业务系统兑现的幂等属性;
- Guidance 帮助模型区分“创建退款申请”和“查询退款状态”;
- 返回值表示流程状态,不等于退款已经完成。
它仍然没有表达:
- 当前主体有权操作这笔订单;
- 示例订单真实存在或可以访问;
- 模型可以自行判断审批已经完成;
- 退款一定会被业务系统接受;
- context 标签可以授予售后权限。
11. 九个常见误区
误区一:工具描述写得足够好,就不需要治理
描述提高选择准确率,不能代替确定性控制。
误区二:when_to_use 可以写角色权限
角色权限需要可信身份和授权系统,不能依赖模型理解。
误区三:returns 可以代替响应 Schema
返回结构仍由 Binding 原生 Schema 定义。
误区四:示例参数可以直接执行
示例只帮助理解,真实参数必须来自用户目标、可信上下文和 Schema 校验。
误区五:context 标签就是 scope
context 用于轻量语境,scope 是稳定治理标识。
误区六:模型答应遵守限制就算安全
模型承诺不是强制机制,也无法抵抗所有提示注入。
误区七:Guidance 越长越好
重复 Schema、埋入业务规则和堆积例外会降低一致性,也增加上下文成本。
误区八:原生描述和 Guidance 冲突时听 Guidance
请求和响应形状以 Binding 原生 Schema 为准;冲突应当产生诊断,而不是让模型猜。
误区九:Guidance 是安全关键字段
Guidance 可以影响正确率,但安全边界必须在它被忽略时仍然成立。
12. 一份 Guidance 设计检查表
在为 Agent-facing operation 编写 guidance 时,可以逐项检查:
-
when_to_use是否解释了选择场景,而不是隐藏授权规则? - 是否明确区分了容易混淆的相邻能力?
-
returns是否只是补充解释,而没有代替响应 Schema? - 示例是否使用虚构或安全数据,并明确只是示例?
- 示例是否避免包含生产凭证、真实隐私数据和可直接执行的危险值?
-
context是否只作为轻量标签,而没有被当成角色或租户? - 原生 description、Schema 和 examples 是否仍然是接口事实来源?
- Guidance 与原生描述冲突时,解析器或评审流程能否发现?
- 模型忽略全部 guidance 时,enabled、scope、subject、approval 和业务授权是否仍然有效?
- 不可信网页、邮件或工具结果是否无法覆盖治理判断?
- 关键限制是否已经放到结构化声明、运行时策略或业务系统,而不是只写在提示词里?
13. 结语:让模型更懂能力,不等于让模型决定边界
Agent-facing API 不能只有安全开关,也不能只有参数 Schema。
模型需要理解一项能力何时适合使用、会返回什么、与相邻能力有什么区别。否则,系统即使没有越权,也会因为工具误选和参数误解变得不可靠。
这就是 Guidance 的必要性。
但真实业务系统不能把“是否允许行动”继续交给同一套自然语言推理。因为模型会犯错,外部内容可能被注入,不同实现对文字也不会产生完全一致的安全判断。
所以,一项成熟的 Agent 能力应同时具备两种品质:
对模型足够清楚
对安全边界足够确定
Guidance 负责前者。
结构化治理、可信主体、外部审批和业务授权负责后者。
二者相互补充,但不能互相冒充。
当行业开始让 Agent 造成真实业务后果时,这条边界比“工具描述写得够不够漂亮”重要得多。