LangChain4j调用大模型

1.会话功能

1.1 spring整合LangChain4j

1.构建springboot项目

2.引入起步依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

3.application.yml中配置大模型

langchain4j:
  open-ai:
    chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}  # 替换成你的真实 API Key 或使用环境变量
      model-name: qwen-plus

4.开发接口,调用大模型

@RestController
public class ChatController {

    @Autowired
    private OpenAiChatModel model;

    @RequestMapping("/chat")
    public String chat(String message) {
        return model.chat(message);
    }
}

注:如果要打印日志,配置文件如下:

langchain4j:
  open-ai:
    chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: qwen-plus
      log-requests: true
      log-responses: true

logging:
  level:
    dev.langchain4j: debug
1.2 使用Aiservice工具类进行构建

手动注册为配置类

1.引入依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-spring-boot-starter</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

2.声明接口

public interface ConsultantService {
    /**
     * 与 AI 顾问进行聊天。
     *
     * @param message 用户输入的内容
     * @return AI 返回的回复内容
     */
    String chat(String message);
}

3.使用AiServices为接口创建代理对象

@Configuration
public class CommonConfig {

    @Autowired
    private OpenAiChatModel model;

    @Bean
    public ConsultantService consultantService() {
        return AiServices.builder(ConsultantService.class)
                         .chatModel(model)
                         .build();
    }
}

4.在Controller中注入并使用

@RestController
public class ChatController {

    @Autowired
    private ConsultantService consultantService;

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return consultantService.chat(message);
    }
}

使用注解自动注入:

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel"
)
public interface ConsultantService {

    /**
     * 用于聊天的方法,message为用户输入的内容
     * @param message 用户输入消息
     * @return AI回复
     */
    String chat(String message);
}
1.3 流式调用
传统调用流式调用
等待时间较长,结果一次返回响应实时输出,快速呈现结果
体验像“发送 - 等待”体验像“边说边听”
不适合对话、文本生成等长内容非常适合聊天机器人、文本生成、语音合成等应用

1.引入依赖

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

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

2.配置流式模型对象

langchain4j:
  open-ai:
    streaming-chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: qwen-plus
      log-requests: true
      log-responses: true

3.切换接口中方法的返回值类型

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAistreamingChatModel"
)
public interface ConsultantService {
    /**
     * 流式聊天接口,返回响应流
     *
     * @param message 用户输入消息
     * @return 响应文本流
     */
    Flux<String> chat(String message);
}

4.修改Controller中的代码

1.4 消息注解
1.@SystemMessage

相当于:“你是XXX的管家。” —— 模型的身份和行为指导

@SystemMessage("你是XXX的管家")
public Flux<String> chat(String message);

@SystemMessage(fromResource = "system.txt")
public Flux<String> chat(String message);
2.@UserMessage

相当于:模型收到的用户输入是“你是XXX的管家。[用户传入内容]”。

@UserMessage("你是XXX的管家,{{it}}")
public Flux<String> chat(String message);

@UserMessage("你是XXX的管家,{{msg}}")
public Flux<String> chat(@V("msg") String message);
1.5 会话记忆

大模型是不具备记忆能力的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起发给大模型。

在这里插入图片描述

1.定义会话记忆对象

@Configuration
public class ChatMemoryConfig {

@Bean
public ChatMemory chatMemory() {
    return MessageWindowChatMemory.builder()
            .maxMessages(20)
            .build();
    }
}

2.配置会话记忆对象

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel",
    chatMemory = "chatMemory"
)
public interface ConsultantService {
    @SystemMessage(fromResource = "system.txt")
    Flux<String> chat(String message);
}
1.6 会话记忆隔离

1.定义会话记忆对象提供者

2.配置会话记忆对象提供者

@Configuration
public class ChatMemoryProviderConfig {

@Bean
public ChatMemoryProvider chatMemoryProvider() {
    return new ChatMemoryProvider() {
        @Override
        public ChatMemory get(Object memoryId) {
            return MessageWindowChatMemory.builder()
                    .id(memoryId)
                    .maxMessages(20)
                    .build();
        }
    };
}

3.ConsultantService接口方法中添加参数memoryId

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel",
    chatMemoryProvider = "chatMemoryProvider"
)
public interface ConsultantService {
     @SystemMessage(fromResource = "system.txt")
    Flux<String> chat(
        @MemoryId String memoryId,
        @UserMessage String message
    );
}

