对话记忆

大型语言模型 (LLM) 是无状态的,这意味着它们不会保留先前交互的信息。

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testChatOptions</span>() {
        <span style="color:#b75501">String</span> <span style="color:#54790d">content</span> <span style="color:#ab5656">=</span> chatClient.prompt()
                .user(<span style="color:#54790d">"我叫小兔子 "</span>)
                .call()
                .content();
        System.out.println(content);
        System.out.println(<span style="color:#54790d">"--------------------------------------------------------------------------"</span>);

       content = chatClient.prompt()
                .user(<span style="color:#54790d">"我叫什么 ?"</span>)
                .call()
                .content();
        System.out.println(content);
    }
</code></span></span>

那我们平常跟一些大模型聊天是怎么记住我们对话的呢?实际上,每次对话都需要将之前的对话消息内置发送给大模型,这种方式称为多轮对话。

SpringAi提供了一个ChatMemory的组件用于存储聊天记录,允许您使用 LLM 跨多个交互存储和检索信息。并且可以为不同用户的多个交互之间维护上下文或状态。
可以在每次对话的时候把当前聊天信息和模型的响应存储到ChatMemory, 然后下一次对话把聊天记录取出来再发给大模型。

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java">`

<span style="color:#656e77">//输出 名字叫徐庶</span>
</code></span></span>

但是这样做未免太麻烦! 能不能简化? 思考一下!

用我们之前的Advisor对话拦截是不是就可以不用每次手动去维护了。 并且SpringAi早已体贴的为我提供了ChatMemoryAutoConfiguration自动配置类

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-xml"><<span style="color:#b75501">dependency</span>>
  <<span style="color:#b75501">groupId</span>>org.springframework.ai</<span style="color:#b75501">groupId</span>>
  <<span style="color:#b75501">artifactId</span>>spring-ai-autoconfigure-model-chat-memory</<span style="color:#b75501">artifactId</span>>
</<span style="color:#b75501">dependency</span>>
</code></span></span>
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@AutoConfiguration</span>
<span style="color:#015692">@ConditionalOnClass({ ChatMemory.class, ChatMemoryRepository.class })</span>
<span style="color:#015692">public</span> <span style="color:#015692">class</span> <span style="color:#b75501">ChatMemoryAutoConfiguration</span> {

	<span style="color:#015692">@Bean</span>
	<span style="color:#015692">@ConditionalOnMissingBean</span>
	ChatMemoryRepository <span style="color:#b75501">chatMemoryRepository</span>() {
		<span style="color:#015692">return</span> <span style="color:#015692">new</span> <span style="color:#b75501">InMemoryChatMemoryRepository</span>();
	}

	<span style="color:#015692">@Bean</span>
	<span style="color:#015692">@ConditionalOnMissingBean</span>
	ChatMemory <span style="color:#b75501">chatMemory</span>(ChatMemoryRepository chatMemoryRepository) {
		<span style="color:#015692">return</span> MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();
	}

}
</code></span></span>

所以我们可以这样用:

PromptChatMemoryAdvisor

SpringAi提供了 PromptChatMemoryAdvisor 专门用于对话记忆的拦截

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@SpringBootTest</span>
<span style="color:#015692">public</span> <span style="color:#015692">class</span> <span style="color:#b75501">ChatMemoryTest</span> {
    ChatClient chatClient;
    <span style="color:#015692">@BeforeEach</span>
    <span style="color:#015692">public</span>  <span style="color:#015692">void</span> <span style="color:#b75501">init</span>(<span style="color:#015692">@Autowired</span>
                      DeepSeekChatModel chatModel,
                      <span style="color:#015692">@Autowired</span>
                      ChatMemory chatMemory) {
        chatClient = ChatClient
                .builder(chatModel)
                .defaultAdvisors(
                    <span style="color:#656e77">// PromptChatMemoryAdvisor拦截器 就会自动将我们与大模型的历史对话记录下来</span>
                        PromptChatMemoryAdvisor.builder(chatMemory).build()
                )
                .build();
    }
    <span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testChatOptions</span>() {
        <span style="color:#b75501">String</span> <span style="color:#54790d">content</span> <span style="color:#ab5656">=</span> chatClient.prompt()
                .user(<span style="color:#54790d">"我叫徐庶 ?"</span>)
        <span style="color:#656e77">// </span>
                .advisors(<span style="color:#015692">new</span> <span style="color:#b75501">ReReadingAdvisor</span>())
                .call()
                .content();
        System.out.println(content);
        System.out.println(<span style="color:#54790d">"--------------------------------------------------------------------------"</span>);

        content = chatClient.prompt()
                .user(<span style="color:#54790d">"我叫什么 ?"</span>)
                .advisors(<span style="color:#015692">new</span> <span style="color:#b75501">ReReadingAdvisor</span>())
                .call()
                .content();
        System.out.println(content);
    }
}
</code></span></span>

