跳转至

检索增强生成(RAG)

约 21341 个字 511 行代码 7 张图片 预计阅读时间 78 分钟

介绍

RAG(Retrieval Augmented Generation,检索增强生成),是一种结合信息检索(Retrieval)和文本生成(Generation)的混合架构

你有没有遇到过这样的情况:向AI提问“公司最新的隐私政策是什么”,结果它一本正经地胡编乱造?这就是传统大型语言模型(LLM)的“幻觉”问题——它们依赖训练数据中的知识,但无法获取最新信息以及一些非公开信息

RAG就像给AI装上了“外挂大脑”,让它在回答问题时,先从外部知识库(如文档、数据库)中检索相关片段,再将这些片段作为上下文,输入给模型。这样,AI的回答就基于真实、最新数据,大幅减少“幻觉”,同时支持动态知识更新。

RAG让AI从“背书机器”升级为“会查资料的专家”,适合需要高准确性的场景(如医疗咨询、法律问答)

RAG工作流程

RAG宏观流程如下:

通过从外部知识库获取相关信息来增强大语言模型(LLM)的输出,从而生成更准确、上下文更丰富的回答,有效解决模型幻觉、知识过时等问题。RAG知识库可以是本地文档、公司内部文档等非公开数据。但这些数据或文档并不能很好地被直接进行检索访问。因此需要将这些数据进行处理,构建成可以被检索的知识库。任何文档或者数据要作为RAG知识库的数据,就需要经过下面的过程:

接着,大模型从向量数据库中读取数据并生成回答返回给用户:

在上面的两个过程图中,涉及到的部分概念解释如下:

  • 文档加载(DocumentLoading):加载不同来源的文档,Spring AI提供了多种不同的文档加载器,可以加载包括PDF在内的非结构化数据,或者包括SQL在内的结构化数据
  • 文本分割(Splitting):文本分割器把Document切分为指定大小的块
  • 存储(Storage):存储涉及到两个环节,分别是:

    • 将切分好的文档块进行嵌入(Embedding),即将文档块转换成向量的形式
    • 将Embedding后的向量数据,存储到向量数据库中
  • 检索(Retrieval):数据存入向量数据库后,当我们需要进行数据检索时,会通过某种检索算法找到与输入问题相似的文档块

  • 输出(Output):把问题以及检索出来的文档块一起提交给LLM,LLM会通过问题和检索出来的提示一起生成更加合理的答案

向量

向量是高维空间中的数值数组(如[0.2,-1.5,3.1,...]),每个维度代表语义特征

在人工智能和自然语言处理领域,向量常被用来将文本、图像、音频等复杂对象映射到高维空间中的点。每一个维度代表某种潜在的语义特征或属性。这些特征不一定对应人类可直观理解的具体概念(如“颜色”或“大小”),但它们共同编码了对象的意义和特性

这个过程通常通过Embedding模型(嵌入模型)实现。当我们把词语输入给同一个模型时,它们会被转换成各自的向量表示,语义相似的文本(如“香蕉”和“橘子”)在向量空间中距离更近

简单的一维数值无法捕捉复杂对象的丰富信息。例如,描述一个人,仅靠一个维度(如“性别”)远远不够。我们需要多个特征来全面刻画它,比如:性别、地区、喜好、身高、体重、年龄等。每个特征都可以被编码为向量的一个维度,最终形成一个多维向量,如[0.8,-1.2,2.5, ..., 1.7](具体数值由模型自动生成)

在这样的高维空间中,我们难以可视化,但机器可以通过计算向量间的距离或角度来判断两个对象是否相似

常用的相似性度量方法包括:

  • 余弦相似度:衡量两个向量方向的夹角,值越接近1表示越相似,公式表示如下:

    \[\text{similarity}=\cos(\theta)=\frac{A\cdot B}{\lVert A\rVert\lVert B\rVert}=\frac{\sum_{i=1}^{n}A_i\times B_i}{\sqrt{\sum_{i=1}^{n}(A_i)^2}\times\sqrt{\sum_{i=1}^{n}(B_i)^2}}\]
  • 欧氏距离:衡量两点之间的直线距离,距离越小越相似,公式表示如下:

    \[d(x,y)=\sqrt{(x_1-y_1)^2+(x_2-y_2)^2+\cdots+(x_n-y_n)^2}=\sqrt{\sum_{i=1}^{n}(x_i-y_i)^2}\]

嵌入模型(Embedding模型)

Embedding是将文本映射为向量的技术(如BERT、OpenAI的text-embedding-ada-002)。好的Embedding能让“人工智能”和“AI”向量高度相似,而“人工智能”和“西红柿”距离很远。就像把中文“充电”翻译成英文“charge”,Embedding是把文字“翻译”成数字语言。Embedding(嵌入)模型是指完成文本向量化过程的模型

Embedding模型就像是一个“文本翻译器”,它的任务是把文字(比如词语、句子或段落)翻译成数字向量,也就是一串能代表其含义的数字。这些数字不是随机的,而是经过精心计算,使得语义相近的内容,对应的向量也彼此接近

计算机天生擅长处理数字,但不理解文字、图片的含义。Embedding的核心思想就是将人类世界的符号(如单词、句子、产品、用户、图片)转换为计算机能够理解的数值形式(即向量,本质上是一个数字列表),并且要求这种转换能够保留原始符号的语义和关系

向量数据库

向量数据库(VectorDatabase)是一种专门用于存储、管理和高效检索高维向量数据的数据库系统。它以向量作为基本存储单元,支持对非结构化数据(如文本、图像、音频、视频)进行语义级相似性搜索

与传统关系型数据库(如MySQL)基于文本匹配不同,向量数据库的核心能力在于:

  1. 向量化处理:可以将原始数据转换为高维向量(向量维度通常为几百到几千之间)
  2. 相似性度量:使用余弦相似度、欧氏距离等方法衡量向量间的语义接近程度,实现“语义搜索”
  3. 高效检索:面对“高维空间中计算距离效率极低”的问题,采用高效的索引算法,在保证较高准确率的前提下大幅提升查询速度

理论上,并不是只有向量数据库才能存向量,也可以在普通数据库(比如MySQL)里加个字段存数组。但是当要从1亿个向量中找最像的一个时,传统数据库会慢得像蜗牛,向量数据库就像开了火箭

RAG入门

Spring AI提供了对RAG完整流程的支持,即下面的步骤:

  1. 文档加载
  2. 文档拆分
  3. 向量转换
  4. 向量存储
  5. 相似检索
  6. 查询增强

但是,前2个步骤属于文档转换和提取,入门部分为了简便,先考虑下面四个步骤:

  1. 文本向量化
  2. 向量存储
  3. 相似性检索
  4. 查询增强

文本向量化

首先引入需要用到的依赖,由于大多数大模型都不支持Embedding,所以本次使用Spring AI Alibaba:

XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-bom</artifactId>
            <version>1.1.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.1.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-extensions-bom</artifactId>
            <version>1.1.2.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-agent-framework</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    </dependency>
    <!-- RAG Advisors依赖 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-advisors-vector-store</artifactId>
        <version>1.1.2</version>
    </dependency>
</dependencies>

接着编写Spring AI Alibaba的配置文件:

YAML
1
2
3
4
spring:
  ai:
    dashscope:
      api-key: sk-xxx

为了便于演示,下面使用Junit测试进行。文本向量化需要用到Embedding模型,Spring AI Alibaba提供了DashScopeEmbeddingModel,其默认使用的模型是text-embedding-v3,根据官方文档,这个模型支持的向量维度默认为1024(对应向量数组长度为1024)。进行文本向量化使用到的方法是embed()方法,这个方法有下面四个版本:

  • embed(String text):把单段文本转成一个向量,返回float[]。最常用,适合对一句话、一个问题、一个短段落做向量化
  • embed(Document document):把一个Document对象的内容转成一个向量,返回float[]。适合你已经把内容封装成文档对象的场景
  • embed(List<String> texts):把多段文本批量转成多个向量,返回List<float[]>。适合一次处理一组文本,结果顺序和输入顺序对应
  • embed(List<Document> documents, EmbeddingOptions options, BatchingStrategy batchingStrategy):把多篇Document批量转成多个向量,返回List<float[]>options用于传递嵌入模型参数,batchingStrategy用于把文档拆成子批次,避免一次输入过大,更适合向量入库和批处理场景

以第一个版本为例,测试代码如下:

Java
1
2
3
4
5
6
7
8
9
@Autowired
private DashScopeEmbeddingModel embeddingModel;

@Test
void test1() {
    String text = "这是一段测试文本";
    float[] embed = embeddingModel.embed(text);
    System.out.println(Arrays.toString(embed));
}

向量存储

文本转化为向量之后,需要把向量存储到向量数据库中,并利用向量数据库来计算两个向量之间的相似度,或者根据一个向量查找跟这个向量相似的向量

SpringAI提供了一套统一的API,让开发人员不用关心底层实现逻辑,就能完成下面的步骤:

  1. 文本转向量(调用Embedding模型)
  2. 存入向量数据库
  3. 接收用户问题→转向量→搜相似内容→返回给大模型做回答

SpringAI支持多种数据库,目前支持的向量数据库参考:Vector Databases。熟悉的一些数据库都可以用来存储向量,比如Elasticsearch、MongoDB、Oracle、Redis、Pinecone等。入门阶段先使用SimpleVectorStore来存储向量

SimpleVectorStore是SpringAI内置的一个内存版向量数据库,无需外部依赖,开箱即用,特别适合本地测试和快速原型开发。SimpleVectorStore实现了VectorStoreVectorStore继承了DocumentWriter(文档写入的接口),所以具备文档写入的能力

下面将文本存储到SimpleVectorStore进行演示:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import org.springframework.ai.document.Document;

@TestConfiguration
static class TestConfig {
    @Bean
    public SimpleVectorStore simpleVectorStore(DashScopeEmbeddingModel embeddingModel) {
        return SimpleVectorStore.builder(embeddingModel).build();
    }
}

@BeforeEach
void buildData() {
    // 1. 声明内容⽂档
    Document doc = Document.builder()
            .text("2025年夏季奥运会将于巴黎举⾏, 预计吸引全球数百万观众")
            .build();
    Document doc2 = Document.builder()
            .text("对⽐学习框架下多语⾔BERT模型的语义表⽰分析")
            .build();
    Document doc3 = Document.builder()
            .text("暮⾊中的⽼槐树在⻛中摇曳, 枯枝划破绯红的晚霞")
            .build();
    Document doc4 = Document.builder()
            .text("基于Transformer的预训练模型在机器翻译中的迁移学习研究")
            .build();

    // 2. 将文本进行向量化, 并且存入向量数据库
    // 存入方法会先对文本进行向量化再存储,所以直接调用其add方法即可
    simpleVectorStore.add(Arrays.asList(doc,doc2, doc3, doc4));
    System.out.println("向量数据库初始化完成");
}

相似性检索

相似性检索就是先把用户问题转换成向量,再到向量数据库里按向量之间的相似度去找最接近的文档或片段,通常还会配合topK、相似度阈值和元数据过滤来控制返回结果

在RAG里,它的作用就是把和问题最相关的上下文先召回出来,再交给大模型组织答案,这样能明显减少“靠记忆猜答案”的情况,让回答更贴近原始资料

对于Spring AI来说,其提供了相似性检索的方法similaritySearch(),这个方法有两个版本:

  • similaritySearch(String query):只传查询文本,SpringAI会用默认的SearchRequest去检索。适合最简单的场景,代码最短
  • similaritySearch(SearchRequest request):传完整检索请求,可以显式指定query(查询关键词)、topK(返回前K个数据)、similarityThreshold(相似度阈值,即最低相似度不能低于指定参数值)以及元信息过滤条件。适合RAG里更精细地控制召回结果,比如只取前5条、只保留相似度高于某个阈值的结果

下面以第二个接口为例:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void similaritySearchTest() {
    SearchRequest request = SearchRequest.builder()
            .query("机器学习")
            .topK(3) 
            .similarityThreshold(0.4)
            .build();
    List<Document> documents = simpleVectorStore.similaritySearch(request);
    System.out.println(documents);
}

