langchain--(4)

发布于:2025-06-21 ⋅ 阅读:(14) ⋅ 点赞:(0)

7 Embedding文本向量化

Embedding文本向量化是一种将非结构化文本转化为低维、连续数值向量的技术,旨在通过数学方式捕捉文本的语义、语法或特征信息,从而让机器更高效地处理语言任务。其核心思想源于流形假设(Manifold Hypothesis),即认为高维原始数据(如文本)实际隐含于低维流形中,通过映射到低维空间可实现语义可分性。

7.1 基础知识

原始文本到模型可输入向量的转化需要经过一下3个过程:

文本(原始形式)——> 分词(Token)——>Token索引化——>向量嵌入(Embedding)

7.1.1 分词(Tokenization)

  • 基于单词的分词(Word-level)

    将文本按空格或标点切分为完整单词(如英文)或独立词汇(如中文“苹果”)。优点是语义完整,但词表规模庞大且易出现未登录词问题

  • 基于字符的分词(Character-level)

    以单个字符为最小单元(如中文“苹”和“果”)。词表规模小(仅需数千字符),但丢失词汇边界信息,导致模型难以捕捉长距离语义

  • 基于子词的分词(Subword-level)

    平衡前两者,通过算法(如BPE、WordPiece)将罕见词拆分为更小单元。例如,“unbelievable”在BERT中被拆为[“un”, “##believable”],其中“##”表示该子词属于前续词。这种方法既能处理未登录词问题,又保留部分语义信息。

7.1.2 Token索引化

通过分词,将词转化为唯一整数索引,可以得到一张词表。以BERT为例,BERT的词表通常包含约30,522个子词,覆盖高频词汇和常见组合,并且添加了一些特殊Token,其词表形式如下:

{"[PAD]": 0, "我": 1, "吃了": 2, "苹果": 3, "[CLS]":4,"[SEP]":5}

7.1.3 向量嵌入

BERT的嵌入层包含一个可学习的Embedding矩阵,尺寸为[Vocab Size × Hidden Size](如30,522×768),该矩阵通过预训练(如掩码语言模型任务)学习每个Token的语义表示。原始文本在分词且索引化后,根据Token索引化后的ID从Embedding矩阵中提取向量,并与位置(Position Embeddings)、段落(Segment Embeddings)嵌入相加,得到最终输入表示。例如:

·输入Token ID=2(“苹果”)会从矩阵中取出对应的768维向量。

BERT模型的最大输入长度(token上限)通常为512个token,超出部分会被丢弃。常见扩展方法如下:

  • 滑动窗口分割:将长文本划分为多个512-token的片段分别处理(如使用stride参数覆盖上下文),但可能丢失全局信息。
  • 专用模型:如BigBird和Longformer通过稀疏注意力机制支持更长序列(例如4096 tokens),但需重新预训练且与BERT架构不同。
  • BELT方法:基于现有BERT模型,通过分段处理与池化技术间接支持长文本,保留预训练权重的同时提升处理能力。

7.2 langchain的向量嵌入

安装阿里云百炼的客户端依赖:

pip install -q langchain_community
pip install -q dashscope

输入一句话为什么得到固定长度的一维向量?

因为BERT在输入序列的起始位置强制添加特殊标记[CLS],其对应的最后一层隐藏状态被用作整个句子的综合表示。

def qen_embedding():
    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))

    from langchain_community.embeddings import DashScopeEmbeddings
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    text = "This is a test query."
    query_result = embedding_model.embed_query(text)
    print(len(query_result))   # 获得一个1536维度的向量,不同模型的向量长度可能不同
------------------------------------------------
1536

7.3 余弦相似度计算

安装依赖:

pip install -q scikit-learn
pip install numpy

text1与text2的语义相似度较高,所以余弦相似度大,得分越高。