配置聊天记录最大存储数量

你要知道, 我们把聊天记录发给大模型, 都是算token计数的。

大模型的token是有上限了, 如果你发送过多聊天记录,可能就会导致token过长。

如下是大模型存储的 token 历史条数上限。

并且更多的token也意味更多的费用, 更久的解析时间. 所以不建议太长
(DEFAULT_MAX_MESSAGES默认20即10次对话)
一旦超出DEFAULT_MAX_MESSAGES只会存最后面N条(可以理解为先进先出),参考MessageWindowChatMemory源码

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Bean</span>
   ChatMemory <span style="color:#b75501">chatMemory</span>(<span style="color:#015692">@Autowired</span> ChatMemoryRepository chatMemoryRepository) {
<span style="color:#656e77">// MessageWindowChatMemory 创建一个历史对话存储的配置,</span>
        <span style="color:#015692">return</span> MessageWindowChatMemory
                .builder()
                .maxMessages(<span style="color:#b75501">10</span>)  <span style="color:#656e77">// 设置最大存储 10 条</span>
                .chatMemoryRepository(chatMemoryRepository).build();
    }
</code></span></span>

配置多用户隔离记忆

如果有多个用户在进行对话, 肯定不能将对话记录混在一起, 不同的用户的对话记忆需要隔离

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testChatOptions</span>() {
        <span style="color:#b75501">String</span> <span style="color:#54790d">content</span> <span style="color:#ab5656">=</span> chatClient.prompt()
                .user(<span style="color:#54790d">"我叫徐庶 ?"</span>)
        <span style="color:#656e77">// 注意:这里要先构建一个 ChatMemory的 Bean,和上面类似,这里我们设置历史对话的用户ID</span>
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,<span style="color:#54790d">"1"</span>))
                .call()
                .content();
        System.out.println(content);
        System.out.println(<span style="color:#54790d">"--------------------------------------------------------------------------"</span>);

        content = chatClient.prompt()
                .user(<span style="color:#54790d">"我叫什么 ?"</span>)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,<span style="color:#54790d">"1"</span>))
                .call()
                .content();
        System.out.println(content);


        System.out.println(<span style="color:#54790d">"--------------------------------------------------------------------------"</span>);

        content = chatClient.prompt()
                .user(<span style="color:#54790d">"我叫什么 ?"</span>)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,<span style="color:#54790d">"2"</span>))
                .call()
                .content();
        System.out.println(content);
    }
</code></span></span>

会发现, 不同的CONVERSATION_ID,会有不同的记忆

原理源码$

主要有前置存储
MessageWindowChatMemory
具体存储实现
ChatMemoryRepository

数据库存储对话记忆

默认情况, 对话内容会存在jvm内存会导致:

  1. 一直存最终会撑爆JVM导致OOM。
  2. 重启就丢了, 如果已想存储到第三方存储进行持久化

