第10章 RAG 知识检索

第10章 RAG 知识检索

本章目标

  • 理解 RAG(检索增强生成)的核心原理和应用场景
  • 掌握 AgentScope-Java 的 RAG 架构设计
  • 学会使用本地知识库(SimpleKnowledge)构建 RAG 系统
  • 了解云端知识库集成(百炼、Dify、RAGFlow、Haystack)
  • 掌握两种 RAG 模式:Generic 模式和 Agentic 模式

10.1 RAG 概述

10.1.1 什么是 RAG?

RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将信息检索与文本生成相结合的技术架构。它通过从外部知识库中检索相关文档,将检索到的信息作为上下文注入到语言模型的提示中,从而增强模型的回答质量。

┌─────────────────────────────────────────────────────────────┐
│                      RAG 工作流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   用户问题        向量检索         上下文增强        生成回答   │
│   ┌─────┐       ┌─────────┐      ┌─────────┐      ┌─────┐  │
│   │ Q   │──────▶│Knowledge│─────▶│ Prompt  │─────▶│ LLM │  │
│   └─────┘       │  Base   │      │+Context │      └──┬──┘  │
│                 └─────────┘      └─────────┘         │     │
│                                                      ▼     │
│                                                  ┌─────┐   │
│                                                  │  A  │   │
│                                                  └─────┘   │
│                                                             │
│   1. 接收问题                                               │
│   2. 将问题转换为向量,在知识库中检索相似文档                   │
│   3. 将检索到的文档作为上下文添加到提示词中                     │
│   4. LLM 结合上下文生成更准确的回答                           │
└─────────────────────────────────────────────────────────────┘

10.1.2 为什么需要 RAG?

问题RAG 如何解决
知识过时LLM 的训练数据有截止日期,无法回答最新信息。RAG 可以实时检索最新知识
幻觉问题LLM 可能生成看似合理但实际错误的内容。RAG 基于真实文档回答,减少幻觉
领域知识通用 LLM 缺乏特定领域专业知识。RAG 可以注入企业文档、专业资料等
隐私安全敏感数据不适合发送给 LLM 训练。RAG 让数据留在本地,只在推理时使用
可解释性LLM 回答来源不透明。RAG 可以追溯答案的文档来源

10.1.3 AgentScope-Java RAG 架构

┌─────────────────────────────────────────────────────────────────┐
│                   AgentScope-Java RAG 架构                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    ReActAgent                            │   │
│  │  ┌─────────────────────┬────────────────────────────┐   │   │
│  │  │    Generic 模式     │      Agentic 模式          │   │   │
│  │  │   (GenericRAGHook)  │ (KnowledgeRetrievalTools)  │   │   │
│  │  └─────────────────────┴────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                              │                                  │
│                              ▼                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Knowledge 接口                        │   │
│  │  ┌──────────────────────────────────────────────────┐   │   │
│  │  │ + addDocuments(documents): Mono<Void>            │   │   │
│  │  │ + retrieve(query, config): Mono<List<Document>>  │   │   │
│  │  └──────────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                              │                                  │
│           ┌──────────────────┼──────────────────┐               │
│           ▼                  ▼                  ▼               │
│  ┌─────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │SimpleKnowledge│    │BailianKnowledge│   │DifyKnowledge│       │
│  │  (本地向量库) │    │  (百炼云知识库) │   │(Dify 知识库)│       │
│  └──────┬──────┘    └──────────────┘    └──────────────┘       │
│         │                                                       │
│    ┌────┴────┐                                                  │
│    ▼         ▼                                                  │
│ ┌───────┐ ┌─────────┐                                          │
│ │Embedding│ │VectorStore│                                       │
│ │ Model  │ │(向量存储) │                                        │
│ └───────┘ └─────────┘                                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

10.2 核心组件详解

10.2.1 Knowledge 接口

Knowledge 是 RAG 系统的核心抽象接口,定义了知识库的基本操作:

package io.agentscope.core.rag;

import io.agentscope.core.rag.model.Document;
import io.agentscope.core.rag.model.RetrieveConfig;
import java.util.List;
import reactor.core.publisher.Mono;

/**
 * 知识库统一接口
 * 提供文档存储和检索的标准 API
 */
public interface Knowledge {

    /**
     * 添加文档到知识库
     * 
     * 文档会被向量化并存储到向量数据库中
     *
     * @param documents 要添加的文档列表
     * @return 完成添加后的 Mono
     */
    Mono<Void> addDocuments(List<Document> documents);

