跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

RAG 实战:利用 Langchain 和 Milvus 构建本地知识库

综述由AI生成如何利用 Langchain 框架结合 Milvus 向量数据库构建基于 RAG(检索增强生成)技术的本地知识库系统。文章首先分析了大语言模型(LLM)面临的训练数据滞后和私有数据不可知等痛点,阐述了 RAG 相比 Prompt Engineering 和 Fine-tuning 在准确性、及时性和安全性方面的优势。随后,通过完整的代码示例演示了从环境安装、PDF 文档加载与分块、Embedding 向量化、Milvus 向量存储到检索与生成的全流程。此外,文章还提供了关于分块策略优化、混合检索、重排序机制及评估体系的进阶建议,帮助开发者构建更高效、精准的企业级知识库应用。

锁机制发布于 2025/2/6更新于 2026/6/322 浏览
RAG 实战:利用 Langchain 和 Milvus 构建本地知识库

RAG 实操教程:Langchain + Milvus 向量数据库创建本地知识库

本文是 Milvus 向量数据库学习的总结篇,旨在通过实战打造自己的知识库系统。

RAG 是什么

RAG(Retrieval-Augmented Generation)翻译为检索增强生成。其核心思想是以最新、最准确的数据建立 LLM(Large Language Model)的语料知识库,从而解决模型知识滞后问题。

LLM 有哪些痛点

我们知道 LLM 的知识库是通过现有的网络公开数据作为数据源来训练的。现在公开的很多模型基于的训练数据会比当前网络上公开的数据早很多,这自然会产生一个问题:网络上最新的数据和知识 LLM 是不知道的。

还有一种情况是企业私有化数据(这些数据是有价值的,也是企业的立足之本)。这些数据网络上肯定不存在,LLM 自然也不知道。

我们在提问 LLM 对于一些不知道的知识时,它很多时候无法回答,甚至会对问题进行胡诌随机回答,也就是产生幻觉。

为什么要用 RAG

如果使用预训练好的 LLM 模型,应用在某些情景下势必会有些词不达意的问题。例如问 LLM 你个人的信息,它会无法回答;这种情况在企业内部也是一样,例如使用 LLM 来回答企业内部的规章条款等。

这种时候主要有三种方式来让 LLM 变得更符合你的需求:

  1. Prompt Engineering:输入提示来指导 LLM 产生所需回应。例如常见的 In-context Learning,通过在提示中提供上下文或范例,来形塑模型的回答方式。例如,提供特定回答风格的示例或包含相关的情境信息,可以引导模型产生更合适的答案。
  2. Fine-tuning(微调):这个过程包括在特定数据集上训练 LLM,使其响应更符合特定需求。例如,一个 EDA 公司会使用其内部文件 Verilog code 进行 Fine-tuning,使其能够更准确地回答关于企业内部问题。但是 Fine-tuning 需要代表性的数据集且量也有一定要求,且 Fine-tuning 并不适合于在模型中增加全新的知识或应对那些需要快速迭代新场景的情况。
  3. RAG(Retrieval Augmented Generation):结合了神经语言模型和检索系统。检索系统从数据库或一组文件中提取相关信息,然后由语言模型使用这些信息来生成答案。我们可以把 RAG 想像成给模型提供一本书或者是文档、教程,让它根据特定的问题去找信息。此方法适用于模型需要整合实时、最新或非常特定的信息非常有用。但 RAG 并不适合教会模型理解广泛的信息或学习新的语言、格式。

目前的研究已经表明,RAG 在优化 LLM 方面,相较于其他方法具有显著的优势。主要的优势体现在以下几点:

  • 准确性:RAG 通过外部知识来提高答案的准确性,有效地减少了虚假信息,使得产生的回答更加准确可信。
  • 及时性:使用检索技术能够识别到最新的信息(用户提供),这使得 LLM 的回答能保持及时性。
  • 透明性:RAG 引用信息来源是用户可以核实答案,因此其透明度非常高,这增强了人们对模型输出结果的信任。
  • 定制能力:透过获取与特定领域数据,RAG 能够为不同领域提供专业的知识支持,定制能力非常高。
  • 安全性和隐私:在安全性和隐私管理方面,RAG 通过数据库来存储知识,对数据使用有较好控制性。相较之下,经过 Fine-tuning 的模型在管理数据存取权限方面不够明确,容易外泄,这对于企业是一大问题。
  • 经济效率:由于 RAG 不需更新模型参数,因此在处理大规模数据集时,经济效率方面更具优势。

