Agent相关-FAISS 与 LangChain 在文档检索中的分工

10 阅读2分钟

FAISS 与 LangChain 在文档检索中的分工

一句话结论

FAISS 只管"向量 → 编号",LangChain 负责其余全部:编码、存原文、编号转原文、打包返回、存盘。

1 整体流程

db = FAISS.from_documents(chunks, embeddings)
retriever = db.as_retriever(search_kwargs={"k": 2})
docs = retriever.invoke(question)
store.save_local(save_path)

内部真正发生的事:

chunks ──embedding──→ 向量 ──FAISS──→ index.faiss
   │
   └──────────────────────────────→ index.pkl(编号→原文)

question ──embedding──→ 查询向量
                          │
                          ▼
                    FAISS 检索 → 编号 [0, 2]
                          │
                          ▼
                   查 index.pkl → 原文
                          │
                          ▼
                   打包成 Document 返回

2 两个文件,两个归属(重点:别被同一路径骗了)

save_local(save_path) 会把两个文件存进同一个目录,很容易误以为都是 FAISS 的,其实归属不同:

文件存什么属于谁FAISS 认不认
index.faiss向量FAISS✅ 这是它的全部世界
index.pkl编号 → 原文LangChain❌ 完全不知道它存在

为什么放一起? 因为 save_local 是 LangChain 封装的"一键保存",它顺手把两者放同一目录方便管理。但同目录 ≠ 同一家。

两边靠插入顺序保证编号一一对应:

index.faiss[0]  ←→  index.pkl["0"]
index.faiss[1]  ←→  index.pkl["1"]
index.faiss[2]  ←→  index.pkl["2"]

3 逐行拆解职责

第 1 行:FAISS.from_documents(chunks, embeddings)

动作谁做的
chunk → 向量Embedding 模型
向量存进索引FAISS
原文按编号存成字典LangChain

结果 db 里挂着两样:向量索引(FAISS) + 编号→原文字典(LangChain)。

第 2 行:db.as_retriever(...)

纯 LangChain,只是把 db 包装成统一接口,不涉及 FAISS。

第 3 行:retriever.invoke(question)

步骤做什么谁做的
①question → 查询向量Embedding 模型
②向量 → 编号 [0, 2]FAISS
③编号 → 原文LangChain
④打包成 Document 返回LangChain

第 4 行:store.save_local(save_path)

动作谁做的
存 index.faissFAISS(faiss.write_index)
存 index.pklLangChain(pickle 那个字典)
把两者打包成一个调用、放同一目录LangChain

4 核心结论

  • FAISS 的戏份只有两处:存向量、返回编号。存盘时也只负责 index.faiss。
  • LangChain 的戏份:调 embedding、维护"编号→原文"映射、把编号还原成原文、打包返回、统一接口、存 index.pkl。
  • FAISS 是纯向量检索库,它不知道"文字"的存在;index.pkl 是 LangChain 为了补回原文而额外维护的,与 FAISS 无关。
  • save_local 把两个文件放同一目录,纯属 LangChain 的封装便利,不代表它们同源。

FAISS 提供向量检索能力,LangChain 提供"检索 + 原文回填 + 一键存盘"的完整链路。