在人工智能的世界里,大语言模型(LLMs)不仅仅是文本生成的能手,它们还能触发实际的操作。这种能力,我们称之为函数调用或函数调用。本文将深入探讨 LangChain4j 框架是如何实现这一强大功能的。
函数调用:LLM 的得力助手
函数调用让 LLM 能够根据输入的提示,生成一个调用特定函数的请求。这个请求包含了函数名称和所需的参数信息。通过这种方式,我们可以将 LLM 的智能与外部工具或 API 无缝连接。
举个例子,众所周知,LLM 在复杂数学计算方面并不擅长。如果您的应用场景涉及大量数学运算,您可以为 LLM 提供一个”数学工具”。LLM 会根据工具的描述,返回需要调用的函数名称和参数。然后,您的系统执行该函数,获取结果,再将结果和原始提示一起发送给 LLM,最终得到综合的回答。
重要提示: LLM 本身并不执行函数,它只是指示应该调用哪个函数以及如何调用。
函数调用的应用场景
- 触发外部操作:如发送邮件、控制智能家居设备等。
- 实时数据获取:解决 LLM 知识更新滞后的问题,如进行实时搜索或数据库查询。
- 复杂逻辑处理:处理 LLM 难以直接计算的复杂数据运算问题。
编码注入函数
public interface FunctionAssistant {
String chat(String message);
}
-
工具说明 ToolSpecification
-
业务逻辑 ToolExecutor
@Bean
public FunctionAssistant functionAssistant(ChatLanguageModel chatLanguageModel) {
// 工具说明 ToolSpecification
ToolSpecification toolSpecification = ToolSpecification.builder()
.name("invoice_assistant")
.description("根据用户提交的开票信息,开具发票")
.addParameter("companyName", type("string"), description("公司名称"))
.addParameter("dutyNumber", type("string"), description("税号"))
.addParameter("amount", type("number"), description("金额"))
.build();
// 业务逻辑 ToolExecutor
ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
String arguments1 = toolExecutionRequest.arguments();
System.out.println("arguments1 =>>>> " + arguments1);
return "开具成功";
};
return AiServices.builder(FunctionAssistant.class)
.chatLanguageModel(chatLanguageModel)
.tools(Map.of(toolSpecification, toolExecutor))
.build();
}
注解注入函数
通过使用注解 @Tool
,可以更方便地集成函数调用。LangChain4j 的 AI 服务会自动处理工具执行,无需手动管理工具请求。
工具定义:只需将Java方法标注为 @Tool
,LangChain4j 就会自动将其转换为 ToolSpecification
,并且在与LLM交互时调用这些方法。
@Slf4j
public class InvoiceHandler {
@Tool("根据用户提交的开票信息进行开票")
public String handle(String companyName, String dutyNumber,@P("金额保留两位有效数字") String amount) {
log.info("companyName =>>>> {} dutyNumber =>>>> {} amount =>>>> {}", companyName, dutyNumber, amount);
return "开票成功";
}
}
@Bean
public FunctionAssistant functionAssistant(ChatLanguageModel chatLanguageModel) {
return AiServices.builder(FunctionAssistant.class)
.chatLanguageModel(chatLanguageModel)
.tools(new InvoiceHandler())
.build();
}
动态工具配置
LangChain4j 支持动态工具配置,开发者可以基于用户输入的上下文,在运行时动态加载工具。通过 ToolProvider
接口,工具集会在每次请求时动态生成。
例如,只有当用户提到 “booking” 时才加载相关的工具:
ToolProvider toolProvider = (toolProviderRequest) -> {
if (toolProviderRequest.userMessage().singleText().contains("booking")) {
ToolSpecification toolSpecification = ToolSpecification.builder()
.name("get_booking_details")
.description("Returns booking details")
.addParameter("bookingNumber", type("string"))
.build();
return ToolProviderResult.builder()
.add(toolSpecification, toolExecutor)
.build();
} else {
return null;
}
};
小结
函数调用为LLM增加了扩展性,使其能够与外部世界互动,实现更复杂的任务。通过LangChain4j的低级和高级API,开发者可以灵活地集成和管理这些工具,从而创建智能化、自动化的应用场景。
这种灵活的架构,结合了对具体任务的自动化调用,能大大增强LLM的实用性,尤其适用于需要集成外部API、进行计算或其他任务的应用。