本地部署大语言模型实践(2):集成外部知识库详细步骤
本文详细介绍了如何在本地部署环境下,利用 Ollama 运行大语言模型并结合 LangChain 框架构建检索增强生成(RAG)系统。内容涵盖环境准备、模型选择、基线测试、嵌入模型配置、向量数据库搭建及完整问答链的实现。通过对比有无外部知识库的测试结果,验证了 RAG 技术在提升模型回答准确性方面的有效性,并提供了关于分块大小、检索策略及参数优化的实用建议。

本文详细介绍了如何在本地部署环境下,利用 Ollama 运行大语言模型并结合 LangChain 框架构建检索增强生成(RAG)系统。内容涵盖环境准备、模型选择、基线测试、嵌入模型配置、向量数据库搭建及完整问答链的实现。通过对比有无外部知识库的测试结果,验证了 RAG 技术在提升模型回答准确性方面的有效性,并提供了关于分块大小、检索策略及参数优化的实用建议。

在上一篇文章中,我们展示了如何通过 Ollama 这款工具,在本地运行大型语言模型。本篇文章将着重介绍如何让模型从外部知识库中检索定制数据,来提升大型语言模型的准确性,让它看起来更'智能'。
本文涉及 LangChain 和 RAG 两个核心概念。我们将通过实际代码演示如何构建一个基于检索增强生成(Retrieval Augmented Generation)的问答系统。
在开始之前,请确保您的开发环境满足以下要求:
pip install langchain langchain-community ollama tiktoken docarray
访问 Ollama 的模型页面,搜索 qwen。本次实验将使用对中文语义理解较好的 qwen:7b 模型。
ollama run qwen:7b
首先编写基础代码,测试模型在没有外部知识辅助下的回答能力。
from langchain_community.chat_models import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# 初始化本地模型
model_local = ChatOllama(model="qwen:7b")
# 定义提示模板
template = "{topic}"
prompt = ChatPromptTemplate.from_template(template)
# 构建链
chain = model_local | StrOutputParser()
# 执行提问
print(chain.invoke("身长七尺,细眼长髯的是谁?"))
模型返回的答案:
这句话描述的是中国古代文学作品《三国演义》中的角色刘备。刘备被描绘为一位身高七尺(约 1.78 米),眼睛细小但有神,长着长须的蜀汉开国皇帝。
可以看到,这是一个开放型问题,没有指定上下文。虽然模型凭借训练数据联想到了三国人物,但答案并不准确(实际上是曹操)。这说明了纯预训练模型在处理特定领域事实时的局限性。
检索增强生成(Retrieval Augmented Generation,简称 RAG)的工作方式是在共享的语义空间中,从外部知识库中检索事实,将这些事实用作决策过程的一部分,以此来提升大型语言模型的准确性。
在人工智能中,嵌入(Embedding)是将数据向量化的过程,可以理解为将人类语言转换为大语言模型所需要的计算机语言的过程。在第二轮测试开始前,我们需要下载一个嵌入模型。
ollama run nomic-embed-text
该模型将使我们的 Ollama 具备将文档向量化的能力。
接下来需要配置 LangChain 的各个组件:文档加载器、文本分割器、向量数据库以及检索链。
我们需要一个 Document Loader 来读取本地文件,并使用 Text Splitter 进行分块处理。
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
# 加载文档
loader = TextLoader("./data/三国演义.txt", encoding="utf-8")
documents = loader.load()
# 文本分割
# chunk_size 控制每个块的大小,chunk_overlap 控制重叠部分以便保留上下文
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=7500,
chunk_overlap=100
)
doc_splits = text_splitter.split_documents(documents)
接下来需要一个向量数据库来存储使用 nomic-embed-text 模型量化的数据。既然是测试,我们就使用内存型的 DocArrayInMemorySearch。
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import DocArrayInMemorySearch
# 初始化嵌入模型
embeddings = OllamaEmbeddings(model='nomic-embed-text')
# 创建向量库
vectorstore = DocArrayInMemorySearch.from_documents(doc_splits, embeddings)
retriever = vectorstore.as_retriever()
最后,将检索器与 LLM 结合,构建完整的问答链。
from langchain_community.chat_models import ChatOllama
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
model_local = ChatOllama(model="qwen:7b")
# 定义提示模板,强制模型仅根据上下文回答
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model_local
| StrOutputParser()
)
# 执行提问
result = chain.invoke("身长七尺,细眼长髯的是谁?")
print(result)
首先下载《三国演义》相关章节作为外部数据库供模型检索。注意该文档中提到的关键信息:
忽见一彪军马,尽打红旗,当头来到,截住去路。为首闪出一将,身长七尺,细眼长髯,官拜骑都尉,沛国谯郡人也,姓曹,名操,字孟德。
模型返回的答案:
身长七尺,细眼长髯的人物是曹操,字孟德,沛国谯郡人。在《三国演义》中,他是主要人物之一。
可见,使用 RAG 后,模型能够根据提供的上下文给出正确答案。
本篇文章我们使用 LangChain 和 RAG 对大语言模型进行了微调,使之生成答案前可以在给到的文档内进行检索,以生成更准确的答案。
RAG 的应用。chunk_size 过大可能导致检索不精确,过小可能丢失上下文。建议根据文档类型尝试不同数值(如 500-2000 字符)。temperature 设置为较低值(如 0.1-0.3),以减少幻觉,提高事实准确性。这次的文章就到这里了,后续我们将继续介绍更多本地 LLM 的实用场景,包括微调与多模态应用。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online