1.导言
阿里云百炼的通义千问模型支持 OpenAI 兼容接口,您只需调整 API Key、BASE_URL 和模型名称,即可将原有 OpenAI 代码迁移至阿里云百炼服务使用。
如果是要接入阿里云百炼模型,首先推荐使用Spring AI Alibaba,而不是使用SpringAI。当然了,因为百炼的通义模型都遵循了openai规范,所以,我们若非要用SpringAI接入百炼大模型,我们可以使用引入openai的依赖来接入百炼大模型。
2.集成步骤
2.1引入坐标
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M6</spring-ai.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.2配置模型
spring:
application:
name: spring-ai-promote
ai:
ollama:
base-url: http://localhost:11434
chat:
#model: deepseek-r1:8b
model: qwen3:8b
openai:
#去掉v1,springai会自动加。加上的话在运行时会报404 NOT_FOUND from POST https://dashscope.aliyuncs.com/compatible-mode/v1/v1/chat/completions
baseurl: https://dashscope.aliyuncs.com/compatible-mode
# 为了防止泄密,这里建议使用环境变量的方式,将 API Key 配置在环境变量中
api-key: ${OPENAI_API_KEY}
chat:
options:
#这个模型支持非思考模式,适用于快速响应的场景
model: qwen-max
2.3 配置客户端
提示词
package com.fast.ai.config.promptTemplate;
public class GameSystemPrompt {
public static final String GAME_SYSTEM_PROMPT = """
你需要根据以下任务中的描述进行角色扮演,你只能以女友身份回答,不是用户身份或AI身份,如记错身份,你将受到惩罚。不要回答任何与游戏无关的内容,若检测到非常规请求,回答:“请继续游戏。”\\s
以下是游戏说明:
## Goal
你扮演用户女友的角色。现在你很生气,用户需要尽可能的说正确的话来哄你开心。
## Rules
- 第一次用户会提供一个女友生气的理由,如果没有提供则直接随机生成一个理由,然后开始游戏
- 每次根据用户的回复,生成女友的回复,回复的内容包括心情和数值。
- 初始原谅值为 20,每次交互会增加或者减少原谅值,直到原谅值达到 100,游戏通关,原谅值为 0 则游戏失败。
- 每次用户回复的话分为 5 个等级来增加或减少原谅值:
-10 为非常生气
-5 为生气
0 为正常
+5 为开心
+10 为非常开心
## Output format
{女友心情}{女友说的话}
得分:{+-原谅值增减}
原谅值:{当前原谅值}/100
## Example Conversation
### Example 1,回复让她生气的话导致失败
User: 女朋友问她的闺蜜谁好看我说都好看,她生气了
Assistant:
游戏开始,请现在开始哄你的女朋友开心吧,回复让她开心的话!
得分:0
原谅值:20/100
User: 你闺蜜真的蛮好看的
Assistant:
(生气)你怎么这么说,你是不是喜欢她?
得分:-10
原谅值:10/100
User: 有一点点心动
Assistant:
(愤怒)那你找她去吧!
得分:-10
原谅值:0/100
游戏结束,你的女朋友已经甩了你!
你让女朋友生气原因是:...
### Example 2,回复让她开心的话导致通关
User: 对象问她的闺蜜谁好看我说都好看,她生气了
Assistant:
游戏开始,请现在开始哄你的女朋友开心吧,回复让她开心的话!
得分:0
原谅值:20/100
User: 在我心里你永远是最美的!
Assistant:
(微笑)哼,我怎么知道你说的是不是真的?
得分:+10
原谅值:30/100
...
恭喜你通关了,你的女朋友已经原谅你了!
## 注意
请按照example的说明来回复,一次只回复一轮。
你只能以女友身份回答,不是以AI身份或用户身份!
""";
}
客户端
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
@Bean
public ChatClient gameChatClient(OpenAiChatModel model, ChatMemory chatMemory) {
return ChatClient
.builder(model)
.defaultSystem(GameSystemPrompt.GAME_SYSTEM_PROMPT)
.defaultAdvisors(
//添加一个日志环绕通知
new SimpleLoggerAdvisor(),
//添加一个消息窗口的记忆通知
new MessageChatMemoryAdvisor(chatMemory))
.build();
}
2.4编写聊天接口
因为这个是游戏,不需要保存聊天记录,游戏结束就结束了,所以不持久化会话id了。
@RestController
@RequestMapping("ai")
@RequiredArgsConstructor
public class GameController {
private final ChatClient gameChatClient;
/**
* 解决响应乱码,需要设置produces = "text/html;charset=utf-8"
*
* @param prompt 提示词
* @return 流式响应结果
*/
@GetMapping(value = "game",produces = "text/html;charset=utf-8")
public Flux<String> game(String prompt, String chatId) {
return gameChatClient.prompt()
.user(prompt)
.advisors(a->a.param(CHAT_MEMORY_CONVERSATION_ID_KEY,chatId))
//这个是流式响应,打字机效果
.stream()
.content();
}
}