读完这篇,你能做什么
能分开测工具本身和模型选择行为,准确定位工具名称、参数或执行链路的错误。
学习理由、准备要求与知识点
为什么学它
工具描述和参数 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["模型选择与真实集成评估"]按顺序看,每一步做了什么
- 明确工具能力、名称与输入来源,定义稳定DTO。
- 检查反射生成元数据并补充业务范围及错误语义。
- 直接测试正常、未找到、非法参数和执行失败。
- 用调用ID核对批次结果的完整性与唯一性。
- 分别评价模型选工具和工具实现,保留失败轨迹。
03对照实现代码
OpenJDK 17 GA,jdk-17+35 · Method.getParameterTypes / getReturnType
下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。
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集合。它是工具适配层的确定性检查,和实际方法签名检查共同减少“类型正确但结果串线”的问题。
代码先调用谁,再调用谁
- 定位工具方法
- 读取参数与返回类型元数据
- 补充输入Schema和输出语义
- 直接执行契约样例
- 按调用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之差就是缺失集合。
n为请求数,m为结果数,e为不同诊断数;集合检查平均线性,TreeSet排序诊断O(e log e)。不包含结果正文解析成本。
保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。
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 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。
能分开测工具本身和模型选择行为,准确定位工具名称、参数或执行链路的错误。
本篇重点加练
工具结果分类和模型选择是两种不同能力,重点检验链路成功是否掩盖语义失败。
- 未找到与执行失败
- 模型选择工具测试
重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。
先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。
基础必做
- 作业 01原理问答
为查笔记与改计划分别写工具能力说明,标出参数来自用户、应用上下文还是模型提议,并识别不能由模型决定的值。
- 提交内容
- 一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
- 怎样算完成
- 逐项回应题目要求,区分事实、假设与个人判断。
- 能用自己的例子解释适用条件,记录尚未弄懂的点。
练到的知识点工具名称与能力边界 · 输入来源与必填参数
- 作业 02代码推演
设计输入Schema与稳定输出DTO,给出缺字段、
null、超长输入和额外字段四种请求,逐项推演验证与序列化过程。- 提交内容
- 手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
- 怎样算完成
- 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
- 主动检查至少一个边界或异常条件,能解释手算与运行差异。
练到的知识点JSON Schema 输入范围 · 稳定输出 DTO
- 作业 03原理问答
为两项名称相近的工具定义可区分的选择条件与未找到合同,说明客户端怎样区分“选错工具”与“正确工具确无数据”。
- 提交内容
- 概念或合同说明、关系图与自造案例,明确事实、假设和适用条件。
- 怎样算完成
- 关键概念有明确边界,能用案例检验声明。
- 未获证据支持的假设单独标注。
练到的知识点未找到与执行失败 · 模型选择工具测试
综合应用
- 作业 04面试场景
同一工具可能返回未找到、业务拒绝、协议消息非法和执行异常。设计错误分类与调用方处理矩阵,避免仅按是否抛异常判断成功。
- 提交内容
- 场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
- 怎样算完成
- 方案回应给定约束,列出至少一种替代方案及代价。
- 每项关键结论说明所需证据,不能核实的部分明确标注。
练到的知识点未找到与执行失败 · 协议错误与业务错误
- 作业 05编程实践
先写工具直接调用测试,再接假模型工具选择测试,加入“选错工具但参数合法”与“工具正确但参数错”的案例,分开报告。
- 提交内容
- 可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
- 怎样算完成
- 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
- 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。
练到的知识点直接工具契约测试 · 模型选择工具测试
- 作业 06排错实验
将工具描述改成有歧义的版本,使用固定请求对照选择记录;检查输出字段升级是否破坏已有调用方。
- 提交内容
- 最小故障输入、复现步骤、观测记录、定位依据及回归用例。
- 怎样算完成
- 其他人可按记录复现故障,并区分现象与已验证原因。
- 定位过程有观测依据,回归用例可以再次暴露原问题。
练到的知识点工具名称与能力边界 · JSON Schema 输入范围 · 稳定输出 DTO
- 作业 07编程实践
实现双工具假调用链,输入含模糊查询与明确查询,工具返回固定数据或未找到;分别验证选择判定与结果解释,不将空列表自动归为成功。
- 提交内容
- 可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
- 怎样算完成
- 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
- 验证目标由合同确定,模拟结果不冒充真实服务证据。
练到的知识点未找到与执行失败 · 模型选择工具测试
- 作业 08排错实验
模型在工具返回未找到后反复选择同一工具,或者换用不相干工具得到非空结果。用消息序列回放检查何时应该停止与如何记录错误归因。
- 提交内容
- 最小故障序列、观测记录、原因核对与可再次触发原问题的测试。
- 怎样算完成
- 故障可以稳定重现,现象与已验证原因分开。
- 观测记录足以判断声明的合同是否被违反。
练到的知识点未找到与执行失败 · 模型选择工具测试
- 作业 09面试场景
工具升级将一类业务拒绝改成“未找到”以减少信息泄露。评审这对模型选工具、用户反馈与评测标签的影响,声明新增验证条件。
- 提交内容
- 场景评审记录,包含约束、备选方案、未决信息和验证计划。
- 怎样算完成
- 方案回应题目约束,取舍能对应到可核验的事实。
- 给出失败或条件变化时的检查方式。
练到的知识点未找到与执行失败 · 模型选择工具测试
进阶挑战 · 掌握前置后选做
- 作业 10设计评审
给第三方工具适配器设计契约测试包,覆盖升级、停用、错误格式与未知字段,注明哪些测试无法证明模型长期选对工具。
- 提交内容
- 设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
- 怎样算完成
- 比较使用一致条件与事先声明的标准,记录失败与未知结果。
- 说明方案的适用前提、未覆盖风险及后续验证方法。
练到的知识点输入来源与必填参数 · 未找到与执行失败 · 直接工具契约测试
思维拓展
先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。
- 作业 11思维拓展 · 反例构造
构造“工具契约测试全部通过且返回非空,模型就完成了正确任务”的最小反例,保留选择过程与结果对应关系。
- 提交内容
- 具体反例、原主张的适用前提、复现或逻辑证明及结论边界。
- 怎样算完成
- 反例满足原主张所声称的前提,确实针对其结论。
- 说明一个反例能推翻什么、不能进一步证明什么。
练到的知识点未找到与执行失败 · 模型选择工具测试
- 作业 12思维拓展 · 条件变化
当工具数从两个扩展到二十个但单工具接口不变时,重新设计选择评测与未找到处理协议,说明原测试集可能遗漏的失败模式。
- 提交内容
- 变更前后条件表、重新评审的方案、检验用例与新增代价。
- 怎样算完成
- 只改变明确列出的条件,比较口径保持一致。
- 修改方案说明收益、代价与仍未验证的范围。
练到的知识点未找到与执行失败 · 模型选择工具测试
完成后,再检验一次
给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。
继续阅读
先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。
- 必读规范英文
MCP 2025-11-25:Tools (新标签页)↗
阅读 tools
/list、tools/call、输入 Schema、结果与错误表示,对照实际消息做契约验收。 - 实践参考文档英文
JSON Schema:对象约束 (新标签页)↗
重点阅读 properties、required、
additionalProperties与缺字段示例,建立最小输入或输出契约。 - 深入参考文档英文
Spring AI:Tool Calling (新标签页)↗
重点阅读工具定义、
ToolContext、结果转换与错误处理,验证模型请求到 Java 执行的完整链路。 - 深入参考文档英文
OpenJDK 17 Method 源码 (新标签页)↗
按指定版本定位
Method.getParameterTypes/getReturnType;对照源码分析理解实际调用边界。