#LLM入门|AI测试# 3.6_创建测试集,人工/LLM评估

评估是确保语言模型(LLM)问答系统质量的重要步骤,它有助于检测模型在不同文档上的表现,发现不足之处,并通过比较不同模型选择最优方案。定期评估还能监测模型性能是否下降。
评估目的包括确认LLM是否满足验收标准,以及分析变更对性能的影响
基本策略是使用LLM和链来评估其他LLM、链和应用。本章以文档问答应用为例,探讨LangChain中评估的处理和考量。
首先,按照 langchain 链的方式构建一个 LLM 的文档问答应用

from langchain.chains import RetrievalQA #检索QA链,在文档上进行检索
from langchain.chat_models import ChatOpenAI #openai模型
from langchain.document_loaders import CSVLoader #文档加载器,采用csv格式存储
from langchain.indexes import VectorstoreIndexCreator #导入向量存储索引创建器
from langchain.vectorstores import DocArrayInMemorySearch #向量存储
#加载中文数据
file = '../data/product_data.csv'
loader = CSVLoader(file_path=file)
data = loader.load()

#查看数据
import pandas as pd
test_data = pd.read_csv(file,skiprows=0)
display(test_data.head()) d
product_namedescription
0全自动咖啡机规格:\n大型 - 尺寸:13.8’’ x 17.3’‘。\n中型 - 尺寸:11.5’’ …
1电动牙刷规格:\n一般大小 - 高度:9.5’‘,宽度:1’'。\n\n为什么我们热爱它:\n我们的…
2橙味维生素C泡腾片规格:\n每盒含有20片。\n\n为什么我们热爱它:\n我们的橙味维生素C泡腾片是快速补充维…
3无线蓝牙耳机规格:\n单个耳机尺寸:1.5’’ x 1.3’'。\n\n为什么我们热爱它:\n这款无线蓝…
4瑜伽垫规格:\n尺寸:24’’ x 68’'。\n\n为什么我们热爱它:\n我们的瑜伽垫拥有出色的…
# 将指定向量存储类,创建完成后,我们将从加载器中调用,通过文档记载器列表加载

index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])


#通过指定语言模型、链类型、检索器和我们要打印的详细程度来创建检索QA链
llm = ChatOpenAI(temperature = 0.0)
qa = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type="stuff", 
    retriever=index.vectorstore.as_retriever(), 
    verbose=True,
    chain_type_kwargs = {
        "document_separator": "<<<<>>>>>"
    }
) d

上述代码的主要功能及作用在上一章节中都已说明,这里不再赘述

1.1 设置测试的数据