def cosine_similarity():
    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))

    from langchain_community.embeddings import DashScopeEmbeddings
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    text1 = "我喜欢吃苹果"
    text2 = "我喜欢吃香蕉"
    text3 = "太阳从东边升起"

    import numpy as np
    embedding1 = np.array(embedding_model.embed_query(text1)).reshape(1, -1)
    embedding2 = np.array(embedding_model.embed_query(text2)).reshape(1, -1)
    embedding3 = np.array(embedding_model.embed_query(text3)).reshape(1, -1)

    from sklearn.metrics.pairwise import cosine_similarity
    similarity12 = cosine_similarity(embedding1, embedding2)[0][0]
    similarity13 = cosine_similarity(embedding1, embedding3)[0][0]

    print(f"\"{text1}\" 与 \"{text2}\" 相似度:{similarity12:.4f}")
    print(f"\"{text1}\" 与 \"{text3}\" 相似度:{similarity13:.4f}")
-----------------------------------------------------------------------------------------------
"我喜欢吃苹果""我喜欢吃香蕉" 相似度:0.6128
"我喜欢吃苹果""太阳从东边升起" 相似度:0.0797

7.4 向量数据持久化

既然已经实现了文本向量化转换,自然需要一款工具来完成向量数据的持久化存储,并支持向量相似度检索。这类工具被统称为向量数据库

在 LangChain 框架中,集成了丰富的向量数据库组件,具体集成列表可查阅官网文档《LangChain 集成的 Vector Store》。接下来,以 Redis为例,演示向量数据的核心操作流程。

注意: 默认的 Redis 社区版不支持向量数据存储,需额外安装redisearch模块才能启用向量存储功能

通过 Docker 容器部署集成redisearch模块的 Redis 服务,具体部署指令如下:

docker run -p 6379:6379 redis/redis-stack-server:latest

持久化案例展示如下,未来对于用户提出的任何问题,都可以在向量数据库中快速检索出和用户问题语义最接近的文本。但是这里需要注意,这里只是检索出可能认为最相关的文本,并不能完全保证用户提出的问题,最终的答案就是这个最相关的文本。基于LangChain框架的良好设计,未来如果想要切换到其他的向量数据库,只需要修改
vector_store的实现类即可,业务代码几乎不需要改动。

def qwen_embedding_save():
    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    from langchain_redis import RedisConfig, RedisVectorStore
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    vector_store = RedisVectorStore(embeddings=embedding_model, config=redis_config)
    vector_store.add_texts(["我喜欢吃苹果", "我不喜欢吃香蕉", "太阳从东边升起"])

    retireval_result = vector_store.similarity_search("我喜欢吃什么?", k=3)

    for doc in retireval_result:
        print(doc.page_content)
-----------------------------------------------------------------------------------------------------
我喜欢吃苹果
我不喜欢吃香蕉
太阳从东边升起

Redis的持久化方式如下:

在这里插入图片描述

为了上述简化这种向量查询,langchain框架中还设计了另外一个类Retriver,来简化这些复杂的检索过程。

retrieval = vector_store.as_retriever(search_kwargs={'k': 3})
retireval_result = retrieval.invoke("我喜欢吃什么?")
for doc in retireval_result:
    print(doc.page_content)
-----------------------------------------------------------------------------------
我喜欢吃苹果
我不喜欢吃香蕉
太阳从东边升起

7.5 链式使用Retrival

vector_store.as_retriever方法返回的是一个VectorStoreRetrieval类,该类也继承Runnable类,所以可以加入LCEL。

def qwen_embedding_retrieval():
    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    from langchain_redis import RedisConfig, RedisVectorStore
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    vector_store = RedisVectorStore(embeddings=embedding_model, config=redis_config)
    vector_store.add_texts(["我喜欢吃苹果", "我不喜欢吃香蕉", "太阳从东边升起"])

    retrieval = vector_store.as_retriever(search_kwargs={'k': 3})

    # 创建提示模板
    prompt = ChatPromptTemplate.from_messages([
        ("human", "{question}"),
    ])
    # 格式转换函数,propmt.invoke方法返回PromptValue,而retrieval.invoke函数需要传入参数为str
    def format_prompt(prompt_value):
        return prompt_value.to_string()

    chain = prompt | format_prompt | retrieval

    result = chain.invoke({"question": "我喜欢吃什么?"})
    for doc in result:
        print(doc.page_content)