    /**
     * 根据查询检索相关文档
     * 
     * 查询会被向量化,然后在知识库中搜索相似文档
     * 结果按相关性分数过滤和排序
     *
     * @param query 搜索查询文本
     * @param config 检索配置(数量限制、分数阈值等)
     * @return 按相关性排序的文档列表
     */
    Mono<List<Document>> retrieve(String query, RetrieveConfig config);
}

10.2.2 Document 文档模型

Document 是 RAG 系统中的核心数据结构,代表一个文档片段:

// Document 结构示例
Document doc = new Document(metadata);

// 核心字段
doc.getId();                  // 文档唯一 ID(自动生成的 UUID)
doc.getMetadata();            // 文档元数据(包含内容)
doc.getEmbedding();           // 向量嵌入(由 EmbeddingModel 生成)
doc.getScore();               // 相似度分数(检索时填充)
doc.getPayload();             // 自定义业务数据

// DocumentMetadata 包含实际内容
metadata.getContent();        // ContentBlock 内容(文本、图片等)
metadata.getContentText();    // 便捷方法:获取文本内容
metadata.getDocId();          // 原始文档 ID
metadata.getChunkId();        // 分块 ID

10.2.3 RetrieveConfig 检索配置

import io.agentscope.core.rag.model.RetrieveConfig;

// 构建检索配置
RetrieveConfig config = RetrieveConfig.builder()
    // 最大返回文档数(默认 5)
    .limit(5)
    
    // 最小相似度分数阈值(0.0-1.0,默认 0.5)
    // 低于此分数的文档会被过滤
    .scoreThreshold(0.5)
    
    // 向量名称(可选,用于多向量场景)
    .vectorName("default")
    
    // 对话历史(可选,用于多轮检索上下文)
    // 百炼等知识库支持基于历史的查询改写
    .conversationHistory(conversationHistory)
    
    .build();

提示scoreThreshold 的最佳值取决于你的嵌入模型和数据质量。建议从 0.5 开始,根据实际效果调整。太高会遗漏相关文档,太低会引入噪声。


10.3 本地知识库:SimpleKnowledge

SimpleKnowledge 是一个完全本地化的 RAG 实现,适合开发测试和中小规模应用。

10.3.1 架构组成

┌────────────────────────────────────────────────────────┐
│                   SimpleKnowledge                       │
├────────────────────────────────────────────────────────┤
│                                                        │
│  ┌────────────────┐        ┌─────────────────────┐    │
│  │ EmbeddingModel │        │    VDBStoreBase     │    │
│  │  (嵌入模型)     │        │    (向量存储)        │    │
│  └───────┬────────┘        └──────────┬──────────┘    │
│          │                            │               │
│          │ 文本 → 向量                 │ 向量存储/检索  │
│          │                            │               │
│  ┌───────┴────────────────────────────┴───────┐      │
│  │              SimpleKnowledge                │      │
│  │  - addDocuments(): 嵌入 + 存储文档         │      │
│  │  - retrieve(): 嵌入查询 + 向量搜索         │      │
│  └─────────────────────────────────────────────┘      │
│                                                        │
└────────────────────────────────────────────────────────┘

10.3.2 完整示例

import io.agentscope.core.embedding.EmbeddingModel;
import io.agentscope.core.embedding.dashscope.DashScopeTextEmbedding;
import io.agentscope.core.rag.Knowledge;
import io.agentscope.core.rag.knowledge.SimpleKnowledge;
import io.agentscope.core.rag.model.Document;
import io.agentscope.core.rag.model.RetrieveConfig;
import io.agentscope.core.rag.reader.ReaderInput;
import io.agentscope.core.rag.reader.SplitStrategy;
import io.agentscope.core.rag.reader.TextReader;
import io.agentscope.core.rag.store.InMemoryStore;
import io.agentscope.core.rag.store.VDBStoreBase;
import java.util.List;

public class SimpleKnowledgeExample {

    // 向量维度(需与嵌入模型匹配)
    private static final int EMBEDDING_DIMENSIONS = 1024;

    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");

        // ========================================
        // 步骤 1:创建嵌入模型
        // ========================================
        // 嵌入模型负责将文本转换为向量
        EmbeddingModel embeddingModel = DashScopeTextEmbedding.builder()
            .apiKey(apiKey)
            .modelName("text-embedding-v3")  // 通义千问嵌入模型
            .dimensions(EMBEDDING_DIMENSIONS)
            .build();