springAi内置提供了以下几种方式(例如 Cassandra、JDBC 或 Neo4j), 这里演示下JDBC方式

  1. 添加依赖
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-xml">        <<span style="color:#b75501">dependency</span>>
            <<span style="color:#b75501">groupId</span>>org.springframework.ai</<span style="color:#b75501">groupId</span>>
            <<span style="color:#b75501">artifactId</span>>spring-ai-starter-model-chat-memory-repository-jdbc</<span style="color:#b75501">artifactId</span>>
        </<span style="color:#b75501">dependency</span>>

        <span style="color:#656e77"><!--jdbc--></span>
        <<span style="color:#b75501">dependency</span>>
            <<span style="color:#b75501">groupId</span>>org.springframework.boot</<span style="color:#b75501">groupId</span>>
            <<span style="color:#b75501">artifactId</span>>spring-boot-starter-jdbc</<span style="color:#b75501">artifactId</span>>
        </<span style="color:#b75501">dependency</span>>


        <span style="color:#656e77"><!--mysql驱动--></span>
        <<span style="color:#b75501">dependency</span>>
            <<span style="color:#b75501">groupId</span>>com.mysql</<span style="color:#b75501">groupId</span>>
            <<span style="color:#b75501">artifactId</span>>mysql-connector-j</<span style="color:#b75501">artifactId</span>>
            <<span style="color:#b75501">scope</span>>runtime</<span style="color:#b75501">scope</span>>
        </<span style="color:#b75501">dependency</span>>
</code></span></span>
  1. 添加配置(目前我们的需要创建一个schema-mysql.sql 文件,就是一个 SQL 脚本,在后面有配置)SPRING_AI_CHAT_MEMORY 表存储用户的历史对话,数据库,我们自行定义将该数据表存储到那个数据库中即可。
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-properties"><span style="color:#015692">spring.ai.chat.memory.repository.jdbc.initialize-schema</span>=<span style="color:#54790d">always</span>
<span style="color:#015692">spring.ai.chat.memory.repository.jdbc.schema</span>=<span style="color:#54790d">classpath:/schema-mysql.sql</span>
</code></span></span>

如下是 MySQL 的配置:

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-yaml"><span style="color:#015692">spring:</span>
  <span style="color:#015692">datasource:</span>
    <span style="color:#015692">username:</span> <span style="color:#54790d">root</span>
    <span style="color:#015692">password:</span> <span style="color:#b75501">123456</span>
    <span style="color:#015692">url:</span> <span style="color:#54790d">jdbc:mysql://localhost:3306/springai?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&</span>
    <span style="color:#015692">driver-class-name:</span> <span style="color:#54790d">com.mysql.cj.jdbc.Driver</span>
</code></span></span>
  1. 配置类
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Configuration</span>
<span style="color:#015692">public</span> <span style="color:#015692">class</span> <span style="color:#b75501">ChatMemoryConfig</span> {


    <span style="color:#015692">@Bean</span>  <span style="color:#656e77">// JdbcChatMemoryRepository 是已经被封装好自动装配好了,就可以使用</span>
    ChatMemory <span style="color:#b75501">chatMemory</span>(<span style="color:#015692">@Autowired</span> JdbcChatMemoryRepository chatMemoryRepository) {
        <span style="color:#015692">return</span> MessageWindowChatMemory
        .builder()
        .maxMessages(<span style="color:#b75501">1</span>)  <span style="color:#656e77">// 设置存储为上面我们传的变量的 jdbc 的存储方式</span>
        .chatMemoryRepository(chatMemoryRepository).build();
    }

}
</code></span></span>
  1. resources/schema-mysql.sql(目前1.0.0版本需要自己定义,没有提供脚本),创建这个SPRING_AI_CHAT_MEMORY 数据表,来存储用户的历史对话
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java">CREATE TABLE IF NOT EXISTS <span style="color:#b75501">SPRING_AI_CHAT_MEMORY</span> (
    `conversation_id` VARCHAR(<span style="color:#b75501">36</span>) NOT NULL,
    `content` TEXT NOT NULL,
    `type` VARCHAR(<span style="color:#b75501">10</span>) NOT NULL,
    `timestamp` TIMESTAMP NOT NULL,

    INDEX `SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX` (`conversation_id`, `timestamp`)
    );