4.Controller中chat接口接收memoryId

1.7 会话记忆持久化

1.准备redis环境

2.引入redis起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.配置redis连接信息

spring:
  data:
    redis:
      host: localhost
      port: 6379

4.提供ChatMemoryStore实现类

@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        String messages = stringRedisTemplate.opsForValue().get(memoryId.toString());
        List<ChatMessage> chatMessages = ChatMessageDeserializer.messagesFromJson(messages);
        return chatMessages;
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> list) {
        String messages = ChatMessageSerializer.messagesToJson(list);
        stringRedisTemplate.opsForValue().set(memoryId.toString(),messages, Duration.ofDays(1));
    }

    @Override
    public void deleteMessages(Object memoryId) {
        stringRedisTemplate.delete(memoryId.toString());
    }
}

5.配置ChatMemoryStore

 private final RedisChatMemoryStore redisChatMemoryStore;

//构建会话记忆对象提供者
    @Bean
    public ChatMemoryProvider chatMemoryProvider(){
        ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {
            @Override
            public ChatMemory get(Object memoryId) {
                MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                        .id(memoryId)
                        .maxMessages(20)
                        .chatMemoryStore(redisChatMemoryStore)
                        .build();
                return memory;
            }
        };
        return chatMemoryProvider;
    }

2.RAG知识库

RAG, Retrieval Augmented Generation, 检索增强生成。通过检索外部知识库的方式增强大模型的生成能力

在这里插入图片描述

2.1 原理:

向量:是数学和物理学中表示大小和方向的量

代数表示:坐标表示,在直角坐标系中,向量可以用一组坐标来表示。
在这里插入图片描述

重点:余弦相似度越大,说明向量方向越接近,两点之间的距离越小

向量数据库: Milvus、Chroma、Pinecone RedisSearch(Reids)、pgvector(PostgreSQL)

在这里插入图片描述

在这里插入图片描述

借助于向量模型,把文档知识数据向量化后存储到向量数据库用户输入的内容,借助于向量模型转化为向量后,与数据库中的向量通过计算余弦相似度的方式,找出相似度比较高的文本片段

在这里插入图片描述

余弦相似度越大,说明向量方向越接近,两点之间的距离越小

由于RAG中,向量都是由文本转换过来的,不同文本对应的向量余弦相似度越大,距离越近文本相似度越高
在这里插入图片描述

2.2 快速入门

在这里插入图片描述

1.存储(构建向量数据库操作对象)

引入依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-easy-rag</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

加载知识数据文档

