大模型能做函数调用,初看确实神奇,不过不知道大家是否跟我有一样的疑问:
**大模型是怎么知道: **
1)当前有哪些接口可以调用的?
2)每个接口能干什么?
3)接口有什么入参出参的?
本文将深入探讨这一话题,快速介绍大模型在函数调用方面的内在机制。
Spring AI中函数调用的工作原理
在Spring AI中,函数调用的实现依赖于开发者定义一个实现了java.util.function.Function接口的Java类,并通过注解描述其输入参数、输出结果及功能。
具体来说,使用@JsonProperty和@JsonPropertyDescription等Jackson注解来详细说明方法的参数与返回值。 Json property标记了函数的输入参数和输出参数,然后Function的Description则表达了这函数是干啥的。
例如,定义一个用于查询消息状态的服务,其中包含了一个接受特定格式请求对象并返回字符串响应的方法。
有了这些定义后面就很简单了,只需要将其注册到Spring ai 配置中,同时提供一段对该函数功能的文字性描述,这段描述对于让大模型理解该函数的功能至关重要。注册时还会给这个函数指定一个标准名称,这将是后续步骤中识别该函数的关键标识符。
当用户发起请求并通过Prompt向大模型提出问题时:
如果大模型判断解决问题需要调用某个已注册的功能,则会在其回应中表达出希望调用此功能的意图。
这时,Spring AI会根据之前注册的信息找到对应的Java函数进行本地调用,并将执行结果作为新的Prompt内容的一部分反馈给大模型,从而形成完整的函数调用循环。
这一过程使得大模型能够间接地利用外部API或服务的能力,增强了其处理复杂任务的能力。
Spring AI Alibaba简介:对接阿里云百炼大模型的利器
Spring AI Alibaba是Spring AI的一个实现,专注于对接阿里云的百炼系列云产品的大模型。它支持对话、文生图、文生语音等功能,并提供Java bean 结构化输出 函数调用等实用工具。Spring AI Alibaba的核心优势在于其能够帮助开发者轻松切换不同的AI服务提供商,只需更改配置即可,无需重写代码。此外,通过抽象化设计,大大减少了对接不同AI接口时的工作量。
**实现调用外部函数step by step **
通过Function Calling,我们可以让大语言模型(LLM)在需要时调用我们定义的函数,从而扩展其功能。本案例中,我们的目标是构建一个基于Spring Boot的应用程序,该程序能利用Spring AI Alibaba 的Function Calling能力调用雪球股票接口获取实时利润表,并对利润率进行简单分析。
具体方案步骤
我们将按照以下步骤来实现这一需求:
- 环境准备:确保使用兼容版本的JDK和Spring Boot。
- 依赖引入:添加必要的依赖项到项目中。
- 配置API Key:为阿里云通义模型申请并配置API Key。
- 创建与注册函数:定义并注册用于调用雪球股票API的Java函数。
- 编写Controller:创建控制器以处理GET请求,并利用PromptTemplate和ChatClient生成响应流。
环境准备
- JDK版本:>= 17
- Spring Boot版本:>= 3.3.x
依赖引入
在pom.xml中添加如下依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M3.1</version>
</dependency>
<!-- 其他必要依赖 -->
</dependencies>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
配置API Key
将API Key添加到环境变量或application.properties中:
spring.ai.dashscope.api-key=YOUR_API_KEY_HERE
步骤1: 定义并注册函数
首先,我们定义一个Java函数,它将负责调用雪球的股票接口并解析返回的数据。此函数需要接受一个参数(例如公司代码),然后返回格式化的财务信息。
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import org.springframework.web.client.RestTemplate;
public class XueQiuFinanceService implements Function<XueQiuFinanceService.FinanceRequest, String> {
@Override
public String apply(FinanceRequest request) {
RestTemplate restTemplate = new RestTemplate();
String url = "https://stock.xueqiu.com/v5/stock/finance/cn/income.json?symbol=" + request.getSymbol() + "&type=all&is_detail=true&count=1";
String response = restTemplate.getForObject(url, String.class);
// 解析response并生成简单分析,这里仅做示意
return "解析后的数据及简要分析:" + response;
}
public static class FinanceRequest {
@JsonProperty(required = true, value = "公司代码")
@JsonPropertyDescription("上市公司的股票代码")
private String symbol;
public FinanceRequest() {}
public FinanceRequest(String symbol) {
this.symbol = symbol;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
}
}
接下来,在Spring配置类中注册该函数:
@Configuration
public class AppConfig {
@Bean
@Description("查询指定公司代码的财务信息")
public Function<XueQiuFinanceService.FinanceRequest, String> xueQiuFinanceFunction() {
return new XueQiuFinanceService();
}
}
步骤2: 创建Controller
创建一个REST Controller,用于接收用户输入并通过ChatClient发起请求。同时,确保设置CORS支持。
@RestController
@RequestMapping("/ai")
@CrossOrigin(origins = "*")
public class ChatController {
private final ChatClient chatClient;
@Autowired
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chatStream")
public Flux<String> chatSteam(@RequestParam String input) {
PromptTemplate promptTemplate = new PromptTemplate("我想知道{company}的最新财务状况");
DashScopeChatOptionsBuilder opsBuilder = DashScopeChatOptions.builder()
.withFunction("xueQiuFinanceFunction");
DashScopeChatOptions ops = opsBuilder.build();
Map<String, Object> map = Map.of("company", input);
Prompt promp = promptTemplate.create(map, ops);
return chatClient.prompt(promp).stream().content();
}
}