</code></span></span>
  1. 测试
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@SpringBootTest</span>
<span style="color:#015692">public</span> <span style="color:#015692">class</span> <span style="color:#b75501">ChatMemoryTest</span> {


    ChatClient chatClient;
    <span style="color:#015692">@BeforeEach</span>
    <span style="color:#015692">public</span>  <span style="color:#015692">void</span> <span style="color:#b75501">init</span>(<span style="color:#015692">@Autowired</span>
                      DeepSeekChatModel chatModel,
                      <span style="color:#015692">@Autowired</span>
                      ChatMemory chatMemory) {
        chatClient = ChatClient
                .builder(chatModel)
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(chatMemory).build()
                )
                .build();
    }
    <span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testChatOptions</span>() {
        <span style="color:#b75501">String</span> <span style="color:#54790d">content</span> <span style="color:#ab5656">=</span> chatClient.prompt()
                .user(<span style="color:#54790d">"你好,我叫徐庶!"</span>)
                .advisors(<span style="color:#015692">new</span> <span style="color:#b75501">ReReadingAdvisor</span>())
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,<span style="color:#54790d">"1"</span>))
                .call()
                .content();
        System.out.println(content);
        System.out.println(<span style="color:#54790d">"--------------------------------------------------------------------------"</span>);

        content = chatClient.prompt()
                .user(<span style="color:#54790d">"我叫什么 ?"</span>)
                .advisors(<span style="color:#015692">new</span> <span style="color:#b75501">ReReadingAdvisor</span>())
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,<span style="color:#54790d">"1"</span>))
                .call()
                .content();
        System.out.println(content); 
    }
}
</code></span></span>

可以看到由于我设置.maxMessages(1)数据库只存一条

扩展:其实我可以让其存储到我们的所有历史对话,因为数据库就是存储数据的吗,而且存储起来的数据可能还是可以用于我们分析测试用户的对话的。那我们取数据库的时候,可以获取最新一条的数据即可。

Redis存储

如果你想用redis , 你需要自己实现ChatMemoryRepository接口(自己实现增、删、查)

Redis 存储更快,我们如果一般就是仅仅只是临时存储用户的 100 条记录什么的,就存到 Redis 当中就好了,超过了 100 条记录,也是会存储到用户最新的那 100 条记录,后续的内容也不用持久化了,丢了就丢了,反正都是用户的一个临时历史对话记录而已。性能也是比 MySQL 更快的。

但是alibaba-ai有现成的实现:(还包括ES)

https://github.com/alibaba/spring-ai-alibaba/tree/main/community/memories

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-xml">      <<span style="color:#b75501">properties</span>>
        <<span style="color:#b75501">jedis.version</span>>5.2.0</<span style="color:#b75501">jedis.version</span>>
      </<span style="color:#b75501">properties</span>>
      
      <<span style="color:#b75501">dependency</span>>
        <<span style="color:#b75501">groupId</span>>com.alibaba.cloud.ai</<span style="color:#b75501">groupId</span>>
        <<span style="color:#b75501">artifactId</span>>spring-ai-alibaba-starter-memory-redis</<span style="color:#b75501">artifactId</span>>
      </<span style="color:#b75501">dependency</span>>
      
      
      <<span style="color:#b75501">dependency</span>>
        <<span style="color:#b75501">groupId</span>>redis.clients</<span style="color:#b75501">groupId</span>>
        <<span style="color:#b75501">artifactId</span>>jedis</<span style="color:#b75501">artifactId</span>>
        <<span style="color:#b75501">version</span>>${jedis.version}</<span style="color:#b75501">version</span>>
      </<span style="color:#b75501">dependency</span>>
</code></span></span>
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-yaml"><span style="color:#015692">spring:</span>
  <span style="color:#015692">ai:</span>
    <span style="color:#015692">memory:</span>
      <span style="color:#015692">redis:</span>
        <span style="color:#015692">host:</span> <span style="color:#54790d">localhost</span>
        <span style="color:#015692">port:</span> <span style="color:#b75501">6379</span>
        <span style="color:#015692">timeout:</span>  <span style="color:#b75501">5000</span>
        <span style="color:#015692">password:</span>
