qinghuan
← 调用工具并检查权限 / 全部笔记

单元 18 / 调用工具并检查权限

P0 · 必会主线L2 · 进阶

把工具定义做成可测试的接口契约

把工具参数、返回值和错误说清楚,再分别测试工具本身,以及模型会不会正确使用它。

本篇目录 · 按需要跳转

读完这篇,你能做什么

能分开测工具本身和模型选择行为,准确定位工具名称、参数或执行链路的错误。

学习理由、准备要求与知识点

为什么学它

工具描述和参数 Schema 是模型与后端之间的接口,需要像普通 API 一样直接测试。

先读这些内容

知识点清单

  • 工具名称与能力边界
  • 输入来源与必填参数
  • JSON Schema 输入范围
  • 稳定输出 DTO
  • 未找到与执行失败
  • 协议错误与业务错误
  • 直接工具契约测试
  • 模型选择工具测试

运行前先确认完整算法使用 Java 17 标准库;JDK 源码基线为 OpenJDK 17 GA。示例是内存中的机制模型,外部服务接入需要另外配置和验证。

01先弄懂它是什么

模型看见的工具说明,要和后端实际做的事一致。这份约定包括名称、描述、输入 Schema、返回 DTO 和错误含义。例如 findNote 接收 noteId,找不到笔记应有明确状态;如果它和数据库故障都只返回 null,模型和调用方就分不清该换个查询,还是停止并排查故障。

测试时可以分两步:先直接给工具各种合法、非法参数,检查实现是否按约定返回;再用固定模型响应或真实模型,检查它会不会选对工具、填对参数。工具本身通过测试,不代表模型一定用对;模型恰好成功调用一次,也不代表工具能正确处理所有边界输入。

反射和注解可以生成部分元数据,但Java类型并不包含全部业务限制。String可能是任意文本,也可能必须是授权笔记ID;int可能只允许一到五。必填、范围、资源归属和输出上限需要在Schema与服务校验中明确,不能只看方法签名。

文中这几个词,先认一认

输入Schema
说明工具参数有哪些字段、类型和限制的结构规则。它不能代替对真实调用身份的验证。
结果关联
根据调用 ID 把结果找回原请求。异步返回顺序可能改变,不能只按数组位置配对。
契约测试
给接口明确的输入,并对照预期检查返回和行为,尤其要包含失败与边界情况。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

先给每个工具确定稳定名称和单一能力,再定义输入及输出。返回状态至少区分正常找到、正常未找到和执行错误;协议层不能解析请求与业务层查无记录也是不同原因。错误消息应让模型知道是否可以换输入,而不暴露内部堆栈或连接信息。

异步批次结果可能乱序,本题只检查请求ID与结果ID集合的一致性。输入请求A、B,结果B、A是合法的;结果A、A说明重复并缺少B;结果C说明未知关联。结果正文是否满足DTO要另测,ID匹配不能证明内容就是正确业务结果。

先拒绝请求列表中重复ID,因为它使后续关联本身不明确。结果侧收集未知、重复和缺失诊断,再排序输出,便于测试稳定性。这个校验适合用在模拟工具轨迹和协议适配层,不能把结果按到达顺序简单zip到请求列表。

正在加载流程图…

图中状态只描述本篇可执行机制;业务调用仍需由外层应用负责。
查看流程图源码(Mermaid)
flowchart LR
  M["方法与业务规则"] --> S["输入 Schema 和输出 DTO"]
  S --> T["直接工具测试"]
  T --> C["模拟模型调用"]
  C --> R["结果 ID 关联审计"]
  R --> E["模型选择与真实集成评估"]

按顺序看,每一步做了什么

  1. 明确工具能力、名称与输入来源,定义稳定DTO。
  2. 检查反射生成元数据并补充业务范围及错误语义。
  3. 直接测试正常、未找到、非法参数和执行失败。
  4. 用调用ID核对批次结果的完整性与唯一性。
  5. 分别评价模型选工具和工具实现,保留失败轨迹。

03对照实现代码

OpenJDK 17 Method 源码 (新标签页)↗

OpenJDK 17 GA,jdk-17+35 · Method.getParameterTypes / getReturnType

下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。

核心机制代码 · java
Method method = NoteTools.class.getDeclaredMethod("findNote", String.class);
Class<?>[] parameters = method.getParameterTypes(); // 反射提供声明类型,不包含资源权限。
Class<?> resultType = method.getReturnType(); // 返回类不自动说明未找到与失败状态。
// 应用仍要定义字段范围、Schema及直接工具契约测试。