---------------------------------------------------------------------------------------------------
我喜欢吃苹果
我不喜欢吃香蕉
太阳从东边升起

8 RAG智能问答系统

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索与文本生成技术的方法,旨在通过外部知识库增强大型语言模型(LLM)的输出质量。

==核心思想:==在生成回答前,先从权威数据源(如文档库、数据库)中检索与问题相关的上下文信息,再将这些信息与原始查询一同输入LLM,从而生成更准确、可靠的回答。减少模型幻觉,避免LLM依赖过时的训练数据。

RAG出现的原因:

  1. 知识局限性 LLM的训练数据固定且静态,无法覆盖实时更新的信息(如新闻财报)或私有领域数据(如企业内部文档)。例如,ChatGPT的训练数据截止至2021年,无法回答2023年后的事件 。RAG通过外部知识库弥补这一缺陷,使模型能“开卷答题”
  2. 幻觉问题 LLM可能在缺乏足够证据时编造答案(如虚构不存在的论文引用)。研究表明,LLM的幻觉率高达15%-20%。RAG通过引入可验证的外部信息,强制模型基于事实生成内容,显著降低错误率
  3. 数据安全与定制化需求 企业不愿将敏感数据上传至第三方模型进行微调,而RAG允许直接对接本地知识库。例如,医疗系统可通过RAG检索病历库生成诊断建议,无需将患者数据暴露给公共LLM
  4. 经济性考量 重新训练LLM(如微调)成本高昂(单次训练费用可达数百万美元),而RAG仅需更新知识库即可适配新领域,成本降低90%以上。

8.1 RAG的基础流程

RAG主要分为indexing索引阶段、Retrieval检索阶段。

索引阶段:

这一阶段主要是要对相关文档进行处理,形成知识库,便于后续检索。通常需要将各种形式的文档转化成为Document,.然后将Document:拆分成小段的Segments,然后将这些
Segments进行Embedding向量化处理,并将结果保存到向量数据库当中,这样,后续的检索工作就可以直接使用向量数据库进行检索了。

在这里插入图片描述

检索阶段:

这一阶段主要是当用户提出一个问题时,可以到向量数据库中检索出跟用户的问题比较关联的Segment。把这些segment和用户的问题一起整理成完整的prompt,再发送给大模型。然后由大模型对信息进行整合,再给用户返回正确答案。

在这里插入图片描述

8.2 Indexing索引阶段

数据来源:美团数据常见问题

8.2.1 加载并解析文档

langchain中提供了非常多Document Loader工具,可以从PDF、HTML、MarkDown、JSON、CSV等各种格式的文档中加载数据。甚至还实现了非常多的扩展工具,可以从网页上加载数据。使用这些工具,可以很方便的加载文档。例如:

def load_text():
    from langchain_community.document_loaders import TextLoader
    loader = TextLoader("./data/example.txt")
    docs = loader.load()
    print(docs)

在LangChain中,TextLoader是BaseLoader的一个实现类。除了TextLoader外,还有非常多的实现类。例如,如果你的知识库文件比较多,你可以尝试使用DirectoryLoader,它会自动递归的加载文件夹中的所有文件。

def load_directory():
    from langchain_community.document_loaders import DirectoryLoader, TextLoader
    loader = DirectoryLoader("./data", glob="**/*.txt",loader_cls=TextLoader, show_progress=True)
    docs = loader.load()
    print(docs)

8.2.2 切分文档

接下来,需要将Documents中的文件切分成一个个比较独立的Segments。一个Segments:表示一个比较独立的知识片段。例如,对于我们这个示例,可以把一个问答就当成一个segment。实现时,就是按照"\n\n"两个换行符进行切分。