</code></span></span>
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Configuration</span>
<span style="color:#015692">public</span> <span style="color:#015692">class</span> <span style="color:#b75501">RedisMemoryConfig</span> {

    <span style="color:#015692">@Value("${spring.ai.memory.redis.host}")</span>
    <span style="color:#015692">private</span> String redisHost;
    <span style="color:#015692">@Value("${spring.ai.memory.redis.port}")</span>
    <span style="color:#015692">private</span> <span style="color:#b75501">int</span> redisPort;
    <span style="color:#015692">@Value("${spring.ai.memory.redis.password}")</span>
    <span style="color:#015692">private</span> String redisPassword;
    <span style="color:#015692">@Value("${spring.ai.memory.redis.timeout}")</span>
    <span style="color:#015692">private</span> <span style="color:#b75501">int</span> redisTimeout;

    <span style="color:#015692">@Bean</span>
    <span style="color:#015692">public</span> RedisChatMemoryRepository <span style="color:#b75501">redisChatMemoryRepository</span>() {
        <span style="color:#015692">return</span> RedisChatMemoryRepository._builder_()
                .host(redisHost)
                .port(redisPort)
                <span style="color:#656e77">// 若没有设置密码则注释该项</span>
<span style="color:#656e77">//           .password(redisPassword)</span>
                .timeout(redisTimeout)
                .build();
    }


    
    <span style="color:#015692">@Bean</span>  <span style="color:#656e77">// RedisChatMemoryRepository 被我们上面 Bean 注入了</span>
    ChatMemory <span style="color:#b75501">chatMemory</span>(<span style="color:#015692">@Autowired</span> RedisChatMemoryRepository redisMemoryRepository) {
        <span style="color:#015692">return</span> MessageWindowChatMemory
        .builder()
        .maxMessages(<span style="color:#b75501">1</span>)  <span style="color:#656e77">// 设置存储为上面我们传的变量的 jdbc 的存储方式</span>
        .chatMemoryRepository(redisMemoryRepository).build();
    }
}
</code></span></span>

多层次记忆架构 痛点

记忆多=聪明(大模型记录了多了用户的历史对话记录,就更加能够理解我们,实现我们的需求了), 但是记忆多会触发 token 上限(每个大模型的 token 是有上限的,不可以无限的存储。)

要知道, 无论你用什么存储对话以及, 也只能保证服务端的存储性能。

但是一旦聊天记录多了依然会超过token上限, 但是有时候我们依然希望存储更多的聊天记录,这样才能保证整个对话更像“人”。

多层次记忆架构(模仿人类)

  • 近期记忆:保留在上下文窗口中的最近几轮对话,每轮对话完成后立即存储(可通过ChatMemory); 10 条
  • 中期记忆:通过RAG检索的相关历史对话(每轮对话完成后,异步将对话内容转换为向量并存入向量数据库) 5条
  • 长期记忆:关键信息的固化总结
    • 方式一:定时批处理
      + 通过定时任务(如每天或每周)对积累的对话进行总结和提炼
      + 提取关键信息、用户偏好、重要事实等
      + 批处理方式降低计算成本,适合大规模处理
    • 方式二:关键点实时处理
      + 在对话中识别出关键信息点时立即提取并存储
      + 例如,当用户明确表达偏好、提供个人信息或设置持久性指令时

结构化输出

基础类型:

以Boolean为例 , 在 agent 中可以用于判定用于的内容2个分支, 不同的分支走不同的逻辑

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java">ChatClient chatClient;
<span style="color:#015692">@BeforeEach</span>
<span style="color:#015692">public</span>  <span style="color:#015692">void</span> <span style="color:#b75501">init</span>(<span style="color:#015692">@Autowired</span>
                  DashScopeChatModel chatModel) {
    chatClient = ChatClient.builder(chatModel).build();
}
<span style="color:#015692">@Test</span>
<span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testBoolOut</span>() {
    <span style="color:#b75501">Boolean</span> <span style="color:#54790d">isComplain</span> <span style="color:#ab5656">=</span> chatClient
    .prompt()
    .system(<span style="color:#54790d">"""
            请判断用户信息是否表达了投诉意图?
            只能用 true 或 false 回答,不要输出多余内容
            """</span>)
    .user(<span style="color:#54790d">"你们家的快递迟迟不到,我要退货!"</span>)
    .call()
    .entity(Boolean.class);  <span style="color:#656e77">// 结构化输出,让大模型输出 Boolean.class java当中的布尔值类型</span>

    <span style="color:#656e77">// 分支逻辑</span>
    <span style="color:#015692">if</span> (Boolean.TRUE.equals(isComplain)) {
        System.out.println(<span style="color:#54790d">"用户是投诉,转接人工客服!"</span>);
    } <span style="color:#015692">else</span> {
        System.out.println(<span style="color:#54790d">"用户不是投诉,自动流转客服机器人。"</span>);
        <span style="color:#656e77">// todo 继续调用 客服ChatClient进行对话</span>
    }
}
</code></span></span>