        // ========================================
        // 步骤 2:创建向量存储
        // ========================================
        // InMemoryStore 适合开发测试,生产环境建议使用持久化存储
        VDBStoreBase vectorStore = InMemoryStore.builder()
            .dimensions(EMBEDDING_DIMENSIONS)  // 必须与嵌入模型维度一致
            .build();

        // ========================================
        // 步骤 3:创建知识库实例
        // ========================================
        Knowledge knowledge = SimpleKnowledge.builder()
            .embeddingModel(embeddingModel)
            .embeddingStore(vectorStore)
            .build();

        // ========================================
        // 步骤 4:准备文档并添加到知识库
        // ========================================
        addDocumentsToKnowledge(knowledge);

        // ========================================
        // 步骤 5:检索相关文档
        // ========================================
        RetrieveConfig config = RetrieveConfig.builder()
            .limit(3)              // 返回前 3 个最相关的文档
            .scoreThreshold(0.3)   // 分数阈值
            .build();

        List<Document> results = knowledge
            .retrieve("AgentScope 支持哪些向量数据库?", config)
            .block();

        // 输出检索结果
        System.out.println("检索到 " + results.size() + " 个相关文档:");
        for (Document doc : results) {
            System.out.printf("  - 分数: %.3f, 内容: %s%n",
                doc.getScore(),
                truncate(doc.getMetadata().getContentText(), 100));
        }
    }

    /**
     * 添加示例文档到知识库
     */
    private static void addDocumentsToKnowledge(Knowledge knowledge) {
        // 示例文档内容
        String[] texts = {
            "AgentScope 是一个多智能体系统框架,由 ModelScope 开发。" +
            "它提供了统一的接口用于构建和管理多智能体应用。",
            
            "AgentScope 支持多种向量存储,包括 InMemoryStore(内存存储)、" +
            "Qdrant、Milvus 和 PgVector(PostgreSQL)。",
            
            "RAG(检索增强生成)是一种增强语言模型的技术," +
            "通过从知识库检索相关信息来减少幻觉并提供最新信息。"
        };

        // 使用 TextReader 读取和分块文本
        TextReader reader = new TextReader(
            512,                    // 每块最大 512 字符
            SplitStrategy.PARAGRAPH,// 按段落分割
            50                      // 块之间 50 字符重叠
        );

        for (String text : texts) {
            // 从字符串创建输入
            ReaderInput input = ReaderInput.fromString(text);
            
            // 读取并分块
            List<Document> docs = reader.read(input).block();
            
            // 添加到知识库(自动嵌入和存储)
            if (docs != null && !docs.isEmpty()) {
                knowledge.addDocuments(docs).block();
                System.out.println("已添加文档: " + truncate(text, 50) + "...");
            }
        }
    }

    private static String truncate(String text, int maxLength) {
        return text.length() > maxLength 
            ? text.substring(0, maxLength) + "..." 
            : text;
    }
}

10.3.3 嵌入模型选择

AgentScope-Java 支持多种嵌入模型:

模型类名适用场景依赖
DashScopeDashScopeTextEmbedding中文场景首选,通义千问系列agentscope-extensions-rag-simple
OpenAIOpenAITextEmbedding英文场景,兼容 APIagentscope-extensions-rag-simple
OllamaOllamaTextEmbedding本地部署,隐私优先agentscope-extensions-rag-simple
// DashScope 嵌入模型(推荐中文场景)
EmbeddingModel dashscopeEmbedding = DashScopeTextEmbedding.builder()
    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
    .modelName("text-embedding-v3")
    .dimensions(1024)
    .build();

// OpenAI 嵌入模型
EmbeddingModel openaiEmbedding = OpenAITextEmbedding.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("text-embedding-3-small")
    .dimensions(1536)
    .build();

// Ollama 本地嵌入模型
EmbeddingModel ollamaEmbedding = OllamaTextEmbedding.builder()
    .baseUrl("http://localhost:11434")
    .modelName("nomic-embed-text")
    .dimensions(768)
    .build();

10.3.4 向量存储选择

存储类型类名特点适用场景
InMemoryStoreInMemoryStore内存存储,重启丢失开发测试、原型验证
PgVectorStorePgVectorStorePostgreSQL + pgvector生产环境,已有 PG 基础设施
QdrantStoreQdrantStore专业向量数据库大规模生产环境
MilvusStoreMilvusStore分布式向量数据库超大规模、高并发
// 内存存储(开发测试)
VDBStoreBase inMemory = InMemoryStore.builder()
    .dimensions(1024)
    .build();

// PostgreSQL + pgvector(生产环境)
VDBStoreBase pgVector = PgVectorStore.builder()
    .jdbcUrl("jdbc:postgresql://localhost:5432/vectordb")
    .username("postgres")
    .password("password")
    .tableName("documents")
    .dimensions(1024)
    .build();

