Solon AI 五步构建 RAG 服务:2025 最新 AI + 向量数据库实战

此文参考自:https://www.toutiao.com/article/7506140643970826779/

引言:RAG 会成为 2025 年 AI 落地核心?

在2025年,检索增强生成(RAG)技术已成为企业级AI应用的标配。传统大模型受限于知识更新慢、业务适配性差,而 RAG 通过动态外接知识库,结合向量数据库与AI推理能力,显著提升回答的准确性与实时性。本文将基于 Solon AI 与 Redis Vector Search,从0到1搭建 RAG 服务,并结合电商客服场景,揭秘如何通过5步实现生产级落地。

一、项目初始化:Solon AI

核心依赖:

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai</artifactId>
</dependency>

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-repo-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-load-pdf</artifactId>
</dependency>

配置参考:

yaml 复制代码
solon.ai.chat:
  ds3:
    apiUrl: "http://127.0.0.1:11434/api/chat" # 使用完整地址(而不是 api_base)
    provider: "ollama" # 使用 ollama 服务时,需要配置 provider
    model: "llama3.2"

solon.ai.embed:
  bgem3:
    apiUrl: "http://127.0.0.1:11434/api/embed" # 使用完整地址(而不是 api_base)
    provider: "ollama" # 使用 ollama 服务时,需要配置 provider
    model: "bge-m3:latest"
        
solon.ai.repo:
  redis:
    server: localhost:6379

实例构建:

java 复制代码
import org.noear.redisx.RedisClient;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.embedding.EmbeddingModel;
import org.noear.solon.ai.rag.RepositoryStorable;
import org.noear.solon.ai.rag.repository.RedisRepository;
import org.noear.solon.ai.rag.repository.redis.MetadataField;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class RagConfig {
    @Bean
    public ChatModel chatModel(@Inject("${solon.ai.chat.ds3}") ChatModel chatModel) {
        return chatModel;
    }

    @Bean
    public EmbeddingModel embeddingModel(@Inject("${solon.ai.embed.bgem3}") EmbeddingModel embeddingModel) {
        return embeddingModel;
    }

    @Bean
    public RedisClient client(@Inject("${solon.ai.repo.redis}") RedisClient client) {  //构建知识库的连接客户端
        return client;
    }
    
    @Bean
    public RepositoryStorable repository(EmbeddingModel embeddingModel, RedisClient client) { //构建知识库
        // 创建元数据索引字段列表(用于支持混合搜索)
        List<MetadataField> metadataFields = new ArrayList<>();
        metadataFields.add(MetadataField.tag("title"));
        metadataFields.add(MetadataField.tag("category"));
        metadataFields.add(MetadataField.numeric("price"));
        metadataFields.add(MetadataField.numeric("stock"));

        return RedisRepository.builder(embeddingModel, client.jedis())
                .metadataIndexFields(metadataFields)
                .build();
    }
}

技术选型优势:

  • Redis Vector Search(建议 Redis 8+):支持千亿级向量毫秒检索,实时数据更新秒级可见
  • Solon AI:统一接口支持各种主流向量数据库,内置流式输出与异步处理。

二、数据处理:文档分块与向量化

1. 文档加载与分块

java 复制代码
@Component
public class RagService {
    public void load(){
        // 加载PDF/Word文档
        List<Document> docs = new PdfLoader("product-manual.pdf").load();

        // 智能分块(动态调整块大小)
        docs = new TokenSizeTextSplitter(500, 64).split(docs);
    }
}

分块策略:

  • 动态分块:根据语义边界(如段落、表格)自动调整块大小,避免信息割裂;
  • 重叠机制:设置64 Token的重叠区,确保上下文连贯性。

2. 向量嵌入与存储

在 RagService 的基础上,进一步补充

java 复制代码
import org.noear.solon.ai.embedding.EmbeddingModel;
import org.noear.solon.ai.rag.Document;
import org.noear.solon.ai.rag.RepositoryStorable;
import org.noear.solon.ai.rag.splitter.TokenSizeTextSplitter;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

import java.io.IOException;
import java.util.List;

@Component
public class RagService {
    @Inject
    private RepositoryStorable  repository;
    @Inject
    private EmbeddingModel embeddingModel;