def split_text():
    from langchain.text_splitter import CharacterTextSplitter
    from langchain_community.document_loaders import TextLoader
    loader = TextLoader("./data/example.txt")
    docs = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="\n\n", keep_separator= False)
    segments = text_splitter.split_documents(docs)
    for segment in segments:
        print(segment.page_content)
 -----------------------------------------------------------------------
Q:在线支付取消订单后钱怎么返还?
    
    订单取消后,款项会在一个工作日内,直接返还到您的美团账户余额。
    
Q:怎么查看退款是否成功?
    
    退款会在一个工作日之内到美团账户余额,可在“账号管理——我的账号”中查看是否到账。
    。。。。。。

测试时,你会发现,CharacterTextSplitter组件切分出来的结果可能和预期结果相比没有那么精确。文档中有31个问答条目,而切分的结果只有6个。这是因为在做RAG文档切分时,通常我们并不需要像传统数据库那样严格的切分文档。最终基于大模型强大的理解能力,即便不是很合理的拆分,也能得到比较好的效果。当然,如果想要按照每个单独的问答进行严格的切分,也不是没有办法。我们也可以自行切分内容:

def split_text_by_myself():
    import re
    from langchain.text_splitter import CharacterTextSplitter
    from langchain_community.document_loaders import TextLoader

    loader = TextLoader(".\美团外卖常见问题.txt", encoding="utf-8")
    docs = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="Q:", keep_separator=False)

    # 自行切分文档
    texts = re.split(r"Q:", docs[0].page_content)

    segments = text_splitter.split_text(docs[0].page_content)
    print("官方拆器拆分:",len(segments))
    # 将文档片段转换为documents
    segments_documents = text_splitter.create_documents(texts)

    print("自行拆分:",len(texts))
    for segment in segments_documents:
        print(segment.page_content)
        print("----------------------------------")
---------------------------------------------------------------------------------------------
官方拆器拆分: 7
自行拆分: 32

8.2.3 文本向量化、持久化

切分出我们需要的知识条目后,就可以对文本进行向量化,并将这些向量化的结果保存到向量数据库当中。这里还是以之前介绍过的Redis作为示例

def qwen_indexing():
    import re
    from langchain.text_splitter import CharacterTextSplitter
    from langchain_community.document_loaders import TextLoader

    loader = TextLoader(".\美团外卖常见问题.txt", encoding="utf-8")
    docs = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="Q:", keep_separator=False)

    # 自行切分文档
    texts = re.split(r"Q:", docs[0].page_content)

    segments = text_splitter.split_text(docs[0].page_content)
    print("官方拆器拆分:", len(segments))
    # 将文档片段转换为documents
    segments_documents = text_splitter.create_documents(texts)

    # 向量化模型
    from langchain_community.embeddings import DashScopeEmbeddings
    embedding_model = DashScopeEmbeddings(model_name="text-embedding-v1")

    # 持久化
    from langchain_redis import RedisConfig, RedisVectorStore
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    vector_store = RedisVectorStore(embeddings=embedding_model, config=redis_config)
    vector_store.add_documents(segments_documents)

8.3 Retrieval检索增强阶段

在这个阶段,主要是要围绕客户提出的问题做一些补充和优化。在接收到用户的一个问题后,我们需要先到向量数据库中去检索一下跟用户提出的问题相关的知识条目。这样未来就可以把用户的问题和本地知识库中相关的知识条目一起发给大模型,让大模型综合考虑之后,给出一个理想的答案。

8.3.1 检索相关信息

def qwen_indexing():
    import re
    from langchain.text_splitter import CharacterTextSplitter
    from langchain_community.document_loaders import TextLoader

    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))

    loader = TextLoader(".\美团外卖常见问题.txt", encoding="utf-8")
    docs = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="Q:", keep_separator=False)

    # 自行切分文档
    texts = re.split(r"Q:", docs[0].page_content)

    segments = text_splitter.split_text(docs[0].page_content)
    print("官方拆器拆分:", len(segments))
    # 将文档片段转换为documents
    segments_documents = text_splitter.create_documents(texts)

    # 向量化模型
    from langchain_community.embeddings import DashScopeEmbeddings
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    # 持久化
    from langchain_redis import RedisConfig, RedisVectorStore
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    vector_store = RedisVectorStore(embeddings=embedding_model, config=redis_config)
    vector_store.add_documents(segments_documents)

    result = vector_store.similarity_search("Q:美团外卖怎么取消退款呢?")
    print(result)
