【深度学习总结】使用PDF构建RAG:结合Langchain和通义千问 ...

打印 上一主题 下一主题

主题 780|帖子 780|积分 2340

【深度学习总结】使用PDF构建RAG:结合Langchain和通义千问

使用平台:趋动云,注册送算力
前言

在大型语言模型(LLMs)应用领域,我们面临着大量寻衅,从特定领域知识的匮乏到信息准确性的逆境,以及可能生成卖弄内容。检索增强生成(RAG)通过引入外部知识库等增补信息源,成为办理这些困难的有效计谋。事实证明,在需要持续更新或特定领域应用的知识密集型场景中,RAG 尤其有效。与其他方法相比,RAG 的一个显著上风在于无需为特定使命重新培训 LLM。最近,RAG 因其在会话助手等应用中的乐成应用而备受瞩目。
RAG构成了一种将输入与相关支持文档的语料库相结合的技能。这些文档被归并到输入提示中,并团结输入到文本生成器中,从而产生最终的输出。这种RAG的这种机制在需要适应不断变革的信息情况的场景中找到了特殊的效用,由于llm所依靠的参数化知识本质上是静态的。通过RAG,语言模型可以直接访问最新的信息,而不需要再练习,促进了生成可靠的、基于检索的输出。本质上,RAG通过检索证据进步了LLM相应的准确性、可控性和相关性,从而证明确在快速发展的情况中办理标题,并有效地缓解了错误信息生成和性能退化的标题。
RAG的一个典型应用步调如下图所示。

在这里,一个用户向ChatGPT提出了一个关于最近一个被广泛讨论的新闻的标题。鉴于ChatGPT依靠于练习前的数据,它最初缺乏提供最新发展的能力。RAG通过从外部数据库中获取和整合知识来补充这一信息差距。在这种情况下,它会网络与用户查询相关的相关新闻文章。这些文章,结合最初的标题,形成了一个全面的提示,使llm能够生成一个知情的答案。典型的RAG遵照了一个传统的过程,包括索引、检索和生成,这也被描述为一个“检索“。
索引:起首以不同的格式清理和提取原始数据,如PDF、HTML、Word和标记,然后将其转换为同一的纯文本格式。为了适应语言模型的上下文限定,文本被分割成更小的、可理解的块。然后使用嵌入模型将块编码到向量表示中,并存储在向量数据库中。这一步对于在后续的检索阶段实现有效的相似性搜索至关重要。
检索:在收到用户查询后,RAG体系使用在索引阶段使用的相同的编码模型来将查询转换为向量表示。然后盘算查询向量和索引语料库中的块向量之间的相似性得分。体系对与查询相似性最大的前k块举行优先排序和检索。这些数据块随后在提示符中被用作扩展的上下文。
生成:所提出的查询和所选择的文档被合成成一个连贯的提示,一个大型语言模型负责制定一个相应。模型的答复方法可能根据特定使命的标准而有所不同,答应它利用其固有的参数知识或限定其对所提供文档中包含的信息的相应。在正在举行的对话的情况下,任何现有的对话汗青都可以集成到提示符中,使模型能够有效地参与多回合的对话交互
教程

PDF文件

使用的是民用飞机维修的PDF文件,可以私信我获取,你也可以用本身的。
准备



  • 通义千问的API-Key
  • 运行情况:将如下内容存入requirements.txt,然后运行:pip install -r requirements.txt
  1. python-dotenv==1.0.1 # For reading environment variables stored in .env file
  2. langchain==0.2.2
  3. langchain-community==0.2.3
  4. dashscope
  5. unstructured==0.14.4 # Document loading
  6. # onnxruntime==1.17.1 # chromadb dependency: on Mac use `conda install onnxruntime -c conda-forge`
  7. # For Windows users, install Microsoft Visual C++ Build Tools first
  8. # install onnxruntime before installing `chromadb`
  9. chromadb==0.5.0 # Vector storage
  10. tiktoken==0.7.0  # For embeddings
复制代码
构建RAG

先导入包:
  1. from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
  2. from langchain.text_splitter import RecursiveCharacterTextSplitter
  3. from langchain.schema import Document
  4. from langchain_community.vectorstores import Chroma
  5. from langchain_community.embeddings.huggingface import HuggingFaceEmbeddings
  6. from dotenv import load_dotenv
  7. import os
  8. import shutil
  9. import dashscope
  10. from dashscope import Generation
  11. from langchain.prompts import ChatPromptTemplate
  12. from http import HTTPStatus
