云计算百科
云计算领域专业知识百科平台

AI: 告别过时信息, 用RAG和一份PDF 为LLM打造一个随需更新的“外脑”

嘿,各位技术同学!今天,我们来聊一个大家在使用大语言模型(LLM)时都会遇到的痛点:知识过时。

无论是像我一样,用 Gemini Pro 学习日新月异的以太坊,还是希望它能精确掌握某个特定工具的最新用法,我们都可能被它“记忆”里的旧知识所困扰。比如,我让它生成 PlantUML 图时,它偶尔会“穿越”回过去,使用一些已经被废弃的旧语法,这无疑增加了我们的学习和开发成本。

为了解决这个问题,我动手开发了一个小项目:一个基于**检索增强生成(RAG)**的智能问答系统。它能读取最新的官方文档(比如 PlantUML 的语言参考指南),并让 Gemini 模型在回答问题前,先查阅这些最新资料。今天,我就和大家分享这个项目的技术实现,希望能给大家带来一些启发。
在这里插入图片描述

项目核心理念:RAG如何解决问题?

在我们深入代码之前,先花一分钟理解一下 RAG 的工作原理。

想象一下,我们让一位非常聪明的实习生(LLM)写一份报告,但他对某个特定领域的最新进展不太了解。我们会怎么做?我们不会让他凭空想象,而是会把最新的行业报告、研究论文(外部知识库)丢给他,说:“看,根据这些资料来写。”

RAG 就是这个过程的自动化版本。它通过一个“检索”步骤,从我们的知识库(PDF、文档、网站等)中找到与用户问题最相关的信息,然后将这些信息连同原始问题一起打包,交给 LLM,让它基于这些“新鲜出炉”的材料来“生成”答案。

这个流程可以用下面的 PlantUML 图清晰地表示:
在这里插入图片描述

技术实现深度解析

现在,让我们深入 main.py 文件,看看这个 RAG 系统是如何一步步构建起来的。

第一步:知识库的建立与“保鲜”

万丈高楼平地起,我们的第一步是建立一个可靠的知识库。在这个项目中,知识来源于一份PDF文档。但我们做了一个非常实用的优化:自动检测文档更新。

代码通过 get_pdf_hash 函数计算 PDF 文件的 SHA256 哈希值。

def get_pdf_hash(file_path):
"""计算文件的 SHA256 哈希值"""
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()

在 load_or_create_vectorstore 函数中,系统启动时会检查持久化目录 chroma_db 中存储的旧哈希值与当前 PDF 文件的哈希值是否一致。

  • 如果一致:太棒了!说明文档没变,直接从磁盘加载已经处理好的向量数据库,秒级启动。
  • 如果不一致或首次运行:说明知识需要更新!系统会自动删除旧的数据库,然后使用 PyPDFLoader 加载新的 PDF,并用 RecursiveCharacterTextSplitter 将其分割成更小的、易于检索的文本块。

这个设计非常关键,它确保了我们的“外脑”永远存储的是最新信息,同时避免了每次运行都重复处理文档的昂贵开销。

第二步:将知识向量化 (Embedding)

计算机不理解文字,只理解数字。为了让机器能够“理解”并比较文本片段的相似度,我们需要将它们转换成向量,这个过程叫做嵌入(Embedding)。

我们使用了 HuggingFace 的 sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 模型。这个模型能将文本块转换成一个包含几百个数字的向量,神奇的是,语义上相似的文本块,其对应的向量在多维空间中的距离也更近。

def setup_embeddings():
"""初始化并返回嵌入模型"""
print("正在初始化嵌入模型…")
embeddings = HuggingFaceEmbeddings(
model_name=EMBEDDING_MODEL_NAME,
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': False}
)
return embeddings

所有从 PDF 中分割出来的文本块都会经过这个模型处理,然后连同它们的向量表示一起存入 Chroma 向量数据库中。

第三步:搭建检索与生成的核心链

现在,我们有了存储知识的数据库和负责回答问题的 LLM,是时候把它们“链接”起来了。这里我们借助了 LangChain 框架的 RetrievalQA 链。

def create_qa_chain(llm, vectorstore):
"""基于LLM和向量数据库创建并返回问答链"""
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
return qa_chain

这个链条的工作流程如下:

  • 设置检索器(Retriever):vectorstore.as_retriever(search_kwargs={"k": 2}) 这行代码创建了一个检索器,当用户提问时,它会去 Chroma 数据库中检索出最相似的 k=2 个文档片段。
  • 选择链类型(Chain Type):chain_type="stuff" 是一种简单直接的策略。它会把检索到的所有文档片段(stuff them)一股脑地塞进一个提示词模板中,和用户的原始问题一起发送给 LLM。
  • 返回源文档:return_source_documents=True 是一个非常有用的调试和验证工具。它让 LLM 在给出答案的同时,也告诉我们它参考了哪些原文片段。这大大增强了结果的透明度和可信度。
  • 实践与效果

    一切准备就绪后,main 函数将所有部分串联起来,并用一个具体问题来测试系统:

    def main():
    """主执行函数,编排整个RAG流程"""
    embeddings = setup_embeddings()
    vectorstore = load_or_create_vectorstore(PDF_FILE_PATH, PERSIST_DIRECTORY, embeddings)
    llm = setup_llm()
    qa_chain = create_qa_chain(llm, vectorstore)

    query = "如何绘制 JSON 数据图?"
    ask_question(qa_chain, query)

    当运行这个脚本时,它会:

  • 初始化模型和向量数据库。
  • 接收问题 如何绘制 JSON 数据图?。
  • 在数据库中找到关于 JSON 数据可视化的相关片段。
  • 将这些片段和问题一起发给 Gemini。
  • Gemini 基于最新的 PlantUML 语法(来自PDF)生成答案,并附上参考来源。
  • 这样,我们就得到了一个既有 Gemini 强大推理能力,又有最新、最准确领域知识的 AI 助手。

    实用建议与未来展望

    这个项目虽然简单,但扩展性很强:

  • 更换知识源:我们可以轻易地将 PDF_FILE_PATH 换成任何我们想要的 PDF 文档,比如以太坊的白皮书、某个开源库的API文档,甚至是我们的学习笔记。
  • 支持更多格式:通过使用 LangChain 提供的其他 DocumentLoader,我们可以让系统读取 .txt, .md 文件,甚至直接爬取网站内容。
  • 部署为服务:使用 FastAPI 或 Flask 将这个问答系统包装成一个 API 服务,让其他人也能方便地使用。
  • 优化检索:对于非常大的文档,可以探索更高级的检索策略,如 Parent Document Retriever,以获得更相关的上下文。
  • 结论

    通过 RAG,我们为大语言模型安装了一个可随时更新、可定制的“外脑”。这个方法不仅有效解决了 LLM 知识滞后的问题,还通过引入可验证的信源,大大提高了生成内容的可信度。最棒的是,实现这一切的技术门槛并不高。

    希望这篇文章能激励大家动手尝试,为自己的学习和工作场景打造一个专属的、永远不会“过时”的AI伙伴。
    https://github.com/xilu0/plantuml-agent/blob/main/main.py

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » AI: 告别过时信息, 用RAG和一份PDF 为LLM打造一个随需更新的“外脑”
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!