不过虽然 RAG 有许多优势,但这 3 种方法并不是互斥的,反而是相辅相成的。结合 RAG 和 Fine-tuning,甚至 Prompt Engineering 可以让模型能力的层次性得增强。这种协同作用特别在特定情境下显得重要,能够将模型的效能推至最佳。

如何解决上面的问题

那如何让 LLM 知道这些最新/私有的数据的知识呢?那就是 RAG。通过将模型建立在外部知识来源的基础上来补充回答,从而提高 LLM 生成回答的质量。

在基于 LLM 实现的问答系统中使用 RAG 有三方面的好处:

  • 确保 LLM 可以回答最新、最准确的内容。并且用户可以访问模型内容的来源,确保可以检查其声明的准确性并最终可信。
  • 通过将 LLM 建立在一组外部的、可验证的事实数据之上,该模型将信息提取到其参数中的机会更少。这减少了 LLM 泄露敏感数据或'幻觉'不正确或误导性信息的机会。
  • RAG 还减少了用户根据新数据不断训练模型并随着数据的变化更新训练参数的需要。通过这种方式企业可以降低相关财务成本。

现在所有基础模型使用的是 Transformer 的 AI 架构。它将大量原始数据转换为其基本结构的压缩表示形式。这种原始的表示基础模型可以适应各种任务,并对标记的、特定于领域的知识进行一些额外的微调。

不过仅靠微调很少能为模型提供在不断变化的环境中回答高度具体问题所需的全部知识,并且微调的时间周期还比较长。所以科学家们提出了 RAG,让 LLM 能够访问训练数据之外的信息。RAG 允许 LLM 建立在专门的知识体系之上,以更准确的回答问题,减低幻觉的产生。

下面我将演示如何使用 Langchain + Milvus 向量数据库创建你的本地知识库。

安装 Langchain

使用下面的命令可以快速安装 Langchain 相关的依赖:

pip install langchain
pip install langchain-community # 默认安装
pip install langchain-core # 默认安装
pip install langchain-cli # LangChain 命令行界面
pip install --upgrade --quiet pypdf # 安装 pdf 加载器的依赖

文档加载器 PDF

在这篇文章中我们使用 PDF 作为我们的知识库文档。

加载文档的过程一般需要下面的步骤:

  1. 解析文档(txt、pdf、html、url、xml、markdown、json 等等)为字符串(Langchain 已经分装了几十种文档加载器,感兴趣的可以去参考官网)。
  2. 将字符串拆分为适合模型的对话窗口的大小,称为 Chunk,Chunk 的大小需要依据模型的会话窗口设定。
  3. 保存拆分好的文档保存到向量数据库中。
  4. 设计向量数据库的数据库、集合、字段,索引等信息。
  5. 从向量数据库中检索需要的数据。

这些步骤 Langchain 已经结合自己的工具连做好了封装,所以我们直接使用 Langchain 来构建 RAG。

from langchain_text_splitters import CharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader

file_path = 'CodeGeeX 模型 API.pdf'

# 初始化 pdf 文档加载器
loader = PyPDFLoader(file_path=file_path)
# 将 pdf 中的文档解析为 langchain 的 document 对象
documents = loader.load()
# 将文档拆分为合适的大小
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
docs = text_splitter.split_documents(documents)