我们查看一下经过档加载器 CSVLoad 加载后生成的 data 内的信息,这里我们抽取 data 中的第九条和第十条数据,看看它们的主要内容:
第九条数据:
data[10] dDocument(page_content=“product_name: 高清电视机\ndescription: 规格:\n尺寸:50’'。\n\n为什么我们热爱它:\n我们的高清电视机拥有出色的画质和强大的音效,带来沉浸式的观看体验。\n\n材质与护理:\n使用干布清洁。\n\n构造:\n由塑料、金属和电子元件制成。\n\n其他特性:\n支持网络连接,可以在线观看视频。\n配备遥控器。\n在韩国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。”, metadata={‘source’: ‘…/data/product_data.csv’, ‘row’: 10}) d
第十条数据:
data[11] dDocument(page_content=“product_name: 旅行背包\ndescription: 规格:\n尺寸:18’’ x 12’’ x 6’'。\n\n为什么我们热爱它:\n我们的旅行背包拥有多个实用的内外袋,轻松装下您的必需品,是短途旅行的理想选择。\n\n材质与护理:\n可以手洗,自然晾干。\n\n构造:\n由防水尼龙制成。\n\n其他特性:\n附带可调节背带和安全锁。\n在中国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。”, metadata={‘source’: ‘…/data/product_data.csv’, ‘row’: 11}) d
看上面的第一个文档中有高清电视机,第二个文档中有旅行背包,从这些细节中,我们可以创建一些例子查询和答案

1.2 手动创建测试数据

需要说明的是这里我们的文档是 csv 文件,所以我们使用的是文档加载器是 CSVLoader ,CSVLoader 会对 csv 文件中的每一行数据进行分割,所以这里看到的 data[10], data[11]的内容则是 csv 文件中的第10条,第11条数据的内容。下面我们根据这两条数据手动设置两条“问答对”,每一个“问答对”中包含一个 query ,一个 answer :

examples = [
    {
        "query": "高清电视机怎么进行护理?",
        "answer": "使用干布清洁。"
    },
    {
        "query": "旅行背包有内外袋吗?",
        "answer": "有。"
    }
] d

1.3 通过LLM生成测试用例

在前面的内容中,我们使用的方法都是通过手动的方法来构建测试数据集,比如说我们手动创建10个问题和10个答案,然后让 LLM 回答这10个问题,再将 LLM 给出的答案与我们准备好的答案做比较,最后再给 LLM 打分,评估的流程大概就是这样。但是这里有一个问题,就是我们需要手动去创建所有的问题集和答案集,那会是一个非常耗费时间和人力的成本。那有没有一种可以自动创建大量问答测试集的方法呢?那当然是有的,今天我们就来介绍 Langchain 提供的方法:QAGenerateChain,我们可以通过QAGenerateChain来为我们的文档自动创建问答集:
由于QAGenerateChain类中使用的PROMPT是英文,故我们继承QAGenerateChain类,将PROMPT加上“请使用中文输出”。下面是generate_chain.py文件中的QAGenerateChain类的源码

from langchain.evaluation.qa import QAGenerateChain #导入QA生成链,它将接收文档,并从每个文档中创建一个问题答案对

# 下面是langchain.evaluation.qa.generate_prompt中的源码,在template的最后加上“请使用中文输出”
from langchain.output_parsers.regex import RegexParser
from langchain.prompts import PromptTemplate
from langchain.base_language import BaseLanguageModel
from typing import Any

template = """You are a teacher coming up with questions to ask on a quiz. 
Given the following document, please generate a question and answer based on that document.

Example Format:
<Begin Document>
...
<End Document>
QUESTION: question here
ANSWER: answer here

These questions should be detailed and be based explicitly on information in the document. Begin!

<Begin Document>
{doc}
<End Document>
请使用中文输出
"""
output_parser = RegexParser(
    regex=r"QUESTION: (.*?)\nANSWER: (.*)", output_keys=["query", "answer"]
)
PROMPT = PromptTemplate(
    input_variables=["doc"], template=template, output_parser=output_parser
)

# 继承QAGenerateChain
class ChineseQAGenerateChain(QAGenerateChain):
    """LLM Chain specifically for generating examples for question answering."""

    @classmethod
    def from_llm(cls, llm: BaseLanguageModel, **kwargs: Any) -> QAGenerateChain:
        """Load QA Generate Chain from LLM."""
        return cls(llm=llm, prompt=PROMPT, **kwargs)



example_gen_chain = ChineseQAGenerateChain.from_llm(ChatOpenAI())#通过传递chat open AI语言模型来创建这个链
new_examples = example_gen_chain.apply([{"doc": t} for t in data[:5]]) 

#查看用例数据
new_examples  d
[{'qa_pairs': {'query': '这款全自动咖啡机的尺寸是多少?',
   'answer': "大型尺寸为13.8'' x 17.3'',中型尺寸为11.5'' x 15.2''。"}},
 {'qa_pairs': {'query': '这款电动牙刷的规格是什么?', 'answer': "一般大小 - 高度:9.5'',宽度:1''。"}},
 {'qa_pairs': {'query': '这种产品的名称是什么?', 'answer': '这种产品的名称是橙味维生素C泡腾片。'}},
 {'qa_pairs': {'query': '这款无线蓝牙耳机的尺寸是多少?',
   'answer': "该无线蓝牙耳机的尺寸为1.5'' x 1.3''。"}},
 {'qa_pairs': {'query': '这款瑜伽垫的尺寸是多少?', 'answer': "这款瑜伽垫的尺寸是24'' x 68''。"}}] d

在上面的代码中,我们创建了一个QAGenerateChain,然后我们应用了QAGenerateChain的 apply 方法对 data 中的前5条数据创建了5个“问答对”,由于创建问答集是由 LLM 来自动完成的,因此会涉及到 token 成本的问题,所以我们这里出于演示的目的,只对 data 中的前5条数据创建问答集。
new_examples[0] d

{'qa_pairs': {'query': '这款全自动咖啡机的尺寸是多少?',
  'answer': "大型尺寸为13.8'' x 17.3'',中型尺寸为11.5'' x 15.2''。"}} d

源数据:
data[0] dDocument(page_content=“product_name: 全自动咖啡机\ndescription: 规格:\n大型 - 尺寸:13.8’’ x 17.3’‘。\n中型 - 尺寸:11.5’’ x 15.2’'。\n\n为什么我们热爱它:\n这款全自动咖啡机是爱好者的理想选择。 一键操作,即可研磨豆子并沏制出您喜爱的咖啡。它的耐用性和一致性使它成为家庭和办公室的理想选择。\n\n材质与护理:\n清洁时只需轻擦。\n\n构造:\n由高品质不锈钢制成。\n\n其他特性:\n内置研磨器和滤网。\n预设多种咖啡模式。\n在中国制造。\n\n有问题? 请随时联系我们的客户服务团队,他们会解答您的所有问题。”, metadata={‘source’: ‘…/data/product_data.csv’, ‘row’: 0}) d

1.4 整合测试集

还记得我们前面手动创建的两个问答集吗?现在我们需要将之前手动创建的问答集合并到QAGenerateChain创建的问答集中,这样在答集中既有手动创建的例子又有 llm 自动创建的例子,这会使我们的测试集更加完善。
接下来我们就需要让之前创建的文档问答链qa来回答这个测试集里的问题,来看看 LLM 是怎么回答的吧:

examples += [ v for item in new_examples for k,v in item.items()]
qa.run(examples[0]["query"]) d
> Entering new RetrievalQA chain...

> Finished chain.





'高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。' d

这里我们看到qa回答了第0个问题:“高清电视机怎么进行护理?” ,这里的第0个问题就是先前我们手动创建的第一个问题,并且我们手动创建的 answer 是:“使用干布清洁。” 这里我们发现问答链qa回答的也是“您只需要使用干布清洁即可”,只是它比我们的答案还多了一段说明:“高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。”。

二、 人工评估

你想知道qa是怎么找到问题的答案的吗?下面让我们打开debug,看看qa是如何找到问题的答案!

import langchain
langchain.debug = True

#重新运行与上面相同的示例,可以看到它开始打印出更多的信息
qa.run(examples[0]["query"]) d
[chain/start] [1:chain:RetrievalQA] Entering Chain run with input:
{
  "query": "高清电视机怎么进行护理?"
}
[chain/start] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain] Entering Chain run with input:
[inputs]
[chain/start] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain > 4:chain:LLMChain] Entering Chain run with input:
{
  "question": "高清电视机怎么进行护理?",
  "context": "product_name: 高清电视机\ndescription: 规格:\n尺寸:50''。\n\n为什么我们热爱它:\n我们的高清电视机拥有出色的画质和强大的音效,带来沉浸式的观看体验。\n\n材质与护理:\n使用干布清洁。\n\n构造:\n由塑料、金属和电子元件制成。\n\n其他特性:\n支持网络连接,可以在线观看视频。\n配备遥控器。\n在韩国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 空气净化器\ndescription: 规格:\n尺寸:15'' x 15'' x 20''。\n\n为什么我们热爱它:\n我们的空气净化器采用了先进的HEPA过滤技术,能有效去除空气中的微粒和异味,为您提供清新的室内环境。\n\n材质与护理:\n清洁时使用干布擦拭。\n\n构造:\n由塑料和电子元件制成。\n\n其他特性:\n三档风速,附带定时功能。\n在德国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 宠物自动喂食器\ndescription: 规格:\n尺寸:14'' x 9'' x 15''。\n\n为什么我们热爱它:\n我们的宠物自动喂食器可以定时定量投放食物,让您无论在家或外出都能确保宠物的饮食。\n\n材质与护理:\n可用湿布清洁。\n\n构造:\n由塑料和电子元件制成。\n\n其他特性:\n配备LCD屏幕,操作简单。\n可以设置多次投食。\n在美国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 玻璃保护膜\ndescription: 规格:\n适用于各种尺寸的手机屏幕。\n\n为什么我们热爱它:\n我们的玻璃保护膜可以有效防止手机屏幕刮伤和破裂,而且不影响触控的灵敏度。\n\n材质与护理:\n使用干布擦拭。\n\n构造:\n由高强度的玻璃材料制成。\n\n其他特性:\n安装简单,适合自行安装。\n在日本制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。"
}
[llm/start] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain > 4:chain:LLMChain > 5:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: Use the following pieces of context to answer the users question. \nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n----------------\nproduct_name: 高清电视机\ndescription: 规格:\n尺寸:50''。\n\n为什么我们热爱它:\n我们的高清电视机拥有出色的画质和强大的音效,带来沉浸式的观看体验。\n\n材质与护理:\n使用干布清洁。\n\n构造:\n由塑料、金属和电子元件制成。\n\n其他特性:\n支持网络连接,可以在线观看视频。\n配备遥控器。\n在韩国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 空气净化器\ndescription: 规格:\n尺寸:15'' x 15'' x 20''。\n\n为什么我们热爱它:\n我们的空气净化器采用了先进的HEPA过滤技术,能有效去除空气中的微粒和异味,为您提供清新的室内环境。\n\n材质与护理:\n清洁时使用干布擦拭。\n\n构造:\n由塑料和电子元件制成。\n\n其他特性:\n三档风速,附带定时功能。\n在德国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 宠物自动喂食器\ndescription: 规格:\n尺寸:14'' x 9'' x 15''。\n\n为什么我们热爱它:\n我们的宠物自动喂食器可以定时定量投放食物,让您无论在家或外出都能确保宠物的饮食。\n\n材质与护理:\n可用湿布清洁。\n\n构造:\n由塑料和电子元件制成。\n\n其他特性:\n配备LCD屏幕,操作简单。\n可以设置多次投食。\n在美国制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。<<<<>>>>>product_name: 玻璃保护膜\ndescription: 规格:\n适用于各种尺寸的手机屏幕。\n\n为什么我们热爱它:\n我们的玻璃保护膜可以有效防止手机屏幕刮伤和破裂,而且不影响触控的灵敏度。\n\n材质与护理:\n使用干布擦拭。\n\n构造:\n由高强度的玻璃材料制成。\n\n其他特性:\n安装简单,适合自行安装。\n在日本制造。\n\n有问题?请随时联系我们的客户服务团队,他们会解答您的所有问题。\nHuman: 高清电视机怎么进行护理?"
  ]
}
[llm/end] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain > 4:chain:LLMChain > 5:llm:ChatOpenAI] [2.86s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。",
        "generation_info": {
          "finish_reason": "stop"
        },
        "message": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain",
            "schema",
            "messages",
            "AIMessage"
          ],
          "kwargs": {
            "content": "高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。",
            "additional_kwargs": {}
          }
        }
      }
    ]
  ],
  "llm_output": {
    "token_usage": {
      "prompt_tokens": 823,
      "completion_tokens": 58,
      "total_tokens": 881
    },
    "model_name": "gpt-3.5-turbo"
  },
  "run": null
}
[chain/end] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain > 4:chain:LLMChain] [2.86s] Exiting Chain run with output:
{
  "text": "高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。"
}
[chain/end] [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain] [2.87s] Exiting Chain run with output:
{
  "output_text": "高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。"
}
[chain/end] [1:chain:RetrievalQA] [3.26s] Exiting Chain run with output:
{
  "result": "高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。"
}