// Qdrant(专业向量数据库)
VDBStoreBase qdrant = QdrantStore.builder()
    .host("localhost")
    .port(6334)
    .collectionName("my_collection")
    .dimensions(1024)
    .build();

10.4 文档读取与分块

10.4.1 Reader 体系

AgentScope-Java 提供了丰富的文档读取器:

┌────────────────────────────────────────────────────────┐
│                    Reader 体系                          │
├────────────────────────────────────────────────────────┤
│                                                        │
│  ┌──────────────┐                                      │
│  │ ReaderInput  │◀─── 输入源抽象                        │
│  │ - fromString()│    - 字符串                          │
│  │ - fromFile()  │    - 文件路径                        │
│  │ - fromBytes() │    - 字节数组                        │
│  └──────────────┘                                      │
│                                                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │                 Reader 实现                        │  │
│  ├──────────────────────────────────────────────────┤  │
│  │ TextReader    │ 纯文本、Markdown、RST            │  │
│  │ PDFReader     │ PDF 文档                          │  │
│  │ WordReader    │ Word 文档 (.docx)                 │  │
│  │ TikaReader    │ 通用格式(基于 Apache Tika)       │  │
│  │ ImageReader   │ 图片(用于多模态嵌入)             │  │
│  └──────────────────────────────────────────────────┘  │
│                                                        │
└────────────────────────────────────────────────────────┘

10.4.2 分块策略

import io.agentscope.core.rag.reader.SplitStrategy;

// 分块策略枚举
public enum SplitStrategy {
    PARAGRAPH,    // 按段落分割(推荐用于文章)
    SENTENCE,     // 按句子分割(保持语义完整)
    CHARACTER,    // 按字符数分割(固定大小)
    TOKEN         // 按 Token 数分割(精确控制)
}
import io.agentscope.core.rag.reader.TextReader;
import io.agentscope.core.rag.reader.SplitStrategy;

// 创建文本读取器
TextReader reader = new TextReader(
    512,                     // chunkSize: 每块目标大小
    SplitStrategy.PARAGRAPH, // strategy: 分块策略
    50                       // overlapSize: 块间重叠字符数
);

// 读取文件
ReaderInput input = ReaderInput.fromFile("/path/to/document.txt");
List<Document> documents = reader.read(input).block();

// 读取字符串
ReaderInput stringInput = ReaderInput.fromString("长文本内容...");
List<Document> docs = reader.read(stringInput).block();

注意overlapSize(重叠大小)很重要!它确保跨块边界的信息不会丢失。通常设置为 chunk 大小的 10%-20%。

10.4.3 PDF 和 Word 文档

import io.agentscope.core.rag.reader.PDFReader;
import io.agentscope.core.rag.reader.WordReader;

// PDF 读取器
PDFReader pdfReader = new PDFReader(
    1000,                    // chunkSize
    SplitStrategy.PARAGRAPH,
    100                      // overlapSize
);

List<Document> pdfDocs = pdfReader
    .read(ReaderInput.fromFile("/path/to/manual.pdf"))
    .block();

// Word 读取器
WordReader wordReader = new WordReader(
    800,
    SplitStrategy.PARAGRAPH,
    80
);

List<Document> wordDocs = wordReader
    .read(ReaderInput.fromFile("/path/to/report.docx"))
    .block();

10.5 云端知识库集成

对于生产环境,AgentScope-Java 支持多种云端知识库服务。

10.5.1 百炼知识库(BailianKnowledge)

阿里云百炼提供企业级的知识库服务,支持自动文档解析、向量化和检索:

import io.agentscope.core.rag.integration.bailian.BailianConfig;
import io.agentscope.core.rag.integration.bailian.BailianKnowledge;

// 配置百炼连接
BailianConfig config = BailianConfig.builder()
    // 阿里云访问密钥
    .accessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
    .accessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
    
    // 工作空间 ID(在百炼控制台获取)
    .workspaceId("llm-xxxxxxxx")
    
    // 知识库索引 ID
    .indexId("mymxbdxxxxxxxx")
    
    // 可选:启用查询改写(多轮对话场景)
    .enableRewrite(true)
    
    .build();

// 创建知识库实例
BailianKnowledge knowledge = BailianKnowledge.builder()
    .config(config)
    .build();

// 检索文档
RetrieveConfig retrieveConfig = RetrieveConfig.builder()
    .limit(5)
    .scoreThreshold(0.5)
    // 可选:传入对话历史用于查询改写
    .conversationHistory(conversationHistory)
    .build();

