一、Langchain操作ChromaDB
1、概述
- 在本项目中,使用 LangChain 作为 RAG 框架核心编排工具,对接 ChromaDB 实现向量检索能力,构建端端的检索增强生成(RAG)流程
- 具体实现上,通过 LangChain 的
DocumentLoader模块完成多源数据(PDF、TXT、Markdown)的加载与解析,并使用TextSplitter对长文本进行分块处理,以适配向量检索的粒度需求。随后调用 Embeddings 模型(如 OpenAI Embeddings 或 BGE Embedding)将文本块转化为向量表示,并通过 ChromaDB VectorStore 进行持久化存储与索引构建。 - 在查询阶段,利用 LangChain 的
Chroma.as_retriever()封装检索器,通过语义相似度计算返回 Top-K 相关文档片段,并将其与用户 Query 一同传入 Prompt Template,由 LLM 生成最终回答,实现“检索 + 生成”的协同增强效果 - 此外,系统支持通过 LangChain 的
RetrievalQA或ConversationalRetrievalChain进行链式调用,实现带历史对话记忆的多轮问答能力,从而提升交互体验与上下文一致性 - 整体方案实现了模块化、可扩展的 RAG 架构,便于快速替换向量数据库或大模型接口,具备良好的工程落地能力
二、基础操作
1、建立连接
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
# Embedding 模型
embedding_model = HuggingFaceEmbeddings(
# 模型名称
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
# 缓存目录
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
# 连接本地已持久化的 ChromaDB
vectorstore = Chroma(
persist_directory="./test_db",
embedding_function=embedding_model
)
print(vectorstore)
2、转为检索器接口
- 把“向量数据库”转换成“检索器接口(Retriever)”,用于标准化 RAG 检索调用方式
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
# Embedding 模型
embedding_model = HuggingFaceEmbeddings(
# 模型名称
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
# 缓存目录
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
# 连接本地已持久化的 ChromaDB
vectorstore = Chroma(
persist_directory="./test_db",
embedding_function=embedding_model
)
# 转为检索器接口
retriever = vectorstore.as_retriever()
print(retriever)
3、存入数据
- 操作的步骤:
- 文本数据的清洗与分块(Chunking)
- 中文语义向量化方法
- ChromaDB 向量数据库的构建与持久化
- LangChain 构建完整向量检索流程
- 基于 embedding 的语义检索原理
import os
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
text = """
华清远见2004年成立于北京中关村,12年来始终专注于嵌入式及移动开发专业人才培养,“做良心教育,做专业教育,做受人尊敬的职业教育”是华清远见一直坚持的核心发展理念。培训内容主要包括嵌入式系统开发,Android开发,物联网开发、HTML5开发、UI设计。从短期高端到长期就业课程培训,再到产品研发,凭借专业的课程内容、强大的师资团队以及先进的研发技术受到客户和学员的好评。迄今已有超过10万名学员从华清远见走出。
华清远见研发实力强大。拥有10余种实训套件与智能产品,100余套自主研发实验设备。同时与众多高校进行实验室共建合作,目前已有超过1100所高校1100多个实验室选择了我们。华清远见拥有众多高端培训课程,每类课程均有独特的教学模式。不同于其他机构,华清远见的培训课程不仅限于理论知识,还有丰富多样的实战项目贯穿其中。从研发到培训,全面提升学员技术水平。
华清远见拥有一支非常强大的师资团队。近200余名讲师投身于研发当中。每位讲师均是从事IT行业多年的资深人士,并有着丰富的项目开发经验。在学员培训过程中实时答疑解惑。
华清远见成都中心设有教学部、教务部、市场部等多个部门,其中教学部根据专业方向分为AI教学部和嵌入式教学部,分别负责不同技术领域的人才培养与课程教学工作。AI教学部主要负责人工智能、大数据等相关课程的教学与项目实践,致力于培养具备实际开发能力的AI技术人才。
cc老师是AI教学部的一名讲师,拥有丰富的人工智能领域教学经验,在课程讲授与项目指导过程中深受学员欢迎。
"""
# 分块器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
separators=["\n\n", "\n", "。", ",", " "], # 语义优先级
)
chunks = text_splitter.split_text(text)
# 中文句号归并处理
def merge_chinese_period(chunks):
merged = []
for chunk in chunks:
# 去掉首尾空格
chunk = chunk.strip()
if chunk.startswith("。") and merged:
# 把开头句号加到前一块末尾
merged[-1] += "。"
# 当前块去掉句号再加入
merged.append(chunk[1:].lstrip())
else:
merged.append(chunk)
return merged
chunks = merge_chinese_period(chunks)
# 存入向量数据库
# 把分块后的文本转为Document对象
documents = [Document(page_content=chunk) for chunk in chunks]
# 向量模型
embedding_model = HuggingFaceEmbeddings(
# 模型名称
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
# 缓存目录
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
# 持久化目录
persist_directory = "./test_db"
# 如果本地已有存储,直接加载;否则生成并保存
if os.path.exists(persist_directory):
vectordb = Chroma(
# 持久化目录
persist_directory=persist_directory,
# 集合名称
collection_name="hqyj",
# 向量模型
embedding_function=embedding_model
)
print("Chroma 向量数据库已加载")
else:
vectordb = Chroma.from_documents(
# 文档
documents=documents,
# 向量模型
embedding=embedding_model,
# 持久化目录
persist_directory=persist_directory,
# 集合名称
collection_name="hqyj",
# 采用 余弦相似度(cosine)作为向量距离度量方式来进行相似度搜索
collection_metadata={"hnsw:space": "cosine"}
)
print("Chroma 向量数据库已生成并保存")
4、检索
- 测试是否可以基于向量数据库中的内容回答问题
import os
from langchain_chroma import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
persist_directory = "./test_db"
vectordb = Chroma(persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model)
# 检索器,检索3个最相关的文档
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
# 提示模板
template = """
你是一个知识问答助手。
根据以下检索到的上下文回答用户问题,
如果答案不在上下文中,请说明“资料中未提及”。
如果答案在上线文中,不需要输出答案来自于上下文内容,只需要输出最终的结果。
上下文:
{context}
问题:
{question}
"""
prompt = PromptTemplate(input_variables=["context", "question"], template=template)
llm = ChatOpenAI(
model="qwen3.5-35b-a3b",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
rag_chain = (
RunnableParallel({
"context": retriever,
"question": RunnablePassthrough()
})
| prompt
| llm
| StrOutputParser()
)
query = "华清远见有哪些部门?"
answer = rag_chain.invoke(query)
print("\n最终回答:\n", answer)
- 检索结果:

5、流程和 API 解读
5.1 执行流程图
用户问题 Query
↓
RunnableParallel(并行处理)
↓
┌────────────────────────────┐
│ │
│ context = retriever │ → ChromaDB语义检索TopK文档
│ question = passthrough │ → 原样传递问题
│ │
└────────────────────────────┘
↓
PromptTemplate(拼接上下文 + 问题)
↓
ChatOpenAI(大模型生成)
↓
StrOutputParser(提取纯文本)
↓
最终答案
5.2 核心模块 API 解读
5.2.1 Chroma 向量数据库
- 作用:连接本地持久化的向量数据库
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
- 参数解释
| 参数 | 作用 |
|---|---|
| persist_directory | 本地数据库路径 |
| collection_name | 向量集合名称(类似表名) |
| embedding_function | 用于查询时的向量化模型 |
5.2.2 Retriever(检索器)
- 作用:把向量库包装成“检索接口”
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
-
k=3:返回最相似的3个文档
-
自动执行:query → embedding → similarity search
-
输出:List[Document]
5.2.3 PromptTemplate(提示词模板)
- 作用:定义 RAG 输入格式
PromptTemplate(input_variables=["context", "question"], template=template)
- 参数解释
| 变量 | 来源 |
|---|---|
| context | retriever返回的文档 |
| question | 用户输入 |
- 提示词模板作用:把“检索内容 + 用户问题”拼成 LLM 输入
5.2.4 ChatOpenAI(大模型)
- 作用:调用大语言模型生成最终答案
llm = ChatOpenAI(
model="qwen3.5-35b-a3b",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
- 参数说明
| 参数 | 说明 |
|---|---|
| model | 使用的LLM模型 |
| api_key | DashScope API密钥 |
| base_url | OpenAI兼容接口地址 |
5.2.5 RunnableParallel(并行执行器)
-
作用:把输入拆成两路并行处理:
- 路径1:context
- 作用:用 query 去 ChromaDB 检索,返回相关文档
"context": retriever- 路径2:question
- 作用:原样传递用户输入,不做任何处理
"question": RunnablePassthrough() - 路径1:context
-
输出结构
{
"context": [Document, Document, Document],
"question": "用户问题"
}
5.2.6 Prompt + LLM + Parser(链式调用)
| prompt
| llm
| StrOutputParser()
- prompt
把 context + question 填入模板,输出:完整提示词字符串
- llm
输入 prompt → 输出模型回答
- StrOutputParser
把 AIMessage → 转换为纯字符串
5.2.7 LCEL 管道
- 本质: LangChain 的函数式流水线
rag_chain = (
RunnableParallel(...)
| prompt
| llm
| StrOutputParser()
)
- 等价于
step1 = retriever + passthrough
step2 = prompt.format(step1_output)
step3 = llm(step2)
step4 = parse_output(step3)
5.2.8 调用执行流程
query = "华清远见有哪些部门?"
answer = rag_chain.invoke(query)
- 执行过程
1. query 输入
2. 并行:
- retriever → 查知识库
- passthrough → 原样问题
3. prompt 拼接
4. LLM生成答案
5. 输出字符串
三、法律数据集
1、数据集格式

2、解析并存储
import os
import pandas as pd
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_huggingface import HuggingFaceEmbeddings
# 读取Excel
df = pd.read_csv(r"F:\workspace\AI\LangChain-1.0\study_rag\法律数据集.csv")
# 数据集提取
data = df['text'].tolist()
# 把分块后的文本转为Document对象
documents = [Document(page_content=item) for item in data]
# 向量模型
embedding_model = HuggingFaceEmbeddings(
# 模型名称
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
# 缓存目录
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
# 持久化目录
persist_directory = "./chroma_db2"
if os.path.exists(persist_directory):
vectordb = Chroma(
# 持久化目录
persist_directory=persist_directory,
# 集合名称
collection_name="hqyj",
# 向量模型
embedding_function=embedding_model
)
print("Chroma 向量数据库已加载")
else:
vectordb = Chroma.from_documents(
# 文档
documents=documents,
# 向量模型
embedding=embedding_model,
# 持久化目录
persist_directory=persist_directory,
# 集合名称
collection_name="hqyj",
# 采用 余弦相似度(cosine)作为向量距离度量方式来进行相似度搜索
collection_metadata={"hnsw:space": "cosine"}
)
print("Chroma 向量数据库已生成并保存")
3、检索
import os
from langchain_chroma import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
persist_directory = "./chroma_db2"
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
# 检索器,检索3个最相关的文档
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
# 提示模板
template = """
你是一个知识问答助手。
根据以下检索到的上下文回答用户问题,
如果答案不在上下文中,请说明“资料中未提及”。
如果答案在上线文中,不需要输出答案来自于上下文内容,只需要输出最终的结果。
上下文:
{context}
问题:
{question}
"""
prompt = PromptTemplate(input_variables=["context", "question"], template=template)
llm = ChatOpenAI(
model="qwen3.5-35b-a3b",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
rag_chain = (
RunnableParallel({
"context": retriever,
"question": RunnablePassthrough()
})
| prompt
| llm
| StrOutputParser()
)
query = "公安机关接到家庭暴力报案后应当做什么事情?"
answer = rag_chain.invoke(query)
print("\n最终回答:\n", answer)
- 文件中的源数据:

- 检索结果:

四、QA 数据集
1、数据集格式

2、解析并存储
import os
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.documents import Document
qa_data = [
{
"id": "faq_1",
"question": "如何修改密码?",
"answer": "进入个人中心 → 安全设置 → 修改密码"
},
{
"id": "faq_2",
"question": "如何申请退款?",
"answer": "在订单页面点击退款按钮申请退款"
},
{
"id": "faq_3",
"question": "退款多久到账?",
"answer": "一般3-5个工作日到账"
}
]
# 向量模型
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
documents = []
for qa in qa_data:
question = qa["question"]
answer = qa["answer"]
embedding_text = f"问题:{question} 答案:{answer}"
doc = Document(
page_content=embedding_text,
metadata={
"id": qa["id"],
"question": question,
"answer": answer,
}
)
documents.append(doc)
persist_directory = "./chroma_db3"
if os.path.exists(persist_directory):
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
print("Chroma 向量数据库已加载")
else:
vectordb = Chroma.from_documents(
documents=documents,
embedding=embedding_model,
persist_directory=persist_directory,
collection_name="hqyj",
collection_metadata={"hnsw:space": "cosine"}
)
print("Chroma 向量数据库已生成并保存")
3、检索
import os
from langchain_chroma import Chroma
from langchain_core._api import LangChainDeprecationWarning
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
import warnings
warnings.filterwarnings("ignore", category=LangChainDeprecationWarning)
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
persist_directory = "./chroma_db3"
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
# 检索器,检索3个最相关的文档
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
# 提示模板
template = """
你是一个知识问答助手。
根据以下检索到的上下文回答用户问题,
如果答案不在上下文中,请说明“资料中未提及”。
如果答案在上线文中,不需要输出答案来自于上下文内容,只需要输出最终的结果。
上下文:
{context}
问题:
{question}
"""
prompt = PromptTemplate(input_variables=["context", "question"], template=template)
llm = ChatOpenAI(
model="qwen3.5-35b-a3b",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
rag_chain = (
RunnableParallel({
"context": retriever,
"question": RunnablePassthrough()
})
| prompt
| llm
| StrOutputParser()
)
query = "退款多久到账?"
answer = rag_chain.invoke(query)
print("\n最终回答:\n", answer)
- 文件中的源数据:

- 检索结果:

五、客服数据集
1、数据集格式

2、解析并存入
import os
import pandas as pd
import json
from langchain_core.documents import Document
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
# 读取 CSV
df = pd.read_csv(r"F:\workspace\AI\LangChain-1.0\study_rag\客服数据集.csv")
documents = []
# 解析数据
for idx, row in df.iterrows():
try:
messages = json.loads(row["messages"])
question = None
answer = None
for msg in messages:
if msg["role"] == "user":
question = msg["content"]
elif msg["role"] == "assistant":
answer = msg["content"]
# 跳过不完整数据
if not question or not answer:
continue
# 构造文本
content = f"问题:{question} 答案:{answer}"
doc = Document(
page_content=content,
metadata={
"question": question,
"answer": answer,
"source": "ecommerce_chat",
"id": f"chat_{idx}"
}
)
documents.append(doc)
except Exception as e:
print("解析失败:", e)
# 向量模型
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
persist_directory = "./chroma_db4"
if os.path.exists(persist_directory):
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
print("Chroma 向量数据库已加载")
else:
vectordb = Chroma.from_documents(
documents=documents,
embedding=embedding_model,
persist_directory=persist_directory,
collection_name="hqyj",
collection_metadata={"hnsw:space": "cosine"},
)
print("Chroma 向量数据库已生成并保存")
3、检索
- 加入了重排序
import os
from langchain_community.vectorstores import Chroma
from langchain_core._api import LangChainDeprecationWarning
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough, RunnableLambda
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
import warnings
from sentence_transformers import CrossEncoder
warnings.filterwarnings("ignore", category=LangChainDeprecationWarning)
# 向量模型
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
cache_folder=r"F:\workspace\AI\langchain_project\embedding_model"
)
persist_directory = "./chroma_db4"
vectordb = Chroma(
persist_directory=persist_directory,
collection_name="hqyj",
embedding_function=embedding_model
)
retriever = vectordb.as_retriever(search_kwargs={"k": 30})
# 重排序模型
rerank_model = CrossEncoder(
model_name_or_path="BAAI/bge-reranker-base",
cache_folder=r"F:\workspace\AI\LangChain-1.0\models"
)
# 重排序函数
def rerank_documents_cross_encoder(docs, query):
# 构造 (query, doc) 对
pairs = [(query, doc.page_content) for doc in docs]
# 模型预测相关性分数
scores = rerank_model.predict(pairs)
print("Cross-Encoder Scores:", scores)
# 根据分数降序排序
sorted_docs = [
doc for _, doc in sorted(zip(scores, docs), key=lambda x: x[0], reverse=True)
]
print("Sorted Docs:", sorted_docs)
return sorted_docs
# 重排序 + 格式化函数
def rerank_and_format(inputs):
print("inputs:", inputs)
docs = inputs["context"]
query = inputs["question"]
docs = rerank_documents_cross_encoder(docs, query)
# 只取 top3,避免上下文太长
docs = docs[:3]
print("docs:", docs)
context = "\n\n".join(doc.page_content for doc in docs)
return {
"context": context,
"question": query
}
# 提示模板
template = """
你是一个知识问答助手。
根据以下检索到的上下文回答用户问题,
如果答案不在上下文中,请说明“资料中未提及”。
如果答案在上线文中,不需要输出答案来自于上下文内容,只需要输出最终的结果。
上下文:
{context}
问题:
{question}
"""
prompt = PromptTemplate(input_variables=["context", "question"], template=template)
llm = ChatOpenAI(
model="qwen3.5-35b-a3b",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
rag_chain = (
RunnableParallel({
"context": retriever,
"question": RunnablePassthrough()
})
| RunnableLambda(rerank_and_format)
| prompt
| llm
| StrOutputParser()
)
# query = "一般发什么快递?"
query = "刚才下单了麻烦早点发货"
answer = rag_chain.invoke(query)
print("\n最终回答:\n", answer)
- 文件中的源数据:

- 检索结果:

六、总结
- 通过 Langchain 中的 API 完成 RAG 系统的开发需要重点掌握:
- 执行流程
- 如何切分数据,使得 RAG 系统性能更好
- 召回和重排序
浙公网安备 33010602011771号