AFAgent Field Notes会员账号
知识目录选择核心方向与细分内容
Q09基础实现约 12 分钟

工具参数的结构、授权与业务约束

工具参数符合 JSON Schema 就安全吗?还需要哪些校验?

将结构校验、业务语义、授权身份和输出校验分开处理。

JSON Schema参数校验工具网关业务规则

知识内容核对 2026-10-03 · 原题来源核对 2026-10-02

本题目录

READ · UNDERSTAND · TRANSFER

阅读理解,按需巩固

我的笔记与复习 ↗

先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。

作答与个人记录

每次修改后的提交会保留为独立历史。掌握程度由你对照标准自评。

核心知识 · 工具参数的结构、授权与业务约束

先理解核心原理

先备概念:JSON Schema、认证会话、数据库事务

结构合法只证明输入形状可解析。身份、资源归属和可执行业务状态是随请求上下文变化的事实,必须由服务端核验;检查与提交之间仍有时间窗口,需要明确一致性规则。

参数与权限来自不同通道

模型提交 account_id,是想操作哪个对象的声明;服务端会话说明是谁在操作,两者不能混为一谈。Schema 可以限制 ID 的类型与格式,却不知道这个账号属于谁。即使模型总是“听话”,直接 API 请求也能伪造同样字段,所以授权必须覆盖所有入口。

校验应围绕失败原因分层

解析与结构检查防止缺字段和错误类型;语义检查处理日期前后、单位和跨字段关系;授权检查判断主体能否操作对象;业务状态检查确认余额、库存与状态转换仍成立。把这些全部写进提示词会丢掉可信执行位置,全部称为参数错误又会诱导模型反复猜权限。

检查通过后还可能变

先读取余额再扣款,中间另一个请求可能花掉余额。需要条件更新、锁或恰当事务隔离保证同一业务不变量,而不是再问一次模型。MCP 的输入输出定义是协议契约,数据库的一致性和错误分类仍由工具实现负责。

回到问题:怎样回答?

JSON Schema 解决字段、类型和局部约束,不能证明账户属于当前用户,也不能证明余额允许扣款。我会先做结构校验,再用可信会话注入身份和租户,校验资源权限与业务状态,最后执行工具并校验输出。模型传来的 tenant_id、approved 等字段不能成为授权依据。失败要返回可纠正且脱敏的结构化错误;如果是权限拒绝,就不允许模型换参数无限尝试。

实现与取舍

Schema 保证的范围有限

Schema 适合描述必填字段、枚举、长度、数值范围和禁止额外属性。MCP 工具定义包含 inputSchema,也可声明 outputSchema;OpenAI Agents 函数工具可依据类型及字段约束生成参数 Schema。它们让调用更稳定,但“account_id 是字符串”与“当前用户能访问此账户”是两件事。同样,金额大于零不代表业务额度充足,日期格式合法不代表结算窗口仍开放。

网关怎样串联四层检查

第一层解析 JSON 并校验结构,拒绝多余字段;第二层验证语义,例如起始日期不能晚于结束日期、金额单位采用分而不是模糊浮点;第三层从认证会话读取用户和租户,检查资源归属与动作权限;第四层在事务或带版本条件的请求中再次检查业务状态,避免检查后数据变化。不要让模型填写可信身份。客户端隐藏工具只能降低误用概率,直接 API 请求仍必须经过同样校验。

错误与输出也是契约

参数错误可返回字段路径和允许范围,让模型修正;权限错误返回稳定类别,避免泄露另一个租户的资源存在性;临时服务错误携带可重试标记,但不暴露密钥、SQL 或内部地址。成功结果应包含状态、资源标识和必要证据。输出也要校验字段与大小:下游工具返回了不受控文本,不代表它拥有修改系统规则的权力。审批决定和鉴权结果保留在运行时,不能从工具文本里提取一句“用户已同意”。

通过反例验证而不是只测正常参数