List<Document> results = knowledge
    .retrieve("产品退货政策是什么?", retrieveConfig)
    .block();

注意:百炼知识库目前不支持通过 API 上传文档,需要在控制台管理文档。

10.5.2 Dify 知识库

import io.agentscope.core.rag.integration.dify.DifyKnowledge;
import io.agentscope.core.rag.integration.dify.DifyRAGConfig;

// 配置 Dify
DifyRAGConfig config = DifyRAGConfig.builder()
    .apiKey(System.getenv("DIFY_API_KEY"))
    .baseUrl("https://api.dify.ai/v1")  // 或自托管地址
    .datasetId("your-dataset-id")
    .build();

// 创建知识库实例
DifyKnowledge knowledge = DifyKnowledge.builder()
    .config(config)
    .build();

10.5.3 RAGFlow 知识库

import io.agentscope.core.rag.integration.ragflow.RAGFlowConfig;
import io.agentscope.core.rag.integration.ragflow.RAGFlowKnowledge;

// 配置 RAGFlow
RAGFlowConfig config = RAGFlowConfig.builder()
    .apiKey(System.getenv("RAGFLOW_API_KEY"))
    .baseUrl("http://localhost:8080")
    .knowledgeBaseId("kb-xxxxx")
    .build();

// 创建知识库
RAGFlowKnowledge knowledge = RAGFlowKnowledge.builder()
    .config(config)
    .build();

10.5.4 Haystack 知识库

import io.agentscope.core.rag.integration.haystack.HayStackConfig;
import io.agentscope.core.rag.integration.haystack.HayStackKnowledge;

// 配置 Haystack
HayStackConfig config = HayStackConfig.builder()
    .pipelineUrl("http://localhost:8000/query")
    .build();

// 创建知识库
HayStackKnowledge knowledge = HayStackKnowledge.builder()
    .config(config)
    .build();

10.6 RAG 模式详解

AgentScope-Java 提供两种 RAG 集成模式:

10.6.1 RAGMode 枚举

public enum RAGMode {
    /**
     * Generic 模式:自动检索
     * 知识在每次推理前通过 Hook 自动检索并注入到提示词中
     */
    GENERIC,

    /**
     * Agentic 模式:主动检索
     * 智能体通过工具主动决定何时检索知识
     */
    AGENTIC,

    /**
     * 禁用模式:不使用 RAG
     */
    NONE
}

10.6.2 Generic 模式(自动检索)

Generic 模式通过 GenericRAGHook 实现,在每次推理前自动检索知识:

┌────────────────────────────────────────────────────────┐
│                  Generic 模式流程                       │
├────────────────────────────────────────────────────────┤
│                                                        │
│   用户提问                                              │
│      │                                                 │
│      ▼                                                 │
│   ┌──────────────────┐                                │
│   │ GenericRAGHook   │◀── 拦截 PreCallEvent           │
│   │ 1. 提取查询      │                                │
│   │ 2. 检索知识库    │                                │
│   │ 3. 注入上下文    │                                │
│   └────────┬─────────┘                                │
│            │                                           │
│            ▼                                           │
│   ┌──────────────────┐                                │
│   │    增强的提示词   │                                │
│   │ <retrieved_knowledge>                              │
│   │   - 文档1: xxx                                     │
│   │   - 文档2: xxx                                     │
│   │ </retrieved_knowledge>                             │
│   └────────┬─────────┘                                │
│            │                                           │
│            ▼                                           │
│   ┌──────────────────┐                                │
│   │      LLM        │                                 │
│   │   生成回答       │                                 │
│   └──────────────────┘                                │
│                                                        │
└────────────────────────────────────────────────────────┘

使用方式一:内置配置(推荐)

import io.agentscope.core.ReActAgent;
import io.agentscope.core.rag.RAGMode;

// 通过 ReActAgent 的内置配置
ReActAgent agent = ReActAgent.builder()
    .name("RAGAssistant")
    .sysPrompt("你是一个有知识库访问权限的助手,请基于知识库内容准确回答问题。")
    .model(chatModel)
    
    // 配置 RAG
    .knowledge(knowledge)                    // 设置知识库
    .ragMode(RAGMode.GENERIC)               // 使用 Generic 模式
    .retrieveConfig(                         // 检索配置
        RetrieveConfig.builder()
            .limit(3)
            .scoreThreshold(0.3)
            .build()
    )
    
    .build();

使用方式二:手动配置 Hook