    public void load() throws IOException {
        // 加载PDF/Word文档
        List<Document> docs = new PdfLoader("product-manual.pdf").load();

        // 智能分块(动态调整块大小)
        docs = new TokenSizeTextSplitter(500, 64).split(docs);

        // 存储(内部自动完成向量嵌入,内部支持分批入库)
        repository.insert(docs);
    }
}

性能优化:

  • 批量处理:数据批次插入,降低I/O开销;
  • 元数据附加:为每个向量附加来源、时间戳等字段,支持精准过滤。

三、检索增强:混合搜索

使用元信息字段 category 过滤(减少匹配范围),并使用向量检索

java 复制代码
@Component
public class RagService {
    @Inject
    private RepositoryStorable repository;
    @Inject
    private EmbeddingModel embeddingModel;

    public void load() throws IOException {
        // 加载PDF/Word文档
        List<Document> docs = new PdfLoader("product-manual.pdf").load();

        // 智能分块(动态调整块大小)
        docs = new TokenSizeTextSplitter(500, 64).split(docs);

        // 存储(内部自动完成向量嵌入)
        repository.insert(docs);
    }

    public List<Document> find(String category, String query) throws IOException {
        return repository.search(new QueryCondition(query)
                .filterExpression("category == '" + category + "'"));
    }
}

场景适配:

  • 元数据检索:处理明确实体(如商品目录);
  • 向量检索:应对复杂语义(如"性价比高的手机推荐")。

四、生成优化:提示工程与流式输出

1. 动态Prompt设计

java 复制代码
String promptTemplate = """
    你是一名电商客服专家,请根据以下上下文回答问题:
    ${context}
    问题:${question}
    要求:回答需包含具体数据,若信息不足则回复"暂未收录"。
    示例:库存查询 → "当前iPhone 20库存为500件,预计48小时发货。"
    """;

关键技巧:

  • 指令约束:限制回答范围,减少幻觉;
  • 示例引导:提供标准回答格式,提升一致性。

2. 流式响应与溯源

写一个控制器,整合 ChatModel 和 RagService

java 复制代码
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.rag.Document;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.List;

@Controller
public class RagController {
    @Inject
    RagService ragService;

    @Inject
    ChatModel chatModel;

    static String promptTemplate = """
        你是一名电商客服专家,请根据以下上下文回答问题:
        #{context}
        问题:#{question}
        要求:回答需包含具体数据,若信息不足则回复"暂未收录"。
        示例:库存查询 → "当前iPhone 20库存为500件,预计48小时发货。"
        """;

    @Mapping("/ask")
    public Flux<String> streamAnswer(String question) throws IOException {
        List<Document> context = ragService.find("商品", question);
        
        ChatMessage message = ChatMessage.ofUserTmpl(promptTemplate)
                .paramAdd("question", question)
                .paramAdd("context", context)
                .generate();

        return Flux.from(chatModel.prompt(message).stream())
                .filter(resp -> resp.hasChoices())
                .map(resp -> resp.getMessage().getContent());
    }
}

用户体验优化:

  • 逐字输出:响应延迟降低至100ms以内(要看模型服务的性能);
  • 来源标记:返回答案关联的文档ID与置信度。

五、实战案例:电商客服RAG系统

场景:秒杀活动问答

需求:用户询问"iPhone 20秒杀库存和优惠规则"。

RAG处理流程:

检索:从商品手册中匹配"iPhone 20"的库存条款与促销规则;

生成:返回"当前库存2000件,限购1台,叠加满减券再降500元"。

相关推荐
皮皮林5511 小时前
使用 Java + WebSocket 实现简单实时双人协同 pk 答题
java·websocket
码小凡3 小时前
优雅!用了这两款插件,我成了整个公司代码写得最规范的码农
java·后端
掉鱼的猫5 小时前
Solon AI 五步构建 RAG 服务:2025 最新 AI + 向量数据库实战
java·redis·后端
java金融5 小时前
FactoryBean 和BeanFactory的傻傻的总是分不清?
java·后端
独立开阀者_FwtCoder5 小时前
Nginx 通过匹配 Cookie 将请求定向到特定服务器
java·vue.js·后端
名曰大神5 小时前
AEM6.5集成Redis详细步骤(附代码)
java·redis·demo·aem
东阳马生架构6 小时前
商品中心—7.自研缓存框架的技术文档
java
晴空月明8 小时前
线程安全与锁机制深度解析
java
天天摸鱼的java工程师10 小时前
你如何处理一个高并发接口的线程安全问题?说说你做过的优化措施
java·后端