开始构建 Spring AI Alibaba-聊天机器人

注意:因为 Spring AI Alibaba 基于 Spring Boot 3.x 开发,因此本地 JDK 版本要求为 17 及以上。

⚠ 申请API-KEY

大模型服务平台百炼控制台

申请成功后将key放在配置文件中

cd spring-ai-alibaba-examples/spring-ai-alibaba-helloworld
./mvnw spring-boot:run

✅模型对话能力

以上示例本质上就是一个普通的 Spring Boot 应用,我们来通过源码解析看一下具体的开发流程。

🔷添加依赖

首先,需要在项目中添加 spring-ai-alibaba-starter 依赖,它将通过 Spring Boot 自动装配机制初始化与阿里云通义大模型通信的 ChatClientChatModel 相关实例。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xmlns="http://maven.apache.org/POM/4.0.0"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.alibaba.cloud.ai</groupId>
		<artifactId>spring-ai-alibaba-examples</artifactId>
		<version>${revision}</version>
		<relativePath>../pom.xml</relativePath>
	</parent>

	<artifactId>spring-ai-alibaba-helloworld</artifactId>
	<version>${revision}</version>

	<description>Spring AI Alibaba Helloworld Example</description>
	<name>Spring AI Alibaba Helloworld Examples</name>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba.cloud.ai</groupId>
			<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>${spring-boot.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-deploy-plugin</artifactId>
				<version>${maven-deploy-plugin.version}</version>
			</plugin>
		</plugins>
	</build>

</project>

🔷注入 ChatClient

接下来,在普通 Controller Bean 中注入 ChatClient 实例,这样你的 Bean 就具备与 AI 大模型智能对话的能力了。

package com.alibaba.cloud.ai.example.helloworld;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import jakarta.servlet.http.HttpServletResponse;
import reactor.core.publisher.Flux;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/helloworld")
public class HelloworldController {

	private static final String DEFAULT_PROMPT = "你是一个博学的智能聊天助手,请根据用户提问回答!";

	private final ChatClient dashScopeChatClient;

	// 也可以使用如下的方式注入 ChatClient
	 public HelloworldController(ChatClient.Builder chatClientBuilder) {
	  	this.dashScopeChatClient = chatClientBuilder
				.defaultSystem(DEFAULT_PROMPT)
				// TODO
				 // 实现 Chat Memory 的 Advisor
				 // 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。
//				 .defaultAdvisors(
//						 new MessageChatMemoryAdvisor(new InMemoryChatMemory())
//				 )
				 // 实现 Logger 的 Advisor
				 .defaultAdvisors(
						 new SimpleLoggerAdvisor()
				 )
				 // 设置 ChatClient 中 ChatModel 的 Options 参数
				 .defaultOptions(
						 DashScopeChatOptions.builder()
								 .withTopP(0.7)
								 .build()
				 )
				 .build();
	 }

	/**
	 * ChatClient 简单调用
	 */
	@GetMapping("/simple/chat")
	public String simpleChat(@RequestParam(value = "query", defaultValue = "你好,很高兴认识你,能简单介绍一下自己吗?")String query) {

		return dashScopeChatClient.prompt(query).call().content();
	}

	/**
	 * ChatClient 流式调用
	 */
	@GetMapping("/stream/chat")
	public Flux<String> streamChat(@RequestParam(value = "query", defaultValue = "你好,很高兴认识你,能简单介绍一下自己吗?")String query, HttpServletResponse response) {

		response.setCharacterEncoding("UTF-8");
		return dashScopeChatClient.prompt(query).stream().content();
	}

👉DashScopeChatOptions 调整与模型对话时的参数

以上示例中,ChatClient 使用默认参数调用大模型,Spring AI Alibaba 还支持通过 DashScopeChatOptions 调整与模型对话时的参数,DashScopeChatOptions 支持两种不同维度的配置方式:

  1. 全局默认值,即 ChatClient 实例初始化参数

application.yaml 文件中指定 spring.ai.dashscope.chat.options.* 或调用构造函数 ChatClient.Builder.defaultOptions(options)DashScopeChatModel(api, options) 完成配置初始化。

  1. 每次 Prompt 调用前动态指定
String result = dashScopeChatClient
.prompt(query)
.options(DashScopeChatOptions.builder().withTopP(0.8).build())
.call()
.content();

关于 DashScopeChatOptions 配置项的详细说明,请查看参考手册。

此外,模型还支持流式调用,这样的数据返回前端会产生“打字机”效果:

	/**
	 * ChatClient 流式调用
	 */
	@GetMapping("/stream/chat")
	public Flux<String> streamChat(@RequestParam(value = "query", defaultValue = "你好,很高兴认识你,能简单介绍一下自己吗?")String query, HttpServletResponse response) {

		response.setCharacterEncoding("UTF-8");
		return dashScopeChatClient.prompt(query).stream().content();
	}

接口调用效果

✅增加聊天记忆能力

一种解决办法是在调用大模型的过程中,由开发者编写的代码来维护多轮的对话记忆,这样会大大增加项目的代码量。
Spring AI Alibaba 提供了 jdbcrediselasticsearch 插件可以让聊天机器人拥有“记忆”。下面以 MySQL 为例,演示如何快速编写一个带有记忆的聊天机器人。

🔶添加依赖

        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-memory-jdbc</artifactId>
            <version>1.0.0.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>

🔶配置数据库连接

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/chatMemory?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: root

🔶实例化 ChatMemoryRepository 对象和 ChatMemory 对象

// 构造 ChatMemoryRepository 和 ChatMemory
        ChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder()
                .jdbcTemplate(jdbcTemplate)
                .build();
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .build();

🔥 构造 ChatClient 时通过 .defaultAdvisors() 注册 MessageChatMemoryAdvisor

    public HelloworldController(JdbcTemplate jdbcTemplate, ChatClient.Builder chatClientBuilder) {
        // 构造 ChatMemoryRepository 和 ChatMemory
        ChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder()
                .jdbcTemplate(jdbcTemplate)
                .build();
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .build();
        this.dashScopeChatClient = chatClientBuilder
                .defaultSystem(DEFAULT_PROMPT)
                .defaultAdvisors(new SimpleLoggerAdvisor())
                // 注册Advisor
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                .defaultOptions(
                        DashScopeChatOptions.builder()
                                .withTopP(0.7)
                                .build()
                )
                .build();
    }

🔥 每次调用大模型时通过.advisors()传递当前会话ID

	/**
	 * ChatClient 使用自定义的 Advisor 实现功能增强.
	 * eg:
	 * http://127.0.0.1:18080/helloworld/advisor/chat/123?query=你好,我叫牧生,之后的会话中都带上我的名字
	 * 你好,牧生!很高兴认识你。在接下来的对话中,我会记得带上你的名字。有什么想聊的吗?
	 * http://127.0.0.1:18080/helloworld/advisor/chat/123?query=我叫什么名字?
	 * 你叫牧生呀。有什么事情想要分享或者讨论吗,牧生?
	 */
	@GetMapping("/advisor/chat/{id}")
	public Flux<String> advisorChat(
			HttpServletResponse response,
			@PathVariable String id,
			@RequestParam String query) {

		response.setCharacterEncoding("UTF-8");

		return this.dashScopeChatClient.prompt(query)
				.advisors(
						a -> a.param(ChatMemory.CONVERSATION_ID, id)
				).stream().content();
	}

🔶测试记忆能力

第一次发送我的名字带上会话id 1

数据库中存储数据

第二次询问我的名字,回答正确

数据库中存储数据

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值