我在跟着大神徐庶老师学习SpringAI的时候发现使用Function Calling回调的时候,参数映射很神奇,然后就开始浅浅的刨根问底.....
下面是我的一段代码。
//内部类,jdk17新特性,密封类。简化书写,直接生成getset放个和有参构造函数
public record CancelBookingRequest(String bookingNumber,String name){}
@Bean
@Description("处理机票退订")
public Function<CancelBookingRequest,String> cancelBooking(){
return cancelBookingRequest -> {
// apply 调用退订方法
flightBookingService.cancelBooking(cancelBookingRequest.bookingNumber(),cancelBookingRequest.name());
return "退订成功!";
};
}
以上代码很简单,就是大模型在发现我有退票意图的时候就会回调我这个cancelBooking方法,退票需要俩参数,分别是:订单号(bookingNumber)、姓名(name)。
我当时和模型的对话,是我的名字叫小王,单号是123。默认传统程序,如果是前后顺序的,肯定是小王给到了bookingNumber,订单号给到了name。但是神奇的是,默认回调回来参数匹配就是正确的!
就很妙!模型会根据你的语义,和设置参数词语的意思,自动给你匹配上,不得不说真是妙啊!!!
我起初还不信,然后我就把参数设置成了aaa,和bbb。结果真是这样,匹配不准确了,他会按照传统的思路,先后顺序的传进来!!
之后我就开始查阅一些资料,想简单了解一下是为什么?
以下是我查询的资料。
1. 参数名称与 JSON Schema 的映射
- 当
CancelBookingRequest
类被注册为工具函数的输入类型时,Spring AI 会通过反射解析其字段名(bookingNumber
和name
),并生成对应的 JSON Schema。该 Schema 会作为元数据传递给大模型,告知模型参数的名称、类型及描述(若有注解)
- 例如,生成的 Schema 可能如下:
{ "type": "object", "properties": { "bookingNumber": {"type": "string"}, "name": {"type": "string"} } }
2. 自然语言解析与结构化绑定
- 大模型(如 OpenAI 或阿里通义千问)收到用户输入后,会基于预定义的 JSON Schema 进行语义解析。例如:
- 用户说:“我名字叫做小王,订单号是123” → 模型识别出
name
和bookingNumber
的对应关系,生成结构化 JSON:{"name": "小王", "bookingNumber": "123"}
- 这一过程依赖模型的上下文理解能力,参数名(如
bookingNumber
)作为键(key)直接匹配 JSON 字段
- 用户说:“我名字叫做小王,订单号是123” → 模型识别出
3. 注解增强语义理解
- 若参数通过
@ToolParam
或@JsonPropertyDescription
添加描述,模型会更精准地匹配。例如: -
描述信息会帮助模型区分参数用途(如“订单编号”对应public record CancelBookingRequest( @ToolParam(description = "机票订单编号") String bookingNumber, @ToolParam(description = "乘客姓名") String name ) {}
bookingNumber
),避免歧义
4. 反序列化与反射调用
- Spring AI 收到模型返回的 JSON 后,通过 Jackson 等库将数据反序列化为
CancelBookingRequest
对象。此时:- JSON 键
name
自动绑定到CancelBookingRequest.name
字段。 - JSON 键
bookingNumber
绑定到CancelBookingRequest.bookingNumber
字段
- JSON 键
- 若字段名与 JSON 键不一致,需通过
@JsonProperty("别名")
显式映射
5. 动态执行的底层支持
- 最终,Spring AI 通过反射调用工具方法(如
cancelBooking()
),并将反序列化的CancelBookingRequest
对象作为参数传入,完成值传递