AI 文摘

使用langchain实现RAG(检索增强生成)





作者: AI寰宇 来源: AI寰宇

检索增强生成(Retrieval-Augmented Generation, RAG),它通过结合检索和生成两种机制,提升了模型在复杂任务上的表现力和准确性。

大语言模型的局限性:

数据依赖性

大语言模型的性能在很大程度上依赖于其训练数据的质量和多样性。如果训练数据存在偏差或不全面,模型可能会学习到错误的模式,并在实际应用中表现出偏差。

幻觉问题 (Hallucination):

大型语言模型在生成文本时产生了一个问题,即模型生成的内容虽然语法正确、流畅自然,但却包含不准确或完全虚构的信息。这种现象被称为“幻觉”,因为模型生成的文本给人一种它“知道”或“理解”了某些事情的感觉,而实际上这些内容可能并不基于真实世界的知识或事实。又分为事实性幻觉: 即模型生成的内容与可验证的现实世界事实不一致,和忠实性幻觉: 模型生成的内容与用户的指令或上下文不一致。

可解释性

大型模型的决策过程往往是黑盒的,很难解释它们为什么会生成特定的输出。这对于需要高度可解释性的应用场景(如医疗、法律)构成了挑战。

常识和世界知识

模型可能缺乏对世界的基本常识或特定领域知识的深入理解,这导致它们在需要这些知识的复杂任务上表现不佳。

RAG的出现:****

为了解决大型模型的局限性,研究者们开始探索如何将外部知识源整合到语言模型中。这种方法允许模型在生成响应时检索和利用最新的、相关的信息,从而提高其准确性和可靠性。RAG模型通过结合检索系统来增强语言模型的能力。检索系统能够快速从大量文档中找到与输入查询最相关的信息,这些信息随后被用作生成模型的上下文。

RAG模型的核心思想是利用检索系统从大量文档中找到与输入查询相关的文档片段,然后将这些片段作为生成模型的上下文,以生成更准确和信息丰富的响应。

RAG模型的处理流程:

Text****Load(文本加载)

在这一步,模型从数据源加载文本数据。这可能涉及到从文件、数据库或其他存储系统读取文本内容。

Text****Split(文本分割)

加载文本后,模型需要将长文本分割成更小的单元,如句子或段落。这有助于模型更有效地处理文本,并为检索阶段做好准备。

Generate and save Embedding(生成并保存嵌入向量)

在这一步,模型为文本或其分割后的单元生成嵌入向量(embeddings)。这些向量是文本的数值表示,能够捕捉文本的语义信息,并用于后续的检索和生成步骤。

User Query(用户提问)

过程开始于用户的一个问题或请求。用户通过界面提交他们想要模型解答的问题。

Data Retrieval(数据检索)

模型接收到用户的问题后,执行检索步骤,从预先构建的知识库或数据集中召回与问题相关的文档或信息片段。这通常涉及到计算问题与数据集中各个文档的相关性得分,并选择得分最高的若干文档。

Prompt Injection(注入Prompt)

检索到的相关文档片段随后被注入到一个提示(Prompt)中。这个提示是一个结构化的文本模板,它将用户的问题和检索到的文档片段结合起来,形成一个新的输入文本。提示的设计对模型的性能有重要影响,因为它需要清晰地引导模型如何结合检索到的信息和原始问题。

LLM Answer Generation(LLM生成答案)

注入了提示的输入文本被送入大型语言模型(Large Language Model,LLM)进行处理。LLM根据提示中的信息生成答案。这个阶段利用了模型的语言理解和文本生成能力,以产生一个连贯、准确且信息丰富的回答。

实战操作:****

由于大模型无法获取实时的天气信息,所以我们以西安的天气信息为例,使用langshain来实现一个简单的RAG:

准备一个名为tianqi.txt的文件,内容是西安4月的天气状况

Text****Load****:

使用document_loaders的TextLoader方法实现,参数是文件路径:


from langchain.document_loaders import TextLoader
  

loader = TextLoader('tianqi.txt')
documents = loader.load()

TextSplit****:

使用CharacterTextSplitter方法实现,separator是以该字符切割,chunk_size是每个块的大小,chunk_overlap是块之间最大的重叠量:


from langchain.text_splitter import CharacterTextSplitter
  

text_splitter = CharacterTextSplitter(separator="\n",chunk_size=50, chunk_overlap=10)
chunks = text_splitter.split_documents(documents)

Generate and save Embedding

使用from_documents方法存储,参数是:1、要存的内容,类型的列表;2、embedding方法;3、persist_directory是存储的路径:


from langchain_community.vectorstores.chroma import Chroma
from langchain_community.embeddings.huggingface import HuggingFaceEmbeddings
  

db = Chroma.from_documents(
    chunks,HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2"),persist_directory="E:\model\embedding"
)

User Query****

用户提问一些模型不知道的问题,比如西安4月中旬的天气状况

Data Retrieval****

使用as_retriever方法查询,查询结果是数组,将查询结果全部取出:****


retriever = db.as_retriever()
docs = retriever.get_relevant_documents("几号下雨")
p_info = ""
for doc in docs:
    p_info = p_info + doc.page_content

Prompt Injection

创建一个prompt模板,将查询到的结果与prompt模板结合,使用PromptTemplate方法:


from langchain.prompts import PromptTemplate
  

prompt_template = """
你是一个问答机器人。
你的人物是根据下述给定的信息回答用户问题。
确保你的回复完全依赖下述已知的信息,不要编造答案。
如果下述已知信息不足以回答用户的问题,请直接回复“我无法回答您的问题”。
  

已知信息:
{info}
  

用户问题:
{question}
  

"""
  

template = PromptTemplate.from_template(prompt_template)
prompt = template.format(info=p_info,question="4月中旬西安几号下雨")

LLM Answer Generation

我们使用Kimi的api,这里使用第三方的llm需要自定义,只需要实现_call方法即可:


from typing import Any
import logging
from langchain_core.language_models import LLM
from openai import OpenAI
  

  

temperautre = 0.3
class Kimi(LLM):
  

    def _llm_type(self) -> str:
        """Return type of LLM."""
        return "kimillm"
  

    def _call(
        self,
        prompt: str,
       **kwargs: Any,
    ) -> str:
        try:
            client = OpenAI(
                api_key=kimi_api_key,
                base_url="https://api.moonshot.cn/v1",
            )
            completion = client.chat.completions.create(
                model="moonshot-v1-8k",
                messages=[
                    {"role": "system", "content": "你是 Kimi,由 Moonshot AI 提供的人工智能助手。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=temperautre,
            )
            return completion.choices[0].message.content
        except Exception as e:
            logging.error(f"Error in kimi: {e}",exc_info=True)
            raise

然后将prompt传入:

output = llm.invoke([HumanMessage(content=prompt)])
print(output)

结果:

更多AI工具,参考Github-AiBard123国内AiBard123

可关注我们的公众号:每天AI新工具