'高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。' d

我们可以看到它首先深入到检索 QA 链中,然后它进入了一些文档链。如上所述,我们正在使用 stuff 方法,现在我们正在传递这个上下文,可以看到,这个上下文是由我们检索到的不同文档创建的。因此,在进行问答时,当返回错误结果时,通常不是语言模型本身出错了,实际上是检索步骤出错了,仔细查看问题的确切内容和上下文可以帮助调试出错的原因。
然后,我们可以再向下一级,看看进入语言模型的确切内容,以及 OpenAI 自身,在这里,我们可以看到传递的完整提示,我们有一个系统消息,有所使用的提示的描述,这是问题回答链使用的提示,我们可以看到提示打印出来,使用以下上下文片段回答用户的问题。
如果您不知道答案,只需说您不知道即可,不要试图编造答案。然后我们看到一堆之前插入的上下文,我们还可以看到有关实际返回类型的更多信息。我们不仅仅返回一个答案,还有 token 的使用情况,可以了解到 token 数的使用情况
由于这是一个相对简单的链,我们现在可以看到最终的响应,通过链返回给用户。这部分我们主要讲解了如何查看和调试单个输入到该链的情况。

三、 通过LLM进行评估实例

来简要梳理一下问答评估的流程:

  • 首先,我们使用 LLM 自动构建了问答测试集,包含问题及标准答案。
  • 然后,同一 LLM 试图回答测试集中的所有问题,得到响应。
  • 下一步,需要评估语言模型的回答是否正确。这里奇妙的是,我们再使用另一个 LLM 链进行判断,所以 LLM 既是“球员”,又是“裁判”。