import io.agentscope.core.rag.GenericRAGHook;

// 创建 RAG Hook
GenericRAGHook ragHook = new GenericRAGHook(
    knowledge,  // 知识库
    RetrieveConfig.builder()
        .limit(5)
        .scoreThreshold(0.5)
        .build()
);

// 将 Hook 添加到智能体
ReActAgent agent = ReActAgent.builder()
    .name("Assistant")
    .model(chatModel)
    .hooks(List.of(ragHook))  // 手动添加 Hook
    .build();

适用场景

  • 用户问题通常需要知识库支持
  • 需要简单的"问答"模式
  • 不需要智能体自主判断是否检索

10.6.3 Agentic 模式(主动检索)

Agentic 模式通过 KnowledgeRetrievalTools 实现,智能体自主决定何时检索:

┌────────────────────────────────────────────────────────┐
│                  Agentic 模式流程                       │
├────────────────────────────────────────────────────────┤
│                                                        │
│   用户提问                                              │
│      │                                                 │
│      ▼                                                 │
│   ┌──────────────────┐                                │
│   │   ReActAgent     │                                │
│   │   推理决策        │                                │
│   └────────┬─────────┘                                │
│            │                                           │
│       需要知识?                                        │
│       ┌────┴────┐                                     │
│       ▼         ▼                                      │
│      是        否                                      │
│       │         │                                      │
│       ▼         │                                      │
│ ┌─────────────┐ │                                     │
│ │retrieve_    │ │                                     │
│ │knowledge    │ │                                     │
│ │工具调用      │ │                                     │
│ └──────┬──────┘ │                                     │
│        │        │                                      │
│        ▼        │                                      │
│ ┌─────────────┐ │                                     │
│ │ 检索结果    │ │                                     │
│ └──────┬──────┘ │                                     │
│        │        │                                      │
│        ▼        ▼                                      │
│   ┌──────────────────┐                                │
│   │  综合信息生成回答  │                                │
│   └──────────────────┘                                │
│                                                        │
└────────────────────────────────────────────────────────┘

使用方式一:内置配置(推荐)

import io.agentscope.core.rag.RAGMode;

ReActAgent agent = ReActAgent.builder()
    .name("RAGAgent")
    .sysPrompt("""
        你是一个智能助手,拥有知识库检索工具。
        当你需要查找信息时,请使用 retrieve_knowledge 工具。
        请在使用工具前解释你的思考过程。
        """)
    .model(chatModel)
    .toolkit(toolkit)
    
    // 配置 Agentic RAG
    .knowledge(knowledge)
    .ragMode(RAGMode.AGENTIC)  // 使用 Agentic 模式
    
    .build();

使用方式二:手动注册工具

import io.agentscope.core.rag.KnowledgeRetrievalTools;
import io.agentscope.core.tool.Toolkit;

// 创建检索工具
KnowledgeRetrievalTools retrievalTools = new KnowledgeRetrievalTools(knowledge);

// 注册到工具包
Toolkit toolkit = new Toolkit();
toolkit.registerObject(retrievalTools);

// 创建智能体
ReActAgent agent = ReActAgent.builder()
    .name("Agent")
    .model(chatModel)
    .toolkit(toolkit)
    .build();

retrieve_knowledge 工具定义

@Tool(
    name = "retrieve_knowledge",
    description = "从知识库检索相关文档。当需要查找特定信息或用户询问知识库内容时使用。"
)
public String retrieveKnowledge(
    @ToolParam(
        name = "query",
        description = "在知识库中搜索的查询文本"
    )
    String query,
    
    @ToolParam(
        name = "limit",
        description = "最多返回的文档数量(默认: 5)",
        required = false
    )
    Integer limit,
    
    Agent agent  // 自动注入,用于获取对话历史
) {
    // 实现检索逻辑...
}

适用场景

  • 智能体需要多种工具,知识检索只是其一
  • 需要智能体自主判断何时使用知识库
  • 复杂的多步推理任务

10.6.4 模式对比与选择

特性Generic 模式Agentic 模式
检索时机每次推理自动检索智能体主动决定
实现方式Hook 拦截工具调用
Token 消耗较高(每次都检索)较低(按需检索)
控制灵活性
适用场景纯知识问答复杂多工具任务
配置复杂度简单中等

10.7 最佳实践

10.7.1 知识库构建建议

// 1. 选择合适的分块策略
// 对于技术文档,建议使用较大的 chunk 保持上下文完整
TextReader techReader = new TextReader(
    1000,                    // 较大的块
    SplitStrategy.PARAGRAPH,
    150                      // 较大的重叠
);

