LangChain4j基础功能

SpringBoot整合LangChain4j

引入依赖

<!--langchain4j起步依赖-->
<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
  <version>1.1.0-beta7</version>
</dependency>

配置大模型

在配置文件application.yml中配置大模型

各类参数可通过服务商官方文档查询

SpringBoot 将自动为 OpenAiChatModel 注入参数

langchain4j:
  open-ai:
    chat-model:
      base-url: https://api.deepseek.com # 接口地址
      api-key: xxxxxxxxx # 秘钥
      model-name: deepseek-chat # 模型名称
      log-requests: true # 请求日志记录
      log-responses: true # 响应日志记录

快速开始

通过配置文件已经自动为对话模型注入了参数,在 Controller 层中尝试直接调用

@RestController
public class ChatController {

    @Autowired
    private OpenAiChatModel model;

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

}

AI Service

AI Service 封装 model 对象与会话记忆、RAG知识库、Tools工具等部件,使得每次调用对话方法时不需要手动依次装配

基本使用

引入AI Service 依赖

<!--AiServices依赖-->
<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-spring-boot-starter</artifactId>
  <version>1.1.0-beta7</version>
</dependency>

声明 AI Service 接口

public interface DemoService {

    String demoChat(String userMessage);

}

为接口创建代理对象

通过配置类构建代理对象

@Configuration
public class CommonAiConfig {

    @Autowired
    private OpenAiChatModel chatModel;

    @Bean
    public DemoService demoService() {
        return AiServices.builder(DemoService.class)
                .chatModel(chatModel)
                .build();
    }

}

在 Controller 中注入并使用

直接注入Service对象使用即可

@RestController
public class ChatController {

    @Resource
    private DemoService demoService;

    @RequestMapping("/chat-service")
    public String chatService(String userMessage) {
        return demoService.demoChat(userMessage);
    }

}

@AiService注解

在 Service 接口上添加 @AiService 注解,自动为 service 接口装配,也可以指定手动装配

若使用注解完成装配,则不需要再编写配置类进行代理对象的构建

手动装配:

@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
        chatModel = "openAiChatModel"
)
public interface DemoService {

    String demoChat(String userMessage);

}

自动装配:

@AiService
public interface DemoService {

    String demoChat(String userMessage);

}

流式调用

引入依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-reactor</artifactId>
  <version>1.1.0-beta7</version>
</dependency>

配置流式调用模型

在配置文件中新增流式模型的配置参数

SpringBoot 自动注入 OpenAiStreamingChatModel 对象

langchain4j:
  open-ai:
    streaming-chat-model:
      base-url: https://api.deepseek.com
      api-key: sk-0802c3e7747d4baf820656e5122dc293
      model-name: deepseek-chat
      log-requests: true # 请求日志记录
      log-responses: true # 响应日志记录

流式接口

在 @AiService 注解中指定流式调用模型openAiStreamingChatModel,将接口返回类型改为Flux<String>

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel"
)
public interface DemoService {

    Flux<String> demoChat(String userMessage);

}

修改 Controller 中的返回类型

添加produces = "text/html;charset=utf-8"防止编码错误

@RestController
public class ChatController {

    @Resource
    private DemoService demoService;

    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
    public Flux<String> chatService(String userMessage) {
        return demoService.demoChat(userMessage);
    }

}

消息注解

注意系统提示词与用户提示词对于 AI 模型的影响能力具有实质的区别。系统提示词影响权重更高

@SystemMessage

在Service接口前使用,设置系统提示词

1.直接指定提示词:

@SystemMessage("系统指定提示词")
Flux<String> demoChat2(String userMessage);

2.通过fromResource指定文件名:

首先在 resouces 目录下新建 prompt 目录存放提示词,再

@SystemMessage(fromResource = "prompt/SystemPrompt1.txt")
Flux<String> demoChat3(String userMessage);

@UserMessage

在Service接口前使用,设置用户提示词

@SystemMessage(fromResource = "prompt/SystemPrompt1.txt")
@UserMessage("用户提示词xxxxxxxxxx")
Flux<String> demoChat3(String userMessage);

同样,用户提示词也可以使用fromResource指定文件名

占位符

1)接口只含单个参数:使用{{it}}放置于系统提示词或用户提示词中的指定位置站位,在调用接口前会自动将占位符替换为对应的参数

2)接口含有多个参数:需要使用@V注解为接口中的参数命名,同时将站位符中的“it”替换为注解新定义的名称

注意:对于一个接口,尽管@V注解可以用于@SystemMessage也可以用于@UserMessage,但只要使用了@V就必须使用@UserMessage注解,否则会发生 500 错误

