Langchain-Chatchat 大模型应用技术原理:RAG 向量库选型、混合检索与 Agent Function Call 实战
本文围绕 Langchain-Chatchat 内置样例知识库文档《大模型应用技术原理》展开,系统梳理 RAG 应用的技术骨架——向量数据库选型标准、索引算法与量化方法、Embedding 模型、混合检索(向量检索 + BM25 关键字检索)以及 RAG 增强(Self-RAG)与 Agent 的 function call 机制,并逐一对照本仓库源码中的知识库服务与检索器实现。读完本文,你既能掌握大模型应用技术选型的方法论,也能在 Langchain-Chatchat 的代码中找到每项技术的落地点。
一、RAG 应用的总体技术骨架
从样例文档的思维导图结构看,一个完整的 RAG(Retrieval-Augmented Generation,检索增强生成)应用由以下层次组成:
- 向量数据库:存储文本切片(chunk)的向量表示,支持相似度检索,是 RAG 的存储底座;
- Embedding 模型:把文本编码为向量,分为 bi-encoder(双塔编码器)与 cross-encoder(交叉编码器)两类;
- 【可选】文本检索引擎:如 ElasticSearch、OpenSearch,提供关键字/全文检索能力;
- 【可选】图数据库:用于结构化知识检索,配合 NL2Cypher 使用;
- 检索:向量检索、关键字检索(BM25)、NL2Cypher、NL2SQL 等多种方式组合;
- RAG 增强:如 Self-RAG,通过反思机制提升检索与生成质量;
- Agent:通过 function call 让大模型调用外部工具,ToolFormer 是这一方向的经典工作。
Langchain-Chatchat 本身就是这条技术链路的一个完整工程实现:其知识库子系统(chatchat/server/knowledge_base/)覆盖文档加载、文本切片、向量化、存储与检索;Agent 子系统(chatchat/server/agent/)则以工具注册表的方式实现 function call。下文逐层展开。
二、向量数据库选型标准
文档给出了四个维度的选型标准,这是向量库选型时的通用方法论。
2.1 开源 vs 闭源 vs 源码可见
- 开源项目(如 faiss、milvus)可自托管、可修改源码,便于审计与二次开发;
- 闭源/托管服务(如 pinecone)以完全云原生方式交付,上手成本最低,但依赖厂商与网络环境;
- 源码可见介于两者之间,商业支持更完善。
2.2 客户端/SDK 语言
选型时需确认服务端是否有目标语言的官方 SDK(Python、Java、Go、Node.js 等)。faiss 支持 C++、Python、Go 客户端;milvus 提供 Python、Java、Go、Node.js SDK,还提供 milvus lite 这种 in-memory 运行形态。
2.3 托管方式
文档将向量库按部署形态划分为四类:
| 形态 | 代表方案 | 特点 |
|---|---|---|
| self-hosted / on-premise | redis、pgvector、milvus | 自托管,数据留在本地,运维成本自担 |
| managed / cloud-native | zilliz、pinecone | 云托管,开箱即用 |
| embeded + cloud-native | chroma、LanceDB | 嵌入式部署,本地轻量使用 |
| self-hosted + cloud-native | vald、drant、weaviate、vespa、elasticsearch | 两种形态均支持 |
Langchain-Chatchat 的 kbs_config 配置恰好体现了这一谱系:同一个应用内同时支持 faiss(本地文件)、milvus(自托管)、zilliz(云托管)、pg/relyt(pgvector 路线)、es(ElasticSearch)、chromadb(嵌入式)等多种后端,详见 settings.py 中的 KBSettings。
2.4 索引方法与量化
文档列出了向量索引算法的完整分类树:
- Flat:暴力精确检索,小数据集下精度最高;
- Tree-based:Annoy、KD-Tree、Trinary Projection Trees;
- IVF:Inverted File,含 IVMF(Inverted Multi-index File);
- Graph-based:HNSW、NSG、Vamana(DiskANN);
- Hashing-based:LSH、Spherical Hashing、Spectral Hashing。
量化方面,文档给出了两种压缩手段的定义:
- PQ(Product Quantization,乘积量化):将特征空间分解为多个低维子空间的笛卡尔乘积,然后单独地对每一个子空间进行量化,从而大幅压缩向量存储;
- SQ(Scalar Quantization,标量量化):将每一个维度量化成指定位数的一个数。
仓库中的实现印证:Langchain-Chatchat 对 Milvus 的默认索引配置就是 Graph-based 中的 HNSW,见 settings.py 的 milvus_kwargs:
"milvus_kwargs": {
"search_params": {
"metric_type": "L2"
},
"index_params": {
"metric_type": "L2",
"index_type": "HNSW"
}
}
这段配置在 MilvusKBService._load_milvus 中被直接传入 Milvus 向量库构造函数的 index_params 与 search_params 参数,说明用户修改 kb_settings.yaml 后,索引算法(如 HNSW 换 IVF)与距离度量(L2、IP 等)可以随配置切换。
三、主流向量库方案解析
3.1 文档中的方案要点
文档将主流方案分为 professional(专业向量库)与 traditional(传统数据库扩展)两类:
专业向量库
- weaviate:文档丰富容易上手;提供混合索引;支持自托管 + 云原生;支持 Python、JS、TS、Go、Java 等客户端;支持 HNSW、HNSW-PQ、DiskANN 等索引;
- chroma、LanceDB:嵌入式 + 云原生形态,适合本地轻量场景;
- pinecone:完全云原生,非常容易上手;支持自建复合索引;
- faiss:来自 Meta AI 的开源项目;同时支持 CPU 和 GPU;支持 C++、Python、Go 客户端;支持 IVF、HNSW 等常见索引方式与 PQ 量化;in-memory 运行;self-hosted;
- milvus:通过代理、负载均衡器、消息代理、Kafka 和 Kubernetes 的组合实现了高度可扩展性(系统也因此变得复杂和资源密集);截至 2023 年它是唯一一个提供可工作 DiskANN 实现的主要供应商;支持在向量相似度检索过程中进行标量字段过滤,实现混合查询;采用存储与计算分离的架构设计;提供 Python、Java、Go、Node.js 等语言 SDK,也提供 milvus lite 等 in-memory 运行方式;提供图形界面客户端。
传统方案:ES(ElasticSearch)、redis、pgvector。
3.2 Langchain-Chatchat 中的向量库落地
支持的后端清单。kb_service/base.py 中的 SupportedVSType 枚举定义了当前仓库实际接入的全部向量后端:
class SupportedVSType:
FAISS = "faiss"
MILVUS = "milvus"
DEFAULT = "default"
ZILLIZ = "zilliz"
PG = "pg"
RELYT = "relyt"
ES = "es"
CHROMADB = "chromadb"
工厂分发。KBServiceFactory.get_service 按 vs_type 字符串惰性导入并实例化对应的 KBService 子类:faiss 返回 FaissKBService,milvus/zilliz/default 返回 MilvusKBService,pg/relyt/es/chromadb 各自对应独立服务类。每个知识库在元数据库中记录自己的 vs_type 与 embed_model,get_service_by_name 可以按名重建服务实例,实现了"一个应用、多种向量后端、互不干扰"的架构。
faiss 的实现要点。FaissKBService 印证了文档中 faiss"in-memory 运行 + self-hosted"的定位:
- 向量库通过
kb_faiss_pool(线程安全的 FAISS 连接池)按(kb_name, vector_name)键加载与缓存,对应配置项CACHED_VS_NUM(缓存向量库数量,见 settings.py); - 增删文档后调用
vs.save_local(self.vs_path)持久化到磁盘,重启后可从磁盘重新加载; - 每个知识库的向量目录名由 Embedding 模型决定:
self.vector_name = self.embed_model.replace(":", "_")。这意味着同一个知识库换用不同 Embedding 模型时必须重建向量库——因为不同模型对同一段文本产生的向量并不可比。
milvus 的实现要点。MilvusKBService 体现了文档所述 milvus"高度可扩展"的一面:连接参数(host/port/user/password/secure)从 kbs_config["milvus"] 读取;删除文档时用主键表达式 pk in {id_list} 批量删除;搜索参数使用 metric_type: "L2"、nprobe: 10(见 MilvusKBService.search)。
各后端的连接配置。以 settings.py 的 kbs_config 为准:
"faiss": {},
"milvus": {"host": "127.0.0.1", "port": "19530", "user": "", "password": "", "secure": False},
"zilliz": {"host": "...vectordb.zilliz.com.cn", "port": "19530", "secure": True},
"pg": {"connection_uri": "postgresql://postgres:postgres@127.0.0.1:5432/langchain_chatchat"},
"relyt": {"connection_uri": "postgresql+psycopg2://postgres:postgres@127.0.0.1:7000/langchain_chatchat"},
"es": {"scheme": "http", "host": "127.0.0.1", "port": "9200", "index_name": "test_index", ...},
"chromadb": {}
这与文档中"self-hosted / managed / embedded"的分类一一对应:milvus 走本地自托管,zilliz 走云托管(secure=True),pg/relyt 走 pgvector 路线,es 走传统检索引擎,chromadb 走嵌入式。
四、Embedding 模型:bi-encoder 与 cross-encoder
文档将 Embedding 模型分为两类:
- bi-encoder(双塔编码器):查询与文档分别独立编码为向量,再做相似度计算。因为文档向量可以离线预计算并存入向量数据库,所以它是 RAG 在线检索的标准选择;
- cross-encoder(交叉编码器):查询与文档拼接后共同编码、直接输出相关性分数,精度通常更高,但每次查询都需实时推理,无法预计算,一般用于**重排(rerank)**环节。
在 Langchain-Chatchat 中的体现:知识库服务构造时都会接收 embed_model 参数(见 KBService.init,默认值来自 get_default_embedding()),并向量库的向量目录名直接由该模型字符串派生(第二节已述)。KBService.add_doc 在入库前会先调用 check_embed_model() 校验模型可用性,失败则拒绝写入,防止不可用模型产生的向量污染知识库。
从源码结构看,文档中"bi-encoder/cross-encoder"的分工在本仓库体现为:入库与检索阶段使用可预计算的编码模型;排序阶段可结合 reranker 模块(chatchat/server/reranker/),后者即 cross-encoder 思想的应用场景。
五、混合检索:向量检索 + BM25 关键字检索
文档"检索"一节点列出向量检索、关键字检索(BM25)、NL2Cypher、NL2SQL 四类方式。Langchain-Chatchat 前两者的结合实现最为完整,是"混合检索"的典型工程范式。
5.1 检索器工厂
retrievers 提供三种检索服务,由 get_Retriever 统一分发:
Retrivals = {
"milvusvectorstore": MilvusVectorstoreRetrieverService,
"vectorstore": VectorstoreRetrieverService,
"ensemble": EnsembleRetrieverService,
}
5.2 纯向量检索
VectorstoreRetrieverService.from_vectorstore 使用 similarity_score_threshold 搜索类型,传入 score_threshold 与 k 两个参数构造检索器,并在返回时再截断到 top_k。
5.3 混合检索(ensemble)的实现
EnsembleRetrieverService.from_vectorstore 完整实现了文档中"向量检索 + 关键字检索(BM25)"的组合:
faiss_retriever = vectorstore.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={"score_threshold": score_threshold, "k": top_k},
)
import jieba
docs = list(vectorstore.docstore._dict.values())
bm25_retriever = BM25Retriever.from_documents(
docs,
preprocess_func=jieba.lcut_for_search, # 中文分词预处理
)
bm25_retriever.k = top_k
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
)
三个值得注意的工程细节:
- 中文分词:BM25 的
preprocess_func使用jieba.lcut_for_search做中文搜索模式分词,避免英文按空格切分对中文语料失效——源码注释中还保留了用 cutword 替换的 TODO,说明分词器是可插拔的; - 加权融合:
EnsembleRetriever以[0.5, 0.5]的权重对两路检索的归一化分数加权平均,即向量语义匹配与 BM25 词频匹配各占一半; - FAISS 路径默认走 ensemble:FaissKBService.do_search 明确调用
get_Retriever("ensemble"),而 Milvus 路径调用get_Retriever("milvusvectorstore")——因为 Milvus 自身的标量过滤能力已经覆盖了部分关键字需求(与文档中 milvus"支持标量字段过滤实现混合查询"的描述一致)。
5.4 检索参数:top_k 与 score_threshold
两个关键参数在 settings.py 的 KBSettings 中定义:
VECTOR_SEARCH_TOP_K: int = 3 # 知识库匹配向量数量
SCORE_THRESHOLD: float = 2.0 # 知识库匹配相关度阈值,取值范围在0-2之间,
# SCORE越小,相关度越高,取到2相当于不筛选,建议设置在0.5左右
对 FAISS 距离度量而言,分数是"距离"而非"相似度":SCORE_THRESHOLD=2.0 意味着默认不筛选任何文档,配置为 0.5 附近可过滤低相关结果。这两个参数沿 search_docs → do_search → as_retriever(search_kwargs=...) 的调用链最终注入向量库检索器,构成可调的召回质量闸门。
六、可选组件:文本检索引擎与图数据库
文档把文本检索引擎(ElasticSearch、OpenSearch)与图数据库列为 RAG 的可选增强:
- 文本检索引擎:Langchain-Chatchat 将其作为一类向量后端接入(
SupportedVSType.ES,es_kb_service.py),配置见 settings.py 的 "es" 段(scheme/host/port/index_name 及证书选项),复用统一的KBService抽象; - 图数据库:配合 NL2Cypher 做结构化知识检索。当前仓库源码中未见图数据库实现,文档将其标记为【可选】,属于技术路线预留而非现有功能。
七、RAG 增强:Self-RAG
文档用较大篇幅介绍了 Self-RAG(Self-Reflective Retrieval-Augmented Generation,自反思检索增强生成),其核心设计分三个层面:
7.1 框架
Self-RAG 不仅可以根据需要自适应地检索段落(模型可以判断是否有必要进行检索增强),还引入了名为**反思令牌(reflection tokens)**的特殊令牌,使 LM 在推理阶段可控。
7.2 训练
训练分两步:首先训练评论家(critic),使用检索器检索到的段落以及反思令牌增强指令-输出数据;然后使用标准的下一个 token 预测目标来训练生成器 LM,使其学会生成自然延续(continuations)以及特殊 tokens(用来检索或批评其自己的生成内容)。
7.3 推理
推理时模型可以适应性地使用检索令牌进行检索,自发判断是否有必要检索;它引入多种细粒度的批评令牌,用于评估生成内容各个方面的质量。生成过程中使用期望的批评令牌概率的线性插值进行 segment 级 beam search,以在每一个时间步骤中确定最佳的 K 个续写方案。
在 Langchain-Chatchat 中的对照:当前仓库的 RAG 链路属于经典 RAG(检索-拼接-生成),未内置 Self-RAG 的反思令牌机制。从源码结构看,chatchat/server/chat/ 与 chatchat/server/agent/ 的模块划分(检索工具与对话生成解耦)为未来在 Agent 层引入"是否需要检索"的自适应判断提供了挂载点,但这属于从代码结构出发的推断,并非现有实现。
八、Agent 与 Function Call
文档的 Agent 部分从 function call(以 ToolFormer 为代表:让模型通过预测特殊标记来自主决定何时、调用哪个工具)展开。Langchain-Chatchat 的 Agent 子系统正是这一思路的工程化实现。
8.1 工具注册机制
tools_registry.py 提供 regist_tool 装饰器,作为 Langchain @tool 装饰器的封装,支持自定义 title、description、return_direct、args_schema、infer_schema 等参数,并维护全局 _TOOLS_REGISTRY 注册表。同目录下的 tools_factory/ 内置了 weather、search_internet、search_youtube、arxiv、text2sql、text2promql、search_local_knowledgebase 等一系列工具实现。
8.2 知识库检索作为 Agent 工具
值得注意的是,Agent 与 RAG 在仓库中并非割裂:tools_factory/search_local_knowledgebase.py 把知识库检索封装为一个可被 LLM 调用的 function call 工具,配合 settings.py 的 KB_INFO 配置("每个知识库的初始化介绍……用于在初始化知识库时显示和 Agent 调用,没写则没有介绍,不会被 Agent 调用"),由大模型自主决定何时向哪个知识库发起检索——这正是文档中 Self-RAG"模型自发判断是否有必要检索"思想在工程上的轻量近似。
8.3 输出解析链路
langchain_chatchat/agents/output_parsers/ 目录下按模型族(glm3、qwen、structured_chat、platform_tools)提供了不同的输出解析器,负责把模型输出的工具调用文本解析为结构化动作,是 function call 循环中"解析-执行-回填"环节的关键组件。
九、小结
回到样例文档《大模型应用技术原理.md》的脉络,本文完成了两条线的工作:
- 方法论线:向量库选型四标准(开源形态/SDK 语言/托管方式/索引方法)、Flat-Tree-IVF-Graph-Hashing 五类索引算法、PQ/SQ 两种量化、bi-encoder 与 cross-encoder 两类 Embedding 模型、向量+BM25 混合检索、Self-RAG 自适应检索增强、Agent function call;
- 实现线:Langchain-Chatchat 用
SupportedVSType+KBServiceFactory覆盖了 faiss/milvus/zilliz/pg/relyt/es/chromadb 七类后端,用EnsembleRetrieverService实现了 jieba 分词 BM25 与向量检索的 0.5/0.5 加权融合,用milvus_kwargs暴露了 HNSW 索引与 L2 度量配置,并用tools_registry+ 输出解析器实现了 function call 的注册与解析。
对于需要在自有知识库上做本地化问答与 Agent 应用的开发者,建议的深入阅读顺序是:先读 settings.py 的 KBSettings 理解全部可调参数,再对照 kb_service/base.py 的抽象接口理解各后端的统一契约,最后进入 retrievers 理解检索融合细节。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00