List<Document> documents = ClassPathDocumentLoader.loadDocuments(“文档路径");

文档加载器,用于把磁盘或者网络中的数据加载进程序

FileSystemDocumentLoader, 根据本地磁盘绝对路径加载

ClassPathDocumentLoader,相对于类路径加载

UrlDocumentLoader,根据url路径加载

文档解析器,用于解析使用文档加载器加载进内存的内容,把非纯文本数据转化成纯文本

TextDocumentParser,解析纯文本格式的文件

ApachePdfBoxDocumentParser,解析pdf格式文件

ApachePoiDocumentParser,解析微软的office文件,例如DOC、PPT、

XLSApacheTikaDocumentParser(默认),几乎可以解析所有格式的文件

例如pdf:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
    <version>1.0.1-beta6</version>
</dependency>
ClassPathDocumentLoader.loadDocuments(“文档路径",new ApachePdfBoxDocumentParser());

构建向量数据库操作对象

InMemoryEmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();

把文档切割、向量化并存储到向量数据库中

EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(store)
        .build();
ingestor.ingest(documents);

整个存储配置:

//构建向量数据库操作对象
    @Bean
    public EmbeddingStore store(){//直接使用embeddingStore可能会报错,与本来就有的默认名冲突
        //1.加载文件
        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content",new ApachePdfBoxDocumentParser());
        //2.构建向量数据库操作对象
        InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
        //构建文本分割器
        DocumentSplitter ds = DocumentSplitters.recursive(500, 100);
        //3.构建一个EmbeddingStoreIngestor对象,完成文本数据切割,向量化,存储
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
//                .embeddingStore(redisEmbeddingStore)
                .embeddingStore(store)
                .embeddingModel(embeddingModel)
                .documentSplitter(ds)
                .build();
        ingestor.ingest(documents);
        return store;
    }

文档分割器,用于把一个大的文档,切割成一个一个的小片段

类名说明
DocumentByParagraphSplitter按照段落分割文本(通常以空行或段落标记为界)
DocumentByLineSplitter按照分割文本(按 \n 或换行符)
DocumentBySentenceSplitter按照句子分割文本(通常基于标点如 ., !, ?
DocumentByWordSplitter按照分割文本(基于空格或分词)
DocumentByCharacterSplitter按照固定数量的字符分割文本(可指定每块字符数)
DocumentByRegexSplitter按照正则表达式匹配进行分割
DocumentSplitters.recursive(...)递归切分器(默认推荐):依次尝试按段落 → 行 → 句子 → 词分割,直到满足块大小要求。
DocumentSplitter documentSplitter = DocumentSplitters.recursive(
        // 每个片段最大容纳的字符数
        maxChunkSize,
        // 两个片段之间重叠字符的个数(overlap)
        overlapSize
);
2.检索(构建向量数据库检索对象)

构建向量数据库检索对象

//构建向量数据库检索对象
    @Bean
    public ContentRetriever contentRetriever(EmbeddingStore store){
        return EmbeddingStoreContentRetriever.builder()
//                .embeddingStore(redisEmbeddingStore)
                .embeddingStore(store)
                .embeddingModel(embeddingModel)
                .maxResults(3)
                .minScore(0.5)
                .build();
    }

配置向量数据库检索对象

@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,
        chatModel = "openAiChatModel",
        contentRetriever = "contentRetriever"
)
3.向量模型

用于把文档分割后的片段向量化或者查询时把用户输入的内容向量化

langchain4j:
  open-ai:
    embedding-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: text-embedding-v3
      log-requests: true
      log-responses: true
      max-segments-per-batch: 10
EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(store)              // 指定向量存储
        .embeddingModel(embeddingModel)    // 指定用于计算向量的嵌入模型
        .maxResults(3)                     // 最多返回3个相似内容
        .minScore(0.6)                     // 最小相似度阈值为0.6
        .build();
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(store)                      // 设置向量存储
        .documentSplitter(documentSplitter)        // 设置文档分割器
        .embeddingModel(embeddingModel)            // 设置嵌入模型
        .build();
2.3 使用向量数据库

准备向量数据库

引入依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-redis-spring-boot-starter</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

配置向量数据库信息

langchain4j:
  community:
    redis:
      host: localhost
      port: 6379

注入RedisEmbeddingStore并使用

EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(store)              // 指定向量存储
        .embeddingModel(embeddingModel)    // 指定用于计算向量的嵌入模型
        .maxResults(3)                     // 最多返回3个相似内容
        .minScore(0.6)                     // 最小相似度阈值为0.6
        .build();
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(store)                      // 设置向量存储
        .documentSplitter(documentSplitter)        // 设置文档分割器
        .embeddingModel(embeddingModel)            // 设置嵌入模型
        .build();

3.Tools工具

在这里插入图片描述

在这里插入图片描述

1.准备工具方法

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    tools = "reservationTool"
)

2.配置工具方法

@Component
public class ReservationTool {

    @Autowired
    private ReservationService reservationService;

    @Tool("添加志愿指导服务预约")
    public void addReservation(
            @P("考生姓名") String name,
            @P("考生性别") String gender,
            @P("考生电话") String phone,
            @P("沟通时间") LocalDateTime communicationTime,
            @P("考生所在省份") String province,
            @P("考生预估分数") Integer estimatedScore) {
        reservationService.insert(
            new Reservation(null, name, gender, phone, communicationTime, province, estimatedScore)
        );
    }

    @Tool("根据考生电话查询考生预约详情")
    public Reservation findReservation(@P("考生电话") String phone) {
        return reservationService.findByPhone(phone);
    }
}

ionService;

@Tool("添加志愿指导服务预约")
public void addReservation(
        @P("考生姓名") String name,
        @P("考生性别") String gender,
        @P("考生电话") String phone,
        @P("沟通时间") LocalDateTime communicationTime,
        @P("考生所在省份") String province,
        @P("考生预估分数") Integer estimatedScore) {
    reservationService.insert(
        new Reservation(null, name, gender, phone, communicationTime, province, estimatedScore)
    );
}

@Tool("根据考生电话查询考生预约详情")
public Reservation findReservation(@P("考生电话") String phone) {
    return reservationService.findByPhone(phone);
}

}


Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