具体来说,第一个语言模型负责回答问题。第二个语言模型链用来进行答案判定。最后我们可以收集判断结果,得到语言模型在这一任务上的效果分数。需要注意的是,回答问题的语言模型链和答案判断链是分开的,职责不同。这避免了同一个模型对自己结果的主观判断。
总之,语言模型可以自动完成构建测试集、回答问题和判定答案等全流程,使评估过程更加智能化和自动化。我们只需要提供文档并解析最终结果即可。

langchain.debug = False

#为所有不同的示例创建预测
predictions = qa.apply(examples) 

# 对预测的结果进行评估,导入QA问题回答,评估链,通过语言模型创建此链
from langchain.evaluation.qa import QAEvalChain #导入QA问题回答,评估链

#通过调用chatGPT进行评估
llm = ChatOpenAI(temperature=0)
eval_chain = QAEvalChain.from_llm(llm)

#在此链上调用evaluate,进行评估
graded_outputs = eval_chain.evaluate(examples, predictions) d
> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain.


> Entering new RetrievalQA chain...

> Finished chain. d
#我们将传入示例和预测,得到一堆分级输出,循环遍历它们打印答案
for i, eg in enumerate(examples):
    print(f"Example {i}:")
    print("Question: " + predictions[i]['query'])
    print("Real Answer: " + predictions[i]['answer'])
    print("Predicted Answer: " + predictions[i]['result'])
    print("Predicted Grade: " + graded_outputs[i]['results'])
    print() d
