LangChain 面试主要考察三个层次:基础概念 (框架定位与核心组件)、核心能力 (LCEL、Memory、RAG、工具调用等实战细节)、以及架构设计(LangGraph、生产部署与风险控制)。以下按面试频率和难度整理核心题目:
一、基础概念篇(一面必问 ★)
1. LangChain 的核心定位是什么?解决了什么问题?
LangChain 是一个专门开发大语言模型应用的框架,主要解决三个问题:
- 标准化封装:将模型调用、向量库、工具集成等多个环节封装成统一接口,开发者不用关心底层差异。
- 快速组装:将常见功能抽象成独立组件,像搭积木一样组合,几行代码就能搭出 RAG 或 Agent。
- 复杂流程编排:提供 Chain、Memory、Agent 等高级能力,让复杂任务的实现变得简单。
加分回答 :补充其核心设计理念是组件化 + 可组合 ,基于 LCEL 实现了统一的 Runnable 接口,所有组件均支持 invoke/stream/batch 三种核心调用方式。相比 LlamaIndex,LangChain 通用性更强,覆盖从基础对话到复杂 Agent 的全场景。
延伸追问:LangChain 的优缺点?优点:生态丰富、组件齐全、快速上手。缺点:过度封装隐藏细节、版本迭代快 API 变化大、生产环境有一定性能开销。
2. LangChain 的五大核心组件是什么?
| 组件 | 作用 |
|---|---|
| Models(模型) | 封装各类 LLM 和 Embedding 模型,支持 OpenAI、通义千问、本地模型等多种提供商 |
| Prompts(提示词) | 提供 PromptTemplate 模板管理,支持变量插值、FewShot 示例、ChatMessage 消息模板等 |
| Chains(链) | 把多个组件串联成执行流程,前一个组件的输出作为后一个组件的输入 |
| Memory(记忆) | 在对话中保持上下文,支持 BufferMemory、SummaryMemory、VectorStoreMemory 等多种实现 |
| Tools & Agents(工具与智能体) | Tools 封装外部功能,Agent 根据用户输入自主决策是否调用工具、调用哪个、传什么参数 |
延伸追问 :Chain 和 Agent 的区别?Chain 是固定的执行流程 ,数据按预设路径流动;Agent 是动态决策,模型自己判断要不要调用工具,更灵活但也更难控制。
3. LLM 和 ChatModel 有什么区别?
| 对比维度 | LLM | ChatModel |
|---|---|---|
| 输入/输出 | 纯文本(string → string) | 消息列表(ListMessage → Message) |
| 典型模型 | 早期 GPT-3 | ChatGPT、通义千问、文心一言 |
| 角色区分 | 无 | 支持 HumanMessage、SystemMessage、AIMessage |
实际开发中 ChatModel 是主流用法,因为支持角色区分,可以用 SystemMessage 设定模型行为。
4. 什么是智能体(Agent)?和普通 LLM 应用的本质区别是什么?
Agent 本质上是一个"具备自主决策能力的 LLM 控制器",它不仅生成文本,还能根据当前状态选择工具、决定下一步行为。
普通 LLM 应用是"你问我答 ",而 Agent 是"你给目标,我自己拆解、执行、纠偏"。这也是为什么 Agent 会放大能力,同时也会放大风险------一旦设计不好,它不是答错一句话,而是可能做错一整串事。
加分回答:不是所有 LLM 应用都适合做 Agent。Agent 的代价非常高,不只是算力,还有不确定性成本。如果业务流程是确定的、可枚举的,用 Agent 反而会让系统更不稳定。
二、LCEL 与 Runnable 篇(二面核心 ★★)
5. LCEL 是什么?它的核心优势是什么?
LCEL(LangChain Expression Language)是 LangChain 官方主推的链构建方式,核心语法是通过 | 管道符,将实现了 Runnable 接口的组件按业务逻辑串联,前一个组件的输出自动作为后一个组件的输入。
核心优势:
- 统一接口 :所有 LCEL 链都实现 Runnable 接口,天然支持
invoke/ainvoke/batch/stream - 流式输出 :自动实现
stream/astream,可逐 token 输出 - 并行执行 :通过
RunnableParallel实现多个组件并行 - 易于观测:与 LangSmith 深度集成,自动记录每一步
6. Runnable 是什么?和传统 Chain 有何差异?
Runnable 是 LangChain 的标准执行接口,被大多数组件实现(模型、解析器、检索器、甚至编译后的 LangGraph 图)。
它提供一致的 API:
invoke/ainvoke:同步/异步调用batch/abatch:批处理stream/astream:流式输出
相比传统 Chain,Runnable 更标准化、可组合、可替换,便于在不同组件间灵活组装。
LCEL 的并行与组合原语:
RunnableSequence:顺序执行RunnableParallel:并行执行
Runnable 是 LangChain 表达语言(LCEL)的核心标准接口,它代表一个可被调用、组合和转换的执行单元 。传统 Chain 是 LangChain 1.0 时代的遗留设计,它们是特定任务的硬编码类 (如 LLMChain、ConversationChain)。
为了让你一眼看透,我先用表格对比,再用代码"打脸"式演示:
1. 核心区别对比
| 对比维度 | 传统 Chain(旧时代) | Runnable(新时代) |
|---|---|---|
| 本质 | 特定任务的硬编码类 (需继承 Chain)。 |
标准接口协议 (任何实现了 invoke/stream 的对象)。 |
| 组合方式 | 用 SimpleSequentialChain 或 SequentialChain 拼接,语法笨重。 |
**用 ` |
| 输入/输出 | 强制绑定键名 (如必须传 input,输出必须是 text)。 |
灵活传递字典 ,每个组件可按需取用或修改 dict 中的字段。 |
| 流式支持 | 很难支持逐 Token 流式输出(需复杂回调)。 | 原生支持 stream 方法,开箱即用。 |
| 批处理 | 不支持或需要手写循环。 | 原生支持 batch 方法,自动高效并发。 |
2. 代码实例:感受"代际碾压"
假设我们要做一个简单的逻辑:用户输入 -> 提示词模板 -> 大模型 -> 输出大写结果。
❌ 传统 Chain 的写法(老旧且别扭)
python
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
llm = ChatOpenAI()
# 1. 必须定义一个模板,变量名固定为 "input"
prompt = PromptTemplate.from_template("讲一个关于 {input} 的笑话")
# 2. 必须实例化 LLMChain 这个特定类
chain = LLMChain(llm=llm, prompt=prompt)
# 3. 调用时,键名必须叫 "input",否则报错
result = chain.invoke({"input": "程序员"})
print(result["text"]) # 输出结果,还要从字典里抠出 "text"
✅ Runnable / LCEL 的写法(丝滑且强大)
python
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI()
# 1. 标准组件都实现了 Runnable 接口
prompt = ChatPromptTemplate.from_template("讲一个关于 {topic} 的笑话")
# 2. 直接用 | 管道符串联(完全解耦)
chain = prompt | llm | StrOutputParser()
# 3. 调用极其自然,参数名由你定义(这里叫 topic)
result = chain.invoke({"topic": "程序员"})
print(result) # 直接打印字符串,不用从字典里挖!
# 🔥 Runnable 的杀手锏:流式输出(传统 Chain 做不到)
for chunk in chain.stream({"topic": "AI"}):
print(chunk, end="") # 一个字一个字地往外蹦
3. 为什么说 Runnable 是"降维打击"?(面试深度加分点)
Runnable 带来的不仅是语法糖,而是架构级别的解放:
- 解耦了输入输出键名 :传统 Chain 强制你传
input和取text,如果链条长了,你会被各种键名映射搞疯。Runnable 支持任意字段名 ,在复杂 RAG 或 Agent 中,你可以传{"question": "...", "context": "..."},哪个节点取哪个字段完全自己控制。 - 统一的基座,让"万物皆可链" :在 Runnable 时代,
prompt、llm、retriever、vectorstore、甚至编译后的 LangGraph 都是 Runnable。你可以写vectorstore | llm,这在传统 Chain 时代是完全不敢想的。 - 批处理性能暴增 :如果用户并发请求(如同时处理 10 个问题),传统链要循环 10 次;Runnable 只需
chain.batch([q1, q2, q3]),底层自动利用线程池并发,时间直接缩短为原来的 1/5。
4. 面试回答话术(让面试官点头)
"Runnable 是 LangChain 的统一执行协议 ,它取代了 1.0 时代那些臃肿的特定 Chain 类。它的核心价值是标准化 :任何组件只要实现了
invoke、stream、batch这三个方法,就可以通过|管道符无缝组合。这也正是 LangChain 从'一堆工具'进化为'可编程框架'的关键转折点。在实际项目中,我完全使用 LCEL 构建业务逻辑,因为它不仅代码量减少 50%,还能原生支持流式输出和并发批处理,这是传统 Chain 无法企及的。"
三、Chain、Tool、Agent、Memory 篇(二面核心 ★★)
7. Chain、Tool、Agent、Memory 的职责边界如何划分?
这是系统设计的核心问题,职责混乱是 Agent 失控的主要原因:
| 组件 | 职责 |
|---|---|
| Chain | 确定性的流程,比如固定步骤的数据处理 |
| Tool | 明确副作用的能力,比如查库、调接口、下发指令 |
| Agent | 在不确定场景下做决策,只做这一件事 |
| Memory | 状态管理,不是知识,更不是万能缓存 |
关键原则:一旦 Tool 里写逻辑、Agent 里塞业务规则,系统后期一定不可维护。
8. LangChain 的 Memory 组件如何工作?有哪些 Memory 类型?
Memory 用于在对话中保持上下文,LangChain 提供多种实现:
| Memory 类型 | 特点 | 适用场景 |
|---|---|---|
| ConversationBufferMemory | 完整保存所有对话 | 短对话 |
| ConversationBufferWindowMemory | 只保留最近 K 轮 | 控制 token 消耗 |
| ConversationSummaryMemory | 自动总结历史对话 | 长对话 |
| ConversationSummaryBufferMemory | 窗口 + 总结混合 | 平衡信息与 token |
| VectorStoreRetrieverMemory | 向量检索相关记忆 | 超长对话、知识库 |
9. 如何在 LangChain 中集成外部工具?Tool 的定义规范是什么?
Tool 是供模型调用的受控函数(含名称、入参模式与执行体),输出通常回传给模型用于后续推理。
python
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""查询指定城市的天气"""
return f"{city}:晴朗 25°C"
定义规范:
- 函数名作为工具名
- docstring 作为工具描述(LLM 据此判断是否调用)
- 参数通过类型注解自动生成 Schema
10. 如何实现一个最小化的 ReAct Agent?
答案要点:用可调用工具 + 具备 tool-calling 的 ChatModel,用 LCEL/Runnable 把"思考→调用→观察→总结"串起来。
python
from langchain.agents import create_react_agent
from langchain.tools import tool
@tool
def search(query: str) -> str:
return f"搜索结果:{query}"
agent = create_react_agent(llm, tools=[search])
agent.invoke({"messages": [HumanMessage(content="查询北京天气")]})
四、RAG 与检索篇(二面核心 ★★)
11. 如何在 LangChain 中实现 RAG?
核心流程:
- 加载文档 :使用
PyPDFLoader等加载器 - 文本切分 :使用
RecursiveCharacterTextSplitter按语义切分 - 向量化存储:通过 Embedding 模型将文本转为向量,存入 Vector Store
- 检索:将用户问题向量化,从 Vector Store 中检索相似文档
- 生成:将检索结果作为上下文,与问题一起交给 LLM 生成回答
python
# 伪代码示意
loader = PyPDFLoader("doc.pdf")
docs = loader.load()
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(splits, embeddings)
retriever = vectorstore.as_retriever()
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever)
12. Retriever 和 Vector Store 的关系是什么?
- Vector Store 是"向量化存储 + 相似度检索"的实现(如 FAISS、Milvus、Chroma)
- Retriever 是"给定查询返回文档"的抽象接口
常见做法是把向量库 .as_retriever() 化,便于在链里统一编排。
为什么推荐 RecursiveCharacterTextSplitter? 它会按分隔符优先级递归切分(默认 \n\n、\n、空格、字符),尽量保持段落/句子/词的语义完整度,是通用文本最推荐的切分器。
为了让你彻底弄懂,我们先看一张关系图,再通过代码实战演示。
🧩 概念关系图(先建立整体认知)
┌─────────────────────────────────────────────────────────┐
│ Retriever │
│ (抽象的"问"与"答"接口) │
│ 职责:接收查询(query),返回文档列表(List[Document]) │
│ 可以内部实现任意检索策略(向量、关键词、混合、重排) │
└────────────────────┬────────────────────────────────────┘
│ 通常通过 .as_retriever() 包装
│
┌────────────────────▼────────────────────────────────────┐
│ Vector Store │
│ (具体的"存储与向量搜索"引擎) │
│ 职责:存储文本 + 对应的向量 + 元数据 │
│ 执行 ANN(近似最近邻)搜索 │
│ 实现:Chroma, FAISS, Milvus, Pinecone... │
└─────────────────────────────────────────────────────────┘
一句话总结 :
Vector Store 是"数据库",Retriever 是"查询接口" 。
就像 MySQL 是"数据库",而 ORM 框架的 find() 方法是"查询接口"。Retriever 可以看作是一个策略化的查询器,它不一定非得使用向量检索(也可以加过滤、重排),但在 90% 的 RAG 场景中,它只是对 Vector Store 的简单包装。
💻 代码实战:从存储到检索的完整流程
python
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.schema import Document
# 1. 准备文档
docs = [
Document(page_content="北京今天晴天,气温25℃", metadata={"city": "北京"}),
Document(page_content="上海今天多云,气温22℃", metadata={"city": "上海"}),
Document(page_content="广州今天阵雨,气温28℃", metadata={"city": "广州"}),
]
# 2. 创建 Vector Store(真正的物理存储)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vectorstore = Chroma.from_documents(
documents=docs,
embedding=embeddings,
persist_directory="./chroma_db"
)
# 此时 Vector Store 已经建立索引,数据持久化到磁盘
# 3. 从 Vector Store 获取 Retriever(生成查询接口)
retriever = vectorstore.as_retriever(
search_kwargs={"k": 2} # 指定返回 Top-2 结果
)
# 4. 通过 Retriever 查询(屏蔽底层细节)
result_docs = retriever.invoke("今天广州天气怎样?")
for doc in result_docs:
print(doc.page_content) # 输出: "广州今天阵雨,气温28℃"
关键点:
vectorstore负责存储和计算相似度(真正的检索引擎)。retriever只是封装了调用逻辑 ,让你可以用统一的invoke方法,而不用手动写vectorstore.similarity_search(...)。
🔍 为什么 Retriever 不仅仅是"马甲"?
尽管上例中 Retriever 只是简单包装,但在复杂场景中,它可以承载更多职责:
python
# 自定义 Retriever:向量检索 + 关键词过滤 + 结果重排
class CustomRetriever(BaseRetriever):
def __init__(self, vectorstore, keyword_filter):
self.vectorstore = vectorstore
self.keyword_filter = keyword_filter
def _get_relevant_documents(self, query):
# 先做向量检索
docs = self.vectorstore.similarity_search(query, k=10)
# 然后按关键词过滤
filtered = [d for d in docs if self.keyword_filter in d.page_content]
# 最后自定义排序
return filtered[:3]
这时 Retriever 就演变为一个独立的业务逻辑单元,而 Vector Store 只负责纯粹的相似度搜索。
📄 补充:为什么推荐 RecursiveCharacterTextSplitter?
原因 :它是最懂"人类语言结构"的切分器。
它按层级 递归切分:优先保段落(\n\n),其次保句子(\n),再保从句(。、!、?),最后保词( )。这样切分能最大程度保留语义完整性。
python
from langchain.text_splitter import RecursiveCharacterTextSplitter
text = """第一章:概述。
这是第一段内容,包含多个句子。这里还有第二个句子。
第二章:细节。
这是第二段的内容。
"""
splitter = RecursiveCharacterTextSplitter(
chunk_size=20, # 目标长度
chunk_overlap=5,
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""]
)
chunks = splitter.split_text(text)
print(chunks)
# 输出会优先按段落切,如果段落超长,再按句子切,不会在单词中间切断。
面试加分点 :如果换成普通 CharacterTextSplitter(按字符数硬切),可能会把一句话切成两半,导致检索时丢失关键实体。Recursive 版本通过递归分隔符,保证了最小的语义损失,是 RAG 生产环境的默认首选。
五、LangGraph 篇(终面拉分 ★★★)
结合你之前深度学习的 LangGraph,这部分是面试中的高分区域。
13. LangGraph 是什么?它与 LangChain 有什么关系?
LangGraph 是 LangChain 生态中用于构建有状态、多步骤复杂工作流的图式编排框架。
- LangChain:提供基础的"链"和"工具"
- LangGraph :提供"状态图 "和"状态机 ",原生支持循环、条件分支和复杂的状态管理
LangChain 官方建议新的 Agent 使用 LangGraph 来构建(更灵活/可控),老的 Agents 有迁移指引。
14. LangGraph 的核心概念有哪些?
| 概念 | 说明 |
|---|---|
| State(状态) | 图的全局共享数据结构,所有节点通过它传递信息 |
| Node(节点) | 执行单元,接收状态并返回状态更新 |
| Edge(边) | 连接节点,定义工作流走向(普通边 + 条件边) |
| Checkpointer | 状态持久化机制,支持会话记忆和时间旅行 |
15. LangGraph 的条件边(Conditional Edge)如何使用?
条件边根据当前状态动态决定下一个节点:
python
def route_after_agent(state: AgentState) -> Literal["tools", "__end__"]:
if state["messages"][-1].tool_calls:
return "tools"
return "__end__"
builder.add_conditional_edges("agent", route_after_agent, {
"tools": "tools",
"__end__": END
})
16. 如何在 LangGraph 中实现记忆(短期/长期)?
- 短期记忆 :通过
MemorySaver或SqliteSaver保存对话状态(messages),基于thread_id隔离会话 - 长期记忆 :通过
AsyncPostgresStore等 Store 组件,手动读写跨会话的用户数据
17. 如何在 LangGraph 中实现人工干预(Human-in-the-Loop)?
两种方式:
interrupt_before:编译时声明,在指定节点前自动暂停interrupt():在节点内部手动调用,可传递自定义提示并接收用户输入
python
# interrupt_before 方式
graph = builder.compile(checkpointer=memory, interrupt_before=["tools"])
# interrupt() 方式
def human_approval(state):
user_input = interrupt("是否继续执行?")
if user_input != "y":
return {"cancel": True}
六、生产部署与可观测性篇(终面拉分 ★★★)
18. 如何把链的每一步"自动打点"到 LangSmith?
配置好 LangSmith 环境变量后,运行 LangChain 代码就会自动产生日志/调用树,也支持分布式链路追踪(跨服务传播 trace)。
bash
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=your_key
export LANGCHAIN_PROJECT=my_project
不用 LangSmith 也能观测吗? 可以,社区也有开源方案(如 Langfuse)接回调/中间件实现 tracing 与指标。
19. LangChain 如何做流式输出?
基于 LCEL 构建的链自动实现 stream/astream,既可流式最终输出 ,也可在 RAG 中流式中间步骤(如改写、检索、整合)。是否能逐 token 还取决于底层模型提供商的原生能力。
20. 如何把 Runnable/链快速对外提供服务?
使用 LangServe,可以将任何 Runnable 链快速部署为 REST API 服务,自动生成 OpenAPI 文档,支持流式响应。
七、MCP 协议篇(加分项 ★★★)
结合你之前学习的 MCP,这是面试中的差异化亮点。
21. 什么是 MCP?它解决了什么问题?
MCP(Model Context Protocol)是标准化 AI 工具接入协议,解决以往工具集成"各自为政"、"高耦合"、"难以跨语言复用"的问题。
- 传统方式 :每接入一个 API,都要写一个
@tool函数 - MCP 方式:工具提供方直接启动 MCP Server,Agent 只需连接该 Server,就能自动获取所有工具列表并调用
22. MCP 和 Function Calling 的关系是什么?
| 对比维度 | Function Calling | MCP |
|---|---|---|
| 定位 | LLM 决策协议(如何表达"我想调用工具") | 工具部署协议(工具在哪、怎么通信) |
| 关注点 | 模型如何生成 tool_calls |
工具如何被注册、发现和调用 |
| 通信方式 | 不规定 | stdio / SSE |
两者配合:Function Calling 让模型学会"填单子",MCP 帮你去"取工具"。
📊 面试难度速查表
| 难度 | 题目编号 | 考察重点 |
|---|---|---|
| ★ 一面必问 | 1-4 | 框架定位、核心组件、Agent 基础概念 |
| ★★ 二面核心 | 5-12 | LCEL、Runnable、Chain/Tool/Agent/Memory、RAG |
| ★★★ 终面拉分 | 13-22 | LangGraph 状态流、人工干预、生产部署、MCP |
面试策略 :基础题看认知完整性 ,进阶题看理解深度 ,落地题看实战经验 ,场景题看体系化设计能力 。建议先吃透实战内容,再结合本文理解记忆,面试时优先答核心得分点,再结合自己的实战项目补充细节。
嵌入模型(Embedding Model) ,简单来说,是一台将"人类的语言"转换成"数学向量"的翻译机器 。它把文本、图像或音频转换成一组固定长度的数字列表(即向量),让计算机能够理解和比较这些内容的"语义"。
结合你之前学习的 RAG(检索增强生成)和向量数据库(Chroma / Milvus),嵌入模型就是那个负责把所有文字转化成坐标的核心部件。
🧠 1. 核心原理:语义即位置
嵌入模型基于深度学习(通常是 Transformer 架构),其核心思想是:语义越相近的文本,在向量空间中的距离就越近。
- "国王" - "男人" + "女人" ≈ "女王":这是最经典的类比。嵌入模型通过大量语料学习,能够捕捉到这种深层的语言规律。
- 不是关键词匹配 :它不依赖"是否包含相同词汇",而是理解"意思是否相同"。
- "天气很热" 和 "今天温度很高" 这两个句子虽然没有一个字相同,但它们的向量在空间中是紧挨在一起的,这就是语义检索的基础。
🛠️ 2. 嵌入模型 vs. 大语言模型(LLM)
这是面试中经常混淆的点,务必区分清楚:
| 对比维度 | 嵌入模型 (Embedding Model) | 大语言模型 (LLM / 生成模型) |
|---|---|---|
| 核心任务 | 理解与匹配(判别式)。把内容转化成坐标,用于检索、聚类、推荐。 | 生成与创作(生成式)。根据上文预测下一个字,用于写作、对话、编程。 |
| 输入/输出 | 输入文本,输出固定长度的向量(例如 768 维的浮点数数组)。 | 输入文本,输出不定长的自然语言文本。 |
| 典型模型 | text-embedding-ada-002 (OpenAI)、BAAI/bge-large-zh (智源)、sentence-transformers/all-MiniLM-L6-v2。 |
GPT-4、Claude 3、Qwen-Plus、DeepSeek-V3。 |
| 参数量级 | 通常较小(几百万到几亿参数),推理速度极快。 | 通常极大(几十亿到上万亿参数),推理速度慢且昂贵。 |
| 在你的项目中的位置 | 在写入向量库前(Indexing)和用户提问时(Querying)使用。 | 在检索到资料后,负责阅读资料并生成最终回答。 |
一句话总结 :嵌入模型决定"找得准不准",大语言模型决定"答得好不好"。
🔍 3. 嵌入模型在 RAG 中的具体角色
结合你之前的代码,嵌入模型贯穿了 RAG 的整个流程:
-
离线阶段(数据入库):
- 你加载 PDF 并切分成 Chunks。
- 调用嵌入模型(如
HuggingFaceEmbeddings)将每个 Chunk 变成向量。 - 将这些向量存入向量数据库(Chroma/Milvus)。
-
在线阶段(用户查询):
- 用户提问。
- 调用同一个嵌入模型,将用户的问题也变成一个向量。
- 拿着这个向量去向量库里进行 相似度计算(如余弦相似度),找出离它最近的 Top-K 个 Chunks。
🎯 4. 如何选择嵌入模型(面试高频考点)
在你本地开发时,用的是 paraphrase-multilingual-MiniLM-L12-v2。而在生产环境中,可以按以下维度选择:
- 语言支持 :如果处理纯中文,
BAAI/bge-large-zh或text-embedding-v3(阿里云)效果更好;处理多语言,可用multilingual-e5-large。 - 向量维度:维度越高(如 1024 维 vs 384 维),表达能力越强,但存储和计算开销也越大。
- 上下文长度 :有些模型只能处理 512 个 token,有些(如
BGE-M3)能处理 8192 个,这对长文档分块很重要。 - Embedding 模型的"致命伤" :它不知道"新鲜事"。比如 2026 年发生了新事件,如果你用 2023 年训练的嵌入模型去检索,它可能会找不到最相关的资料。解决方案是:用更强的模型微调,或使用支持混合检索(BM25 + 向量)的策略来兜底。
💡 5. 面试常见追问与回答话术
Q:既然 LLM 能理解文本,为什么不直接用 LLM 来做检索?
A:LLM 做一次推理耗时约 1~2 秒,成本约 $0.01;而嵌入模型算一次向量仅需 < 10ms,成本几乎为零。在 RAG 系统中,检索阶段要处理海量候选数据(百万级),必须依赖高效的嵌入模型。
Q:为什么每次都要用同一个嵌入模型?
A :因为不同模型生成的向量空间分布不同。如果你用模型 A 给数据库做索引,却用模型 B 给用户提问做查询,那么"风和日丽"和"天气不错"在各自的向量空间中不兼容,会导致检索结果完全错误。必须保持模型版本一致。
Q:如何评估一个嵌入模型的好坏?
A :主要看 MTEB(大规模文本嵌入基准测试) 排行榜。主要关注 检索(Retrieval) 任务的平均准确率(NDCG@10),以及在中文数据集(如 C-MTEB)上的表现。