@SystemMessage(fromResource = "prompt/SystemPrompt1.txt")
@UserMessage("用户提示词{{msg1}}xxxxxxx{{msg2}}")
Flux<String> demoChat4(@V("msg1") String userMessage1, @V("msg2") String userMessage2);

会话记忆

大模型不具有会话记忆功能,唯一的方法就是将之前的聊天记录和本次提问一起发送给大模型

会话记忆对象(存储于内存)

ChatMemory源码

public interface ChatMemory {
    Object id();// 会话记忆存储对象的唯一标识

    void add(ChatMessage var1);//  增加一条会话记录

    default void add(ChatMessage... messages) {
        if (messages != null && messages.length > 0) {
            this.add((Iterable)Arrays.asList(messages));
        }

    }

    default void add(Iterable<ChatMessage> messages) {
        if (messages != null) {
            messages.forEach(this::add);
        }

    }

    List<ChatMessage> messages();// 获取所有会话记录

    void clear();//清除所有会话记录
}

配置并使用会话记忆对象

编写会话记忆配置类,对会话记忆进行配置

@Configuration
public class ChatMemoryConfig {

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

}

@AIService指定会话记忆对象

@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
        chatModel = "openAiChatModel",
        chatMemory = "chatMemoryDemo"// 指定会话记忆对象
)
public interface DemoService {

    @SystemMessage("系统指定提示词")
    Flux<String> demoChat(String userMessage);

}

会话记忆隔离

定义并使用会话记忆提供者

1.编写会话记忆提供者配置类:

不再需要定义和配置ChatMemory对象

@Configuration
public class ChatMemoryProviderConfig {

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

}

2.在AI Service中使用会话记忆提供者:

对于AI Service接口中的参数,若包含@MemoryId注解时,用户消息必须添加@UserMessage注解

@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
        chatModel = "openAiChatModel",
        streamingChatModel = "openAiStreamingChatModel",
        //chatMemory = "chatMemoryDemo",// 指定对话记忆对象
        chatMemoryProvider = "chatMemoryProvider"
)
public interface DemoService {

    Flux<String> demoChat(@MemoryId String memoryId,
                          @UserMessage String userMessage);
}

3.在 Controller 层中接收 memoryId:

@RestController
public class ChatController {

    @Resource
    private DemoService demoService;

    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
    public Flux<String> chatService(String memoryId, String userMessage) {
        return demoService.demoChat(memoryId, userMessage);
    }

}

会话记忆持久化

MessageWindowChatMemory源码使用ChatMemoryStore进行存储,会话记忆存储在JVM的内存中

public class MessageWindowChatMemory implements ChatMemory {
    private final Object id;
    private final Integer maxMessages;
    private final ChatMemoryStore store;
}

缓存

1)框架中含有RedisChatMemoryStore用于缓存对话消息,只需要配置Redis链接即可

public class RedisChatMemoryStore implements ChatMemoryStore {
    private final JedisPooled client;
    private final String keyPrefix;
    private final Long ttl;

2)Redis链接配置

@Configuration
@ConfigurationProperties(prefix = "spring.data.redis")
@Data
public class RedisChatMemoryStoreConfig {

    private String host;

    private int port;

    private String password;

    private long ttl;

    @Bean
    public RedisChatMemoryStore redisChatMemoryStore() {
        RedisChatMemoryStore.Builder builder = RedisChatMemoryStore.builder()
                .host(host)
                .port(port)
                .password(password)
                .ttl(ttl);
        if (StrUtil.isNotBlank(password)) {
            builder.user("default");
        }
        return builder.build();
    }

}

3)创建chatMemory对象时为其chatMemoryStore组件添加redisChatMemoryStore

MessageWindowChatMemory chatMemory = MessageWindowChatMemory
        .builder()
        .id(appId)
        .chatMemoryStore(redisChatMemoryStore)
        .maxMessages(20)
        .build();

持久化

使用MySQL存储每轮对话记忆即可

-- 对话历史表
create table chat_history
(
    id          bigint auto_increment comment 'id' primary key,
    message     text                               not null comment '消息',
    messageType varchar(32)                        not null comment 'user/ai',
    appId       bigint                             not null comment '应用id',
    userId      bigint                             not null comment '创建用户id',
    createTime  datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    updateTime  datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    isDelete    tinyint  default 0                 not null comment '是否删除',
    INDEX idx_appId (appId),                       -- 提升基于应用的查询性能
    INDEX idx_createTime (createTime),             -- 提升基于时间的查询性能
    INDEX idx_appId_createTime (appId, createTime) -- 游标查询核心索引
) comment '对话历史' collate = utf8mb4_unicode_ci;

