函数调用基础
什么是函数调用
函数调用(Function Calling)是大模型的核心能力,允许模型识别用户意图并将其转化为结构化函数调用。通过这种方式,模型可以与外部系统交互,执行数据查询、API调用、工具使用等操作,并将结果整合到对话中。
💡核心价值
函数调用使大模型能够实时获取业务系统数据,弥补知识时效性限制,提供更精准、实时的回答,显著增强模型在专业领域的应用价值。
核心优势: 将非结构化自然语言转换为结构化参数,实现人机交互到系统操作的无缝衔接,大幅提升业务流程自动化水平。
业务场景说明
通过自然语言告诉大模型"帮我查询小明同学的数学成绩",大模型会自动识别意图、匹配函数、提取参数,最终调用后端代码查询数据库并返回结果。
sequenceDiagram
participant User as User
participant ChatGPT as ChatGPT
participant API as Math Score API
User->>ChatGPT: 输入自然语言请求:<br/>张三数学成绩怎么样?
Note over ChatGPT: 分析提取参数: 张三
ChatGPT->>API: 调用数学成绩API
API-->>ChatGPT: 返回张三成绩
ChatGPT-->>User: 输出张三成绩
执行流程
函数调用的完整执行流程包括用户输入、函数匹配、参数提取、业务执行和结果返回五个阶段:
graph LR
A[用户输入自然语言] --> B{用户是否指定函数?}
B -->|否| C[向量搜索匹配函数]
B -->|是| D[直接使用指定函数]
C --> E{找到匹配函数?}
E -->|否| F[返回提示信息]
E -->|是| G[更新上下文函数名]
D --> H[获取AI函数助手]
G --> H
H --> I[大模型提取参数]
I --> J[执行参数校验]
J --> K[调用业务逻辑]
K --> L[流式返回结果]
自动匹配函数机制
ℹ向量搜索匹配
当用户未明确指定函数时,系统通过向量相似度搜索自动匹配语义最相近的函数。这种机制让用户无需记忆函数名称,只需用自然语言描述需求即可。
核心实现逻辑:
// 使用向量搜索查找FUNCTION类型的函数
EmbeddingSearchResult<TextSegment> searchResult = EmbeddingProvider.search(
chatMessageDTO.getContent(),
metadataKey(EmbedBizTypeEnums.Fields.type)
.isEqualTo(EmbedBizTypeEnums.FUNCTION.getType())
);
// 如果未找到匹配函数,返回提示信息
if (Objects.isNull(searchResult) || searchResult.matches().isEmpty()) {
return Flux.just(new AiMessageResultDTO("未找到相关功能,请点击下方+按钮选择目标功能"));
}
// 获取最匹配的函数名并更新到上下文
String functionName = searchResult.matches().get(0).embedded().metadata().getString(TEMP_ID);
chatMessageDTO.getExtDetails().setFuncName(functionName);
ChatMessageContextHolder.set(chatMessageDTO);
⚠函数描述的重要性
向量搜索的匹配精度完全取决于函数描述的准确性。务必在 functionDesc() 方法中清晰、详细地描述函数功能和适用场景。
流式响应处理
系统使用 Reactor 响应式编程模型实现流式返回,提升用户体验:
// 获取对应模型的AI函数助手
AiFunctionAssistantService aiFunctionAssistant = modelProvider
.getAiFunctionAssistant(chatMessageDTO.getModelName())
.getValue();
// 流式处理用户请求并返回结果
return aiFunctionAssistant.chatFlux(chatMessageDTO.getContent())
.map(AiMessageResultDTO::new);
开发自定义函数
定义接收实体类
当用户在前端输入自然语言查询(如"小明成绩是多少?")时,需要将非结构化查询转换为后端可处理的结构化JSON数据。定义接收实体类用于接收大模型解析后的参数:
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonClassDescription("学生信息")
public class StudentRequest extends BaseAiRequest {
@FieldPrompt("学生姓名")
private String studentName;
}
💡注解说明
@JsonClassDescription 用于描述实体类用途,@FieldPrompt 用于提示大模型该字段的含义,这些描述信息会影响参数提取的准确性。
实现函数接口
@Component
@RequiredArgsConstructor
public class MathScoreFunctionCalling implements FunctionCalling<StudentRequest> {
/**
* 功能描述,多个函数时AI根据描述选择调用哪个函数
*/
@Override
public String functionDesc() {
return "学生成绩查询助手: 能根据您的描述帮您查询学生的数学成绩";
}
/**
* 参数校验,大模型返回的数据不一定稳定,必须进行业务校验
*/
@Override
public R checkParams(StudentRequest studentRequest, PigxUser userDetails,
ChatMessageDTO.ExtDetails extDetails) {
if (StrUtil.isBlank(studentRequest.getStudentName())) {
return R.failed("学生姓名不能为空");
}
return R.ok();
}
/**
* 业务处理逻辑
*/
@Override
public R<String> handle(StudentRequest studentRequest, PigxUser userDetails,
ChatMessageDTO.ExtDetails extDetails) {
// 模拟根据学生姓名查询数学成绩
if ("小明".equals(studentRequest.getStudentName())) {
return R.ok("98");
}
return R.failed("查询失败,学生信息不存在");
}
}
⚠必须实现参数校验
所有业务函数必须实现 checkParams() 方法进行严格的参数校验,因为大模型返回的数据不一定稳定可靠。
测试使用
在前端的 AI 联动界面中,您可以使用自然语言进行各种提问,例如"查询小明的数学成绩"、"小明这次考试考得怎么样"或"告诉我小明的成绩"等。系统会自动理解您的意图,调用相应的函数,并准确返回小明的数学成绩。
业务应用场景
函数调用是连接大模型能力与业务系统的关键桥梁。通过将业务功能封装为标准化接口,实现自然语言到结构化操作的智能转换。
教育行业: 智能成绩分析
业务场景: 家长询问"小明最近三次数学考试的平均分是多少?"
实现方式: ScoreAnalysisFunction 对接学校考试系统,自动解析时间范围、学科类型、统计维度,动态计算指定维度的学习趋势。
业务价值: 减少教师30%的重复查询工作,提升家长服务响应速度至秒级。
电商行业: 订单状态追踪
业务场景: 用户提问"我昨天买的手机发货了吗?订单号23456"
实现方式: OrderQueryFunction 自动提取订单号,对接ERP系统实时查询。通过JWT token验证用户身份,确保订单数据隔离。
业务价值: 降低客服中心50%的常规查询量,提升用户自助服务率。
医疗行业: 检查报告解读
业务场景: 患者询问"上周三做的血常规报告有什么异常指标?"
实现方式: MedicalReportFunction 对接HIS系统,智能标记异常数据,结合医学知识图谱进行指标关联分析。
业务价值: 缩短患者报告解读等待时间从2天到实时响应。