Example 0:
Question: 高清电视机怎么进行护理?
Real Answer: 使用干布清洁。
Predicted Answer: 高清电视机的护理非常简单。您只需要使用干布清洁即可。避免使用湿布或化学清洁剂,以免损坏电视机的表面。
Predicted Grade: CORRECT

Example 1:
Question: 旅行背包有内外袋吗?
Real Answer: 有。
Predicted Answer: 是的,旅行背包有多个实用的内外袋,可以轻松装下您的必需品。
Predicted Grade: CORRECT

Example 2:
Question: 这款全自动咖啡机的尺寸是多少?
Real Answer: 大型尺寸为13.8'' x 17.3'',中型尺寸为11.5'' x 15.2''。
Predicted Answer: 这款全自动咖啡机有两种尺寸可选:
- 大型尺寸为13.8'' x 17.3''。
- 中型尺寸为11.5'' x 15.2''。
Predicted Grade: CORRECT

Example 3:
Question: 这款电动牙刷的规格是什么?
Real Answer: 一般大小 - 高度:9.5'',宽度:1''。
Predicted Answer: 这款电动牙刷的规格是:高度为9.5英寸,宽度为1英寸。
Predicted Grade: CORRECT

Example 4:
Question: 这种产品的名称是什么?
Real Answer: 这种产品的名称是橙味维生素C泡腾片。
Predicted Answer: 这种产品的名称是儿童益智玩具。
Predicted Grade: INCORRECT

Example 5:
Question: 这款无线蓝牙耳机的尺寸是多少?
Real Answer: 该无线蓝牙耳机的尺寸为1.5'' x 1.3''。
Predicted Answer: 这款无线蓝牙耳机的尺寸是1.5'' x 1.3''。
Predicted Grade: CORRECT