上面有两个参数需要注意下:

  • chunk_size=1000:表示拆分的文档的大小,也就是上面所说的要设置为多少合适取决于所使用 LLM 的窗口大小。
    • 如果设置小了,那么我们一次查询的数据的信息量就会少,势必会导致信息的缺失。
    • 如果设置大了,一次检索出来的数据就会比较大,LLM 产生的 token 就会多,费用贵,信息不聚焦等问题。
  • chunk_overlap=100:这个参数表示每个拆分好的文档重复多少个字符串。
    • 为什么要重复:如果拆分后的 Chunk 没有重复,很有可能会产生语义错误。
    • 比如这样一段文本:....小米汽车的续航里程为 700 公里....如果文本正好从 700 的哪里拆分开的话,那给人展示的时候就会产生究竟是 700m 还是 700 公里才歧义。
    • chunk_overlap如果设置比较大的值也不合适。这样每个文档的重复度就会很大,导致有用的信息就会减少,从而 LLM 回复的内容有可能缺少关键的信息。

Milvus 向量数据库

关于 Milvus 可以参考官方文档。下面我们安装 pymilvus 库:

pip install --upgrade --quiet pymilvus

如果你使用的不是 Milvus 数据库,那也没关系,Langchain 已经给我们分装了几十种向量数据库,你选择你需要的数据库即可。本文中我们是系列教程中一篇,所以我们使用 Milvus 向量库。

Embedding Model

这里需要明确的两个功能是:

  • Embedding Model:所做的工作就是将 Image、Document、Audio 等信息向量化。
  • Vector DB:负责保存多维向量。

我这里使用 AzureOpenAIEmbeddings 是个收费的模型。有开源的 Embedding Model 可以部署在本地使用,如果你的机器性能足够好。如果要本地部署可以参考 Docker 部署 Llama2 模型。

这里我使用 AzureOpenAIEmbeddings,相关配置我放到了 .env 文件中,并使用 dotenv 加载。

# AZURE config
AZURE_OPENAI_ENDPOINT=''
AZURE_OPENAI_API_KEY=''
OPENAI_API_VERSION=2024-03-01-preview
AZURE_DEPLOYMENT_NAME_GPT35 = "gpt-35-turbo"
AZURE_DEPLOYMENT_NAME_GPT4 = "gpt-4"
AZURE_EMBEDDING_TEXT_MODEL = "text-embedding-ada-002"

这里各位可以依据自己的情况设定即可。

向量化 + 存储

上面已经说明了向量库以及 Embedding Model 的关系。我们直接使用 Langchain 提供的工具来完成 Embedding 和 Store。

# 初始化 embedding model
from langchain_openai import AzureOpenAIEmbeddings
embeddings = AzureOpenAIEmbeddings()

from langchain_community.vectorstores import Milvus
vector = Milvus.from_documents(
    documents=documents, # 设置保存的文档
    embedding=embeddings, # 设置 embedding model
    collection_name="book", # 设置 集合名称
    drop_old=True,
    connection_args={"host": "127.0.0.1", "port": "19530"}, # Milvus 连接配置
)

执行完成上面的代码,我们就将 PDF 中文档内容保存到 Vector DB 中。

字段 vector 就是保存的多维向量。

Milvus Search

虽然现在我们还没有使用 LLM 的任何能力,但是我们已经可以使用 Vector 的搜索功能了。

query = "CodeGeeX 模型 API 参数有那些?"
docs = vector.similarity_search(query)
print(docs)

# 带 score 搜索
query = "CodeGeeX 模型 API 参数有那些?"
docs = vector.similarity_search_with_score(query, k=2)
print(docs)

similarity_search 与 similarity_search_with_score 的区别就是 similarity_search_with_score 搜索出来会带有一个 Score 分值的字段,某些情况下这个 Score 很有用。

Langchain 不仅仅提供了基础的搜索能力,还有其他的搜索方法,感兴趣的可以去研究下。

RAG Chat

准备工作我们已经就绪,接下来我们使用 Langchain 构建我们的 Chat。

