使用 Mistral AI API 在 Java 和 Spring AI 中進行函數調用
1. 概述
使用大型語言模型,我們可以檢索大量有用的信息。我們可以了解任何事物的許多新事實,並根據互聯網上的現有數據獲得答案。我們可以要求它們處理輸入資料並執行各種操作。但是,如果我們要求模型使用 API 來準備輸出呢?
為此,我們可以使用函數呼叫。函數呼叫允許法學碩士與資料互動和操作資料、執行計算或檢索超出其固有文字功能的資訊。
在本文中,我們將探討什麼是函數呼叫以及如何使用它來將 LLM 與我們的內部邏輯整合。作為模型提供者,我們將使用Mistral AI API 。
2.米斯特拉爾人工智慧API
Mistral AI 專注於為開發者和企業提供開放且可移植的生成式 AI 模型。我們可以將它用於簡單的提示以及函數呼叫整合。
2.1.檢索 API 金鑰
要開始使用 Mistral API,我們首先需要檢索 API 金鑰。讓我們進入API 金鑰管理控制台:
要啟動任何金鑰,我們必須設定計費配置或使用試用期(如果可用):
解決完所有問題後,我們可以按下Create new key
按鈕來取得 Mistral API 金鑰。
2.2.使用範例
我們先從一個簡單的提示開始。我們將要求 Mistral API 傳回患者狀態清單。讓我們實作這樣一個呼叫:
@Test
void givenHttpClient_whenSendTheRequestToChatAPI_thenShouldBeExpectedWordInResponse() throws IOException, InterruptedException {
String apiKey = System.getenv("MISTRAL_API_KEY");
String apiUrl = "https://api.mistral.ai/v1/chat/completions";
String requestBody = "{"
+ "\"model\": \"mistral-large-latest\","
+ "\"messages\": [{\"role\": \"user\", "
+ "\"content\": \"What the patient health statuses can be?\"}]"
+ "}";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
logger . info ("Model response: " + responseBody);
Assertions.assertThat(responseBody)
.containsIgnoringCase("healthy");
}
我們建立了一個 HTTP 請求並將其傳送到/chat/completions
端點。然後,我們使用 API 金鑰作為授權標頭值。正如預期的那樣,在回應中我們看到元資料和內容本身:
Model response: {"id":"585e3599275545c588cb0a502d1ab9e0","object":"chat.completion",
"created":1718308692,"model":"mistral-large-latest",
"choices":[{"index":0,"message":{"role":"assistant","content":"Patient health statuses can be
categorized in various ways, depending on the specific context or medical system being used.
However, some common health statuses include:
1.Healthy: The patient is in good health with no known medical issues.
...
10.Palliative: The patient is receiving care that is focused on relieving symptoms and improving quality of life, rather than curing the underlying disease.",
"tool_calls":null},"finish_reason":"stop","logprobs":null}],
"usage":{"prompt_tokens":12,"total_tokens":291,"completion_tokens":279}}
函數呼叫的例子比較複雜,呼叫前需要做很多準備。我們將在下一節中發現它。
3. Spring AI集成
讓我們來看一些使用 Mistral API 進行函數呼叫的範例。使用Spring AI我們可以避免大量的準備工作,讓框架為我們做這件事。
3.1.依賴關係
所需的依賴項位於Spring 里程碑儲存庫中。讓我們將其添加到pom.xml
中:
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
現在,讓我們新增 Mistral API 整合的依賴項:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mistral-ai-spring-boot-starter</artifactId>
<version>0.8.1</version>
</dependency>
3.2.配置
現在讓我們將先前獲得的 API 金鑰新增到屬性檔案中:
spring:
ai:
mistralai:
api-key: ${MISTRAL_AI_API_KEY}
chat:
options:
model: mistral-small-latest
這就是我們開始使用 Mistral API 所需的全部內容。
3.3.具有一個功能的用例
在我們的演示範例中,我們將建立一個函數,根據患者的 ID 返回其健康狀況。
讓我們從建立患者記錄開始:
public record Patient(String patientId) {
}
現在讓我們為患者的健康狀況建立另一筆記錄:
public record HealthStatus(String status) {
}
在下一步中,我們將建立一個配置類別:
@Configuration
public class MistralAIFunctionConfiguration {
public static final Map<Patient, HealthStatus> HEALTH_DATA = Map.of(
new Patient("P001"), new HealthStatus("Healthy"),
new Patient("P002"), new HealthStatus("Has cough"),
new Patient("P003"), new HealthStatus("Healthy"),
new Patient("P004"), new HealthStatus("Has increased blood pressure"),
new Patient("P005"), new HealthStatus("Healthy"));
@Bean
@Description("Get patient health status")
public Function<Patient, HealthStatus> retrievePatientHealthStatus() {
return (patient) -> new HealthStatus(HEALTH_DATA.get(patient).status());
}
}
在這裡,我們指定了包含患者健康數據的數據集。此外,我們還建立了retrievePatientHealthStatus()
函數,該函數傳回給定患者ID 的健康狀態。
現在,讓我們透過在整合中呼叫它來測試我們的函數:
@Import(MistralAIFunctionConfiguration.class)
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class MistralAIFunctionCallingManualTest {
@Autowired
private MistralAiChatModel chatClient;
@Test
void givenMistralAiChatClient_whenAskChatAPIAboutPatientHealthStatus_thenExpectedHealthStatusIsPresentInResponse() {
var options = MistralAiChatOptions.builder()
.withFunction("retrievePatientHealthStatus")
.build();
ChatResponse paymentStatusResponse = chatClient.call(
new Prompt("What's the health status of the patient with id P004?", options));
String responseContent = paymentStatusResponse.getResult().getOutput().getContent();
logger . info (responseContent);
Assertions.assertThat(responseContent)
.containsIgnoringCase("has increased blood pressure");
}
}
我們匯入了MistralAIFunctionConfiguration
類,以將retrievePatientHealthStatus()
函數加入測試 Spring 上下文中。我們也注入了MistralAiChatClient
,它將由 Spring AI 啟動器自動實例化。
在對聊天 API 的請求中,我們指定了提示文本,其中包含患者 ID 之一以及用於檢索健康狀態的函數名稱。然後我們呼叫 API 並驗證回應是否包含預期的健康狀態。
此外,我們還記錄了整個回應文本,以下是我們看到的內容:
The patient with id P004 has increased blood pressure.
3.4.具有多種功能的用例
我們還可以指定多個功能,人工智慧會根據我們發送的提示決定使用哪一個。
為了展示這一點,讓我們擴展我們的HealthStatus
記錄:
public record HealthStatus(String status, LocalDate changeDate) {
}
我們新增了上次更改狀態的日期。
現在我們來修改配置類別:
@Configuration
public class MistralAIFunctionConfiguration {
public static final Map<Patient, HealthStatus> HEALTH_DATA = Map.of(
new Patient("P001"), new HealthStatus("Healthy",
LocalDate.of(2024,1, 20)),
new Patient("P002"), new HealthStatus("Has cough",
LocalDate.of(2024,3, 15)),
new Patient("P003"), new HealthStatus("Healthy",
LocalDate.of(2024,4, 12)),
new Patient("P004"), new HealthStatus("Has increased blood pressure",
LocalDate.of(2024,5, 19)),
new Patient("P005"), new HealthStatus("Healthy",
LocalDate.of(2024,6, 1)));
@Bean
@Description("Get patient health status")
public Function<Patient, String> retrievePatientHealthStatus() {
return (patient) -> HEALTH_DATA.get(patient).status();
}
@Bean
@Description("Get when patient health status was updated")
public Function<Patient, LocalDate> retrievePatientHealthStatusChangeDate() {
return (patient) -> HEALTH_DATA.get(patient).changeDate();
}
}
我們已填入每個狀態項目的變更日期。我們也建立了retrievePatientHealthStatusChangeDate()
函數,該函數傳回有關狀態變更日期的資訊。
讓我們看看如何將兩個新函數與 Mistral API 結合使用:
@Test
void givenMistralAiChatClient_whenAskChatAPIAboutPatientHealthStatusAndWhenThisStatusWasChanged_thenExpectedInformationInResponse() {
var options = MistralAiChatOptions.builder()
.withFunctions(
Set.of("retrievePatientHealthStatus",
"retrievePatientHealthStatusChangeDate"))
.build();
ChatResponse paymentStatusResponse = chatClient.call(
new Prompt(
"What's the health status of the patient with id P005",
options));
String paymentStatusResponseContent = paymentStatusResponse.getResult()
.getOutput().getContent();
logger . info (paymentStatusResponseContent);
Assertions.assertThat(paymentStatusResponseContent)
.containsIgnoringCase("healthy");
ChatResponse changeDateResponse = chatClient.call(
new Prompt(
"When health status of the patient with id P005 was changed?",
options));
String changeDateResponseContent = changeDateResponse.getResult().getOutput().getContent();
logger . info (changeDateResponseContent);
Assertions.assertThat(paymentStatusResponseContent)
.containsIgnoringCase("June 1, 2024");
}
在本例中,我們指定了兩個函數名稱並發送了兩個提示。首先,我們詢問了患者的健康狀況。然後我們問這個狀態什麼時候會改變的。我們已驗證結果包含預期資訊。除此之外,我們還記錄了所有回复,如下所示:
The patient with id P005 is currently healthy.
The health status of the patient with id P005 was changed on June 1, 2024.
4。
函數呼叫是擴展 LLM 功能的一個很好的工具。我們也可以用它來將 LLM 與我們的邏輯整合。
在本教程中,我們探討如何透過呼叫一個或多個函數來實現基於 LLM 的流程。使用這種方法,我們可以實現與 AI API 整合的現代應用程式。
像往常一樣,完整的源代碼可以在 GitHub 上找到。