Method.getParameterTypes暴露声明的参数类型,getReturnType暴露声明返回类型。它们可帮助框架构造工具元数据,但不执行该方法的业务逻辑。

泛型、注解与参数名称需要其他反射信息及构建配置配合,不能从一个String.class推断出完整JSON Schema。业务语义仍需要明确描述和验证。

反射调用成功也只是Java方法运行成功,方法可能返回错误DTO或错误资源。本篇将结构元数据、实现契约和模型路由分成独立验收步骤。

完整算法不调用反射,而是验证协议关联ID集合。它是工具适配层的确定性检查,和实际方法签名检查共同减少“类型正确但结果串线”的问题。

代码先调用谁,再调用谁

  1. 定位工具方法
  2. 读取参数与返回类型元数据
  3. 补充输入Schema和输出语义
  4. 直接执行契约样例
  5. 按调用ID核对整条轨迹

04动手写一个例子

工具请求与结果关联审计

输入唯一请求ID列表和任意结果ID列表,输出排序后的missing、unknown、duplicate诊断;结果顺序可不同。重复请求ID拒绝。Java17 Main.java运行固定自测。

输入 1
请求A/B,结果B/A
输出 1
无错误
输入 2
请求A/B,结果A/A/C
输出 2
duplicate:A、missing:B、unknown:C

先把请求ID放入集合并拒绝重复,使每个合法结果最多对应一个请求。没有这个前置,所谓“一对一结果”就没有清晰定义。

扫描结果时分别检查是否在请求集合,以及是否已经见过该结果ID。未知和重复是独立问题,同一个未知ID重复出现可以同时报告两类诊断。

结果扫描结束后,遍历请求集合找未出现者。只有确认批次结束或截止时间到达才报告缺失,过程中尚未返回的请求应保持等待状态,而不是提前认定永久失败。

为什么这样写是对的seen精确包含已到达结果ID;unknown标识不属于请求集合的ID,duplicate标识出现超过一次的ID;批次结束后请求集合与seen之差就是缺失集合。

时间 平均O(n+m+e log e)额外空间 O(n+m+e)

n为请求数,m为结果数,e为不同诊断数;集合检查平均线性,TreeSet排序诊断O(e log e)。不包含结果正文解析成本。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

Main.java · 完整可运行程序 · Java
import java.util.*;
public class Main {
    static List<String> audit(List<String> requested,List<String> results){
        Set<String> expected=new HashSet<>();
        for(String id:requested)if(id==null||!expected.add(id))throw new IllegalArgumentException("request id"); // 请求身份必须唯一。
        Set<String> seen=new HashSet<>();Set<String> errors=new TreeSet<>();
        for(String id:results){
            if(id==null)throw new IllegalArgumentException("result id");
            if(!expected.contains(id))errors.add("unknown:"+id);
            if(!seen.add(id))errors.add("duplicate:"+id); // 到达次序不用于关联。
        }
        for(String id:expected)if(!seen.contains(id))errors.add("missing:"+id); // 仅在批次已结束时执行。
        return new ArrayList<>(errors);
    }
    static void eq(List<String> e,List<String> a){if(!e.equals(a))throw new AssertionError(a);}
    public static void main(String[] args){
        eq(List.of(),audit(List.of("A","B"),List.of("B","A")));
        eq(List.of("duplicate:A","missing:B","unknown:C"),audit(List.of("A","B"),List.of("A","A","C")));
        eq(List.of(),audit(List.of(),List.of()));
        eq(List.of("missing:A"),audit(List.of("A"),List.of()));
        eq(List.of("unknown:X"),audit(List.of(),List.of("X")));
        try{audit(List.of("A","A"),List.of("A"));throw new AssertionError();}catch(IllegalArgumentException expected){}
        System.out.println("PASS 6 tests");
    }
}

这些特殊情况也要试一试

  • 结果乱序正常,不能按位置配对。
  • 批次未结束时未到达不等于永久缺失。
  • ID一致仍需验证结果内容与业务资源身份。
进阶选读 · 后续再读:协议版本与兼容性测试矩阵

场景工具输入或输出DTO升级,旧客户端和已暂停任务仍可能恢复。

做法建立版本化Schema与历史轨迹回放,测试新增可选字段、枚举扩展、错误类型及旧状态迁移;把兼容性政策写成可执行断言。

复杂度对v个版本组合与t类用例,朴素矩阵O(v²t)次验证,可按明确支持范围缩减;覆盖样本不等于证明所有输入兼容。

好处与代价全面矩阵成本高,但只测最新客户端会漏掉恢复路径;应优先覆盖长期运行任务实际保留的版本。

05项目里怎么用