需要注意的是,如果返回的文档对象不足topK指定的值,则返回实际数量的结果,而不会凑数据

查询增强

通过上面的案例可以观察到,如何根据关键词从向量数据库中进行搜索相似语义的词。但是在实际应用中,AI模型本身是“知识封闭”的,即它只能基于训练时所见的数据生成回答,无法知晓训练数据之外的新信息(如企业私有文档、最新政策等)。那么,如何将向量数据库中的内容作为额外上下文传递给大模型(LLM),使其在推理时“看到”这些外部知识?

Spring AI提供了基于Advisor机制的开箱即用支持,用于实现检索增强生成(RAG,Retrieval-AugmentedGeneration)。其中QuestionAnswerAdvisorRetrievalAugmentationAdvisor是Spring AI中实现RAG的两个核心组件,分别适用于不同层次和复杂度的场景:

  1. QuestionAnswerAdvisor(面向问答场景的语义检索增强):QuestionAnswerAdvisor是专为问答系统设计的Advisor实现。当你希望快速构建一个基于知识库的智能客服或FAQ助手时,它是首选方案。在用户提问时,它会自动将问题转换为Embedding向量,并在配置好的向量存储(VectorStore)中进行相似性搜索,找出最相关的文档片段。例如,当用户提问:“如何申请年假?”时,QuestionAnswerAdvisor会:

    1. 调用Embedding模型将问题编码为向量
    2. 在企业内部文档的向量数据库中检索top-k最相似的段落
    3. 将这些段落作为上下文拼接到原始Prompt中
    4. 最终将增强后的Prompt交给LLM进行回答生成

    这种方式不仅提升了回答的准确性,还确保了输出内容源自可信的知识源,避免了“幻觉”问题。适用场景:企业内部制度查询、产品帮助文档问答、标准化流程咨询等结构化程度较高的问答任务

  2. RetrievalAugmentationAdvisor(灵活可控的通用RAG增强层):相较于QuestionAnswerAdvisor的“开箱即用”,RetrievalAugmentationAdvisor提供了更高级别的可定制能力。它不局限于问答场景,而是作为一个通用的增强层,适用于任何需要引入外部知识的生成任务。开发者可以通过实现自定义的Retriever接口来控制检索逻辑,比如结合关键词匹配与向量相似度的混合检索策略,或者引入重排序(re-ranker)机制提升召回质量。同时,还可以通过PromptTemplate灵活定义上下文如何融入最终提示

目前先以QuestionAnswerAdvisor为例,测试代码如下:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Test
void chatTest() {
    String message = "机器学习";
    // 使用向量数据库初始化QuestionAnswerAdvisor
    QuestionAnswerAdvisor advisor = QuestionAnswerAdvisor.builder(simpleVectorStore)
            .searchRequest(SearchRequest.builder()
                    .query(message)
                    .topK(3)
                    .similarityThreshold(0.4)
                    .build())
            .build();

    System.out.println(chatClient.prompt()
            .user(message)
            .advisors(advisor)
            .call().content());
}

QuestionAnswerAdvisor有一个默认提示词模板,内容如下:

Java
1
private static final PromptTemplate DEFAULT_PROMPT_TEMPLATE = new PromptTemplate("{query}\n\nContext information is below, surrounded by ---------------------\n\n---------------------\n{question_answer_context}\n---------------------\n\nGiven the context and provided history information and not prior knowledge,\nreply to the user comment. If the answer is not in the context, inform\nthe user that you can't answer the question.\n");

其中{query}表示用户关键词,{question_answer_context}表示问题答案上下文,这两个是变量,用于获取数据,其余内容可以自定义,例如下面的模板:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
PromptTemplate CUSTOM_PROMPT_TEMPLATE = new PromptTemplate("""
请根据以下上下文回答用户问题。

用户问题:{query}

上下文信息如下:
---------------------
{question_answer_context}
---------------------

如果上下文中没有答案,请明确告诉用户你无法回答。
""");

接着,在创建QuestionAnswerAdvisor对象时,通过promptTemplate()方法指定该模板:

Java
1
2
3
4
5
QuestionAnswerAdvisor advisor = 
    QuestionAnswerAdvisor.builder(simpleVectorStore)
        .promptTemplate(promptTemplate)
        // ...
        .build();

提取、转换和加载(ETL)

介绍

前面介绍了RAG(检索增强生成)的基本操作之后,接下来继续深入学习,来聊聊RAG中一个非常关键的环节——ETL

RAG的核心理念是通过从大量数据中检索相关信息来增强生成式AI模型的能力,从而提高生成内容的质量和相关性。而ETL过程正是实现这一目标的关键环节——它将原始文档转化为可以被高效检索和使用的结构化数据,为后续的检索和生成过程奠定基础

ETL是三个英语单词的首字母缩写:

  • Extract(提取):从原始数据源读取并捕获数据,输出为初步解析的中间格式(如纯文本或基础结构化数据),常见源包括:

    • PDF、Word、PPT文档
    • 数据库记录、日志、API响应
    • 网页内容
  • Transform(转换):对提取的数据进行清洗、标准化和适配目标系统。目的是让数据变得“聪明,好用”。常见操作:

    • 文本清洗:比如去除乱码、广告、页眉页脚、统一编码
    • 分块:比如将长文本按语义(句子/段落边界)或长度切分为固定大小块
    • 元数据标注:比如给文本块打上标签,比如来源文件名、创建时间、业务分类等
  • Load(加载):将转换后的数据持久化存储至目标系统。典型操作是:

    • 存入向量数据库(如Milvus、Pinecone、Redis、ES)
    • 原始文本块与元数据同步存储(向量数据库内置或外部对象存储如S3),确保向量与原文本的映射关系

提取、转换和加载(ETL)框架是检索增强生成(RAG)用例中数据处理的支柱。简单来说,ETL就是把原始数据从各种来源“拿过来”,经过清洗和加工,变成结构清晰、适合使用的格式,最后“送进去”目标系统的过程

ETL参考图如下:

ETL API介绍

Spring AI框架对ETL也提供了支持,ETL管道负责将原始、非结构化的数据源转换为结构化的向量存储格式,确保数据处于最适合AI模型检索的优化状态。Spring AI的ETL API设计简洁而强大,主要由三个核心组件构成,每个组件都对应着ETL过程中的一个关键阶段,整体框架如下图:

其中Document是ETL API的核心数据模型,它构成了整个数据处理流程的基本单元。一个Document实例包含文本、元数据(描述文档来源、类型等)和可选的其他媒体类型,如图像、音频和视频,其基本组成如下图:

为了可以提取到数据源的内容并将其转化为Document,Spring AI提供了DocumentReader接口,其实现了Supplier<List<Document>>,拿到提取后的Document对象后,还需要对内容进行处理,确保内容符合要求,此时需要用到DocumentTransformer接口,该类实现了Function<List<Document>, List<Document>>,有了处理好的数据之后,就需要将这些数据进行存储,以便查询检索的时候使用,此时需要用到DocumentWriter接口,该接口实现了Consumer<List<Document>>

上面提到的三大接口在Spring AI中都有常见的实现,可以参考下图:

文档阅读器

在Spring AI中,提供了针对下面的文档阅读器:

  1. JSON:JsonReader
  2. Text:TextReader
  3. HTML(Jsoup):JsoupDocumentReader
  4. Markdown:MarkdownDocumentReader
  5. PDF页面:PagePdfDocumentReader
  6. PDF段落:ParagraphPdfDocumentReader
  7. Tika(DOCX、PPTX、HTML等):TikaDocumentReader

下面针对上面的阅读器进行基础的演示,首先引入Spring AI的依赖:

XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<dependencies>
  <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-openai</artifactId>
      <version>1.1.2</version> <!-- 版本根据Maven仓库任意指定即可 -->
  </dependency>
<dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.1.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Note

除了Spring AI官方,Spring AI Alibaba也提供了文档阅读器,在官方支持的文件类型基础之上,还有其他的类型,具体参考文档

JSON阅读器

JsonReader是一个用于将JSON数据转换为Document对象的工具类,主要用于从JSON文件中提取结构化内容并生成文档对象

  • 对于JSON对象:它返回一个包含单个文档的列表,即一个JSON对象对应一个Document
  • 对于JSON数组:它返回一个文档列表,数组中的每个元素对应一个Document

在Spring AI中,JsonReader提供了三种构造方法:

JsonReader提供三种构造方式:

  1. JsonReader(Resource resource):基本构造函数
  2. JsonReader(Resource resource, String... jsonKeysToUse):指定提取内容的JSON键
  3. JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String... jsonKeysToUse):指定键和元数据生成器

以下面的两段JSON为例:

JSON
1
2
3
4
5
6
7
{
    "sites": [
        { "name":"baidu" , "url":"www.baidu.com" },
        { "name":"google" , "url":"www.google.com" },
        { "name":"微博" , "url":"www.weibo.com" }
    ]
}
JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[
    {
        "id": 1,
        "brand": "Trek",
        "description": "A high-performance mountain bike for trail riding."
    },
    {
        "id": 2,
        "brand": "Cannondale",
        "description": "An aerodynamic road bike for racing enthusiasts."
    }
]

编写下面的测试代码可以得到JSON阅读器提取的结果:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.springframework.core.io.Resource;