Example 6:
Question: 这款瑜伽垫的尺寸是多少?
Real Answer: 这款瑜伽垫的尺寸是24'' x 68''。
Predicted Answer: 这款瑜伽垫的尺寸是24'' x 68''。
Predicted Grade: CORRECT d

从上面的返回结果中我们可以看到,在评估结果中每一个问题中都包含了Question,Real Answer,Predicted Answer和Predicted Grade 四组内容,其中Real Answer是有先前的QAGenerateChain创建的问答测试集中的答案,而Predicted Answer则是由我们的qa链给出的答案,最后的Predicted Grade则是由上面代码中的QAEvalChain回答的。
在本章中,我们学习了使用 LangChain 框架实现 LLM 问答效果自动化评估的方法。与传统手工准备评估集、逐题判断等方式不同,LangChain 使整个评估流程自动化。它可以自动构建包含问答样本的测试集,然后使用语言模型对测试集自动产生回复,最后通过另一个模型链自动判断每个回答的准确性。这种全自动的评估方式极大地简化了问答系统的评估和优化过程,开发者无需手动准备测试用例,也无需逐一判断正确性,大大提升了工作效率
借助LangChain的自动评估功能,我们可以快速评估语言模型在不同文档集上的问答效果,并可以持续地进行模型调优,无需人工干预。这种自动化的评估方法解放了双手,使我们可以更高效地迭代优化问答系统的性能。
总之,自动评估是 LangChain 框架的一大优势,它将极大地降低问答系统开发的门槛,使任何人都可以轻松训练出性能强大的问答模型。

