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 实现。
连续追问与解答
沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 1 层服务端为什么不能信任模型传来的 tenant_id?
从结构校验延伸到数据来源可信度,避免身份字段越界。
参考解答
tenant_id 是模型可控输入,不能证明当前身份。服务端从验证后的会话或委托令牌读取可访问租户,查询与写入同时带该范围;若用户合法切换租户,先检查成员资格再选择可信上下文。可以让模型表达目标租户意图,但最终授权不能来自它填的值。
第 1 层Schema 合法但余额不足,该如何返回错误?
合法形状仍可能违背业务条件,错误类型决定下一步行为。
参考解答
返回业务错误,如类别为 insufficient_funds、可重试为 false,并给当前用户允许知晓的金额或修正提示。不要当网络故障自动重试,也不要让模型擅自减少金额继续执行。若用户修改动作,重新做授权、批准与余额检查;错误不能泄露其他账号的余额。
第 1 层校验通过后权限撤销了,怎样避免时间差问题?
一次授权快照不能永久批准未来操作。
参考解答
敏感动作在实际提交处重验授权,并设计权限撤销的生效边界。若权限与写入在同一数据库,可在事务中锁定或比较权限版本;若跨服务,用版本条件、短期凭据和执行端校验降低窗口,但不能宣称存在跨系统原子保证。已提交动作如何处理需业务规则明确。
沿着这个回答继续深入
第 2 层授权存在独立服务,提交前再查一次就没有竞态了吗?
重验减少窗口但不消除跨服务时间差,需要说清一致性目标。
参考解答
没有。查询返回与远端写入之间仍可能撤权。明确是按请求开始时授权、提交时授权还是需要强同步撤销;高影响动作可用执行端可验证的短期授权或集中提交入口。若必须即时撤销,就需要协调机制与其可用性代价,不能只多查一次。
沿着这个回答继续深入
第 3 层用户取消权限时动作已经提交,应该回滚吗?
一致性规则遇到已发生副作用,必须与撤销和补偿语义连接。
参考解答
先确认提交事实,按撤销策略决定是否发起补偿。一般权限撤销阻止之后的动作,不自动抹掉合法提交;若业务要求追回,补偿也需独立权限、回执和失败状态。日志保留采用的授权版本及提交时间,避免事后把成功改成从未执行。
举一反三:条件变了,怎样推导?
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
租户管理员代理操作
改变的条件:单用户资源变成受限委托
延伸问题:管理员身份是否可以忽略资源归属?
推导与参考解答
不能。检查其管理员范围、被代理对象和动作权限,审计同时记录操作者与受益主体。受限委托可能允许查看但不允许导出或转账,Schema 相同不代表权限相同;查询结果按实际范围裁剪。
保持不变的原理:主体、资源和动作必须在可信上下文里联合判断。
只读批量查询
改变的条件:单资源写入变成跨资源读取
延伸问题:只读是不是只需 Schema?
推导与参考解答
仍需逐资源授权或查询时按权限过滤,并限制分页、结果大小和敏感字段。无写副作用减少事务问题,却不消除隐私与存在性泄露;禁止资源可返回统一拒绝,不能让批量结果暴露其名称。
保持不变的原理:结构正确与有权访问始终分开,读权限同样是真实边界。
易错点
- 把 Schema 合法当成授权通过
- 只在前端隐藏工具,服务端不验证
- Python 中直接 isinstance(value, int),意外接受 bool
参考资料
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
检查自己理解到哪一步
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
- 基础达标
- 区分字段格式正确与业务上可执行。
- 中高级信号
- 校验身份、实体归属、范围、单位与跨字段约束。
- 资深信号
- 能处理动态权限、陈旧实体状态和校验后的竞态。
巩固练习 按需完成 · 建议 15 分钟
检查一个合法 JSON 付款请求,指出 Schema 之外需要哪些验证。
展开验收要求与检查点
- 金额单位明确
- 账户归属独立检查
- 参数改变会重新校验
重点检查
- 区分结构校验、业务规则与资源授权
- 身份来自可信服务端上下文而非模型参数
- 能够说明额外字段、布尔数值和结果校验的风险