复制代码
然后将PDF数据转换为向量存储起来:
  1. # Load environment variables. Assumes that project contains .env file with API keys
  2. load_dotenv()
  3. # 设置镜像,便于下载后面的HuggingFaceEmbeddings
  4. os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
  5. # huggingface下载地址
  6. os.environ["HF_HOME"] = "/gemini/code/huggingface"
  7. # huggingface下载地址
  8. os.environ["TRANSFORMERS_CACHE"] = "/gemini/code/huggingface"
  9. os.environ["SENTENCE_TRANSFORMERS_HOME"] = "/gemini/code/huggingface/bce-embedding-base_v1"
  10. # 向量存放位置
  11. CHROMA_PATH = "chroma"
  12. # 存放数据
  13. DATA_PATH = "data/books"
  14. dashscope.api_key = "你的通义千问api key"
  15. print(os.getenv('DASHSCOPE_API_KEY'))
  16. def prepare_db():
  17.     # 处理读个pdf
  18.     pdf_paths = ["data/books/M1.pdf",
  19.                  "data/books/M2-航空器维修R1.pdf",
  20.                  "data/books/M3-飞机结构和系统R1.pdf",
  21.                  "data/books/M4-直升机结构和系统.pdf",
  22.                  "data/books/M5-航空涡轮发动机R1.pdf",
  23.                  "data/books/M6-活塞发动机及其维修.pdf",
  24.                  "data/books/M7-航空器维修基本技能.pdf",
  25.                  "data/books/M8-航空器维修实践R1.pdf"]
  26.     documents = []
  27.     count = 0
  28.     for pdf_path in pdf_paths:
  29.         loader = PyPDFLoader(pdf_path)
  30.         doc = loader.load()
  31.         documents.extend(doc)
  32.         count += 1
  33.         print(f"处理第{count}本")
  34.     print(len(documents))
  35.     text_splitter = RecursiveCharacterTextSplitter(
  36.         chunk_size=300,
  37.         chunk_overlap=100,
  38.         length_function=len,
  39.         add_start_index=True,
  40.     )
  41.     chunks = text_splitter.split_documents(documents)
  42.     print(f"Split {len(documents)} documents into {len(chunks)} chunks.")
  43.     document = chunks[10]
  44.     print(document.page_content)
  45.     print(document.metadata)
  46.     if os.path.exists(CHROMA_PATH):
  47.         shutil.rmtree(CHROMA_PATH)
  48.     # 将文本保存为向量存储
  49.     model_name = "maidalun1020/bce-embedding-base_v1"
  50.     model_kwargs = {'device': 'cuda'}
  51.     encode_kwargs = {'normalize_embeddings': False}
  52.     embeddings = HuggingFaceEmbeddings(
  53.         model_name=model_name,
  54.         model_kwargs=model_kwargs,
  55.         encode_kwargs=encode_kwargs,
  56.         cache_folder="/gemini/code/huggingface/",
  57.     )
  58.     # Create a new DB from the documents.
  59.     db = Chroma.from_documents(
  60.         chunks, embeddings, persist_directory=CHROMA_PATH
  61.     )
  62.     db.persist()
  63.     print(f"Saved {len(chunks)} chunks to {CHROMA_PATH}.")
复制代码
然后调用通义千问的API,用户输入标题,然后根据标题从向量库中查找相关的内容,跟标题结合起来,一起喂给通义千问:
  1. def query():
  2.     model_name = "maidalun1020/bce-embedding-base_v1"
  3.     model_kwargs = {'device': 'cuda'}
  4.     encode_kwargs = {'normalize_embeddings': False}
  5.     embeddings = HuggingFaceEmbeddings(
  6.         model_name=model_name,
  7.         model_kwargs=model_kwargs,
  8.         encode_kwargs=encode_kwargs,
  9.         # 模型缓存路径
  10.         cache_folder="/gemini/code/huggingface/",
  11.     )
  12.     # 改成你的保存的路径
  13.     db = Chroma(persist_directory="./chroma/aae4fae7-3477-4094-8a7d-c5df8be2223a", embedding_function=embeddings)
  14.         # 提示模板
  15.     PROMPT_TEMPLATE = """
  16.     仅根据下列文本回答问题:
  17.     {context}
  18.     """
  19.     while True:
  20.         query = input('请输入问题:')
  21.         results = db.similarity_search_with_relevance_scores(query, k=5)
  22.         if len(results) == 0:
  23.             print(f"Unable to find matching results.")
  24.             return
  25.         # 拼接成输入给大模型的内容
  26.         context_text = "\n\n---\n\n".join([doc.page_content for doc, _score in results])
  27.         messages = [
  28.             {'role': 'system', 'content': PROMPT_TEMPLATE.format(context=context_text)},
  29.             {'role': 'user', 'content': f"请回答如下问题:{query}"}
  30.         ]
  31.         print(messages)
  32.         responses = Generation.call(Generation.Models.qwen_max,
  33.                                     api_key=os.getenv('DASHSCOPE_API_KEY'),
  34.                                     messages=messages,
  35.                                     result_format='message')
  36.         # 如果你不确定responses的结果,可以打印处理
  37.         # print(responses.output)
  38.         sources = [doc.metadata.get("source", None) for doc, _score in results]
  39.         if responses.status_code == HTTPStatus.OK:
  40.             whole_message = responses.output["choices"][0]["message"]["content"]
  41.         else:
  42.             whole_message = "error"
  43.             print('Failed request_id: %s, status_code: %s, code: %s, message:%s' %
  44.                 (responses.request_id, responses.status_code, responses.code,
  45.                 responses.message))
  46.         formatted_response = f"Response: {whole_message}\nSources: {sources}"
  47.         print(formatted_response)
复制代码
参考链接

langchain-rag-tutorial

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

羊蹓狼

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表