------------------------------------------------------------------------------------------------
[Document(metadata={}, page_content='在线支付订单如何退款?\n    \n    商家接单前,您可以直接取消订单,订单金额会自动退款到美团余额;商家接单后,您在点击“申请退款”,在线申请。提交退款申请之后,商家有24小时处理您的退款申请。商家同意退款,或24小时内没有处理您的退款申请,您的支付金额会退款至您的美团余额。'), Document(metadata={}, page_content='怎么取消退款呢?\n    \n    请在订单页点击“不退款了”,商家还会正常送餐的。'), 
Document(metadata={}, page_content='在线支付取消订单后钱怎么返还?\n    \n    订单取消后,款项会在一个工作日内,直接返还到您的美团账户余额。'), Document(metadata={}, page_content='申请退款后,商家拒绝了怎么办?\n    \n    申请退款后,如果商家拒绝,此时回到订单页面点击“退款申诉”,美团客服介入处理。')]

8.3.2 构建prompt提示词

查询出跟用户问题相关的“知识”后,就需要将用户的问题和相关的“知识”整合到一起,才能发给大模型。下面是一个比较简单的模板示例

# 构建提示词
    prompt_template = ChatPromptTemplate.from_messages([
        ("user","""你是一个答疑机器人,你的任务是根据下述给定的已知信息回答用户的问题。"
         "已知信息":{context},
         "用户问题":{question},
         如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复“我无法回答您的问题”。
         请不要输出已知信息中不包含的信息或答案。
         请用中文回答用户问题。""")
    ])

    # 聚合信息
    text = []
    for result in Q_result:
        text.append(result.page_content)

    prompt = prompt_template.invoke({"context":text,"question":"美团外卖怎么取消退款呢?"}

8.3.3 调用大模型

不同的回答效果可以自行尝试

def qwen_retrieval():
    import re
    from langchain.text_splitter import CharacterTextSplitter
    from langchain_community.document_loaders import TextLoader

    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))

    loader = TextLoader(".\美团外卖常见问题.txt", encoding="utf-8")
    docs = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="Q:", keep_separator=False)

    # 自行切分文档
    texts = re.split(r"Q:", docs[0].page_content)

    segments = text_splitter.split_text(docs[0].page_content)

    # 将文档片段转换为documents
    segments_documents = text_splitter.create_documents(texts)

    # 向量化模型
    from langchain_community.embeddings import DashScopeEmbeddings
    embedding_model = DashScopeEmbeddings(model="text-embedding-v1")

    # 持久化
    from langchain_redis import RedisConfig, RedisVectorStore
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    vector_store = RedisVectorStore(embeddings=embedding_model, config=redis_config)
    vector_store.add_documents(segments_documents)

    Q_result = vector_store.similarity_search("Q:美团外卖怎么取消退款呢?")

    # 构建提示词
    prompt_template = ChatPromptTemplate.from_messages([
        ("user","""你是一个答疑机器人,你的任务是根据下述给定的已知信息回答用户的问题。"
         "已知信息":{context},
         "用户问题":{question},
         如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复“我无法回答您的问题”。
         请不要输出已知信息中不包含的信息或答案。
         请用中文回答用户问题。""")
    ])

    # 聚合信息
    text = []
    for result in Q_result:
        text.append(result.page_content)

    prompt = prompt_template.invoke({"context":text,"question":"美团外卖怎么取消退款呢?"})

    # 调用大模型
    llm = ChatQwen(model="qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")

    def format_prompt(prompt_value):
        return prompt_value.to_string()

    print(llm.invoke(prompt).content)
-----------------------------------------------------------------------------------------------------------
我无法回答您的问题