// 对于问答对,可以使用较小的块
TextReader qaReader = new TextReader(
    300,
    SplitStrategy.SENTENCE,
    30
);

// 2. 添加元数据提高检索质量
DocumentMetadata metadata = new DocumentMetadata(content, docId, chunkId);
// 可以通过 payload 添加业务元数据
// metadata.setPayload(Map.of("category", "技术文档", "version", "2.0"));

// 3. 定期更新知识库
// 删除过时文档
vectorStore.delete(outdatedDocId).block();
// 添加新文档
knowledge.addDocuments(newDocuments).block();

10.7.2 检索配置优化

// 针对不同场景的配置示例

// 高精度检索(宁缺毋滥)
RetrieveConfig preciseConfig = RetrieveConfig.builder()
    .limit(3)
    .scoreThreshold(0.7)  // 高阈值
    .build();

// 高召回检索(宁多勿少)
RetrieveConfig recallConfig = RetrieveConfig.builder()
    .limit(10)
    .scoreThreshold(0.3)  // 低阈值
    .build();

// 平衡配置(推荐默认)
RetrieveConfig balancedConfig = RetrieveConfig.builder()
    .limit(5)
    .scoreThreshold(0.5)
    .build();

10.7.3 生产环境建议

// 1. 使用持久化向量存储
VDBStoreBase productionStore = PgVectorStore.builder()
    .jdbcUrl(System.getenv("DATABASE_URL"))
    .username(System.getenv("DB_USER"))
    .password(System.getenv("DB_PASSWORD"))
    .tableName("knowledge_vectors")
    .dimensions(1024)
    .build();

// 2. 配置执行超时和重试
ExecutionConfig execConfig = ExecutionConfig.builder()
    .timeout(Duration.ofSeconds(30))
    .maxRetries(3)
    .build();

EmbeddingModel embeddingModel = DashScopeTextEmbedding.builder()
    .apiKey(apiKey)
    .modelName("text-embedding-v3")
    .dimensions(1024)
    .executionConfig(execConfig)
    .build();

// 3. 考虑使用云知识库服务
// - 百炼:企业级,自动管理
// - Dify:开源可控,功能丰富
// - RAGFlow:开源,深度解析

10.8 完整示例

以下是一个综合了 RAG 各组件的完整示例:

import io.agentscope.core.ReActAgent;
import io.agentscope.core.embedding.EmbeddingModel;
import io.agentscope.core.embedding.dashscope.DashScopeTextEmbedding;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.rag.Knowledge;
import io.agentscope.core.rag.RAGMode;
import io.agentscope.core.rag.knowledge.SimpleKnowledge;
import io.agentscope.core.rag.model.Document;
import io.agentscope.core.rag.model.RetrieveConfig;
import io.agentscope.core.rag.reader.ReaderInput;
import io.agentscope.core.rag.reader.SplitStrategy;
import io.agentscope.core.rag.reader.TextReader;
import io.agentscope.core.rag.store.InMemoryStore;
import io.agentscope.core.tool.Toolkit;
import java.util.List;
import java.util.Scanner;

/**
 * RAG 知识问答智能体示例
 * 演示如何构建一个基于知识库的问答系统
 */
public class RAGChatbotExample {

    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        int dimensions = 1024;

        // ========================================
        // 1. 构建知识库基础设施
        // ========================================
        System.out.println("初始化知识库...");

        // 嵌入模型
        EmbeddingModel embeddingModel = DashScopeTextEmbedding.builder()
            .apiKey(apiKey)
            .modelName("text-embedding-v3")
            .dimensions(dimensions)
            .build();

        // 向量存储
        InMemoryStore vectorStore = InMemoryStore.builder()
            .dimensions(dimensions)
            .build();

        // 知识库
        Knowledge knowledge = SimpleKnowledge.builder()
            .embeddingModel(embeddingModel)
            .embeddingStore(vectorStore)
            .build();

        // ========================================
        // 2. 加载知识内容
        // ========================================
        System.out.println("加载知识文档...");
        loadKnowledgeDocuments(knowledge);

        // ========================================
        // 3. 创建 RAG 智能体
        // ========================================
        System.out.println("创建智能体...\n");

        DashScopeChatModel chatModel = DashScopeChatModel.builder()
            .apiKey(apiKey)
            .modelName("qwen-max")
            .stream(true)
            .build();