<think>好的,我现在需要帮助用户实现一个基于RAG的法律问答系统,使用Python。首先,我得理清楚用户的需求和数据情况。用户有一个CSV文件,包含3.6万条法律问答,四列:title、question、reply、is_best。其中有些question是空的,这时候需要用title作为问题。is_best为1的是优质答案。 首先,用户可能对RAG的基本流程不太熟悉,我需要先考虑整个流程。RAG通常包括数据预处理、文本向量化、构建索引、问句检索和生成回答这几个步骤。需要确认用户的数据是否需要清洗,比如处理空值、合并问题字段。然后,选择嵌入模型,可能用Hugging Face的sentence-transformers,比如paraphrase-multilingual-MiniLM-L12-v2,适合中文文本。接着,构建向量数据库,FAISS比较适合,因为它高效且易于集成。 然后,代码部分需要分步骤写。先导入必要的库,比如pandas处理数据,sentence-transformers生成嵌入,FAISS构建索引。可能还需要考虑环境配置,比如安装这些库。用户可能对安装库不熟悉,是否需要给出pip install命令?不过用户可能已经有环境,所以先写代码,必要时提示安装。 数据预处理部分,需要读取CSV,处理question为空的情况,用title填充。然后合并问题和答案,可能将title/question和reply合并为上下文,用于检索。但RAG通常检索相关上下文,然后生成答案,所以可能需要将每个QA对处理成文档,供检索用。或者,用户可能只需要用问题来检索对应的答案,这时候需要将问题作为索引,答案作为检索结果。需要明确这一点。 接下来,生成嵌入向量,建立FAISS索引。保存索引文件,方便后续加载。然后,处理用户查询,同样生成嵌入,用FAISS搜索相似的问题,获取最相关的答案。可能需要设置返回top_k个结果,比如top_k=5。 最后,用检索到的问题-答案对作为上下文,输入到生成模型中。用户可能没有指定生成模型,是否需要用LLM?比如ChatGPT或本地模型。但用户可能希望先用简单的检索最相关的答案,直接返回。或者,需要结合检索的答案生成更准确的回答。需要确认用户的预期。 用户可能没有提到生成模型,可能只需要检索最相关的答案。所以代码可能只需要检索并返回最匹配的答案。或者,用户希望用检索到的信息来增强生成模型的回答。这时候需要集成像Hugging Face的pipeline或者OpenAI的API。但用户可能希望用本地模型,避免API调用。或者,用户可能想先用简单的版本,所以可能先实现检索部分,生成部分后续再添加。 另外,需要考虑计算资源。sentence-transformers的模型是否适合用户的机器,比如是否需要有GPU加速。不过MiniLM模型相对较小,可以在CPU上运行。FAISS也支持CPU。 代码步骤大概如下: 1. 数据预处理:读取CSV,处理空question,合并title和question作为问题。 2. 生成嵌入:加载模型,将问题转换为向量。 3. 构建FAISS索引并保存。 4. 用户查询时,加载索引,生成查询向量,检索相似问题,返回对应答案。 可能还需要处理重复问题,或者答案质量(is_best=1优先)。但用户可能希望先用所有数据,或者优先选择is_best=1的答案。但数据中每个问题可能有多个回复,is_best标记最佳答案。所以在预处理时,可能需要筛选出is_best=1的答案,或者将多个答案合并。但根据数据情况,可能每个问题对应多个回复,其中is_best为1的是最佳答案。因此,在构建索引时,可能只需要索引最佳答案,或者将所有答案都索引,但检索时取最佳。需要用户澄清,但根据问题描述,可能每个行是一个问答对,is_best表示该回复是否被认可。因此,可能存在同一个问题多个回复,但只有部分is_best=1。所以在构建索引时,可能需要将问题和对应的最佳答案作为文档,或者将所有回复都索引,但检索时优先选择最佳答案。 但用户可能希望对于每个问题,对应多个答案,所以在检索时,可能需要返回最相关的答案,或者综合多个答案生成回复。但RAG通常的做法是将相关文档作为上下文输入生成模型。所以可能需要将每个QA对作为一个文档,生成嵌入时使用问题部分,检索到后,将对应的答案作为上下文输入生成模型。 综上,代码的大致结构应该是: - 读取数据,处理空question,合并title和question作为问题文本。 - 提取问题和对应的答案,可能过滤is_best=1的答案,或者保留所有,但用户可能需要决定如何处理。 - 生成问题的嵌入向量。 - 构建FAISS索引。 - 用户输入问题,生成嵌入,检索最相似的问题,返回对应的答案。 现在需要将这些步骤转化为代码。可能需要注意的细节: 1. 数据预处理:使用pandas读取csv,填充空question。 df[&#39;question&#39;] = df[&#39;question&#39;].fillna(df[&#39;title&#39;]) 2. 可能只需要处理is_best=1的数据,因为其他答案可能质量不高。但用户的数据中可能有些问题只有非最佳答案,所以可能需要保留所有,但优先选择is_best=1。或者用户可能希望全部使用,所以暂时不过滤,后续再处理。 3. 生成嵌入时,需要将问题文本转换为向量。使用sentence-transformers模型。 4. FAISS索引的创建:将向量存入索引,并保存。 5. 检索时,取最相似的top_k个问题,然后返回对应的答案。 用户可能需要一个简单的示例代码,包括这些步骤。因此,代码可以分成数据准备、构建索引、查询处理三个部分。 可能的代码结构: ```python # 导入库 import pandas as pd from sentence_transformers import SentenceTransformer import faiss import numpy as np # 数据预处理 df = pd.read_csv(&#39;lawzhidao_filter.csv&#39;) df[&#39;question&#39;] = df[&#39;question&#39;].fillna(df[&#39;title&#39;]) # 选择最佳答案(可选) # df = df[df[&#39;is_best&#39;] == 1] # 初始化模型 model = SentenceTransformer(&#39;paraphrase-multilingual-MiniLM-L12-v2&#39;) # 生成嵌入向量 questions = df[&#39;question&#39;].tolist() question_embeddings = model.encode(questions) # 转换为FAISS需要的格式 dimension = question_embeddings.shape[1] index = faiss.IndexFlatL2(dimension) index.add(question_embeddings.astype(np.float32)) # 保存索引 faiss.write_index(index, &#39;lawzhidao.index&#39;) # 保存问题和答案的对应关系 df.to_pickle(&#39;qa_data.pkl&#39;) # 查询函数 def query_question(query, top_k=5): # 加载索引和数据 index = faiss.read_index(&#39;lawzhidao.index&#39;) df = pd.read_pickle(&#39;qa_data.pkl&#39;) #
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值