8.3.4 RAG整合(chain)

def qwen_rag(query:str):
    # 加载API
    os.environ.setdefault("DASHSCOPE_API_KEY", load_key("DASHSCOPE_API_KEY"))
    # 加载本地数据
    loader = TextLoader(".\美团外卖常见问题.txt", encoding="utf-8")
    docs = loader.load()
    # 分割文本
    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0, separator="Q:", keep_separator=False)
    segments = text_splitter.split_documents(docs)
    # 配置Redis
    redis_config = RedisConfig(
        index_name="my_index",
        redis_url="redis://127.17.0.2:6379/0",
        distance_metric="COSINE",
        embedding_dimensions=1536
    )
    # 向量存储库
    vector_store = RedisVectorStore(embeddings=DashScopeEmbeddings(model="text-embedding-v1"), config=redis_config)
    # 相似度检索
    Q_result = vector_store.similarity_search(query)

    # 构建提示词
    prompt_template = ChatPromptTemplate.from_messages([
        ("user", """你是一个答疑机器人,你的任务是根据下述给定的已知信息回答用户的问题。"
             "已知信息":{context},
             "用户问题":{question},
             如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复“我无法回答您的问题”。
             请不要输出已知信息中不包含的信息或答案。
             请用中文回答用户问题。""")
    ])

    # 格式转化
    def format_prompt(prompt_value):
        return prompt_value.to_string()

    # 大模型
    llm = ChatQwen(model="qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")

    # 格式化输出
    parser = StrOutputParser()

    chain = prompt_template | format_prompt | llm | parser
    print(chain.invoke({"context":Q_result,"question":query}))
---------------------------------------------------------------------------------------------------------------------
已知信息中没有提到如何取消退款的操作,因此我无法回答您的问题。

8.4 RAG应用效果的评估

RAG(Retrieval-Augmented Generation)应用效果的评估需从检索质量生成质量系统性能三个方面去评估。

8.4.1 检索质量评估

上下文相关性(Context Relevance) 衡量检索到的上下文与用户查询的相关程度。例如,用户提问“特斯拉Model X如何”,若检索到关于特斯拉电动汽车的文本或图片,则相关性高;若检索到无关内容(如宠物护理),则相关性低。相关指标如下:

Hit Rate(命中率)

定义:

衡量在检索结果的前 KK 个文档中是否包含至少一个相关文档。它关注的是“是否能找到答案”,而非答案的排序位置。

计算公式:
H i t R a t e @ K = 总查询数量 在前 K 个检索结果中包含相关文档的查询数量 Hit Rate@K= \frac{总查询数量}{在前 K 个检索结果中包含相关文档的查询数量} HitRate@K=在前K个检索结果中包含相关文档的查询数量总查询数量
K=5,表示检查每个查询的前5个结果中是否有至少一个相关文档。

MRR(平均倒数排名)

定义:

衡量第一个相关文档在检索结果中的位置。它关注“答案出现得有多早”,对排序质量更敏感。

计算公式:
M R R = 1 N ∑ i = 1 n 1 r a n k i MRR = \frac{1}{N} \sum^n_{i=1} \frac{1}{rank_i} MRR=N1i=1nranki1

8.4.2 生成质量评估

通过构造标准答案数据集,计算生成文本与参考文本之间的词汇重叠程度评估质量。例如,某金融问答系统的准确率需达到90%以上才能满足业务需求。

评价指标可参考imageCaption任务的指标,如BLUE、CIDEr等。

8.4.3 评估流程与优化建议

  1. 数据准备:构建包含问题、标准答案参考上下文的测试集(如1000条样本)。
  2. 组件级评估:分别测试检索器(如向量数据库)与生成器(如LLM)的性能,定位瓶颈。
  3. 端到端评估:模拟真实场景,从用户提问到生成答案的全流程测试,计算整体准确率。
  4. 迭代优化:根据评估结果调整检索策略(如重排序压缩)或生成提示词(Prompt Engineering)

网站公告

今日签到

点亮在社区的每一天
去签到