结构化输出

基础实现

直接定义目标 POJO 类并用于AI Service接口的返回类型,LangChain4j 框架会自动要求 AI 返回 JSON 格式内容,并自动将内容填充到对象中

LangChain4j 框架支持多种类型,参考官方文档:[https://docs.langchain4j.info/tutorials/structured-outputs]

示例:

record Person(String firstName, String lastName) {}

enum Sentiment {
    POSITIVE, NEGATIVE, NEUTRAL
}

interface Assistant {

    Person extractPersonFrom(String text);

    Sentiment extractSentimentFrom(String text);
}

稳定性优化

设置maxToken

LLM 通常设置有输出的最大 Token 数,若输出达到最大 Token 数时,JSON 格式的结果仍然没有输出完毕,则会发生截断,导致错误

示例:deepseek

langchain4j:
  open-ai:
    chat-model:
      max-tokens: 8129 # 设置最大Tokes,降低 JSON 解析错误

配置 json 格式返回要求

LLM 的官方文档通常会给出配置方法(构建 chatModel 或编写配置文件时添加)

示例:deepseek

langchain4j:
  open-ai:
    chat-model:
      strict-json-schema: true # 要求严格返回 JSON 格式字符串
      response-format: json_object # 要求严格返回 JSON 格式字符串

为 POJO 类添加字段描述

使用@Description注解,为类和字段添加详细描述

示例:

/**
 * HTML 生成结果
 */
@Data
@Description("生成 HTML 代码文件的结果")
public class HtmlCodeResult {

    /**
     * HTML 代码
     */
    @Description("HTML代码")
    private String htmlCode;
    /**
     * 描述
     */
    @Description("生成代码的描述")
    private String description;
}

系统提示词优化

prompt 严格规范LLM 的输出格式,精确到每一部分的格式,并要求以JSON格式返回字段

工具调用

工具定义

编写 AI 工具,使用@Tool描述方法,@P描述方法参数

@Slf4j
public class FileWriteTool {

    @Tool("写入文件到指定路径")
    public String writeFile(
            @P("文件的相对路径")
            String relativeFilePath,
            @P("要写入文件的内容")
            String content
    ) {
        // 具体实现
    }
}

工具装配

在构建 AI Service 时,使用.tools()方法将所有工具类对象装配

AiServices.builder(AiCodeGeneratorService.class)
                        .chatModel(chatModel)
                        .tools((Object[]) toolManager.getAllTools())// 绑定工具
                        .build();

稳定性优化

1.幻觉问题:

通过.hallucinatedToolNameStrategy()方法,处理 AI 出现幻觉调用不存在的工具的情况

2.无限循环:

通过.maxSequentialToolsInvocations()方法,设置工具调用次数上限,防止无限调用工具死循环

AiServices.builder(AiCodeGeneratorService.class)
                        .chatModel(chatModel)
                        .tools((Object[]) toolManager.getAllTools())// 绑定工具
                        .hallucinatedToolNameStrategy(toolExecutionRequest -> ToolExecutionResultMessage.from(
                                toolExecutionRequest, "Error: there is no tool called " + toolExecutionRequest.name()
                        ))// 当AI出现幻觉调用不存在的工具时的处理方法
                        .maxSequentialToolsInvocations(30)// 最多连续调用工具30次,防止无限循环
                        .build();

输入输出护轨

护轨

输入护轨:对用户提示词进行安全校验

输出护轨:对 AI 输出内容进行安全校验

实践

创建“输入护轨类”与“输出护轨”类,分别继承InputGuardrail接口与OutputGuardrail接口

输入:

/**
 * 输入护轨
 */
public class PromptSafetyInputGuardrail implements InputGuardrail {

    /**
     * 审查逻辑
     *
     * @param userMessage 用户消息
     * @return 是否通过
     */
    @Override
    public InputGuardrailResult validate(UserMessage userMessage) {
        // 校验业务
    }
}

输出:

/**
 * AI 输出护轨
 */
public class RetryOutputGuardrail implements OutputGuardrail {

    /**
     * AI 输出校验
     *
     * @param responseFromLLM AI 响应内容
     * @return 校验结果
     */
    @Override   
    public OutputGuardrailResult validate(AiMessage responseFromLLM) {
        // 校验业务
    }
}

装配:

在创建AIService对象时装配

AiServices.builder(AiCodeGeneratorService.class)
                        .chatModel(chatModel)
                        .inputGuardrails(new PromptSafetyInputGuardrail())// 添加输入护轨
                        .outputGuardrails(new RetryOutputGuardrail())// 添加输出护轨,为了流式输出这里不使用
                        .build();

RAG知识库

原理

概念

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

向量数据库:以向量的形式存储外部知识

向量相似度:两个向量夹角的余弦值。两个向量的余弦相似度越高,说明向量对应的文本相似度越高

存储过程

1)首先文本 Document 首先被文本分割器 Text Splitter 分割为文本片段 Segment