工具描述要让模型知道何时使用与何时不使用,参数名与类型保持稳定。返回DTO避免直接暴露持久实体,尤其用户标识、内部备注和权限字段。Schema约束和服务校验应从同一业务规则出发,避免文档说最多五条而实现允许任意数量。

测试时可以让替身工具按脚本返回乱序、缺失、重复或错误结果,检查接入代码会不会把 A 请求的资料错交给 B。真实模型测试主要检查它是否选对工具、填好参数;模拟数据库故障则检查工具怎样区分并返回错误。这些测试各证明不同的部分,应分别报告,不能用一个总通过率代替全部检查。

工具失败反馈要稳定可处理。未找到可以提示补充ID,权限拒绝不能建议换一个用户ID重试,基础设施异常应由应用决定有限恢复。模型不是错误策略的唯一裁决者,尤其涉及身份和写操作时。

容易踩的坑

  • 用数组位置关联异步工具请求与结果。
  • 把Java参数类型当成全部业务Schema。
  • 未找到与执行异常都返回null。
  • 只测试模型选对一次工具,不测工具边界。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
反射生成元数据减少重复声明业务约束仍需补充规范方法签名的工具集合
显式Schema范围和版本清晰需与实现保持一致对外或长期兼容工具
轨迹契约测试可检查乱序和关联错误不代表真实模型选择质量异步适配层与恢复流程

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01直接工具测试与模型测试验证什么?

展开参考答案与推导

前者验证给定参数下实现行为,后者验证模型是否选择适合的工具和参数;两者不能互相替代。

02未找到是不是工具故障?

展开参考答案与推导

通常是合法业务结果,应与参数错误、权限拒绝和基础设施故障区分,便于选择下一步。

03反射能自动推断资源归属吗?

展开参考答案与推导

不能。方法类型不包含调用者与资源权限关系,必须在服务层基于可信身份检查。

换个情况,还会处理吗

01并行工具结果倒序返回,如何防串线?

展开参考答案与推导

用调用ID建立映射并验证唯一性和完整性,不按结果数组位置绑定请求。

02输出新增字段导致旧任务恢复失败怎么办?

展开参考答案与推导

核对Schema版本和迁移政策,用历史轨迹回放定位;新版本发布应覆盖仍可能恢复的旧状态。

03权限拒绝后模型不断改ID,如何处理?

展开参考答案与推导

把拒绝作为受控终止或用户补充入口,应用禁止通过改身份绕过,不把它当普通可修复参数错误。

写代码试一试

01乱序结果是否报错?

输入 / 条件
请求A,B;结果B,A
输出 / 预期
无错误

提示 关联依据是ID。

展开参考答案与推导

集合一致且各出现一次即通过关联检查;正文仍需按各自ID读取对应业务结果。

02未知ID重复怎样报告?

输入 / 条件
请求空;结果X,X
输出 / 预期
duplicate:X和unknown:X

提示 两项规则独立。

展开参考答案与推导

X不属于请求集合,且出现两次;错误集合去重同类诊断但不合并不同原因。

03何时产生missing?

输入 / 条件
请求A尚在运行
输出 / 预期
保持等待,批次终止后才审计

提示 时间边界属于契约。

展开参考答案与推导

本函数输入假定结果集合已封闭;流式过程中应维护pending状态,截止或结束时再输出缺失诊断。

读完之后,独立完成

课后作业:自己做一遍

本篇共 12 道作业,先完成 9 道基础与综合任务,再按前置知识挑战进阶题。其中包含 2 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能分开测工具本身和模型选择行为,准确定位工具名称、参数或执行链路的错误。

本篇重点加练

工具结果分类和模型选择是两种不同能力,重点检验链路成功是否掩盖语义失败。

  • 未找到与执行失败
  • 模型选择工具测试

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    为查笔记与改计划分别写工具能力说明,标出参数来自用户、应用上下文还是模型提议,并识别不能由模型决定的值。

    提交内容
    一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
    怎样算完成
    • 逐项回应题目要求,区分事实、假设与个人判断。
    • 能用自己的例子解释适用条件,记录尚未弄懂的点。

    练到的知识点工具名称与能力边界 · 输入来源与必填参数

  2. 作业 02代码推演

    设计输入Schema与稳定输出DTO,给出缺字段、null、超长输入和额外字段四种请求,逐项推演验证与序列化过程。

    提交内容
    手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
    怎样算完成
    • 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
    • 主动检查至少一个边界或异常条件,能解释手算与运行差异。

    练到的知识点JSON Schema 输入范围 · 稳定输出 DTO

  3. 作业 03原理问答

    为两项名称相近的工具定义可区分的选择条件与未找到合同,说明客户端怎样区分“选错工具”与“正确工具确无数据”。

    提交内容
    概念或合同说明、关系图与自造案例,明确事实、假设和适用条件。
    怎样算完成
    • 关键概念有明确边界,能用案例检验声明。
    • 未获证据支持的假设单独标注。

    练到的知识点未找到与执行失败 · 模型选择工具测试

