跳到主要内容 基于 Chroma 和 Ollama 搭建本地 RAG 应用 | 极客日志
Python AI 算法
基于 Chroma 和 Ollama 搭建本地 RAG 应用 本文介绍了如何使用 Ollama 本地部署大语言模型,结合 ChromaDB 向量数据库和 LangChain 框架构建本地 RAG 问答应用。内容包括环境配置、模型加载、网页内容解析与分块、向量化存储、提示词工程以及使用 Gradio 构建交互界面。通过该方案可实现基于私有数据的离线智能问答,无需依赖云端 API。同时补充了常见问题处理与性能优化建议,帮助用户更好地落地本地 AI 应用。
花里胡哨 发布于 2025/2/6 更新于 2026/4/20 1 浏览本篇文章我们将基于 Ollama 本地运行大语言模型(LLM),并结合 、 来建立一个小型的基于网页内容进行本地问答的 应用。
ChromaDB
LangChain
RAG
概念介绍 LLM (Large Language Model) 是通过使用海量的文本数据集(书籍、网站等)训练出来的,具备通用语言理解和生成的能力。虽然它可以推理许多内容,但它们的知识仅限于特定时间点之前用于训练的数据。
LangChain 是一个用于开发由大型语言模型(LLM)驱动的应用程序的框架。提供了丰富的接口、组件、能力简化了构建 LLM 应用程序的过程。
Ollama 是一个免费的开源框架,可以让大模型很容易的运行在本地电脑上。
RAG (Retrieval Augmented Generation)是一种利用额外数据增强 LLM 知识的技术,它通过从外部数据库获取当前或相关上下文信息,并在请求大型语言模型(LLM)生成响应时呈现给它,从而解决了生成不正确或误导性信息的问题。
加载并解析网页内容。
将文本分割成块(Chunking)。
使用嵌入模型将文本转换为向量。
将向量存储到向量数据库(Chroma)。
用户提问时检索相关向量。
结合检索内容与 Prompt 生成回答。
基于上述 RAG 步骤,接下来我们将使用代码完成它。
开始搭建
1. 环境准备 依据 Ollama 使用指南完成大模型的本地下载和运行。
ollama pull llama3
ollama pull nomic-embed-text
2. 安装依赖 安装 langchain、langchain-community、bs4 等库。
pip install langchain langchain-community bs4
3. 初始化 LangChain 对象 初始化 langchain 提供的 Ollama 对象,配置流式输出。
from langchain_community.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
llm = Ollama(
model="llama3" ,
temperature=0.1 ,
top_p=0.4 ,
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)
temperature : 控制文本生成的创造性。为 0 时响应是可预测,始终选择下一个最可能的单词,这对于事实和准确性非常重要的答案是非常有用的。为 1 时生成文本会选择更多的单词,会产生更具创意但不可能预测的答案。
top_p : 核心采样决定了生成时要考虑多少可能的单词。高 top_p 值意味着模型会考虑更多可能的单词,甚至是可能性较低的单词,从而使生成的文本更加多样化。
较低的 temperature 和较高的 top_p,可以产生具有创意的连贯文字。由于 temperature 较低,答案通常具有逻辑性和连贯性,但由于 top_p 较高,答案仍然具有丰富的词汇和观点。比较适合生成信息类文本,内容清晰且能吸引读者。
4. 获取 RAG 检索内容并分块 使用 BeautifulSoup 解析网页内容,按照标签、类名、ID 等方式来定位和提取需要的内容。
import bs4
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
loader = WebBaseLoader(
web_paths=("https://vuejs.org/guide/introduction.html#html" ,),
bs_kwargs=dict (
parse_only=bs4.SoupStrainer(
class_=("content" ,),
)
),
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000 , chunk_overlap=200 )
splits = text_splitter.split_documents(docs)
chunk_overlap : 分块的重叠部分,重叠有助于降低将语句与与其相关的重要上下文分开的可能性。
chunk_size : 分块的大小,合理的分词设置会提高 RAG 的效果。
5. 向量化存储 内容基于本地的词嵌入模型 nomic-embed-text 嵌入向量数据库中。
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OllamaEmbeddings(model="nomic-embed-text" )
)
此处的嵌入模型也可以使用其他的比如 llama3、mistral,但是在本地运行太慢了,它们和 nomic-embed-text 一样不支持中文的词嵌入。如果想试试建立一个中文的文档库,可以试试 herald/dmeta-embedding-zh 词嵌入的模型,支持中文。
ollama pull herald/dmeta-embedding-zh:latest
6. 设置 Prompt 规范输出 from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(
input_variables=['context' , 'question' ],
template=
"""You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the
question. you don't know the answer, just say you don't know
without any explanation Question: {question} Context: {context} Answer:""" ,
)
7. 实现检索问答 from langchain.chains import RetrievalQA
retriever = vectorstore.as_retriever()
qa_chain = RetrievalQA.from_chain_type(
llm,
retriever=retriever,
chain_type_kwargs={"prompt" : prompt}
)
question = "what is vue?"
result = qa_chain.invoke({"query" : question})
print (result["result" ])
question = "what is react?"
result = qa_chain.invoke({"query" : question})
print (result["result" ])
构建用户界面 Gradio 是一个用于构建交互式机器学习界面的 Python 库。Gradio 使用非常简单。你只需要定义一个有输入和输出的函数,然后 Gradio 将自动为你生成一个界面。用户可以在界面中输入数据,然后观察模型的输出结果。
import gradio as gr
from langchain_community.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
from langchain.chains import RetrievalQA
from langchain_core.prompts import PromptTemplate
def init_ollama_llm (model, temperature, top_p ):
return Ollama(
model=model,
temperature=temperature,
top_p=top_p,
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)
def content_web (url ):
loader = WebBaseLoader(web_paths=(url,))
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000 , chunk_overlap=200 )
splits = text_splitter.split_documents(docs)
return splits
def chroma_retriever_store_content (splits ):
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OllamaEmbeddings(model="nomic-embed-text" )
)
return vectorstore.as_retriever()
def rag_prompt ():
return PromptTemplate(
input_variables=['context' , 'question' ],
template=
"""You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the
question. you don't know the answer, just say you don't know
without any explanation Question: {question} Context: {context} Answer:""" ,
)
def ollama_rag_chroma_web_content (web_url, question, temperature, top_p ):
llm = init_ollama_llm('llama3' , temperature, top_p)
splits = content_web(web_url)
retriever = chroma_retriever_store_content(splits)
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={"prompt" : rag_prompt()})
return qa_chain.invoke({"query" : question})["result" ]
demo = gr.Interface(
fn=ollama_rag_chroma_web_content,
inputs=[
gr.Textbox(label="web_url" , value="https://vuejs.org/guide/introduction.html" , info="爬取内容的网页地址" ),
"text" ,
gr.Slider(0 , 1 , step=0.1 ),
gr.Slider(0 , 1 , step=0.1 )
],
outputs="text" ,
title="Ollama+RAG Example" ,
description="输入网页的 URL,然后提问,获取答案"
)
demo.launch()
运行后会输出网页地址 Running on local URL: http://127.0.0.1:7860,打开后即可进行交互。
常见问题与优化建议
显存不足 :本地运行大模型对 GPU 显存有一定要求。如果显存不足,可以尝试使用量化版本的小模型(如 llama3:8b-instruct-q4_0),或者减少 chunk_size 以降低内存占用。
检索效果不佳 :如果检索到的上下文不相关,可以尝试调整 chunk_overlap 的值,增加重叠部分以保留更多上下文信息;也可以尝试不同的嵌入模型,如 bge-m3 等性能更好的开源模型。
响应速度慢 :本地推理速度受硬件限制。可以通过预加载模型到内存中减少启动延迟,或者使用更快的 CPU 指令集优化推理过程。
中文支持 :默认英文模型对中文理解有限。务必使用支持中文的嵌入模型(如 dmeta-embedding-zh)和适合中文语境的 LLM,并在 Prompt 中明确指示使用中文回答。
通过以上步骤,即可完成一个功能完备的本地 RAG 问答系统。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online