@Test
void test1(@Value("classpath:/file/object.json") Resource resource) {
    JsonReader jsonReader = new JsonReader(resource);
    List<Document> documents = jsonReader.read();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出如下:

Text Only
1
2
1
数据信息:{sites=[{name=baidu, url=www.baidu.com}, {name=google, url=www.google.com}, {name=微博, url=www.weibo.com}]}元信息:{}
Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.springframework.core.io.Resource;

@Test
void test2(@Value("classpath:/file/array.json") Resource resource) {
    JsonReader jsonReader = new JsonReader(resource);
    List<Document> documents = jsonReader.read();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出如下:

Text Only
1
2
3
2
数据信息:{id=1, brand=Trek, description=A high-performance mountain bike for trail riding.}元信息:{}
数据信息:{id=2, brand=Cannondale, description=An aerodynamic road bike for racing enthusiasts.}元信息:{}

如果想根据根对象的key找到具体的字段时,可以在构造JsonReader时传递需要的key,以JSON数组为例:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void test2(@Value("classpath:/file/array.json") Resource resource) {
    // 取出
    JsonReader jsonReader = new JsonReader(resource, "brand", "id");
    List<Document> documents = jsonReader.read();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

需要注意的是,key必须为根对象的,因为JsonReader是按“当前 JSON 对象层级”去提取 jsonKeysToUse 的,不会自动递归进子数组,所以根对象上找不到可提取字段时,就会保留整个对象内容.例如对于上面的JSON对象,根对象只有sites,所以哪怕传递了name等字段,提取的结果依旧是整个sites构成的Document对象

在上面的演示中,不论是JSON数组还是JSON对象,元信息都是空的,如果想要有部分元信息,可以使用JsonMetadataGenerator,默认情况下提供一个实现类EmptyJsonMetadataGenerator,表示不携带任何元信息,效果与上面的演示结果一致。如果要携带元信息,可以自行实现JsonMetadataGenerator接口,以JSON数组为例:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Test
void test3(@Value("classpath:/file/array.json") Resource resource) {
    // 参数的Map用于接收完整的Json
    JsonMetadataGenerator jsonMetadataGenerator = (map) -> {
        Map<String, Object> newMap = new HashMap<>();
        // 保留部分Json数据作为元信息
        newMap.put("id", map.get("id"));
        // 使用自定义数据作为元信息
        newMap.put("author", "epsda");
        return newMap;
    };
    JsonReader jsonReader = new JsonReader(resource, jsonMetadataGenerator, "brand", "id");
    List<Document> documents = jsonReader.read();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
1
2
3
4
5
6
7
2
数据信息:brand: Trek
id: 1
元信息:{author=epsda, id=1}
数据信息:brand: Cannondale
id: 2
元信息:{author=epsda, id=2}

纯文本阅读器

TextReader用于将纯文本文件(例如.txt文件)转换为Document对象。默认情况下,TextReader会将一个完整的纯文本文件作为一个Document

以下面的文本文档为例:

Text Only
1
2
3
The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.

编写TextReader代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void test1(@Value("classpath:/file/test.txt")Resource resource) {
    TextReader textReader = new TextReader(resource);
    List<Document> documents =
            textReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
1
2
3
4
1
数据信息:The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.元信息:{charset=UTF-8, source=test.txt}

在上面的结果中可以看到,对于纯文本来说,会有默认的元信息,如果想自定义元信息,可以通过getCustomMetadata()方法,获取一个可修改的Map,添加的键值对会全局注入到生成的Document中,例如下面的代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Test
void test2(@Value("classpath:/file/test.txt")Resource resource) {
    TextReader textReader = new TextReader(resource);
    Map<String, Object> customMetadata =
            textReader.getCustomMetadata();
    // 加入自定义元信息
    customMetadata.put("author", "epsda");
    List<Document> documents =
            textReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
1
2
3
4
1
数据信息:The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.元信息:{charset=UTF-8, source=test.txt, author=epsda}

HTML阅读器

读取HTML文件,Spring AI官方给的是JsoupDocumentReader,需要引入下面的依赖:

XML
1
2
3
4
5
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-jsoup-document-reader</artifactId>
    <version>1.1.2</version>
</dependency>

使用方式上还是和上面两种阅读器比较类似,以下面的HTML代码为例:

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Web Page</title>
    <meta name="description" content="A sample web page for Spring AI">
    <meta name="keywords" content="spring, ai, html, example">
    <meta name="author" content="John Doe">
    <meta name="date" content="2024-01-15">
    <link rel="stylesheet" href="style.css">
</head>
<body>
<header>
    <h1>Welcome to My Page</h1>
</header>
<nav>
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/about">About</a></li>
    </ul>
</nav>
<article>
    <h2>Main Content</h2>
    <p>This is the main content of my web page.</p>
    <p>It contains multiple paragraphs.</p>
    <a href="https://www.example.com">External Link</a>
</article>
<footer>
    <p>&copy; 2024 John Doe</p>
</footer>
</body>
</html>

编写下面的测试代码:

Java
1
2
3
4
5
6
7
8
9
@Test
void test1(@Value("classpath:/file/test.html")Resource resource) {
    JsoupDocumentReader jsoupDocumentReader = new JsoupDocumentReader(resource);
    List<Document> documents = jsoupDocumentReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
1
2
1
数据信息:Welcome to My Page Home About Main Content This is the main content of my web page. It contains multiple paragraphs. External Link © 2024 John Doe元信息:{description=A sample web page for Spring AI, keywords=spring, ai, html, example, title=My Web Page}

除了上面的通过资源进行对象创建外,JsoupDocumentReader还支持传入JsoupDocumentReaderConfig对象,允许用户自定义JsoupDocumentReader的行为,例如:

  • charset:指定HTML文档的字符编码(默认为UTF-8
  • selector:用于指定从哪些元素中提取文本的Jsoup CSS选择器(默认为body
  • separator:用于连接多个选中元素文本的字符串(默认为\n
  • allElements:如果为true,则提取<body>元素中的全部文本,忽略selector(默认为false
  • groupByElement:如果为true,则为selector匹配到的每个元素创建一个独立的Document(默认为false
  • includeLinkUrls:如果为true,则提取绝对链接URL,并将它们添加到元数据中(默认为false
  • metadataTags:要从中提取内容的<meta>标签名称列表(默认为["description","keywords"]
  • additionalMetadata:允许你向所有创建的Document对象添加自定义元数据

参考代码见官方文档

Markdown阅读器

读取Markdown文件,可以使用MarkdownDocumentReader,需要引入下面的依赖:

XML
1
2
3
4
5
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-markdown-document-reader</artifactId>
    <version>1.1.2</version>
</dependency>

以下面的Markdown内容为例:

Markdown
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
This is a Java sample application:

```java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
```

Markdown also provides the possibility to `use inline code formatting throughout` the entire sentence.

---

Another possibility is to set block code without specific highlighting:

```
./mvnw spring-javaformat:apply
```

编写下面的代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Test
void test1(@Value("classpath:/file/test.md")Resource resource) {
    MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder().build();
    MarkdownDocumentReader markdownDocumentReader = new MarkdownDocumentReader(resource, config);
    List<Document> documents =
            markdownDocumentReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

与前面几种阅读器不同的是,对于MarkdownDocumentReader来说,提供的构造方法如果需要传递Resource对象,就必须传递MarkdownDocumentReaderConfig,除非使用字符串形式的文件地址,例如:

Java
1
MarkdownDocumentReader markdownDocumentReader = new MarkdownDocumentReader("classpath:/file/test.md");

对于MarkdownDocumentReaderConfig来说,其允许用户自定义MarkdownDocumentReader的行为:

  • horizontalRuleCreateDocument:当设置为true时,Markdown中的水平分割线会创建新的Document对象
  • includeCodeBlock:当设置为true时,代码块会和上下文文本合并到同一个Document中;当为false时,代码块会生成独立的Document对象
  • includeBlockquote:当设置为true时,引用块会和上下文文本合并到同一个Document中;当为false时,引用块会生成独立的Document对象
  • additionalMetadata:允许你为所有创建出来的Document对象添加自定义元数据

具体使用示例参考官方文档

PDF阅读器

Spring AI提供了两个用于读取PDF文档的工具类,分别是PagePdfDocumentReaderParagraphPdfDocumentReader,均基于Apache PDFBox库实现,能够将PDF文件解析为结构化的文本内容,即Document对象列表,适用于后续的AI处理,如大模型输入、文本向量化、RAG检索等。下面对这两个工具类进行介绍:

  • PagePdfDocumentReader:按“页”拆分PDF。官方说明是把解析出来的页面分组为Document,默认pagesPerDocument=1,并且会在元数据里记录文件名、起始页、结束页等信息。适合想保留页码边界、按页检索、或者PDF本身结构不稳定的场景
  • ParagraphPdfDocumentReader:按“段落”拆分PDF。它会利用PDF的目录/书签,也就是TOC信息,把输入PDF切成一个个段落,每个段落输出一个Document。更适合目录清晰、章节结构明确的PDF,方便按章节理解和检索

首先引入下面的依赖:

XML
1
2
3
4
5
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pdf-document-reader</artifactId>
    <version>1.1.2</version>
</dependency>

以PDF文件(test.pdf)为例,编写如下的代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void test1(@Value("classpath:/file/test.pdf")Resource resource) {
    PagePdfDocumentReader pagePdfDocumentReader = new PagePdfDocumentReader(resource);
    List<Document> documents =
            pagePdfDocumentReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}
Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void test2(@Value("classpath:/file/test.pdf")Resource resource) {
    ParagraphPdfDocumentReader paragraphPdfDocumentReader = new ParagraphPdfDocumentReader(resource);
    List<Document> documents =
            paragraphPdfDocumentReader.get();
    System.out.println(documents.size());
    documents.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

想要配置阅读器,可以使用PdfDocumentReaderConfig,其PagePdfDocumentReaderParagraphPdfDocumentReader共用的配置类,用来控制PDF读取时的分组、边距、文本格式化和段落位置处理。它通过builder()创建,通过build()生成不可变配置。它的主要配置项是:

  • withPagesPerDocument(int):控制每个Document包含多少页,0表示所有页放进同一个Document,默认值是1
  • withPageTopMargin(int):配置页面顶部边距,默认值是0
  • withPageBottomMargin(int):配置页面底部边距,默认值是0
  • withPageExtractedTextFormatter(ExtractedTextFormatter):设置提取文本的格式化器,用来处理页面抽取出来的文本格式
  • withReversedParagraphPosition(boolean):配置是否反转段落位置,默认值是false

具体示例可以参考官方文档

通用文档阅读器

TikaDocumentReaderSpring AI提供的一个通用文档读取器,基于Apache Tika引擎实现,能够从多种格式的文件中提取纯文本内容,并将其统一转换为Document对象列表。Tika支持多格式自动识别与解析,无需手动指定文件格式。包括常见的Office文档(如DOCXXLSXPPTX)、PDFHTML、音频、视频和图像文件,完整文件列表可以参考文档

要使用Tika需要引入对应的依赖:

XML
1
2
3
4
5
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
    <version>1.1.2</version>
</dependency>

使用方式和前面的阅读器类似,此处不再进一步演示

文档转换器

在大模型应用中,原始文档通常太长、格式混乱或缺乏结构化元数据,无法直接输入给LLM使用,为此Spring AI提供了一组文档转换器(Document Transformers),它们就像一个“智能流水线”,把原始文档一步步加工成适合向量化、检索和生成的高质量片段

主要包含4个组件:

  1. TextSplitter(文本切分器):把长文切成小块
  2. ContentFormatTransformer(内容格式转换器):统一清洗文本
  3. KeywordMetadataEnricher(关键词提取器):借助AI模型自动提取关键词,类似给文档“贴标签”
  4. SummaryMetadataEnricher(摘要生成器):借助AI模型生成文档摘要

这些工具共同作用,提升后续AI处理的准确性与效率

文本切分器

TokenTextSplitterTextSplitter的一个实现,它基于OpenAI推荐的CL100K_BASE的分词编码方案,用于将长文本按token数量切分为多个较小的Document实例。可以把TokenTextSplitter理解为一个“智能断句”的分块专家

Note

一个token不等于一个汉字!中文通常每1~2个汉字占1个token,具体取决于词汇和语境。

以前面文档阅读器部分的纯文本文件为例,使用TokenTextSplitterTokenTextSplitter有两种常见的创建方式:

  1. TokenTextSplitter():无参构造方法,直接使用默认切分策略。按当前官方文档,默认chunkSize800minChunkSizeChars350minChunkLengthToEmbed5maxNumChunks10000keepSeparator默认是true,编码默认使用CL100K_BASE。适合你先快速接入,再观察切分效果
  2. TokenTextSplitter(int defaultChunkSize, int minChunkSizeChars, int minChunkLengthToEmbed, int maxNumChunks, boolean keepSeparator):带参构造方法,允许你手动控制切分行为:

    • defaultChunkSize:每个块的目标token数,决定切得多大
    • minChunkSizeChars:达到这个字符数后,才更积极地尝试按标点断开。需要注意,此处默认的标点是英文标点,如果需要按照中文标点,则需要重写分割方法。如果Spring AI依赖是1.1.4及以上,可以通过设置punctuationMarks指定中文标点,例如.withPunctuationMarks(List.of('。', '?', '!', ';'))
    • minChunkLengthToEmbed:太短的片段会被过滤掉
    • maxNumChunks:最多切出多少段,防止无限拆分
    • keepSeparator:是否保留换行等分隔符

以无参为例:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Test
void test1(@Value("classpath:/file/test.txt")Resource resource) {
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .build();
    List<Document> apply = splitter.apply(documents);
    System.out.println(apply.size());
    apply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
1
2
3
4
1
数据信息:The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.元信息:{charset=UTF-8, chunk_index=0, parent_document_id=92e41033-24d8-4d6a-9b26-8e17ed470e5c, source=test.txt, total_chunks=1}

修改Spring AI依赖版本为1.1.4并适当调整参数,新增中文内容:

Text Only
1
2
3
4
The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.
这是一段适合用于文本分割测试的中文纯文本内容。它包含多个完整句子,句子之间有清晰的停顿,也有一些稍长的描述,方便观察切分后的效果。比如在知识库问答场景中,系统通常需要先把原始文档拆成若干较小的片段,再分别进行向量化和检索。为了让切分结果更自然,文本最好同时包含标点、换行和不同长度的句子。这样既能测试按句切分的能力,也能测试在内容较长时是否会出现断句不合理的问题。

编写代码例如:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Test
void test2(@Value("classpath:/file/test.txt")Resource resource) {
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withMinChunkSizeChars(50)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))
            .withMaxNumChunks(100)
            .withChunkSize(100)
            .build();
    List<Document> apply = splitter.apply(documents);
    System.out.println(apply.size());
    apply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果:

Text Only
1
2
3
4
5
6
7
4
数据信息:The Extract, Transform, and Load (ETL) framework serves as the backbone of data processing within the Retrieval Augmented Generation (RAG) use case.
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
The RAG use case is text to augment the capabilities of generative models by retrieving relevant information from a body of data to enhance the quality and relevance of the generated output.元信息:{charset=UTF-8, chunk_index=0, parent_document_id=63093330-1d2c-4a05-a02e-c2c92384ac18, source=test.txt, total_chunks=4}
数据信息:这是一段适合用于文本分割测试的中文纯文本内容。它包含多个完整句子,句子之间有清晰的停顿,也有一些稍长的描述,方便观察切分后的效果。元信息:{charset=UTF-8, chunk_index=1, parent_document_id=63093330-1d2c-4a05-a02e-c2c92384ac18, source=test.txt, total_chunks=4}
数据信息:比如在知识库问答场景中,系统通常需要先把原始文档拆成若干较小的片段,再分别进行向量化和检索。为了让切分结果更自然,文本最好同时包含标点、换行和不同长度的句子。元信息:{charset=UTF-8, chunk_index=2, parent_document_id=63093330-1d2c-4a05-a02e-c2c92384ac18, source=test.txt, total_chunks=4}
数据信息:这样既能测试按句切分的能力,也能测试在内容较长时是否会出现断句不合理的问题。元信息:{charset=UTF-8, chunk_index=3, parent_document_id=63093330-1d2c-4a05-a02e-c2c92384ac18, source=test.txt, total_chunks=4}

TokenTextSplitter处理文本内容的流程如下:

  1. 它会先使用CL100K_BASE编码将输入文本编码为token
  2. 它会基于chunkSize把编码后的文本切分为多个片段
  3. 对于每个片段:

    1. 它会先将片段解码回文本
    2. 只有当总token数量超过分块大小时,它才会尝试在minChunkSizeChars之后,结合配置的punctuationMarks查找合适的断点
    3. 如果找到了断点,它就会在该位置截断片段
    4. 它会对片段进行裁剪,并根据keepSeparator设置选择性移除换行符
    5. 如果最终片段长度大于minChunkLengthToEmbed,就会将其加入输出
  4. 这个过程会一直持续,直到所有token都被处理完,或者达到maxNumChunks

  5. 如果还有剩余文本,并且它的长度大于minChunkLengthToEmbed,就会作为最后一个片段加入

内容格式转化器

ContentFormatTransformerSpring AI框架中用于统一管理和调整文档内容格式的处理器。它常用于处理从文件中读取的文档,确保它们以整洁、安全的方式被AI看到和使用。简单说,就是让杂乱的文档变得整齐划一,该露的露,该藏的藏。常用于RAG系统中对加载的文档进行标准化预处理,从而提升后续检索与生成的质量和可控性

它就像一个“文档化妆师”,不改变文档原本的内容,而是决定在什么时候、哪些信息要展示、哪些信息要隐藏,并且统一排版格式

关键词提取器

KeywordMetadataEnricher是一个基于大模型的元数据增强器,利用ChatModel分析文档内容,生成关键词列表,并作为字符串添加至文档元数据中。默认使用的元数据键是excerpt_keywords。可以把KeywordMetadataEnricher看做一个“自动打标签的机器人”

KeywordMetadataEnricher提供了两个常见的构造方法:

  • KeywordMetadataEnricher(ChatModel chatModel,int keywordCount):使用默认的关键词提取模板,按指定数量提取关键词。适合只想控制“提取几个关键词”,不想自定义提示词的场景
  • KeywordMetadataEnricher(ChatModel chatModel,PromptTemplate keywordsTemplate):使用自定义模板来提取关键词。适合想控制提示词、输出格式,或者想让关键词提取更贴合业务语境的场景

以读取纯文本文件为例,文件内容如下:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
商场会员卡办理规则
尊敬的顾客:
欢迎您选择加入我们的会员大家庭!以下是本商场会员卡的办理规则,希望您仔细阅读并理解,以便更好地享受会员权益。
一、会员卡类型
本商场提供两种会员卡类型:普通会员卡和金卡会员卡。
普通会员卡:免费办理。
金卡会员卡:需缴纳年费 299元。
二、办理条件
年龄要求:年满18周岁及以上,具有完全民事行为能力的个人均可申请办理会员卡。
身份验证:办理会员卡时,需提供有效身份证件(身份证、护照等)进行登记,以确保会员信息的真实性和准确性。
联系方式:请提供有效的手机号码和电子邮箱地址,以便商场及时向您发送会员专属优惠信息、活动通知等。
三、办理流程
线上办理:您可以通过本商场官方网站或手机应用程序,填写会员申请表,上传身份证件照片,并提交申请。审核通过后,我们将通过短信或邮件通知您会员卡办理成功,并告知您会员卡号及初始密码。
线下办理:您也可以前往商场客服中心,由工作人员协助您填写会员申请表,并提交身份证件进行审核。审核通过后,现场为您发放会员卡,并告知您会员卡号及初始密码。
四、会员权益
积分累计:会员在本商场内消费可获得积分,每消费 1元 获得 1积分。积分可用于兑换商场内的商品、服务或抵扣现金(具体兑换规则详见积分兑换细则)。
专属折扣:会员可享受商场内部分品牌提供的专属折扣优惠。普通会员享受 95折 优惠,金卡会员享受 9折 优惠。
优先服务:会员在商场内购物时,可享受优先结账、优先退换货等服务。
生日特权:会员生日当月,可享受商场赠送的生日礼品或专属优惠券,价值 50元。
会员活动:会员可优先参与商场举办的各类会员专属活动,如新品试用、时尚秀、会员专享购物节等。
五、会员卡使用规则
消费积分:会员在本商场内消费时,需出示会员卡或告知收银员会员卡号,以便积分累计。若未出示会员卡或未告知会员卡号,导致积分未累计的,商场不予补录积分。
积分查询:会员可通过本商场官方网站、手机应用程序或客服热线查询积分余额及积分明细。
积分有效期:会员积分自累计之日起有效期为 一年,逾期未使用的积分将自动清零。
会员卡挂失与补办:若会员卡不慎遗失或被盗,会员应立即通过本商场客服热线进行挂失。挂失成功后,会员可携带有效身份证件前往商场客服中心办理补卡手续,补卡需缴纳工本费 20元。
六、会员卡升级与降级
升级条件:普通会员在一年内累计消费金额达到 5000元,可自动升级为金卡会员,并享受金卡会员权益。
降级规则:金卡会员若在一年内未达到 3000元 的消费保级标准,则自动降级为普通会员。
七、会员卡注销
会员若因个人原因不再使用会员卡,可携带有效身份证件及会员卡前往商场客服中心办理会员卡注销手续。注销成功后,会员卡内剩余积分将自动清零,已缴纳的金卡年费不予退还。
本商场会员卡办理规则的最终解释权归本商场所有。如有任何疑问,欢迎随时咨询商场客服人员。
祝您购物愉快!

使用第一个构造方法的两个参数:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Autowired
private ChatModel chatModel;

@Test
void test1(@Value("classpath:/file/test.txt") Resource resource) {
    // 读取文件
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
            .keywordCount(2)
            .build();
    // 切割文本——为了更好的演示出效果
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withMinChunkSizeChars(50)
            .withMaxNumChunks(100)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))
            .withChunkSize(100)
            .build();
    List<Document> splitterApply = splitter.apply(documents);
    List<Document> enricherApply = enricher.apply(splitterApply);
    System.out.println(enricherApply.size());
    enricherApply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
16
数据信息:商场会员卡办理规则
尊敬的顾客:
欢迎您选择加入我们的会员大家庭!以下是本商场会员卡的办理规则,希望您仔细阅读并理解,以便更好地享受会员权益。元信息:{charset=UTF-8, chunk_index=0, excerpt_keywords=会员卡办理,会员权益, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:一、会员卡类型
本商场提供两种会员卡类型:普通会员卡和金卡会员卡。
普通会员卡:免费办理。
金卡会员卡:需缴纳年费 299元。元信息:{charset=UTF-8, chunk_index=1, excerpt_keywords=会员卡类型, 年费政策, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:二、办理条件
年龄要求:年满18周岁及以上,具有完全民事行为能力的个人均可申请办理会员卡。
身份验证:办理会员卡时,需提供有效身份证件(身份证、护照等)进行登记,以确保会员信息的真实性和准确性元信息:{charset=UTF-8, chunk_index=2, excerpt_keywords=会员卡办理, 身份验证, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:。
联系方式:请提供有效的手机号码和电子邮箱地址,以便商场及时向您发送会员专属优惠信息、活动通知等。
三、办理流程
线上办理:您可以通过本商场官方网站或手机应用程序,填写会员申请表,上传身份证件照片,并提交申请。元信息:{charset=UTF-8, chunk_index=3, excerpt_keywords=会员注册, 信息采集, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:审核通过后,我们将通过短信或邮件通知您会员卡办理成功,并告知您会员卡号及初始密码。
线下办理:您也可以前往商场客服中心,由工作人员协助您填写会员申请表,并提交身份证件进行审核。元信息:{charset=UTF-8, chunk_index=4, excerpt_keywords=会员卡办理,审核通知, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:审核通过后,现场为您发放会员卡,并告知您会员卡号及初始密码。
四、会员权益
积分累计:会员在本商场内消费可获得积分,每消费 1元 获得 1积分。元信息:{charset=UTF-8, chunk_index=5, excerpt_keywords=会员卡, 积分累计, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:积分可用于兑换商场内的商品、服务或抵扣现金(具体兑换规则详见积分兑换细则)。
专属折扣:会员可享受商场内部分品牌提供的专属折扣优惠。元信息:{charset=UTF-8, chunk_index=6, excerpt_keywords=积分兑换,会员折扣, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:普通会员享受 95折 优惠,金卡会员享受 9折 优惠。
优先服务:会员在商场内购物时,可享受优先结账、优先退换货等服务。元信息:{charset=UTF-8, chunk_index=7, excerpt_keywords=会员折扣, 优先服务, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:生日特权:会员生日当月,可享受商场赠送的生日礼品或专属优惠券,价值 50元。
会员活动:会员可优先参与商场举办的各类会员专属活动,如新品试用、时尚秀、会员专享购物节等。元信息:{charset=UTF-8, chunk_index=8, excerpt_keywords=生日礼品, 会员专属活动, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:五、会员卡使用规则
消费积分:会员在本商场内消费时,需出示会员卡或告知收银员会员卡号,以便积分累计。若未出示会员卡或未告知会员卡号,导致积分未累计的,商场不予补录积分。元信息:{charset=UTF-8, chunk_index=9, excerpt_keywords=会员卡积分, 积分补录, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:积分查询:会员可通过本商场官方网站、手机应用程序或客服热线查询积分余额及积分明细。
积分有效期:会员积分自累计之日起有效期为 一年,逾期未使用的积分将自动清零。元信息:{charset=UTF-8, chunk_index=10, excerpt_keywords=积分查询, 有效期一年, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:会员卡挂失与补办:若会员卡不慎遗失或被盗,会员应立即通过本商场客服热线进行挂失。挂失成功后,会员可携带有效身份证件前往商场客服中心办理补卡手续,补卡需缴纳元信息:{charset=UTF-8, chunk_index=11, excerpt_keywords=挂失流程,补卡手续, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:工本费 20元。
六、会员卡升级与降级
升级条件:普通会员在一年内累计消费金额达到 5000元,可自动升级为金卡会员,并享受金卡会员权益。元信息:{charset=UTF-8, chunk_index=12, excerpt_keywords=会员卡升级, 消费累计, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:降级规则:金卡会员若在一年内未达到 3000元 的消费保级标准,则自动降级为普通会员。
七、会员卡注销
会员若因个人原因不再使用会员卡,可携带有效身份证件及会员卡前往商场客服中心办理元信息:{charset=UTF-8, chunk_index=13, excerpt_keywords=降级规则, 会员卡注销, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:会员卡注销手续。注销成功后,会员卡内剩余积分将自动清零,已缴纳的金卡年费不予退还。
本商场会员卡办理规则的最终解释权归本商场所有。元信息:{charset=UTF-8, chunk_index=14, excerpt_keywords=会员卡注销,积分清零, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}
数据信息:如有任何疑问,欢迎随时咨询商场客服人员。
祝您购物愉快!元信息:{charset=UTF-8, chunk_index=15, excerpt_keywords=customer service, shopping experience, parent_document_id=74cc59a7-e91a-4cae-9ec1-2937bf006284, source=rules.txt, total_chunks=16}

如果不喜欢默认生成的关键字,可以在提示词模板中自定义需要的提示词,重点关注自定义提示词模板部分:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
void test2(@Value("classpath:/file/rules.txt") Resource resource) {
    // 读取文件
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    // 自定义提示词模板
    PromptTemplate promptTemplate = new PromptTemplate("""
        根据给定的文本: {context_str}, 生成成关键字, 只允许以下关键字
        [会员宗旨, 会员类型, 会员注册, 积分制度, 会员权益, 会员行为, 会员服务, 公告, 隐私保护]
        只返回关键字, 其他信息不返回
        """);
    KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
            .keywordsTemplate(promptTemplate)
            .keywordCount(2)
            .build();
    // 切割文本——为了更好的演示出效果
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withMinChunkSizeChars(50)
            .withMaxNumChunks(100)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))
            .withChunkSize(100)
            .build();
    List<Document> splitterApply = splitter.apply(documents);
    List<Document> enricherApply = enricher.apply(splitterApply);
    System.out.println(enricherApply.size());
    enricherApply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
16
数据信息:商场会员卡办理规则
尊敬的顾客:
欢迎您选择加入我们的会员大家庭!以下是本商场会员卡的办理规则,希望您仔细阅读并理解,以便更好地享受会员权益。元信息:{charset=UTF-8, chunk_index=0, excerpt_keywords=会员注册, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:一、会员卡类型
本商场提供两种会员卡类型:普通会员卡和金卡会员卡。
普通会员卡:免费办理。
金卡会员卡:需缴纳年费 299元。元信息:{charset=UTF-8, chunk_index=1, excerpt_keywords=会员类型, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:二、办理条件
年龄要求:年满18周岁及以上,具有完全民事行为能力的个人均可申请办理会员卡。
身份验证:办理会员卡时,需提供有效身份证件(身份证、护照等)进行登记,以确保会员信息的真实性和准确性元信息:{charset=UTF-8, chunk_index=2, excerpt_keywords=会员注册, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:。
联系方式:请提供有效的手机号码和电子邮箱地址,以便商场及时向您发送会员专属优惠信息、活动通知等。
三、办理流程
线上办理:您可以通过本商场官方网站或手机应用程序,填写会员申请表,上传身份证件照片,并提交申请。元信息:{charset=UTF-8, chunk_index=3, excerpt_keywords=会员注册, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:审核通过后,我们将通过短信或邮件通知您会员卡办理成功,并告知您会员卡号及初始密码。
线下办理:您也可以前往商场客服中心,由工作人员协助您填写会员申请表,并提交身份证件进行审核。元信息:{charset=UTF-8, chunk_index=4, excerpt_keywords=会员注册, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:审核通过后,现场为您发放会员卡,并告知您会员卡号及初始密码。
四、会员权益
积分累计:会员在本商场内消费可获得积分,每消费 1元 获得 1积分。元信息:{charset=UTF-8, chunk_index=5, excerpt_keywords=会员权益, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:积分可用于兑换商场内的商品、服务或抵扣现金(具体兑换规则详见积分兑换细则)。
专属折扣:会员可享受商场内部分品牌提供的专属折扣优惠。元信息:{charset=UTF-8, chunk_index=6, excerpt_keywords=积分制度, 会员权益, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:普通会员享受 95折 优惠,金卡会员享受 9折 优惠。
优先服务:会员在商场内购物时,可享受优先结账、优先退换货等服务。元信息:{charset=UTF-8, chunk_index=7, excerpt_keywords=会员权益, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:生日特权:会员生日当月,可享受商场赠送的生日礼品或专属优惠券,价值 50元。
会员活动:会员可优先参与商场举办的各类会员专属活动,如新品试用、时尚秀、会员专享购物节等。元信息:{charset=UTF-8, chunk_index=8, excerpt_keywords=会员权益, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:五、会员卡使用规则
消费积分:会员在本商场内消费时,需出示会员卡或告知收银员会员卡号,以便积分累计。若未出示会员卡或未告知会员卡号,导致积分未累计的,商场不予补录积分。元信息:{charset=UTF-8, chunk_index=9, excerpt_keywords=积分制度, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:积分查询:会员可通过本商场官方网站、手机应用程序或客服热线查询积分余额及积分明细。
积分有效期:会员积分自累计之日起有效期为 一年,逾期未使用的积分将自动清零。元信息:{charset=UTF-8, chunk_index=10, excerpt_keywords=积分制度, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:会员卡挂失与补办:若会员卡不慎遗失或被盗,会员应立即通过本商场客服热线进行挂失。挂失成功后,会员可携带有效身份证件前往商场客服中心办理补卡手续,补卡需缴纳元信息:{charset=UTF-8, chunk_index=11, excerpt_keywords=会员服务, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:工本费 20元。
六、会员卡升级与降级
升级条件:普通会员在一年内累计消费金额达到 5000元,可自动升级为金卡会员,并享受金卡会员权益。元信息:{charset=UTF-8, chunk_index=12, excerpt_keywords=会员权益, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:降级规则:金卡会员若在一年内未达到 3000元 的消费保级标准,则自动降级为普通会员。
七、会员卡注销
会员若因个人原因不再使用会员卡,可携带有效身份证件及会员卡前往商场客服中心办理元信息:{charset=UTF-8, chunk_index=13, excerpt_keywords=会员行为, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:会员卡注销手续。注销成功后,会员卡内剩余积分将自动清零,已缴纳的金卡年费不予退还。
本商场会员卡办理规则的最终解释权归本商场所有。元信息:{charset=UTF-8, chunk_index=14, excerpt_keywords=会员服务, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}
数据信息:如有任何疑问,欢迎随时咨询商场客服人员。
祝您购物愉快!元信息:{charset=UTF-8, chunk_index=15, excerpt_keywords=会员服务, parent_document_id=95dc74ba-3ec3-4ef3-92c0-5160396e3ec3, source=rules.txt, total_chunks=16}

因为内容过多,此处提供一个文本对比工具进行比对,重点关注元信息部分的区别

需要注意的是,如果设置了自定义的模板,keywordCount值会被忽略,这一点在控制台可以看到:

Text Only
1
2026-04-07T20:13:21.632+08:00  WARN 48840 --- [spring-ai-document-transformer] [           main] o.s.a.m.t.KeywordMetadataEnricher        : keywordCount will be ignored as keywordsTemplate is set.

摘要生成器

SummaryMetadataEnricher利用ChatModel为每个文档生成摘要信息,并将其作为元数据的一部分添加到文档中。也可以根据需要,指定为当前文档或相邻文档(上一个和下一个)生成摘要,添加到元数据中。可以把SummaryMetadataEnricher看做一个“会写读书笔记的助手”

SummaryMetadataEnricher支持三种摘要类型(通过SummaryType枚举指定):

  • CURRENT:当前文档摘要
  • PREVIOUS:前一个文档摘要
  • NEXT:下一个文档摘要

SummaryMetadataEnricher常见的构造方法如下:

  • SummaryMetadataEnricher(ChatModel chatModel,List<SummaryType> summaryTypes):这是最常用的基础构造方法。只要传入大模型和要生成哪些摘要类型,它就会使用默认摘要模板去生成对应的摘要元数据,适合快速接入
  • SummaryMetadataEnricher(ChatModel chatModel,List<SummaryType> summaryTypes,String summaryTemplate,MetadataMode metadataMode):这是可定制版本。它更适合想调整摘要提示词,或者想控制哪些元数据参与处理的场景。除了chatModelsummaryTypes两个参数之外,还可以自己传summaryTemplate自定义用于总结的提示词模板,另外还可以使用MetadataMode,用于控制Document在格式化输出时,元数据要保留到什么程度。MetadataMode是一个枚举类型,有四种常量:

    • NONE:不包含元数据,只输出正文内容
    • EMBED:输出适合向量化embedding使用的内容,通常会保留一部分对检索有帮助的元数据
    • INFERENCE:输出适合推理、生成回答时使用的内容,通常会保留一部分对模型理解更有帮助的元数据
    • ALL:输出全部元数据,正文和元数据都会完整保留

使用第一种构造方法的参数,生成三种摘要:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Autowired
private ChatModel chatModel;

@Test
void test1(@Value("classpath:/file/rules.txt") Resource resource) {
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    // 切割文本——为了更好的演示出效果
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withMinChunkSizeChars(50)
            .withMaxNumChunks(100)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))
            .withChunkSize(100)
            .build();
    SummaryMetadataEnricher enricher =
            new SummaryMetadataEnricher(chatModel, List.of(SummaryMetadataEnricher.SummaryType.PREVIOUS,
            SummaryMetadataEnricher.SummaryType.CURRENT, SummaryMetadataEnricher.SummaryType.NEXT));
    List<Document> splitterApply = splitter.apply(documents);
    List<Document> enricherApply = enricher.apply(splitterApply);
    System.out.println(enricherApply.size());
    enricherApply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
16
数据信息:商场会员卡办理规则
尊敬的顾客:
欢迎您选择加入我们的会员大家庭!以下是本商场会员卡的办理规则,希望您仔细阅读并理解,以便更好地享受会员权益。元信息:{charset=UTF-8, chunk_index=0, section_summary=**Key Topics:**  
- Introduction to the mall membership card application process.  
- Welcome message for new members.  
- Instructions for customers to read and understand the rules to fully benefit from membership privileges.  

**Key Entities:**  
- Mall membership card  
- Customers (referred to as "尊敬的顾客" – respected customers)  
- Membership benefits/rights (会员权益)  
- Membership community/family (会员大家庭), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership card types offered by the mall  
- Differences between card tiers (cost, eligibility)  

**Key Entities:**  
- 普通会员卡 (Standard Membership Card) – free to apply  
- 金卡会员卡 (Gold Membership Card) – annual fee of ¥299  
- The mall (implied as the issuing entity)}
数据信息:一、会员卡类型
本商场提供两种会员卡类型:普通会员卡和金卡会员卡。
普通会员卡:免费办理。
金卡会员卡:需缴纳年费 299元。元信息:{charset=UTF-8, chunk_index=1, section_summary=**Key Topics:**  
- Membership card types offered by the mall  
- Differences between card tiers (cost, eligibility)  

**Key Entities:**  
- 普通会员卡 (Standard Membership Card) – free to apply  
- 金卡会员卡 (Gold Membership Card) – annual fee of ¥299  
- The mall (implied as the issuing entity), prev_section_summary=**Key Topics:**  
- Introduction to the mall membership card application process.  
- Welcome message for new members.  
- Instructions for customers to read and understand the rules to fully benefit from membership privileges.  

**Key Entities:**  
- Mall membership card  
- Customers (referred to as "尊敬的顾客" – respected customers)  
- Membership benefits/rights (会员权益)  
- Membership community/family (会员大家庭), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**核心主题**:会员卡办理条件  
**关键实体与要求**:  
1. **申请人资格**  
   - 年龄:年满18周岁及以上  
   - 民事行为能力:具有完全民事行为能力  
2. **身份验证**  
   - 所需证件:有效身份证件(如身份证、护照)  
   - 目的:确保会员信息的真实性与准确性}
数据信息:二、办理条件
年龄要求:年满18周岁及以上,具有完全民事行为能力的个人均可申请办理会员卡。
身份验证:办理会员卡时,需提供有效身份证件(身份证、护照等)进行登记,以确保会员信息的真实性和准确性元信息:{charset=UTF-8, chunk_index=2, section_summary=**核心主题**:会员卡办理条件  
**关键实体与要求**:  
1. **申请人资格**  
   - 年龄:年满18周岁及以上  
   - 民事行为能力:具有完全民事行为能力  
2. **身份验证**  
   - 所需证件:有效身份证件(如身份证、护照)  
   - 目的:确保会员信息的真实性与准确性, prev_section_summary=**Key Topics:**  
- Membership card types offered by the mall  
- Differences between card tiers (cost, eligibility)  

**Key Entities:**  
- 普通会员卡 (Standard Membership Card) – free to apply  
- 金卡会员卡 (Gold Membership Card) – annual fee of ¥299  
- The mall (implied as the issuing entity), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership contact information requirements  
- Membership application process (online method)  

**Key Entities:**  
- Mobile phone number  
- Email address  
- Mall (商场)  
- Official website  
- Mobile application  
- Membership application form  
- ID card photo}
数据信息:。
联系方式:请提供有效的手机号码和电子邮箱地址,以便商场及时向您发送会员专属优惠信息、活动通知等。
三、办理流程
线上办理:您可以通过本商场官方网站或手机应用程序,填写会员申请表,上传身份证件照片,并提交申请。元信息:{charset=UTF-8, chunk_index=3, section_summary=**Key Topics:**  
- Membership contact information requirements  
- Membership application process (online method)  

**Key Entities:**  
- Mobile phone number  
- Email address  
- Mall (商场)  
- Official website  
- Mobile application  
- Membership application form  
- ID card photo, prev_section_summary=**核心主题**:会员卡办理条件  
**关键实体与要求**:  
1. **申请人资格**  
   - 年龄:年满18周岁及以上  
   - 民事行为能力:具有完全民事行为能力  
2. **身份验证**  
   - 所需证件:有效身份证件(如身份证、护照)  
   - 目的:确保会员信息的真实性与准确性, parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership card approval notification process  
- Offline membership application procedure  

**Key Entities:**  
- SMS/email (notification channels)  
- Membership card number & initial password (provided upon approval)  
- Mall customer service center (offline application location)  
- Staff (assists with offline process)  
- Membership application form (offline requirement)  
- ID document (required for offline verification)}
数据信息:审核通过后,我们将通过短信或邮件通知您会员卡办理成功,并告知您会员卡号及初始密码。
线下办理:您也可以前往商场客服中心,由工作人员协助您填写会员申请表,并提交身份证件进行审核。元信息:{charset=UTF-8, chunk_index=4, section_summary=**Key Topics:**  
- Membership card approval notification process  
- Offline membership application procedure  

**Key Entities:**  
- SMS/email (notification channels)  
- Membership card number & initial password (provided upon approval)  
- Mall customer service center (offline application location)  
- Staff (assists with offline process)  
- Membership application form (offline requirement)  
- ID document (required for offline verification), prev_section_summary=**Key Topics:**  
- Membership contact information requirements  
- Membership application process (online method)  

**Key Entities:**  
- Mobile phone number  
- Email address  
- Mall (商场)  
- Official website  
- Mobile application  
- Membership application form  
- ID card photo, parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Card Issuance:** The process of receiving a physical membership card after approval.
2.  **Membership Benefits Introduction:** The beginning of a section detailing the privileges of being a member.
3.  **Points Accumulation:** A specific benefit where spending money earns reward points.

**Key Entities:**
*   **Member / Customer:** The individual who undergoes the approval process and receives the card and benefits.
*   **Membership Card:** The physical card issued, containing a unique card number and initial password.
*   **The Mall /商场:** The specific retail establishment where the membership is valid and where spending earns points.
*   **Points /积分:** The reward currency earned through purchases.}
数据信息:审核通过后,现场为您发放会员卡,并告知您会员卡号及初始密码。
四、会员权益
积分累计:会员在本商场内消费可获得积分,每消费 1元 获得 1积分。元信息:{charset=UTF-8, chunk_index=5, section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Card Issuance:** The process of receiving a physical membership card after approval.
2.  **Membership Benefits Introduction:** The beginning of a section detailing the privileges of being a member.
3.  **Points Accumulation:** A specific benefit where spending money earns reward points.

**Key Entities:**
*   **Member / Customer:** The individual who undergoes the approval process and receives the card and benefits.
*   **Membership Card:** The physical card issued, containing a unique card number and initial password.
*   **The Mall /商场:** The specific retail establishment where the membership is valid and where spending earns points.
*   **Points /积分:** The reward currency earned through purchases., prev_section_summary=**Key Topics:**  
- Membership card approval notification process  
- Offline membership application procedure  

**Key Entities:**  
- SMS/email (notification channels)  
- Membership card number & initial password (provided upon approval)  
- Mall customer service center (offline application location)  
- Staff (assists with offline process)  
- Membership application form (offline requirement)  
- ID document (required for offline verification), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Usage of Membership Points:** Points can be exchanged for goods, services, or used as cash vouchers within the mall.
2.  **Exclusive Member Discounts:** Members receive special discounts offered by select brands within the mall.

**Key Entities:**
*   **Points / Membership Points**
*   **Mall**
*   **Goods and Services**
*   **Cash Vouchers / Cash Deductions**
*   **Members / Members (implied)**
*   **Brands (within the mall)**}
数据信息:积分可用于兑换商场内的商品、服务或抵扣现金(具体兑换规则详见积分兑换细则)。
专属折扣:会员可享受商场内部分品牌提供的专属折扣优惠。元信息:{charset=UTF-8, chunk_index=6, section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Usage of Membership Points:** Points can be exchanged for goods, services, or used as cash vouchers within the mall.
2.  **Exclusive Member Discounts:** Members receive special discounts offered by select brands within the mall.

**Key Entities:**
*   **Points / Membership Points**
*   **Mall**
*   **Goods and Services**
*   **Cash Vouchers / Cash Deductions**
*   **Members / Members (implied)**
*   **Brands (within the mall)**, prev_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Card Issuance:** The process of receiving a physical membership card after approval.
2.  **Membership Benefits Introduction:** The beginning of a section detailing the privileges of being a member.
3.  **Points Accumulation:** A specific benefit where spending money earns reward points.

**Key Entities:**
*   **Member / Customer:** The individual who undergoes the approval process and receives the card and benefits.
*   **Membership Card:** The physical card issued, containing a unique card number and initial password.
*   **The Mall /商场:** The specific retail establishment where the membership is valid and where spending earns points.
*   **Points /积分:** The reward currency earned through purchases., parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership benefits (discounts and priority services)  

**Key Entities:**  
- 普通会员 (Regular Member) – receives a 5% discount (95折)  
- 金卡会员 (Gold Card Member) – receives a 10% discount (9折)  
- Priority services: fast checkout and priority return/exchange services in the mall}
数据信息:普通会员享受 95折 优惠,金卡会员享受 9折 优惠。
优先服务:会员在商场内购物时,可享受优先结账、优先退换货等服务。元信息:{charset=UTF-8, chunk_index=7, section_summary=**Key Topics:**  
- Membership benefits (discounts and priority services)  

**Key Entities:**  
- 普通会员 (Regular Member) – receives a 5% discount (95折)  
- 金卡会员 (Gold Card Member) – receives a 10% discount (9折)  
- Priority services: fast checkout and priority return/exchange services in the mall, prev_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Usage of Membership Points:** Points can be exchanged for goods, services, or used as cash vouchers within the mall.
2.  **Exclusive Member Discounts:** Members receive special discounts offered by select brands within the mall.

**Key Entities:**
*   **Points / Membership Points**
*   **Mall**
*   **Goods and Services**
*   **Cash Vouchers / Cash Deductions**
*   **Members / Members (implied)**
*   **Brands (within the mall)**, parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership benefits (birthday privileges, exclusive activities)  
- Promotional offers (gifts, coupons)  
- Event access (priority participation in member-only events)  

**Key Entities:**  
- Members (会员)  
- Shopping mall/商场 (implied as the benefit provider)  
- Birthday gifts (生日礼品) or exclusive coupons (专属优惠券) worth 50元  
- Member-exclusive activities: new product trials (新品试用), fashion shows (时尚秀), shopping festivals (会员专享购物节)}
数据信息:生日特权:会员生日当月,可享受商场赠送的生日礼品或专属优惠券,价值 50元。
会员活动:会员可优先参与商场举办的各类会员专属活动,如新品试用、时尚秀、会员专享购物节等。元信息:{charset=UTF-8, chunk_index=8, section_summary=**Key Topics:**  
- Membership benefits (birthday privileges, exclusive activities)  
- Promotional offers (gifts, coupons)  
- Event access (priority participation in member-only events)  

**Key Entities:**  
- Members (会员)  
- Shopping mall/商场 (implied as the benefit provider)  
- Birthday gifts (生日礼品) or exclusive coupons (专属优惠券) worth 50元  
- Member-exclusive activities: new product trials (新品试用), fashion shows (时尚秀), shopping festivals (会员专享购物节), prev_section_summary=**Key Topics:**  
- Membership benefits (discounts and priority services)  

**Key Entities:**  
- 普通会员 (Regular Member) – receives a 5% discount (95折)  
- 金卡会员 (Gold Card Member) – receives a 10% discount (9折)  
- Priority services: fast checkout and priority return/exchange services in the mall, parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- 会员卡使用规则 (Membership Card Usage Rules)  
- 消费积分 (Spending Points Accumulation)  
- 积分累计流程 (Points Accumulation Process)  
- 未出示会员卡的后果 (Consequences of Not Presenting the Card)  

**Key Entities:**  
- 会员 (Member)  
- 商场 (Shopping Mall)  
- 收银员 (Cashier)  
- 会员卡/会员卡号 (Membership Card/Card Number)}
数据信息:五、会员卡使用规则
消费积分:会员在本商场内消费时,需出示会员卡或告知收银员会员卡号,以便积分累计。若未出示会员卡或未告知会员卡号,导致积分未累计的,商场不予补录积分。元信息:{charset=UTF-8, chunk_index=9, section_summary=**Key Topics:**  
- 会员卡使用规则 (Membership Card Usage Rules)  
- 消费积分 (Spending Points Accumulation)  
- 积分累计流程 (Points Accumulation Process)  
- 未出示会员卡的后果 (Consequences of Not Presenting the Card)  

**Key Entities:**  
- 会员 (Member)  
- 商场 (Shopping Mall)  
- 收银员 (Cashier)  
- 会员卡/会员卡号 (Membership Card/Card Number), prev_section_summary=**Key Topics:**  
- Membership benefits (birthday privileges, exclusive activities)  
- Promotional offers (gifts, coupons)  
- Event access (priority participation in member-only events)  

**Key Entities:**  
- Members (会员)  
- Shopping mall/商场 (implied as the benefit provider)  
- Birthday gifts (生日礼品) or exclusive coupons (专属优惠券) worth 50元  
- Member-exclusive activities: new product trials (新品试用), fashion shows (时尚秀), shopping festivals (会员专享购物节), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
1. **积分查询方式** – 会员可通过商场官网、手机App或客服热线查询积分余额与明细。  
2. **积分有效期** – 积分自累计之日起有效期为一年,逾期未用将自动清零。  

**Key Entities:**  
- 会员  
- 商场官方网站  
- 手机应用程序  
- 客服热线  
- 积分(余额、明细、有效期)}
数据信息:积分查询:会员可通过本商场官方网站、手机应用程序或客服热线查询积分余额及积分明细。
积分有效期:会员积分自累计之日起有效期为 一年,逾期未使用的积分将自动清零。元信息:{charset=UTF-8, chunk_index=10, section_summary=**Key Topics:**  
1. **积分查询方式** – 会员可通过商场官网、手机App或客服热线查询积分余额与明细。  
2. **积分有效期** – 积分自累计之日起有效期为一年,逾期未用将自动清零。  

**Key Entities:**  
- 会员  
- 商场官方网站  
- 手机应用程序  
- 客服热线  
- 积分(余额、明细、有效期), prev_section_summary=**Key Topics:**  
- 会员卡使用规则 (Membership Card Usage Rules)  
- 消费积分 (Spending Points Accumulation)  
- 积分累计流程 (Points Accumulation Process)  
- 未出示会员卡的后果 (Consequences of Not Presenting the Card)  

**Key Entities:**  
- 会员 (Member)  
- 商场 (Shopping Mall)  
- 收银员 (Cashier)  
- 会员卡/会员卡号 (Membership Card/Card Number), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided text, the key topics and entities are:

**Key Topics:**
*   Loss/Theft of Membership Card
*   Card Suspension (挂失)
*   Card Replacement Procedure

**Key Entities:**
*   Member (会员)
*   Mall Customer Service Hotline (本商场客服热线)
*   Mall Customer Service Center (商场客服中心)
*   Valid ID Document (有效身份证件)
*   Replacement Fee (补卡需缴纳)}
数据信息:会员卡挂失与补办:若会员卡不慎遗失或被盗,会员应立即通过本商场客服热线进行挂失。挂失成功后,会员可携带有效身份证件前往商场客服中心办理补卡手续,补卡需缴纳元信息:{charset=UTF-8, chunk_index=11, section_summary=Based on the provided text, the key topics and entities are:

**Key Topics:**
*   Loss/Theft of Membership Card
*   Card Suspension (挂失)
*   Card Replacement Procedure

**Key Entities:**
*   Member (会员)
*   Mall Customer Service Hotline (本商场客服热线)
*   Mall Customer Service Center (商场客服中心)
*   Valid ID Document (有效身份证件)
*   Replacement Fee (补卡需缴纳), prev_section_summary=**Key Topics:**  
1. **积分查询方式** – 会员可通过商场官网、手机App或客服热线查询积分余额与明细。  
2. **积分有效期** – 积分自累计之日起有效期为一年,逾期未用将自动清零。  

**Key Entities:**  
- 会员  
- 商场官方网站  
- 手机应用程序  
- 客服热线  
- 积分(余额、明细、有效期), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=**Key Topics:**  
- Membership card upgrade and downgrade policies  
- Upgrade conditions and automatic promotion process  

**Key Entities:**  
- Card processing fee: 20 RMB  
- Regular (普通) member  
- Gold card (金卡) member  
- Upgrade threshold: 5,000 RMB cumulative annual spending  
- Benefits: Gold card member rights}
数据信息:工本费 20元。
六、会员卡升级与降级
升级条件:普通会员在一年内累计消费金额达到 5000元,可自动升级为金卡会员,并享受金卡会员权益。元信息:{charset=UTF-8, chunk_index=12, section_summary=**Key Topics:**  
- Membership card upgrade and downgrade policies  
- Upgrade conditions and automatic promotion process  

**Key Entities:**  
- Card processing fee: 20 RMB  
- Regular (普通) member  
- Gold card (金卡) member  
- Upgrade threshold: 5,000 RMB cumulative annual spending  
- Benefits: Gold card member rights, prev_section_summary=Based on the provided text, the key topics and entities are:

**Key Topics:**
*   Loss/Theft of Membership Card
*   Card Suspension (挂失)
*   Card Replacement Procedure

**Key Entities:**
*   Member (会员)
*   Mall Customer Service Hotline (本商场客服热线)
*   Mall Customer Service Center (商场客服中心)
*   Valid ID Document (有效身份证件)
*   Replacement Fee (补卡需缴纳), parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Downgrade Rule:** The condition under which a Gold Card member is automatically downgraded.
2.  **Membership Cancellation:** The procedure for a member to voluntarily terminate their membership.

**Key Entities:**
*   **Gold Card Member (金卡会员):** The subject of the downgrade rule.
*   **Regular Member (普通会员):** The status a Gold Card member is downgraded to.
*   **Downgrade Threshold (消费保级标准):** The specific requirement of spending **3,000 RMB within one year** to maintain Gold Card status.
*   **Member (会员):** The individual who can initiate cancellation.
*   **Mall Customer Service Center (商场客服中心):** The location where cancellation is processed.
*   **Required Documents:** Valid identification card (有效身份证件) and the membership card (会员卡).}
数据信息:降级规则:金卡会员若在一年内未达到 3000元 的消费保级标准,则自动降级为普通会员。
七、会员卡注销
会员若因个人原因不再使用会员卡,可携带有效身份证件及会员卡前往商场客服中心办理元信息:{charset=UTF-8, chunk_index=13, section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Downgrade Rule:** The condition under which a Gold Card member is automatically downgraded.
2.  **Membership Cancellation:** The procedure for a member to voluntarily terminate their membership.

**Key Entities:**
*   **Gold Card Member (金卡会员):** The subject of the downgrade rule.
*   **Regular Member (普通会员):** The status a Gold Card member is downgraded to.
*   **Downgrade Threshold (消费保级标准):** The specific requirement of spending **3,000 RMB within one year** to maintain Gold Card status.
*   **Member (会员):** The individual who can initiate cancellation.
*   **Mall Customer Service Center (商场客服中心):** The location where cancellation is processed.
*   **Required Documents:** Valid identification card (有效身份证件) and the membership card (会员卡)., prev_section_summary=**Key Topics:**  
- Membership card upgrade and downgrade policies  
- Upgrade conditions and automatic promotion process  

**Key Entities:**  
- Card processing fee: 20 RMB  
- Regular (普通) member  
- Gold card (金卡) member  
- Upgrade threshold: 5,000 RMB cumulative annual spending  
- Benefits: Gold card member rights, parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided section, here is a summary of its key topics and entities:

**Key Topics:**
1.  **Membership Card Cancellation:** The procedure for canceling a store membership card.
2.  **Consequences of Cancellation:** The specific outcomes that occur once cancellation is completed:
    *   **Forfeiture of Points:** Any remaining points on the card are automatically reset to zero.
    *   **Non-refundable Fee:** The annual fee paid for a Gold Card will not be refunded.
3.  **Interpretation Authority:** A statement reserving the right of final interpretation of the membership rules for the store.

**Key Entities:**
*   **The Store/Mall:** Referred to as "本商场" (this mall/store), it is the entity that issues the cards, sets the rules, and holds the right of final interpretation.
*   **Membership Card:** The card held by the customer, specifically mentioning a **Gold Card** tier with an annual fee.
*   **Member/卡内剩余积分:** The customer's remaining points balance, which is subject to forfeiture.
*   **金卡年费:** The annual fee for the Gold Card membership level.}
数据信息:会员卡注销手续。注销成功后,会员卡内剩余积分将自动清零,已缴纳的金卡年费不予退还。
本商场会员卡办理规则的最终解释权归本商场所有。元信息:{charset=UTF-8, chunk_index=14, section_summary=Based on the provided section, here is a summary of its key topics and entities:

**Key Topics:**
1.  **Membership Card Cancellation:** The procedure for canceling a store membership card.
2.  **Consequences of Cancellation:** The specific outcomes that occur once cancellation is completed:
    *   **Forfeiture of Points:** Any remaining points on the card are automatically reset to zero.
    *   **Non-refundable Fee:** The annual fee paid for a Gold Card will not be refunded.
3.  **Interpretation Authority:** A statement reserving the right of final interpretation of the membership rules for the store.

**Key Entities:**
*   **The Store/Mall:** Referred to as "本商场" (this mall/store), it is the entity that issues the cards, sets the rules, and holds the right of final interpretation.
*   **Membership Card:** The card held by the customer, specifically mentioning a **Gold Card** tier with an annual fee.
*   **Member/卡内剩余积分:** The customer's remaining points balance, which is subject to forfeiture.
*   **金卡年费:** The annual fee for the Gold Card membership level., prev_section_summary=Based on the provided section, the key topics and entities are:

**Key Topics:**
1.  **Membership Downgrade Rule:** The condition under which a Gold Card member is automatically downgraded.
2.  **Membership Cancellation:** The procedure for a member to voluntarily terminate their membership.

**Key Entities:**
*   **Gold Card Member (金卡会员):** The subject of the downgrade rule.
*   **Regular Member (普通会员):** The status a Gold Card member is downgraded to.
*   **Downgrade Threshold (消费保级标准):** The specific requirement of spending **3,000 RMB within one year** to maintain Gold Card status.
*   **Member (会员):** The individual who can initiate cancellation.
*   **Mall Customer Service Center (商场客服中心):** The location where cancellation is processed.
*   **Required Documents:** Valid identification card (有效身份证件) and the membership card (会员卡)., parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16, next_section_summary=Based on the provided content, the section is a short closing statement from a document (likely a set of rules or guidelines).

**Key Topics:**
*   **Customer Service:** Directing readers to contact customer service for inquiries.
*   **Pleasant Experience:** Expressing a wish for the reader to have an enjoyable shopping experience.

**Key Entities:**
*   **商场客服人员 (Mall Customer Service Personnel):** The point of contact for any questions.
*   **您 (You):** The customer or reader of the document.

**Summary:** This concluding section provides a polite closing, offering customer service support and a standard well-wishing message for a pleasant shopping trip.}
数据信息:如有任何疑问,欢迎随时咨询商场客服人员。
祝您购物愉快!元信息:{charset=UTF-8, chunk_index=15, section_summary=Based on the provided content, the section is a short closing statement from a document (likely a set of rules or guidelines).

**Key Topics:**
*   **Customer Service:** Directing readers to contact customer service for inquiries.
*   **Pleasant Experience:** Expressing a wish for the reader to have an enjoyable shopping experience.

**Key Entities:**
*   **商场客服人员 (Mall Customer Service Personnel):** The point of contact for any questions.
*   **您 (You):** The customer or reader of the document.

**Summary:** This concluding section provides a polite closing, offering customer service support and a standard well-wishing message for a pleasant shopping trip., prev_section_summary=Based on the provided section, here is a summary of its key topics and entities:

**Key Topics:**
1.  **Membership Card Cancellation:** The procedure for canceling a store membership card.
2.  **Consequences of Cancellation:** The specific outcomes that occur once cancellation is completed:
    *   **Forfeiture of Points:** Any remaining points on the card are automatically reset to zero.
    *   **Non-refundable Fee:** The annual fee paid for a Gold Card will not be refunded.
3.  **Interpretation Authority:** A statement reserving the right of final interpretation of the membership rules for the store.

**Key Entities:**
*   **The Store/Mall:** Referred to as "本商场" (this mall/store), it is the entity that issues the cards, sets the rules, and holds the right of final interpretation.
*   **Membership Card:** The card held by the customer, specifically mentioning a **Gold Card** tier with an annual fee.
*   **Member/卡内剩余积分:** The customer's remaining points balance, which is subject to forfeiture.
*   **金卡年费:** The annual fee for the Gold Card membership level., parent_document_id=45fa190d-ecf2-45c3-8284-d2349e44b4f5, source=rules.txt, total_chunks=16}

但是上面的内容太长了,可以考虑指定自定义的提示词模板,例如下面的代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Autowired
private ChatModel chatModel;

@Test
void test1(@Value("classpath:/file/rules.txt") Resource resource) {
    TextReader textReader = new TextReader(resource);
    List<Document> documents = textReader.get();
    // 切割文本——为了更好的演示出效果
    TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withMinChunkSizeChars(50)
            .withMaxNumChunks(100)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))
            .withChunkSize(100)
            .build();
    String customPrompt = "根据给定的文本: {context_str}, 生成文档摘要, 限制在50字以内, 只返回摘要, 其他信息不返回";
    SummaryMetadataEnricher enricher =
            new SummaryMetadataEnricher(chatModel, List.of(SummaryMetadataEnricher.SummaryType.PREVIOUS,
            SummaryMetadataEnricher.SummaryType.CURRENT, SummaryMetadataEnricher.SummaryType.NEXT), customPrompt,
                    MetadataMode.NONE);
    List<Document> splitterApply = splitter.apply(documents);
    List<Document> enricherApply = enricher.apply(splitterApply);
    System.out.println(enricherApply.size());
    enricherApply.forEach(document ->
            System.out.println("数据信息:" + document.getText() +
                    "元信息:" + document.getMetadata()));
}

输出结果如下:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
16
数据信息:商场会员卡办理规则
尊敬的顾客:
欢迎您选择加入我们的会员大家庭!以下是本商场会员卡的办理规则,希望您仔细阅读并理解,以便更好地享受会员权益。元信息:{charset=UTF-8, chunk_index=0, section_summary=商场会员卡办理规则介绍,请仔细阅读以享受会员权益。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=商场提供普通会员卡(免费)和金卡会员卡(年费299元)。}
数据信息:一、会员卡类型
本商场提供两种会员卡类型:普通会员卡和金卡会员卡。
普通会员卡:免费办理。
金卡会员卡:需缴纳年费 299元。元信息:{charset=UTF-8, chunk_index=1, section_summary=商场提供普通会员卡(免费)和金卡会员卡(年费299元)。, prev_section_summary=商场会员卡办理规则介绍,请仔细阅读以享受会员权益。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=办理会员卡需年满18周岁,提供有效身份证件进行实名登记。}
数据信息:二、办理条件
年龄要求:年满18周岁及以上,具有完全民事行为能力的个人均可申请办理会员卡。
身份验证:办理会员卡时,需提供有效身份证件(身份证、护照等)进行登记,以确保会员信息的真实性和准确性元信息:{charset=UTF-8, chunk_index=2, section_summary=办理会员卡需年满18周岁,提供有效身份证件进行实名登记。, prev_section_summary=商场提供普通会员卡(免费)和金卡会员卡(年费299元)。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=提供联系方式,通过官网或APP填写申请表并上传身份证即可办理会员。}
数据信息:。
联系方式:请提供有效的手机号码和电子邮箱地址,以便商场及时向您发送会员专属优惠信息、活动通知等。
三、办理流程
线上办理:您可以通过本商场官方网站或手机应用程序,填写会员申请表,上传身份证件照片,并提交申请。元信息:{charset=UTF-8, chunk_index=3, section_summary=提供联系方式,通过官网或APP填写申请表并上传身份证即可办理会员。, prev_section_summary=办理会员卡需年满18周岁,提供有效身份证件进行实名登记。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员卡可通过短信或邮件通知办理成功,或线下至客服中心填写申请表并提交身份证审核。}
数据信息:审核通过后,我们将通过短信或邮件通知您会员卡办理成功,并告知您会员卡号及初始密码。
线下办理:您也可以前往商场客服中心,由工作人员协助您填写会员申请表,并提交身份证件进行审核。元信息:{charset=UTF-8, chunk_index=4, section_summary=会员卡可通过短信或邮件通知办理成功,或线下至客服中心填写申请表并提交身份证审核。, prev_section_summary=提供联系方式,通过官网或APP填写申请表并上传身份证即可办理会员。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=审核通过发卡,消费1元积1分。}
数据信息:审核通过后,现场为您发放会员卡,并告知您会员卡号及初始密码。
四、会员权益
积分累计:会员在本商场内消费可获得积分,每消费 1元 获得 1积分。元信息:{charset=UTF-8, chunk_index=5, section_summary=审核通过发卡,消费1元积1分。, prev_section_summary=会员卡可通过短信或邮件通知办理成功,或线下至客服中心填写申请表并提交身份证审核。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=积分可兑换商品或现金,会员享部分品牌专属折扣。}
数据信息:积分可用于兑换商场内的商品、服务或抵扣现金(具体兑换规则详见积分兑换细则)。
专属折扣:会员可享受商场内部分品牌提供的专属折扣优惠。元信息:{charset=UTF-8, chunk_index=6, section_summary=积分可兑换商品或现金,会员享部分品牌专属折扣。, prev_section_summary=审核通过发卡,消费1元积1分。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员享折扣与优先服务,金卡9折,普通95折。}
数据信息:普通会员享受 95折 优惠,金卡会员享受 9折 优惠。
优先服务:会员在商场内购物时,可享受优先结账、优先退换货等服务。元信息:{charset=UTF-8, chunk_index=7, section_summary=会员享折扣与优先服务,金卡9折,普通95折。, prev_section_summary=积分可兑换商品或现金,会员享部分品牌专属折扣。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员生日当月获50元礼品或优惠券,可优先参与新品试用等专属活动。}
数据信息:生日特权:会员生日当月,可享受商场赠送的生日礼品或专属优惠券,价值 50元。
会员活动:会员可优先参与商场举办的各类会员专属活动,如新品试用、时尚秀、会员专享购物节等。元信息:{charset=UTF-8, chunk_index=8, section_summary=会员生日当月获50元礼品或优惠券,可优先参与新品试用等专属活动。, prev_section_summary=会员享折扣与优先服务,金卡9折,普通95折。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员消费需出示卡或告知卡号方可积分,未出示导致未积分的不予补录。}
数据信息:五、会员卡使用规则
消费积分:会员在本商场内消费时,需出示会员卡或告知收银员会员卡号,以便积分累计。若未出示会员卡或未告知会员卡号,导致积分未累计的,商场不予补录积分。元信息:{charset=UTF-8, chunk_index=9, section_summary=会员消费需出示卡或告知卡号方可积分,未出示导致未积分的不予补录。, prev_section_summary=会员生日当月获50元礼品或优惠券,可优先参与新品试用等专属活动。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员可通过官网、APP或客服查询积分,积分有效期为一年,逾期自动清零。}
数据信息:积分查询:会员可通过本商场官方网站、手机应用程序或客服热线查询积分余额及积分明细。
积分有效期:会员积分自累计之日起有效期为 一年,逾期未使用的积分将自动清零。元信息:{charset=UTF-8, chunk_index=10, section_summary=会员可通过官网、APP或客服查询积分,积分有效期为一年,逾期自动清零。, prev_section_summary=会员消费需出示卡或告知卡号方可积分,未出示导致未积分的不予补录。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员卡遗失需立即电话挂失,凭身份证至客服中心补办并缴费。}
数据信息:会员卡挂失与补办:若会员卡不慎遗失或被盗,会员应立即通过本商场客服热线进行挂失。挂失成功后,会员可携带有效身份证件前往商场客服中心办理补卡手续,补卡需缴纳元信息:{charset=UTF-8, chunk_index=11, section_summary=会员卡遗失需立即电话挂失,凭身份证至客服中心补办并缴费。, prev_section_summary=会员可通过官网、APP或客服查询积分,积分有效期为一年,逾期自动清零。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=工本费20元。会员年消费满5000元可升级金卡。}
数据信息:工本费 20元。
六、会员卡升级与降级
升级条件:普通会员在一年内累计消费金额达到 5000元,可自动升级为金卡会员,并享受金卡会员权益。元信息:{charset=UTF-8, chunk_index=12, section_summary=工本费20元。会员年消费满5000元可升级金卡。, prev_section_summary=会员卡遗失需立即电话挂失,凭身份证至客服中心补办并缴费。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=金卡会员年消费未满3000元降为普通会员;可凭身份证及会员卡至客服中心注销。}
数据信息:降级规则:金卡会员若在一年内未达到 3000元 的消费保级标准,则自动降级为普通会员。
七、会员卡注销
会员若因个人原因不再使用会员卡,可携带有效身份证件及会员卡前往商场客服中心办理元信息:{charset=UTF-8, chunk_index=13, section_summary=金卡会员年消费未满3000元降为普通会员;可凭身份证及会员卡至客服中心注销。, prev_section_summary=工本费20元。会员年消费满5000元可升级金卡。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=会员卡注销后积分清零,年费不退,解释权归商场所有。}
数据信息:会员卡注销手续。注销成功后,会员卡内剩余积分将自动清零,已缴纳的金卡年费不予退还。
本商场会员卡办理规则的最终解释权归本商场所有。元信息:{charset=UTF-8, chunk_index=14, section_summary=会员卡注销后积分清零,年费不退,解释权归商场所有。, prev_section_summary=金卡会员年消费未满3000元降为普通会员;可凭身份证及会员卡至客服中心注销。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16, next_section_summary=欢迎咨询客服,祝您购物愉快。}
数据信息:如有任何疑问,欢迎随时咨询商场客服人员。
祝您购物愉快!元信息:{charset=UTF-8, chunk_index=15, section_summary=欢迎咨询客服,祝您购物愉快。, prev_section_summary=会员卡注销后积分清零,年费不退,解释权归商场所有。, parent_document_id=cde7e2eb-deea-4244-bfac-337c3922c33b, source=rules.txt, total_chunks=16}

文档写入器

在RAG入门部分已经介绍过最简单的SimpleVectorStore,在文档中还介绍了FileDocumentWriterRedisVectorStore以及PineconeVectorStore,此处不再赘述

重排序(Re-Ranking)

在当前Retrieval-Augmented Generation(RAG)架构广泛应用的背景下,向量数据库已成为连接大模型与外部知识的核心桥梁。通过将文本转化为高维向量,并基于余弦相似度等度量方式进行相似搜索,我们可以快速从海量文档中“找到看起来相关的片段”,但是,在实际应用中,我们发现其排序结果并不总是最优,即最相似的向量≠最相关的答案。所以,重排序(Re-Ranking)正在成为高质量RAG系统不可或缺的一环。

比如:查询“如何申请产假”。文档A:“员工请病假需提交医院证明。”,文档B:“女职工享有188天带薪产假及哺乳时间。”从词向量角度看,“请假”、“申请”、“病假”、“产假”可能处于相近空间区域,系统或许会误判文档A更相关;但从真实需求出发,文档B显然更具回答价值。

真正相关的文档被排在后面,会导致送入给LLM的上下文质量大打折扣,导致检索的结果不准确。为解决这个问题,业界普遍采用重排序的模式来提升检索质量

Re-Ranking(重排序)是指在初步检索出一批候选文档后,使用一个更加精细、专精于相关性判断的模型,重新评估每个文档与查询之间的匹配程度,并按新得分重新排序

这一过程类似于搜索引擎的工作机制:

  1. 先用倒排索引+向量检索快速召回几百个候选网页。
  2. 再用精排排序模型打分筛选,最终呈现前10条结果。

工作流程如下:

  1. 粗排阶段(Retrieve):使用向量数据库进行快速ANN搜索,召回一批候选文档(如top-50)
  2. 精排阶段(Rerank):调用更精细的排序模型(如Cross-Encoder类重排序模型),计算每个文档与原始查询之间的细粒度语义匹配分数
  3. 根据重排序后的得分重新排列文档顺序,选取top-k高质量上下文
  4. 将优化后的上下文注入Prompt,交由LLM生成最终回答

在Spring AI中,也提供了对应的重排序组件RetrievalRerankAdvisor,结合SimpleVectorStore使用示例如下:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@SpringBootTest
public class TestRerank {

    @TestConfiguration
    static class TestConfig {
        @Bean
        public VectorStore vectorStore(DashScopeEmbeddingModel embeddingModel) {
            return SimpleVectorStore.builder(embeddingModel).build();
        }
    }

    @Autowired
    VectorStore vectorStore;

    @BeforeEach
    public void init(@Value("classpath:file/rule.txt") Resource resource) {
        // 读取
        TextReader textReader = new TextReader(resource);
        textReader.getCustomMetadata().put("filename", resource.getFilename());
        List<Document> documents = textReader.read();

        // 分隔
        TokenTextSplitter splitter = new TokenTextSplitter(200, 10, 5, 10000, true);
        List<Document> apply = splitter.apply(documents);

        // 存储向量(内部会自动向量化)
        vectorStore.add(apply);
    }

    @Test
    public void testRerank(
            @Autowired DashScopeChatModel dashScopeChatModel,
            @Autowired DashScopeRerankModel rerankModel) {

        ChatClient chatClient = ChatClient.builder(dashScopeChatModel)
                .build();

        RetrievalRerankAdvisor retrievalRerankAdvisor =
                new RetrievalRerankAdvisor(vectorStore, rerankModel
                        , SearchRequest.builder().topK(200).build());

        String content = chatClient.prompt().user("金卡会员折扣")
                .advisors(retrievalRerankAdvisor)
                .call()
                .content();

        System.out.println(content);
    }
}