        // 使用 Agentic 模式,让智能体自主决定何时检索
        ReActAgent agent = ReActAgent.builder()
            .name("KnowledgeAssistant")
            .sysPrompt("""
                你是一个智能知识助手,拥有访问公司知识库的能力。
                
                工作原则:
                1. 当用户问题涉及知识库内容时,使用 retrieve_knowledge 工具检索
                2. 基于检索到的信息提供准确回答
                3. 如果知识库没有相关信息,诚实告知用户
                4. 始终说明信息来源
                
                请用简洁专业的语言回答问题。
                """)
            .model(chatModel)
            .toolkit(new Toolkit())
            .memory(new InMemoryMemory())
            
            // RAG 配置
            .knowledge(knowledge)
            .ragMode(RAGMode.AGENTIC)
            
            .build();

        // ========================================
        // 4. 开始对话
        // ========================================
        System.out.println("=== 知识问答助手 ===");
        System.out.println("试试问:");
        System.out.println("  - AgentScope 是什么?");
        System.out.println("  - 支持哪些向量数据库?");
        System.out.println("  - RAG 有什么优势?");
        System.out.println("输入 'exit' 退出\n");

        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("你: ");
            String input = scanner.nextLine().trim();
            
            if ("exit".equalsIgnoreCase(input)) {
                System.out.println("再见!");
                break;
            }
            
            if (input.isEmpty()) continue;

            // 调用智能体
            System.out.print("助手: ");
            agent.stream(input)
                .doOnNext(msg -> System.out.print(msg.getTextContent()))
                .blockLast();
            System.out.println("\n");
        }
        
        scanner.close();
    }

    /**
     * 加载示例知识文档
     */
    private static void loadKnowledgeDocuments(Knowledge knowledge) {
        String[] documents = {
            // 产品介绍
            "AgentScope-Java 是 AgentScope 框架的 Java 实现版本。" +
            "它提供了构建多智能体应用的完整解决方案,支持 ReAct 算法、" +
            "工具调用、记忆管理等核心功能。",
            
            // 技术特性
            "AgentScope-Java 基于 Project Reactor 实现响应式编程," +
            "使用 Mono 和 Flux 处理异步操作,非常适合构建高并发的智能体应用。",
            
            // 向量存储
            "AgentScope 支持多种向量存储后端,包括:" +
            "InMemoryStore(内存存储,适合开发测试)、" +
            "PgVectorStore(PostgreSQL + pgvector,适合生产)、" +
            "QdrantStore(专业向量数据库)、" +
            "MilvusStore(分布式向量数据库)。",
            
            // RAG 功能
            "RAG(检索增强生成)是 AgentScope 的核心功能之一。" +
            "它通过从知识库检索相关文档来增强 LLM 的回答质量," +
            "有效减少幻觉并支持实时知识更新。" +
            "AgentScope 支持 Generic 和 Agentic 两种 RAG 模式。"
        };

        TextReader reader = new TextReader(500, SplitStrategy.PARAGRAPH, 50);

        for (String doc : documents) {
            try {
                List<Document> chunks = reader
                    .read(ReaderInput.fromString(doc))
                    .block();
                    
                if (chunks != null && !chunks.isEmpty()) {
                    knowledge.addDocuments(chunks).block();
                }
            } catch (Exception e) {
                System.err.println("加载文档失败: " + e.getMessage());
            }
        }
        
        System.out.println("已加载 " + documents.length + " 个知识文档");
    }
}

10.9 本章小结

本章详细介绍了 AgentScope-Java 的 RAG(检索增强生成)功能:

  1. RAG 原理:通过检索外部知识增强 LLM 的回答能力
  2. 核心组件

- Knowledge 接口:统一的知识库抽象 - DocumentRetrieveConfig:数据和配置模型 - 多种 Reader:文档读取和分块

  1. 本地知识库SimpleKnowledge + 嵌入模型 + 向量存储
  2. 云端知识库:百炼、Dify、RAGFlow、Haystack 集成
  3. 两种模式

- Generic 模式:自动检索,简单易用 - Agentic 模式:主动检索,灵活可控

RAG 是让智能体"知其所以然"的关键技术,掌握它能够构建真正有用的企业级 AI 应用。


练习

  1. 使用 SimpleKnowledge 构建一个本地知识库,添加一些文档并测试检索效果
  2. 尝试不同的分块策略(PARAGRAPHSENTENCECHARACTER),比较检索质量
  3. 将 RAG 模式从 GENERIC 切换到 AGENTIC,观察智能体行为的变化
  4. (进阶)集成 PgVectorStore,实现持久化的知识库存储

上一章:第09章-MCP协议集成 | 下一章:第11章-Pipeline管道

← 返回目录