03 LangChain面试题
1、为什么选择使用LangChain?
在实际开发中,直接调用大模型的API来构建应用,很快会遇到几个问题:
- Prompt管理混乱
提示词散落在代码各处,修改一个地方可能漏掉另一个地方,变得越来越难以维护。
- 切换模型成本高
每个大模型厂商的API格式都不一样,OpenAI、DeepSeek、Claude都有自己的调用方式。如果需要切换模型,需要改动大量代码。
- 复杂功能难以维护
想实现多轮对话、工具调用、知识库检索等功能时,逻辑越来越混乱,代码难以维护。
LangChain正是为了解决这些问题而诞生的,它对模型封装、记忆管理、工具调用等模块进行抽象,提供了统一的接口,切换模型只需修改模型名称,各个模块的交互与具体模型无关。
在使用大模型的原生SDK调用时,修改模型要修改很多代码,而在LangChain中只需要修改模型名称即可,LangChain会根据模型名称去自动创建对应模型的对象:
# 切换模型只需要改这一个地方
llm = init_chat_model("gpt-4o-mini", temperature=0)
# 或者
llm = init_chat_model("deepseek-chat", temperature=0)2、LangChain有哪些核心组件?
在LangChain v1.0中,主要包含六个核心模块:
- Models(模型)
LangChain统一了不同厂商模型的调用方式。在v1.0中,将各个模型的集成包独立拆分(如langchain-openai、langchain-anthropic等),通过init_chat_model可以用统一的方式初始化模型,切换模型只需修改对应供应商,对应模型名称字符串。
from langchain.chat_models import init_chat_model
# 使用OpenAI
llm = init_chat_model("openai:gpt-5.4")
# 切换到Claude,只需改模型名称
llm = init_chat_model("anthropic:claude-sonnet-4-6")- Agent(智能体)
Agent是LangChain v1.0版本的核心,Agent的本质是模型在循环中调用工具,直到任务完成。提供了create_agent方法来快速创建Agent,在它的内部帮我们完成了这个Agent循环。
创建一个Agent核心有四个参数:
model:使用大语言模型
tools:可调用的工具列表
system prompt:系统提示词
middleware:中间件,用于扩展Agent能力
from langchain.agents import create_agent
agent = create_agent(
model="claude-sonnet-4-6",
tools=[search_web, analyze_data],
system_prompt="你是一个专为程序员服务的智能助手"
)create_agent底层基于LangGraph构建,天然支持检查点(Checkpoint)、流式输出(Streaming)、人机协作(Human-in-the-loop)和时间旅行(Time Travel)等能力。
- Tools(工具)
工具让Agent能够与外部世界进行交互,比如:获取实时数据、执行代码、查询数据库、调用API等。任何Python函数都可以通过@tool装饰器快速定义为工具,函数参数和类型作为输入Schema,方法注释作为工具描述。
from langchain.tools import tool
@tool
def search_database(query: str, limit: int = 10) -> str:
"""查询数据库匹配对应记录"""
return f"Found {limit} results for '{query}'"在工具内部还可以通过ToolRuntime参数访问运行时上下文,包括短期记忆(State)、长期记忆(Store)、用户上下文(Context)等信息。
- Middleware(中间件)
Middleware是LangChain v1.0中最重要的扩展机制,它允许在Agent执行的各个步骤插入自定义逻辑。Middleware在Agent循环的不同阶段暴露了钩子函数:
| 钩子 | 触发时机 | 典型用途 |
|---|---|---|
before_agent | Agent开始执行前 | 加载记忆、校验输入 |
before_model | 每次LLM调用前 | 更新提示词、裁剪消息 |
wrap_model_call | 包裹LLM调用 | 动态选择模型、拦截请求 |
wrap_tool_call | 包裹工具调用 | 错误处理、动态工具注册 |
after_model | 每次LLM响应后 | 输出校验、内容审查 |
after_agent | Agent结束后 | 保存结果、清理资源 |
LangChain内置了多个常用中间件:
from langchain.agents import create_agent
from langchain.agents.middleware import (
PIIMiddleware, # PII脱敏
SummarizationMiddleware, # 对话摘要压缩
HumanInTheLoopMiddleware # 人工审批
)
agent = create_agent(
model="gpt-5.5",
tools=[read_email, send_email],
middleware=[
PIIMiddleware("email", strategy="redact"),
SummarizationMiddleware(model="claude-sonnet-4-6", trigger={"tokens": 500}),
HumanInTheLoopMiddleware(interrupt_on={"send_email": True}),
]
)- Memory(记忆)
Memory让Agent具备上下文感知和跨会话记忆能力。v1.0通过LangGraph的机制实现两种记忆:
- 短期记忆(
State):基于LangGraph的State对象,存储当前会话的消息历史和自定义字段,会话结束即消失 - 长期记忆(
Store):基于LangGraph的Store,以命名空间+键值对的方式持久化存储数据,跨会话可用
此外,SummarizationMiddleware可以在对话过长时自动压缩历史消息,防止超出模型的上下文窗口大小。
- RAG相关组件
在LangChain中,通过文档加载器(Document Loader)、文本分割器(Text Splitter)、文本嵌入(Embedding)、向量数据库(Vector Store)和检索器(Retriever)等模块的组合来实现RAG,让大模型能够基于向量检索匹配语义最相近的文本片段进行回答,减少幻觉。
3、Runnable 是什么?
Runnable 是 LangChain 里最基础的执行单元。可以把它理解成为一段可以执行的代码,在LangChain中:模型、Prompt模板、Retriever、Output Parser,甚至一个普通函数,只要实现了Runnable类,就能用同一套方法去调用:
Runnable接口提供了几个标准方法:
invoke():单次调用batch():批量调用stream():流式输出ainvoke()/abatch()/astream():对应的异步版本
一个Prompt模板是Runnable,可以调用invoke去渲染模板,一个model也是Runnable,可以使用invoke来调用LLM,在LangChain中,大部分组件都实现了Runnable类,因此,在LangChain才可以很轻松的实现LCEL表达式。
4、RunnableSequence 是什么?
RunnableSequence作用就是把多个Runnable按顺序连接,前一个的输出自动作为后一个Runnable的输入。
最常见的写法就是LCEL,调用时会依次执行:先渲染Prompt,再调用模型,最后用输出解析器输出。
chain = prompt | model | output_parserRunnableSequence 的特点是流程固定、步骤明确,适合写问答、摘要、分类等场景。它跟Agent的区别在于:Agent会自主决定下一步做什么,而RunnableSequence完全是按照顺序执行。
5、LCEL 是什么?
LCEL全称LangChain Expression Language,是 LangChain 提供的一套链式组合写法。核心是用管道符 | 将Runnable连起来。
比如一个RAG流程可以写成:
chain = (
{"context": retriever, "question": lambda x: x["question"]}
| prompt
| model
| parser
)LCEL要解决的问题很简单:以前要把上一个组件的执行结果传递给下一个组件。以前需要写很多中间变量和代码,现在直接用管道符表达,流程一目了然。
LCEL支持几种常见模式:
- 顺序执行:
prompt | model | parser - 并行执行:用
RunnableParallel同时跑多个Runnable,结果合并成一个字典 - 分支逻辑:根据条件走不同链路
LCEL更适合步骤固定的场景。如果业务流程涉及循环、人工审批、断点恢复这些场景,推荐使用LangGraph。
6、Output Parser 的作用是什么?
Output Parser(输出解析器)用来把大模型返回的文本,转换成特定的数据结构进行输出。大模型默认输出通常是自然语言,比如:用户名是张三,年龄是 28 岁。但程序更希望拿到结构化结果,比如:
{
"name": "张三",
"age": 28
}在LangChain中,Output Parser的作用主要有两个:
- 把模型输出的字符串解析成
JSON、对象、列表、枚举等结构化数据。 - 检查模型返回的数据是否符合预期格式,比如字段是否缺失、类型是否正确。
在 LangChain 里,Output Parser常用于普通文本模型输出解析。不过现在,很多模型已经支持使用结构化输出和工具调用去约束输出结果,这些方式比单纯依赖文本解析更稳定。
7、Structured Output 如何实现?
Structured Output(结构化输出)是让模型按照预先定义好的结构返回结果,而不是随意生成的自然语言文本。
常见实现方式有三种。
- 通过提示词定义结构
先定义输出格式,比如用Pydantic、JSON Schema等描述字段。
from pydantic import BaseModel, Field
class UserInfo(BaseModel):
name: str = Field(description="用户名")
age: int = Field(description="年龄")在提示词中,告诉LLM按照这个Schema格式返回:
{
"name": "张三",
"age": 28
}- 使用模型原生
Structured Output能力
现在很多模型都支持原生结构化输出,例如gpt、claude等模型都有类似能力。
在 LangChain 中,可以使用:
structured_llm = llm.with_structured_output(UserInfo)
result = structured_llm.invoke("提取用户信息:张三今年 28 岁")这样返回的result就不是普通字符串,而是一个UserInfo对象。
- 使用
Tool Calling实现结构化输出
Tool Calling(工具调用)也可以用来实现Structured Output。将要结构化输出的对象结构,作为工具的入参,通过提示词让LLM调用这个工具,LLM返回的工具调用参数,就是我们想要的结构化输出数据了。
例如定义一个工具:
{
"name": "extract_user_info",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"]
}
}模型会返回类似:
{
"name": "extract_user_info",
"arguments": {
"name": "张三",
"age": 28
}
}8、LangChain v1.x 与 v0.x 有哪些区别?
LangChain v1.x 相比 v0.x,架构更清晰,用法更稳定。主要区别如下。
- Agent 架构变化
v0.x 里常见写法是使用AgentExecutor、initialize_agent等方式创建Agent。
v1.x 中更推荐使用新的Agent API,例如:
from langchain.agents import create_agentv1.x 的Agent底层基于LangGraph,天然支持更可靠的状态管理、循环控制、持久化和人工介入。
- LangGraph 成为 Agent 的底层基础
v0.x 里 LangChain 和 LangGraph 更像两个相对独立的项目。
v1.x 中,LangChain 的Agent构建在 LangGraph 之上。简单Agent可以继续用LangChain创建;复杂流程、状态机、多Agent编排,则更适合直接用 LangGraph。
- 包结构更模块化
v0.x 后期已经开始对依赖进行拆分,v1.x则更加深度地进行拆分。
常见包包括:
langchain
langchain-core
langchain-community
langchain-openai
langchain-anthropic这样可以减少主包体积,也让不同模型、向量库、工具的集成更清晰。
9、LangChain 如何实现 Tool Calling?
Tool Calling(工具调用)是让LLM在需要时调用外部工具来完成任务,比如查数据库、调接口、执行计算、搜索资料等。
LangChain 实现Tool Calling分为以下几步:
- 定义工具
可以用 @tool 装饰器定义一个工具:
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""查询指定城市的天气。"""
return f"{city} 今天晴,25 度。"一个工具一定要有清晰的名称、参数和说明。模型会根据这些信息判断什么时候调用工具,以及如何调用工具。
- 绑定工具到模型
将工具绑定到LLM对象上。
llm_with_tools = llm.bind_tools([get_weather])- 模型生成工具调用
用户输入:
北京今天天气怎么样?模型会返回对应的工具调用参数。
{
"name": "get_weather",
"args": {
"city": "北京"
}
}- 执行工具
LangChain会根据模型返回的工具名和参数,调用对应的 Python 函数。
工具执行结果例如:
北京 今天晴,25 度。- 把工具结果交回模型
工具执行成功后,将工具执行结果包装到工具消息中,模型拿到工具调用结果后,生成最终的回答。
你好,北京今天晴,气温 25 度,气温舒适。如果通过LangChain提供的create_agent来创建Agent,那么这个工具调用过程,将由Agent自动完成。
简单示例:
from langchain.agents import create_agent
agent = create_agent(
model=llm,
tools=[get_weather],
system_prompt="你是一个天气助手"
)
result = agent.invoke({
"messages": [
{"role": "user", "content": "北京今天天气怎么样?"}
]
})10、LangChain 如何接入 MCP?
MCP,全称是Model Context Protocol,MCP的作用是将外部工具、服务以统一的协议暴露给模型使用。在LangChain中接入MCP的思路是:把MCP Server提供的工具,转换成LangChain工具,然后再交给Agent使用。
- 启动
MCP Server
MCP Server提供了例如操作文件系统、数据库、浏览器、GitHub、内部业务系统等工具。MCP Server可以通过stdio、SSE、HTTP等方式通信。
- 加载
MCP工具
通过MCP适配器加载工具。首先需要安装langchain-mcp-adapters包。
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"math": {
"command": "python",
"args": ["./math_server.py"],
"transport": "stdio",
}
})
tools = await client.get_tools()这里拿到的 tools 就是 LangChain 可以识别的工具列表。
- 将工具绑定到
Agent
from langchain.agents import create_agent
agent = create_agent(
model=llm,
tools=tools,
system_prompt="你可以使用外部工具完成任务"
)- 调用
MCP工具
当用户提出问题时,模型会判断是否需要使用MCP工具。
result = await agent.ainvoke({
"messages": [
{"role": "user", "content": "帮我计算 123 * 456"}
]
})如果模型决定调用工具,LangChain 会通过适配器把调用转发给MCP Server,调用完成后再把结果返回给模型,模型再生成最终结果,MCP的意义在于把工具进行了标准化,让不同的Agent可以共享这些工具,无需重复实现这些工具逻辑,另外,这些工具本身可能是Java、C#、Python实现的,通过MCP就可以屏蔽这些实现细节。
11、LangChain 和 LlamaIndex 有什么区别?
LangChain和LlamaIndex都可以用来构建Agent应用,但两者的侧重点不同。
LangChain适合通用Agent应用开发框架,它关注的是如何把模型、工具、记忆、提示词等能力集成到一个完整的应用中。它适合用来构建Agent、工具调用、工作流编排等场景。
LlamaIndex解决的是”企业数据怎么接入大模型”的问题,要做企业知识库、文档问答、复杂RAG检索系统,优先考虑LlamaIndex。
两者对比如下:
| 对比维度 | LangChain | LlamaIndex |
|---|---|---|
| 核心定位 | 构建LLM应用和Agent | 构建数据索引和RAG系统 |
| 关注重点 | 模型调用、工具调用、Agent编排、工作流 | 文档加载、索引构建、检索增强生成 |
| 适合场景 | Agent、多工具调用、复杂任务链路 | 企业知识库、文档问答、数据检索 |
| 抽象方式 | Model、Tool、Agent、Middleware、Memory | Document、Node、Index、Retriever、Query Engine |
| 编排能力 | 更强,尤其是结合LangGraph | 相对弱,更聚焦检索链路 |
| 数据处理能力 | 有RAG能力,但不是唯一核心 | 更强,特别是多数据源和索引策略 |
实际上,在项目中两者可以组合使用:用LlamaIndex负责文档解析、索引构建和检索,用LangChain或LangGraph负责任务编排、工具调用和Agent流程控制。
12、你用过哪些Agent框架?选型是如何选的?
常用的Agent框架包括:LangChain / LangGraph、AutoGen、CrewAI。
- LangChain / LangGraph
LangChain适合快速构建Agent应用,提供了模型、工具、记忆、中间件等组件。LangGraph更适合生产级复杂Agent,它把Agent执行过程构建成图结构,可以显式定义State、Node、Edge、Conditional Edge,并支持Checkpoint、断点恢复、人工审批、循环执行等能力。
如果项目对流程可控性、状态持久化、可观测性要求高,优先选择LangGraph。
- AutoGen
AutoGen更适合多Agent对话协作,多个Agent负责不同的分工,比如Planner、Coder、Reviewer、Executor之间的协作。它的优势是比较好地支持多Agent交互,但如果需要严格控制流程,每一步都要可追踪、可恢复,就需要额外做很多开发工作。
- CrewAI
CrewAI 是一个专门做多Agent协作的框架。它最大的特点就是简单,定义好Agent、任务和执行流程后,很快就能跑起来一个多角色协作系统。比如让一个Agent查资料,一个Agent做分析,另一个Agent写报告,这种场景用 CrewAI 开发效率很高。
但如果流程开始变复杂,例如需要根据不同情况走不同分支、保存执行状态、支持人工介入或者让Agent之间进行复杂协作,CrewAI 的可控性就没有那么强了。这时候 LangGraph 往往会是更合适的选择。
选型原则可以参考:
- 如果只是简单
LLM调用或少量工具调用,不一定需要Agent框架,直接使用模型SDK加函数调用即可。 - 如果是典型
Agent应用,需要工具调用、记忆、上下文管理,可以选择LangChain。 - 如果是生产级
Agent流程,需要分支、循环、人工审批、断点恢复,优先选择LangGraph。 - 如果核心是多角色协作和对话式任务拆解,可以考虑AutoGen或CrewAI。
- 如果核心是知识库问答和
RAG,可以优先选择LlamaIndex,再结合LangGraph做流程编排。
13、LangChain和LangGraph有什么区别?
LangChain 更关注如何快速构建Agent应用,包括调用大模型、管理Prompt、工具调用、RAG、结构化输出等,当我们需要开发一个简单的问答机器人、知识库助手等简单Agent时,使用 LangChain 就足够了。
LangGraph 更关注Agent的执行流程。当Agent的任务变得复杂后,仅仅调用模型和工具已经不够了,还需要考虑任务应该如何拆分、下一步执行什么、失败后是否重试、是否需要人工介入、流程中断后如何恢复等问题,这时就可以选择使用LangGraph。
可以这样理解:LangChain 解决的是”Agent能做什么”的问题,LangGraph 解决的就是”Agent应该怎么做”的问题。LangChain 提供各种能力组件,而 LangGraph 负责把这些组件按照特定流程组织起来。
在实际项目中,两者往往是配合使用的。比如一个多Agent系统中,Planner负责制定计划,Researcher负责搜索资料,Writer负责生成报告,整个执行流程由 LangGraph 控制;而每个Agent内部调用大模型、搜索工具、向量数据库等能力,则由 LangChain 提供。
因此,对于普通的RAG、Tool Calling、结构化输出等场景,LangChain 通常已经足够;而对于多步骤任务、多Agent协作、复杂状态流转等场景,LangGraph 会更加合适。实际上现在很多生产环境中的Agent项目,通过 LangChain 构建Agent,而流程编排则由 LangGraph 完成。