既然是聊天也就是我们跟模型的一问一答的形式来体现。这两年 LLM 的出现,关于 LLM 的知识里面我们估计最熟悉就是角色设定了。

  • 什么是角色设定:在大型语言模型 (LLM) 中,角色设定指的是为 AI 助手创建一个特定的人格或身份。这个设定包括 AI 助手的说话风格、知识领域、价值观、行为方式等各个方面。通过这些设定,AI 助手可以扮演不同的角色,比如专业的客服、风趣幽默的聊天对象,或是特定领域的专家顾问。
  • 作用:角色设定可以让 AI 助手的回答更加符合特定的场景和用户的期望。此外,角色设定还可以帮助限定 AI 助手的行为边界,避免其做出不恰当或有害的回应。设定明确的角色定位,有助于 AI 助手更好地理解自己的身份和职责,从而提供更加合适和有帮助的回答。

在 Chat 中我们同样也需要一个简单的 Prompt:

template = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know.
 
Question: {question} 
 
Context: {context} 
 
Answer:
"""

这个 Prompt 中很明显我们设定了两个变量 question, context。

  • question:这个会在后面被替换为用户的输入,也就是用户的问题。
  • context:这个变量我们在后面会替换为向量检索出来的内容。

请思考下:我们最后提供给 LLM 的内容只是用户的问题呢还是问题连带内容一起给到 LLM?

Chat Chain

基于上面的内容我们基本的工作已经完成,下面就是我们基于 Langchain 构建 Chat。

import os
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template(template)
print(prompt)

# 加载 chat model
from langchain_openai import AzureChatOpenAI
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
llm = AzureChatOpenAI(
    azure_deployment=os.environ.get('AZURE_DEPLOYMENT_NAME_GPT35')
)

retriever = vector.as_retriever()

chain = (
    RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
    | prompt
    | llm
    | StrOutputParser()
)

对于初学者可能有个问题就是:为什么这里有个 AzureChatOpenAI() 的实例 llm。 这是个好问题,对于初学者会被各种 LLM 搞晕。

  • AzureOpenAIEmbeddings():这是一个负责将文本向量化化的 Model。
  • AzureChatOpenAI():是一个 Chat 模型。负责聊天的 Model。

基于 Langchain 的链式调用构建 Chat:

chain = (
    RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
    | prompt
    | llm
    | StrOutputParser()
)

这里看到 Prompt 中的两个变量 context, question 会被替换。

为什么我们要写变量在 Prompt 中?

  • 工程化:我们在做 LLM 相关的工作最重要的就是 Prompt 工程。这也是个重要的话题后面再说。
  • 灵活:便于动态调整输入,提高系统的可维护性。

测试

示例一:

question = "CodeGeeX 模型 API 参数有那些?"
answer = chain.invoke(question)
print(answer)

输出:

CodeGeeX 模型 API 的参数包括:
- prompt:用户输入的提示词
- max_tokens:模型输出最大 tokens
- temperature:采样温度,控制输出的随机性
- top_p:另一种采样方法,模型考虑具有 top_p 概率质量 tokens 的结果
- stream:用于同步调用时,控制模型生成内容的返回方式,可以设置为 false 或 true

示例二:

question = "请给一个 chat 模型非流式请求示例"
answer = chain.invoke(question)
print(answer)

输出:

流式请求示例:
curl --location 'http://{ip}/prod/model/api/infillingStreaming' \
--header 'Content-Type: application/json' \
--data '{
    "model": "codegeex",
    "prompt": "package problem1;\nclass Solution{\n    public int \nremoveDuplicates(int[] nums) {\n        int cnt = 1;\n        for (int i = 1; \ni < nums.length; ++i)\n            if (nums[i] != nums[i - 1]) {\n             \n   nums[cnt] = nums[i];\n                ++cnt;\n            }\n        return \ncnt;\n    }\n}",
    "max_tokens": 1024,
    "temperature": 0.2,
    "top_p": 0.95,
    "stream": true
}'

对比 PDF 中的内容,很明显这个结果就是对的。

进阶优化建议

在实际生产环境中,除了基本的流程实现,还需要关注以下优化点以提升系统性能和用户体验:

1. 分块策略优化

默认的字符切分(CharacterTextSplitter)虽然简单,但在处理复杂文档时可能破坏语义。建议尝试以下策略:

  • Semantic Splitter:基于语义完整性进行切分,保持段落逻辑。
  • RecursiveCharacterTextSplitter:按字符优先级递归切分,通常比单一字符切分效果更好。
  • Metadata 保留:在切分时保留页码、章节标题等元数据,有助于后续溯源。

2. 检索策略增强

  • Hybrid Search:结合关键词搜索(BM25)和向量相似度搜索,提高召回率。
  • Re-ranking:在检索后引入重排序模型(如 BGE-Reranker),对初步检索结果进行二次打分,提升 Top-K 结果的准确性。
  • Query Transformation:对用户查询进行改写(Query Rewriting),将其转化为更适合检索的表述。

3. 评估体系构建

  • 人工评估:定期抽样检查回答质量,标注准确率。
  • 自动化指标:使用 RAGAS 等框架计算 Faithfulness(忠实度)、Answer Relevance(答案相关性)等指标。
  • A/B 测试:对比不同 Embedding 模型或不同 Chunk Size 下的效果差异。

4. 性能与成本

  • 缓存机制:对高频问题结果进行缓存,减少 Token 消耗。
  • 异步处理:对于长文档处理或高并发场景,采用异步队列处理任务。
  • 模型选择:根据预算选择合适的 Embedding 和 LLM 模型,平衡效果与成本。

总结

本文主要是 Milvus 向量数据实战总结。

  • LLM 痛点以及解决方案
  • RAG 是什么,为什么选用 RAG。
  • Langchain 文档加载器,Embedding Model,Chat Model
  • 文档拆分的注意点,Embedding Model,Chat Model 区别。
  • Chat 示例代码及进阶优化建议。

通过上述步骤,你可以快速搭建一个基于 Langchain 和 Milvus 的个性化本地知识库系统,有效解决大模型知识滞后和幻觉问题。

目录

  1. RAG 实操教程:Langchain + Milvus 向量数据库创建本地知识库
  2. RAG 是什么
  3. LLM 有哪些痛点
  4. 为什么要用 RAG
  5. 如何解决上面的问题
  6. 安装 Langchain
  7. 文档加载器 PDF
  8. 初始化 pdf 文档加载器
  9. 将 pdf 中的文档解析为 langchain 的 document 对象
  10. 将文档拆分为合适的大小
  11. Milvus 向量数据库
  12. Embedding Model
  13. AZURE config
  14. 向量化 + 存储
  15. 初始化 embedding model
  16. Milvus Search
  17. 带 score 搜索
  18. RAG Chat
  19. Chat Chain
  20. 加载 chat model
  21. 测试
  22. 进阶优化建议
  23. 1. 分块策略优化
  24. 2. 检索策略增强
  25. 3. 评估体系构建
  26. 4. 性能与成本
  27. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • JavaScript 获取本周周一零点时间方法
  • AirSim 无人机仿真环境部署与配置指南
  • ComfyUI 提示词助手实战:通过自动化流程提升 AI 绘画效率
  • AirSim 无人机仿真实战:起飞与降落控制
  • ComfyUI 云服务器部署实战与优化指南
  • 前端实战:基于 Vue3 实现无限滚动、懒加载与瀑布流模块及优化策略
  • C++ 继承:面向对象代码复用的核心机制
  • 基于 UDP 的手机通话语音局域网传输与 AI 处理 Python 脚本
  • Stable Diffusion 潜空间扩散生成流程解析
  • STM32 项目 Git 版本管理实战指南
  • LLaMA 大模型 LoRA 微调实践与部署指南
  • 自然语言处理在社交媒体分析中的实战应用
  • 9 本大模型与人工智能入门经典书籍推荐
  • Linux 基础开发工具:Git 版本管理与 GDB/CGDB 调试技巧
  • LLaMA-Factory 低成本微调实战指南
  • FLUX.1-dev FP8 模型部署与低显存优化实战
  • AI 大模型产品经理转行指南:核心能力与实战路径
  • PyCharm Copilot 插件 Claude 模型不可用问题修复
  • 自然语言处理在法律领域的应用与实战
  • Java SpringBoot+Vue3+MyBatis 仓库管理系统设计与实现

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online