Pojo类型:

用购物APP应该见过复制一个地址, 自动为你填入每个输入框。 用大模型轻松完成!

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">public</span> <span style="color:#015692">record</span> <span style="color:#b75501">Address</span>(
    String name,        // 收件人姓名
    String phone,       // 联系电话
    String province,    // 省
    String city,        // 市
    String district,    // 区/县
    String detail       // 详细地址
) {}

<span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testEntityOut</span>() {
        <span style="color:#b75501">Address</span> <span style="color:#54790d">address</span> <span style="color:#ab5656">=</span> chatClient.prompt()
        <span style="color:#656e77">// .systemshi 是一个系统提示词,优先级更高</span>
                .system(<span style="color:#54790d">"""
                        请从下面这条文本中提取收货信息
                        """</span>)
                .user(<span style="color:#54790d">"收货人:张三,电话13588888888,地址:浙江省杭州市西湖区文一西路100号8幢202室"</span>)
                .call()
                .entity(Address.class);  <span style="color:#656e77">// 大模型会根据文本内容,将其中的用户的对话信息识别存储到我们的 Address的对象类</span>
        System.out.println(address);
    }
</code></span></span>
<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">public</span> <span style="color:#015692">record</span> <span style="color:#b75501">Address</span>(
    String name,        // 收件人姓名
    String phone,       // 联系电话
    String province,    // 省
    String city,        // 市
    String district,    // 区/县
    String detail       // 详细地址
) {}
</code></span></span>

原理

ChatModel或者直接使用低级API:

<span style="color:#000000"><span style="background-color:#fefef2"><code class="language-java"><span style="color:#015692">@Test</span>
    <span style="color:#015692">public</span> <span style="color:#015692">void</span> <span style="color:#b75501">testLowEntityOut</span>(
           <span style="color:#015692">@Autowired</span> DashScopeChatModel chatModel) {
        <span style="color:#656e77">// BeanOutputConverter 转换器</span>
        BeanOutputConverter<ActorsFilms> beanOutputConverter =
                <span style="color:#015692">new</span> <span style="color:#b75501">BeanOutputConverter</span><>(ActorsFilms.class);

        <span style="color:#b75501">String</span> <span style="color:#54790d">format</span> <span style="color:#ab5656">=</span> beanOutputConverter.getFormat();

        <span style="color:#b75501">String</span> <span style="color:#54790d">actor</span> <span style="color:#ab5656">=</span> <span style="color:#54790d">"周星驰"</span>;

        <span style="color:#b75501">String</span> <span style="color:#54790d">template</span> <span style="color:#ab5656">=</span> <span style="color:#54790d">"""
        提供5部{actor}导演的电影.
        {format}
        """</span>;

        <span style="color:#b75501">PromptTemplate</span> <span style="color:#54790d">promptTemplate</span> <span style="color:#ab5656">=</span> PromptTemplate.builder().template(template).variables(Map.of(<span style="color:#54790d">"actor"</span>, actor, <span style="color:#54790d">"format"</span>, format)).build();
        <span style="color:#b75501">ChatResponse</span> <span style="color:#54790d">response</span> <span style="color:#ab5656">=</span> chatModel.call(
                promptTemplate.create()
        );

        <span style="color:#b75501">ActorsFilms</span> <span style="color:#54790d">actorsFilms</span> <span style="color:#ab5656">=</span> beanOutputConverter.convert(response.getResult().getOutput().getText());
        System.out.println(actorsFilms);
    }</code></span></span>
Logo

更多推荐