找回密码
 立即注册
首页 业界区 业界 langchain 快速入门(三):搭建RAG知识库

langchain 快速入门(三):搭建RAG知识库

任佳湍 2026-1-24 16:45:00
简介

LLM大模型一般训练的数据都是滞后的,这是就需要用到RAG知识库,RAG知识库可以降低大模型在输出答案时的幻觉,也能够让大模型知识拓展。
知识库架构知识

检索流程图
  1. 用户输入 (User Query)
  2.              |
  3.              v
  4.     +-----------------------+
  5.     |   提示词 (Prompt)      |
  6.     +-----------------------+
  7.              |
  8.              | (1) 转化为向量 (Embedding)
  9.              v
  10.     +-----------------------+
  11.     |   文字向量模型 (EMB)    |
  12.     +-----------------------+
  13.              |
  14.              | (2) 相似度检索 (Search)
  15.              v
  16.     +-----------------------+         +-----------------------+
  17.     |  RAG 向量数据库 (DB)    | <-----> |   本地知识库/文档集     |
  18.     +-----------------------+         +-----------------------+
  19.              |
  20.              | (3) 召回相关片段 (Context)
  21.              v
  22.     +-----------------------+
  23.     |   大语言模型 (LLM)      | <--- (将提示词与背景片段拼接)
  24.     +-----------------------+
  25.              |
  26.              | (4) 最终生成 (Generation)
  27.              v
  28.     +-----------------------+
  29.     |      输出结果          |
  30.     +-----------------------+
复制代码
代码解释

代码的流程如下:

  • 初始化RAG:文本切片->文本向量模型->构建向量数据库
  • 询问ai:提示词->文本向量模型->向量数据库检索->组合prompt->喂给LLM->回答问题->记录历史对话
文本切片
  1. from operator import itemgetter
  2. import os
  3. from langchain_community.chat_models.tongyi import ChatTongyi
  4. from langchain_community.vectorstores import FAISS
  5. from langchain_community.embeddings import DashScopeEmbeddings
  6. from langchain_text_splitters import RecursiveCharacterTextSplitter
  7. from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
  8. from langchain_core.documents import Document
  9. from langchain_core.runnables import RunnablePassthrough
  10. from langchain_core.output_parsers import StrOutputParser
  11. from langchain_core.messages import HumanMessage, AIMessage
  12. from sqlalchemy import true
  13.   
  14. #apikey
  15. os.environ["DASHSCOPE_API_KEY"] = "你的apikey"
  16. FAISS_PATH = "my_faiss_index"
  17. raw_text = """
  18. 【公司内部机密:代号“深蓝计划”】
  19. 1. 项目目标:开发一款能听懂猫语的翻译器。
  20. 2. 核心技术:基于Transformer的“喵声波”分析算法。
  21. 3. 团队暗号:如果有人问“今天天气怎么样?”,必须回答“我想吃鱼”。
  22. 4. 截止日期:2026年12月31日。
  23. 5. 经费预算:仅剩50元人民币,主要用于购买猫条。
  24. """
  25. #初始化文本
  26. docs = [Document(page_content=raw_text)]
  27. text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
  28. split_docs = text_splitter.split_documents(docs)
  29.   
  30. #初始化模型
  31. llm = ChatTongyi(model="qwen-plus")
  32. embeddings = DashScopeEmbeddings(model="text-embedding-v1")
  33. #创建向量数据库
  34. if os.path.exists(FAISS_PATH):
  35.     print("向量数据库已存在")
  36.     ragdb = FAISS.load_local(FAISS_PATH, embeddings, allow_dangerous_deserialization=True)
  37. else:
  38.     print("创建向量数据库")
  39.     ragdb = FAISS.from_documents(split_docs, embeddings)
  40.     ragdb.save_local(FAISS_PATH)
  41. #构建提示词chain
  42. def format_docs(docs):
  43.     return "\n\n".join(doc.page_content for doc in docs)
  44. final_prompt = ChatPromptTemplate.from_messages([
  45.     ("system", """
  46.     你是一个专业的问答助手,你的任务是根据上下文简洁的回答用户的问题。
  47.     <context>
  48.     {context}
  49.     </context>
  50.     """),
  51.     MessagesPlaceholder(variable_name="history"),
  52.     ("human", "{input}")
  53. ])
  54. chain = (
  55.     #查询rag
  56.     RunnablePassthrough.assign(
  57.         context = itemgetter("input") | ragdb.as_retriever() | format_docs
  58.     )
  59.     | RunnablePassthrough.assign(
  60.         answer = {"input":itemgetter("input"), "context":itemgetter("context"), "history":itemgetter("history")} | final_prompt | llm | StrOutputParser()
  61.     )
  62. )
  63. history = []
  64. while true:
  65.     input_q = input("我:")
  66.   
  67.     respond = chain.invoke({
  68.         "input": input_q,
  69.         "history": history})
  70.     print("answer:" + respond["answer"])
  71.     print("=="*30)
  72.    
  73.     history.append(HumanMessage(content=input_q))
  74.     history.append(AIMessage(content=respond['answer']))
复制代码
这里利用了langchain提供的文本分词器RecursiveCharacterTextSplitter(递归分词)
构建向量数据库
  1. docs = [Document(page_content=raw_text)]
  2. text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
  3. split_docs = text_splitter.split_documents(docs)
复制代码
这部分要注意:新版FAISS读取现有数据库要设置:allow_dangerous_deserialization=True,不然会报错
提示词模板
  1. llm = ChatTongyi(model="qwen-plus")
  2. embeddings = DashScopeEmbeddings(model="text-embedding-v1")
  3. #创建向量数据库
  4. if os.path.exists(FAISS_PATH):
  5.     print("向量数据库已存在")
  6.     ragdb = FAISS.load_local(FAISS_PATH, embeddings, allow_dangerous_deserialization=True)
  7. else:
  8.     print("创建向量数据库")
  9.     ragdb = FAISS.from_documents(split_docs, embeddings)
  10.     ragdb.save_local(FAISS_PATH)
复制代码
之前没有讲到历史对话记录,这次补充下:
MessagesPlaceholder这个是langchain框架的占位符(其实是框架写好了prompt模板,告诉ai这个是历史对话),使用时将历史对话记录的数组放在这里设置的字段中,在添加历史对话时要使用相关的类进行声明对话(告诉ai这句话是ai说的还是用户说的)
  1. final_prompt = ChatPromptTemplate.from_messages([
  2.     ("system", """
  3.     你是一个专业的问答助手,你的任务是根据上下文简洁的回答用户的问题。
  4.     <context>
  5.     {context}
  6.     </context>
  7.     """),
  8.     MessagesPlaceholder(variable_name="history"),
  9.     ("human", "{input}")
  10. ])
复制代码
Chain链的解释(核心逻辑)
  1. history.append(HumanMessage(content=input_q))
  2. history.append(AIMessage(content=respond['answer']))
复制代码
Chain链流程:

  • 查询RAG的chain:获取input字段->内容交给向量数据库检索->将检索的内容(数组)转换为字符串格式->保存到context字段并传递给下一个任务
  • 询问LLM的chain:获取input,context,history字段->填充上面定义的prompt模板->喂给LLM模型->解析成文本并保存在answer字段
itemgetter是获取上一个任务传递过来的字段内容。
如果❤喜欢❤本系列教程,就点个关注吧,后续不定期更新~

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

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