2)接着文本片段 Segment 被嵌入模型 Embdding Model 转化为向量片段 Embddings

3)最终文本片段 Segment 与 向量片段一起存储入向量数据库

检索过程

1)首先用户询问 Query 被嵌入模型 Embdding Model 转化为询问向量片段 Query Embdding

2)接着询问向量片段 Query Embdding进入向量数据库 Embdding Store 中检索出相关文本片段 Relevant Segment

3)最终用户询问 Query 与相关文本片段 Relevant Segment 一同交予大模型处理

快速开始(easy-RAG)

引入依赖

简易的内存向量数据库

<!--RAG-easy-->
<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-easy-rag</artifactId>
  <version>1.1.0-beta7</version>
</dependency>

存储

1)创建向量数据库操作对象ingestor,同时将创建的向量数据库embeddingStore交予操作对象

2)将读入的文档交予ingestor,将自动执行文档的切分、向量化、存储

/**
 * 向量数据库操作对象
 */
@Configuration
public class EmbeddingStoreConfig {

    /**
     * 配置向量数据库操作对象
     *
     * @return 向量数据库操作对象 Bean
     */
    @Bean
    public EmbeddingStore<TextSegment> embeddingStore() {
        // 1. 加载文档进内存(若为 null 则替换为空列表,避免后续 NPE)
        List<Document> documentList = ClassPathDocumentLoader.loadDocuments("content");
        // 2. 构建向量数据库操作对象(使用接口类型声明)
        EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
        // 3. 构建 EmbeddingStoreIngestor 并在有文档时执行切分/向量化/存储
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .embeddingStore(embeddingStore)
                .build();
        // 执行
        ingestor.ingest(documentList);
        // 4. 返回对象,交由 IOC 管理
        return embeddingStore;
    }

}

检索

构建向量数据库检索对象contentRetriever,同时设定部分参数

/**
 * 向量数据库检索对象
 */
@Configuration
public class ContentRetrieverConfig {

    /**
     * 向量数据库操作对象
     */
    @Resource
    private EmbeddingStore<TextSegment> store;

    /**
     * 配置向量数据库检索对象
     * @return 向量数据库检索对象 Bean
     */
    @Bean
    public ContentRetriever contentRetriever() {
        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(store)// 添加向量数据库操作对象
                .minScore(0.5)// 最小匹配程度
                .maxResults(3)// 最大结果条数
                .build();
    }

}

装配 AI Service 接口

将向量数据库检索对象contentRetriever装配至 AI Service 接口

@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
        chatModel = "openAiChatModel",
        contentRetriever = "contentRetriever"// 配置向量数据库检索对象
)
public interface DemoService {

    Flux<String> demoChat(@MemoryId String memoryId,
                          @UserMessage String userMessage);

}

核心 API

结构

EmbeddingStoreIngestor已经封装了具体的操纵,开发者只需选择装配时选择哪种文档分割器、向量模型、向量数据库操作对象

文档加载器Document Loader

文档加载器:用于将磁盘或网络中的数据加载进程序

部分加载器对象:

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

ClassPathDocumentLoader,相对于类路径加载

UrlDocumentLoader,根据url路径加载

文档解析器Document Parser

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

部分解析器对象:

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

ApachePdfBoxDocumentParser,解析pdf格式文件

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

尽管默认文件解析器能够解析几乎所有的文件,但对于特定文件如PDF文件,默认解析能力不如专门的PDF解析器

使用:

1)引入依赖

<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
  <version>1.1.0-beta7</version>
</dependency>

2)直接在读取文件方法后new出解析对象即可

List<Document> documentList = ClassPathDocumentLoader.loadDocuments("content",new ApachePdfBoxDocumentParser());

文本分割器Document Splitter

文本分割器:将一个大文档切割成一个个小片段

部分分割器对象:

DocumentByParagraphSplitter,按照段落分割文本

DocumentSplotters.recursive(...)(默认),递归分割器,优先按照段落划分,而后依次是按照行、句、词分割

使用方式:

1)构建文本分割器对象:设置每个片段最大字符数量,两相邻片段之间重叠字符个数

两相邻片段之间重叠字符个数:

目的:提高两个相邻片段的关联性,使得划分后不会出现断章取义问题

操作:将上一片段的后一小部分添加至下一片段的首部;将下一片段的前一小部分添加至上一片段的尾部

2)设置文本分割器对象

// 构建文本分割器,并分别设置片段长度与重复字符长度
DocumentSplitter documentSplitter = DocumentSplitters.recursive(500, 100);
// 3. 构建 EmbeddingStoreIngestor 并在有文档时执行切分/向量化/存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(embeddingStore)
.documentSplitter(documentSplitter)
.build();

向量模型EmbeddingModel

向量模型:把文档分割后的片段和用户输入内容向量化

1.配置向量模型信息:

langchain4j:
  open-ai:
    embedding-model:
      base-url: xxxx
      api-key: xxxx
      model-name: xxxx
      log-requests: true # 请求日志记录
      log-responses: true # 响应日志记录
      max-segments-per-batch: 10 # 每次发送的最大片段数量

2.设置EmbeddingModel:

分别注入向量模型并装配入向量数据库操作对象与检索对象

1)操作对象:

/**
 * 向量数据库操作对象
 */
@Configuration
public class EmbeddingStoreConfig {

    @Resource
    private EmbeddingModel embeddingModel;

    /**
     * 配置向量数据库操作对象
     *
     * @return 向量数据库操作对象 Bean
     */
    @Bean
    public EmbeddingStore<TextSegment> embeddingStore() {
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .embeddingModel(embeddingModel)
                .build();
        return embeddingStore;
    }

}

1)检索对象

/**
 * 向量数据库检索对象
 */
@Configuration
public class ContentRetrieverConfig {

    @Resource
    private EmbeddingModel embeddingModel;

    /**
     * 向量数据库操作对象
     */
    @Resource
    private EmbeddingStore<TextSegment> store;

    /**
     * 配置向量数据库检索对象
     * @return 向量数据库检索对象 Bean
     */
    @Bean
    public ContentRetriever contentRetriever() {
        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(store)// 添加向量数据库操作对象
                .minScore(0.5)// 最小匹配程度
                .maxResults(3)// 最大结果条数
                .embeddingModel(embeddingModel)
                .build();
    }

}

向量数据库操作对象EmbeddingStore(持久化向量数据库)

向量数据库操作对象:用户操作向量数据库(添加、检索)

注意:若要进行持久化,则不在使用InMemoryEmbeddingStore(操作内存数据库)

示例:

1)引入RedisEmbeddingStore依赖

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

2)配置

langchain4j:
  community:
    redis:
      host: xxxx
      port: 6379

3)注入并使用

操作对象:

注意已经使用外部向量数据库后,不在需要为操作对象添加Bean,防止每次运行都在此将全部数据向量化

/**
 * 向量数据库操作对象
 */
@Configuration
public class EmbeddingStoreConfig {

    @Resource
    private EmbeddingModel embeddingModel;

    @Resource
    private RedisEmbeddingStore redisEmbeddingStore;

    /**
     * 配置向量数据库操作对象
     *
     * @return 向量数据库操作对象 Bean
     */
    //@Bean
    public EmbeddingStore<TextSegment> embeddingStore() {
        // 1. 加载文档进内存(若为 null 则替换为空列表,避免后续 NPE)
        List<Document> documentList = ClassPathDocumentLoader.loadDocuments("content");
        // 2. 构建 EmbeddingStoreIngestor 并在有文档时执行切分/向量化/存储
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(redisEmbeddingStore)// 装配向量数据库操作对象
        .embeddingModel(embeddingModel)// 装配向量模型
        .build();
        // 执行
        ingestor.ingest(documentList);
        // 3. 返回对象,交由 IOC 管理
        return redisEmbeddingStore;
    }

}

检索对象:

/**
 * 向量数据库检索对象
 */
@Configuration
public class ContentRetrieverConfig {

    @Resource
    private EmbeddingModel embeddingModel;

    @Resource
    private RedisEmbeddingStore redisEmbeddingStore;

    /**
     * 配置向量数据库检索对象
     * @return 向量数据库检索对象 Bean
     */
    @Bean
    public ContentRetriever contentRetriever() {
        return EmbeddingStoreContentRetriever.builder()
        .embeddingStore(redisEmbeddingStore)// 添加向量数据库操作对象
        .minScore(0.5)// 最小匹配程度
        .maxResults(3)// 最大结果条数
        .embeddingModel(embeddingModel)// 装配向量模型
        .build();
    }

}

评论

  1. 水云身
    1 天前
    2025-12-22 15:28:47

    顶尖

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