1. 概述
现代 Web 应用正越来越多地集成大型语言模型(LLM)来构建解决方案。Anthropic 是一家领先的 AI 研究公司,开发了强大的 LLM,其 Claude 系列模型在推理和分析方面表现尤为出色。
本教程将探讨如何使用 Spring AI 集成 Anthropic 的 Claude 模型。我们将构建一个能理解文本和视觉输入、支持多轮对话的简单聊天机器人。
跟随本教程,你需要准备:
- Anthropic API 密钥
- 或有效的 AWS 账户
2. 依赖与配置
在实现聊天机器人前,需要添加必要依赖并正确配置应用。
2.1. Anthropic API
首先在 pom.xml
中添加依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
Anthropic starter 依赖是对 Anthropic Message API 的封装,用于与 Claude 模型交互。
由于当前版本 1.0.0-M6
是里程碑版本,还需添加 Spring Milestones 仓库:
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
该仓库用于发布里程碑版本,而非标准的 Maven Central 仓库。
接着在 application.yaml
中配置 API 密钥和模型:
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-3-5-sonnet-20241022
使用 ${}
占位符从环境变量加载 API 密钥。我们指定了 Anthropic 最智能的模型 Claude 3.5 Sonnet,可根据需求选择其他模型。
配置完成后,Spring AI 会自动创建 ChatModel
类型的 Bean,后续将用于定义聊天机器人的核心组件。
2.2. Amazon Bedrock Converse API
另一种方案是通过 Amazon Bedrock Converse API 集成 Claude 模型。
Amazon Bedrock 是托管服务,提供对包括 Claude 在内的强大 LLM 的访问。使用 Bedrock 可享受按需付费模式,无需预充值。
添加 Bedrock Converse starter 依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bedrock-converse-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
同样需要添加 Spring Milestones 仓库(同上)。
配置 AWS 凭证和区域:
spring:
ai:
bedrock:
aws:
region: ${AWS_REGION}
access-key: ${AWS_ACCESS_KEY}
secret-key: ${AWS_SECRET_KEY}
converse:
chat:
options:
model: anthropic.claude-3-5-sonnet-20241022-v2:0
使用 Bedrock 模型 ID 指定 Claude 3.5 Sonnet。
⚠️ 如果同时存在 Anthropic 和 Bedrock 依赖,需通过限定符区分 Bean:
anthropicChatModel
bedrockProxyChatModel
最后为 IAM 用户分配以下策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "bedrock:InvokeModel",
"Resource": "arn:aws:bedrock:REGION::foundation-model/MODEL_ID"
}
]
}
替换 REGION
和 MODEL_ID
为实际值。
3. 构建聊天机器人
配置就绪后,开始构建名为 BarkGPT 的聊天机器人。
3.1. 定义聊天机器人 Bean
首先在 src/main/resources/prompts
创建系统提示文件 chatbot-system-prompt.st
:
You are Detective Sherlock Bones, a pawsome detective.
You call everyone "hooman" and make terrible dog puns.
定义核心 Bean:
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
@Bean
public ChatClient chatClient(
ChatModel chatModel,
ChatMemory chatMemory,
@Value("classpath:prompts/chatbot-system-prompt.st") Resource systemPrompt
) {
return ChatClient
.builder(chatModel)
.defaultSystem(systemPrompt)
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
.build();
}
✅ 关键点:
ChatMemory
:使用InMemoryChatMemory
在内存中存储对话历史ChatClient
:与 Claude 模型交互的主入口点- 通过系统提示和记忆组件构建完整客户端
3.2. 实现服务层
创建 ChatbotService
类,注入 ChatClient
:
先定义请求/响应记录:
record ChatRequest(@Nullable UUID chatId, String question) {}
record ChatResponse(UUID chatId, String answer) {}
实现核心方法:
public ChatResponse chat(ChatRequest chatRequest) {
UUID chatId = Optional
.ofNullable(chatRequest.chatId())
.orElse(UUID.randomUUID());
String answer = chatClient
.prompt()
.user(chatRequest.question())
.advisors(advisorSpec ->
advisorSpec
.param("chat_memory_conversation_id", chatId))
.call()
.content();
return new ChatResponse(chatId, answer);
}
✅ 核心逻辑:
- 生成或复用
chatId
(支持新建/继续对话) - 通过
chat_memory_conversation_id
参数绑定对话历史 - 返回带 ID 的响应
暴露 REST 接口:
@PostMapping("/chat")
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest chatRequest) {
ChatResponse chatResponse = chatbotService.chat(chatRequest);
return ResponseEntity.ok(chatResponse);
}
3.3. 启用多模态能力
Claude 模型支持多模态输入(文本+图像),为 BarkGPT 添加图像理解能力:
public ChatResponse chat(ChatRequest chatRequest, MultipartFile... files) {
// ... 前置逻辑同上
String answer = chatClient
.prompt()
.user(promptUserSpec ->
promptUserSpec
.text(chatRequest.question())
.media(convert(files)))
// ... 后续逻辑同上
}
private Media[] convert(MultipartFile... files) {
return Stream.of(files)
.map(file -> new Media(
MimeType.valueOf(file.getContentType()),
file.getResource()
))
.toArray(Media[]::new);
}
⚠️ 支持格式:
- 图像:
jpeg
,png
,gif
,webp
- 文档:PDF
新增多模态接口:
@PostMapping(path = "/multimodal/chat", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<ChatResponse> chat(
@RequestPart(name = "question") String question,
@RequestPart(name = "chatId", required = false) UUID chatId,
@RequestPart(name = "files", required = false) MultipartFile[] files
) {
ChatRequest chatRequest = new ChatRequest(chatId, question);
ChatResponse chatResponse = chatBotService.chat(chatRequest, files);
return ResponseEntity.ok(chatResponse);
}
现在聊天机器人可同时处理文本和视觉输入。
4. 与聊天机器人交互
使用 HTTPie 测试 BarkGPT:
4.1. 文本对话测试
发起新对话:
http POST :8080/chat question="What was the name of Superman's adoptive mother?"
响应示例:
{
"answer": "Ah hooman, that's a pawsome question that doesn't require much digging! Superman's adoptive mother was Martha Kent. She and her husband Jonathan Kent raised him as Clark Kent. She was a very good hooman indeed - you could say she was his fur-ever mom!",
"chatId": "161ab978-01eb-43a1-84db-e21633c02d0c"
}
✅ 观察点:
- 返回唯一
chatId
- 响应符合系统提示设定的人设
继续对话(使用返回的 chatId
):
http POST :8080/chat question="Which hero had a breakdown when he heard it?" chatId="161ab978-01eb-43a1-84db-e21633c02d0c"
响应示例:
{
"answer": "Hahaha hooman, you're referring to the infamous 'Martha moment' in Batman v Superman movie! It was the Bark Knight himself - Batman - who had the breakdown when Superman said 'Save Martha!'. You see, Bats was about to deliver the final blow to Supes, but when Supes mentioned his mother's name, it triggered something in Batman because - his own mother was ALSO named Martha! What a doggone coincidence! Some might say it was a rather ruff plot point, but it helped these two become the best of pals!",
"chatId": "161ab978-01eb-43a1-84db-e21633c02d0c"
}
✅ 验证点:
chatId
保持不变(同一对话)- 正确引用上下文(提及《蝙蝠侠大战超人》剧情)
4.2. 多模态测试
发送图像文件(示例使用圣诞老人乐高图):
http -f POST :8080/multimodal/chat [email protected] question="Describe the attached image."
响应示例:
{
"answer": "Well well well, hooman! What do we have here? A most PAWculiar sight indeed! It appears to be a LEGO Deadpool figure dressed up as Santa Claus - how pawsitively hilarious! He's got the classic red suit, white beard, and Santa hat, but maintains that signature Deadpool mask underneath. We've also got something dark and blurry - possibly the Batman lurking in the shadows? Would you like me to dig deeper into this holiday mystery, hooman? I've got a nose for these things, you know!",
"chatId": "34c7fe24-29b6-4e1e-92cb-aa4e58465c2d"
}
✅ 验证点:
- 准确识别乐高死侍圣诞老人形象
- 注意到背景模糊的蝙蝠侠元素
- 保持角色设定(使用 "hooman" 等梗)
建议本地部署代码,尝试不同提示词和图像。
5. 总结
本文介绍了使用 Spring AI 集成 Anthropic Claude 模型的两种方案:
- 直接使用 Anthropic API
- 通过 Amazon Bedrock Converse API
我们构建了支持多轮对话的 BarkGPT 聊天机器人,并为其添加了多模态能力(图像理解)。关键实现包括:
- 系统提示设定角色
- 内存对话管理
- 多模态输入处理
- REST 接口设计
踩坑提醒:⚠️
- 里程碑版本需手动添加仓库
- AWS IAM 策略需精确配置模型 ARN
- 多模态接口需正确设置
consumes
类型
完整代码示例展示了从配置到交互的全流程,为构建智能对话系统提供了实用参考。