综合应用

  1. 作业 04面试场景

    同一工具可能返回未找到、业务拒绝、协议消息非法和执行异常。设计错误分类与调用方处理矩阵,避免仅按是否抛异常判断成功。

    提交内容
    场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
    怎样算完成
    • 方案回应给定约束,列出至少一种替代方案及代价。
    • 每项关键结论说明所需证据,不能核实的部分明确标注。

    练到的知识点未找到与执行失败 · 协议错误与业务错误

  2. 作业 05编程实践

    先写工具直接调用测试,再接假模型工具选择测试,加入“选错工具但参数合法”与“工具正确但参数错”的案例,分开报告。

    提交内容
    可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
    怎样算完成
    • 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
    • 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。

    练到的知识点直接工具契约测试 · 模型选择工具测试

  3. 作业 06排错实验

    将工具描述改成有歧义的版本,使用固定请求对照选择记录;检查输出字段升级是否破坏已有调用方。

    提交内容
    最小故障输入、复现步骤、观测记录、定位依据及回归用例。
    怎样算完成
    • 其他人可按记录复现故障,并区分现象与已验证原因。
    • 定位过程有观测依据,回归用例可以再次暴露原问题。

    练到的知识点工具名称与能力边界 · JSON Schema 输入范围 · 稳定输出 DTO

  4. 作业 07编程实践

    实现双工具假调用链,输入含模糊查询与明确查询,工具返回固定数据或未找到;分别验证选择判定与结果解释,不将空列表自动归为成功。

    提交内容
    可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
    怎样算完成
    • 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
    • 验证目标由合同确定,模拟结果不冒充真实服务证据。

    练到的知识点未找到与执行失败 · 模型选择工具测试

  5. 作业 08排错实验

    模型在工具返回未找到后反复选择同一工具,或者换用不相干工具得到非空结果。用消息序列回放检查何时应该停止与如何记录错误归因。

    提交内容
    最小故障序列、观测记录、原因核对与可再次触发原问题的测试。
    怎样算完成
    • 故障可以稳定重现,现象与已验证原因分开。
    • 观测记录足以判断声明的合同是否被违反。

    练到的知识点未找到与执行失败 · 模型选择工具测试

  6. 作业 09面试场景

    工具升级将一类业务拒绝改成“未找到”以减少信息泄露。评审这对模型选工具、用户反馈与评测标签的影响,声明新增验证条件。

    提交内容
    场景评审记录,包含约束、备选方案、未决信息和验证计划。
    怎样算完成
    • 方案回应题目约束,取舍能对应到可核验的事实。
    • 给出失败或条件变化时的检查方式。

    练到的知识点未找到与执行失败 · 模型选择工具测试

进阶挑战 · 掌握前置后选做

  1. 作业 10设计评审

    给第三方工具适配器设计契约测试包,覆盖升级、停用、错误格式与未知字段,注明哪些测试无法证明模型长期选对工具。

    提交内容
    设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
    怎样算完成
    • 比较使用一致条件与事先声明的标准,记录失败与未知结果。
    • 说明方案的适用前提、未覆盖风险及后续验证方法。

    练到的知识点输入来源与必填参数 · 未找到与执行失败 · 直接工具契约测试

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 11思维拓展 · 反例构造

    构造“工具契约测试全部通过且返回非空,模型就完成了正确任务”的最小反例,保留选择过程与结果对应关系。

    提交内容
    具体反例、原主张的适用前提、复现或逻辑证明及结论边界。
    怎样算完成
    • 反例满足原主张所声称的前提,确实针对其结论。
    • 说明一个反例能推翻什么、不能进一步证明什么。

    练到的知识点未找到与执行失败 · 模型选择工具测试

  2. 作业 12思维拓展 · 条件变化

    当工具数从两个扩展到二十个但单工具接口不变时,重新设计选择评测与未找到处理协议,说明原测试集可能遗漏的失败模式。

    提交内容
    变更前后条件表、重新评审的方案、检验用例与新增代价。
    怎样算完成
    • 只改变明确列出的条件,比较口径保持一致。
    • 修改方案说明收益、代价与仍未验证的范围。

    练到的知识点未找到与执行失败 · 模型选择工具测试

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

打开资料库,找下一份学习材料 ↗