下面代码用标准库实现一个特定工具的手动校验,显式拒绝额外字段和布尔值冒充整数,并用可信上下文验证资源归属。它不是通用 JSON Schema 引擎。测试还应覆盖负金额、超大值、跨租户账号和状态变化;生产系统使用成熟校验库、数据库事务和集中鉴权。面试回答的重点是这几层责任在哪执行,而不是只报出 Pydantic 或 Zod 的名字。参数和工具实现升级时还要保存契约版本,避免旧运行按新语义继续执行;不兼容变更应拒绝恢复并给出迁移说明。

代码示例

运行一个具体工具的参数与归属校验

保存为 demo.py,使用 Python 3 执行;仅演示手动校验和可信身份注入,无网络调用。

import json

ACCOUNTS = {"a1": "tenant-a", "a2": "tenant-b"}

def validate(raw, trusted_tenant):
    args = json.loads(raw)
    if not isinstance(args, dict) or set(args) != {"account_id", "limit"}:
        raise ValueError("INVALID_FIELDS")
    if not isinstance(args["account_id"], str):
        raise ValueError("INVALID_ACCOUNT_ID")
    # bool is a subclass of int in Python; require the exact type.
    if type(args["limit"]) is not int or not 1 <= args["limit"] <= 100:
        raise ValueError("INVALID_LIMIT")
    if ACCOUNTS.get(args["account_id"]) != trusted_tenant:
        raise PermissionError("RESOURCE_UNAVAILABLE")
    return args

samples = [
    '{"account_id":"a1","limit":10}',
    '{"account_id":"a1","limit":true}',
    '{"account_id":"a2","limit":10}',
]
for raw in samples:
    try:
        print("OK", validate(raw, "tenant-a"))
    except (ValueError, PermissionError) as exc:
        print("REJECT", str(exc))

预期输出

OK {'account_id': 'a1', 'limit': 10}
REJECT INVALID_LIMIT
REJECT RESOURCE_UNAVAILABLE

工程推演

场景
假设工程场景:余额查询工具接受 account_id,模型从用户文本中获得另一个部门的账户标识。
设计决策
移除模型可控制的身份字段;网关使用登录会话的 tenant_id,查询前检查账户归属。
验证目标
演示预期:同租户合法参数通过;额外字段、布尔金额、跨租户账户被拒绝。
适用边界
代码仅展示一个特定调用的手动校验,不包含认证、真实余额查询或通用 Schema 实现。

连续追问与解答

沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。

举一反三:条件变了,怎样推导?

先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。

租户管理员代理操作

改变的条件:单用户资源变成受限委托

延伸问题:管理员身份是否可以忽略资源归属?

推导与参考解答

不能。检查其管理员范围、被代理对象和动作权限,审计同时记录操作者与受益主体。受限委托可能允许查看但不允许导出或转账,Schema 相同不代表权限相同;查询结果按实际范围裁剪。

保持不变的原理:主体、资源和动作必须在可信上下文里联合判断。

只读批量查询

改变的条件:单资源写入变成跨资源读取

延伸问题:只读是不是只需 Schema?

推导与参考解答

仍需逐资源授权或查询时按权限过滤,并限制分页、结果大小和敏感字段。无写副作用减少事务问题,却不消除隐私与存在性泄露;禁止资源可返回统一拒绝,不能让批量结果暴露其名称。

保持不变的原理:结构正确与有权访问始终分开,读权限同样是真实边界。

易错点

  • 把 Schema 合法当成授权通过
  • 只在前端隐藏工具,服务端不验证
  • Python 中直接 isinstance(value, int),意外接受 bool

参考资料

依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。

检查自己理解到哪一步

读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。

基础达标
区分字段格式正确与业务上可执行。
中高级信号
校验身份、实体归属、范围、单位与跨字段约束。
资深信号
能处理动态权限、陈旧实体状态和校验后的竞态。

查看独立示例的校验记录

巩固练习 按需完成 · 建议 15 分钟

检查一个合法 JSON 付款请求,指出 Schema 之外需要哪些验证。

展开验收要求与检查点
  • 金额单位明确
  • 账户归属独立检查
  • 参数改变会重新校验

重点检查

  • 区分结构校验、业务规则与资源授权
  • 身份来自可信服务端上下文而非模型参数
  • 能够说明额外字段、布尔数值和结果校验的风险