跳转到主要内容

面试题库

Python LangChain LangGraph 面试题

Python 基础与并发、LangChain 组件、RAG、Agent、LangGraph 状态图,共 20 题。

  • Python
  • AI
  • 面试

Python、LangChain、LangGraph 面试题及答案

来源:resource/Python LangChain LangGraph面试题及答案.md

适用方向:Python 后端开发、LLM 应用开发、RAG 工程、AI Agent 工程、LangChain / LangGraph 项目落地。

建议复习顺序:Python 基础与并发 -> LangChain 核心组件 -> RAG 与 Agent -> LangGraph 状态图 -> 场景设计与排障。

1. Python 中 list、tuple、dict、set 的区别是什么?

参考答案:

list 是可变有序序列,适合存储需要增删改和保持顺序的数据。tuple 是不可变有序序列,适合表达固定结构的数据,例如坐标、函数返回的多值结果。dict 是键值对结构,底层基于哈希表,适合按 key 快速查询。set 是无序且元素唯一的集合,适合去重、交集、并集、差集等集合运算。

常见复杂度:

  • list 按索引访问是 O(1),中间插入和删除通常是 O(n)。
  • dict 和 set 平均查询、插入、删除是 O(1)。
  • tuple 不可变,因此可以作为 dict 的 key,前提是内部元素也可哈希。

面试中可以补充:在需要频繁判断元素是否存在时,优先考虑 set;在需要表达固定不可变结构时,优先考虑 tuple。

2. Python 的浅拷贝和深拷贝有什么区别?

参考答案:

浅拷贝只复制对象最外层容器,内部嵌套对象仍然和原对象共享引用。深拷贝会递归复制对象及其内部嵌套对象,复制后两者通常互不影响。

示例:

import copy

a = [[1, 2], [3, 4]]
b = copy.copy(a)
c = copy.deepcopy(a)

a[0].append(99)
print(b)  # [[1, 2, 99], [3, 4]]
print(c)  # [[1, 2], [3, 4]]

高频考点是:浅拷贝对嵌套可变对象不安全,深拷贝更独立但成本更高。在真实项目中,不要无脑深拷贝大对象,应结合数据结构和性能成本选择。

3. Python 装饰器的原理是什么?常见使用场景有哪些?

参考答案:

装饰器本质上是一个接收函数并返回新函数的高阶函数。它可以在不修改原函数代码的情况下,为函数增加额外行为。

常见场景包括:

  • 日志记录。
  • 权限校验。
  • 缓存。
  • 重试。
  • 性能统计。
  • 参数校验。
  • Web 框架中的路由注册。

示例:

from functools import wraps
import time

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} cost {time.time() - start:.3f}s")
        return result
    return wrapper

面试加分点:使用 functools.wraps 可以保留原函数的名称、文档字符串等元信息,避免调试和框架反射时出现问题。

4. 迭代器、生成器和可迭代对象的区别是什么?

参考答案:

可迭代对象是实现了 __iter__ 方法的对象,可以被 for 循环遍历,例如 list、dict、str。

迭代器是实现了 __iter__ 和 __next__ 的对象,每次调用 next() 返回一个值,直到抛出 StopIteration。

生成器是一种特殊迭代器,通常由带 yield 的函数创建。它不会一次性生成全部结果,而是按需惰性产生数据。

生成器适合处理:

  • 大文件逐行读取。
  • 数据流处理。
  • 分页 API 拉取。
  • 管道式数据转换。

回答时可以强调:生成器的优势是节省内存,但它通常只能顺序消费一次。

5. Python 的 GIL 是什么?它对多线程有什么影响?

参考答案:

GIL 是 Global Interpreter Lock,即全局解释器锁。在 CPython 中,同一时刻通常只有一个线程能执行 Python 字节码。

影响是:

  • 对 CPU 密集型任务,多线程不能充分利用多核 CPU。
  • 对 I/O 密集型任务,多线程仍然有价值,因为线程在等待网络、磁盘、数据库时可以切换。

常见选择:

  • I/O 密集型:threading、asyncio。
  • CPU 密集型:multiprocessing、进程池、C 扩展、NumPy 等释放 GIL 的库。
  • 高并发网络服务:通常使用异步 I/O 或多进程部署。

面试中不要简单说“Python 多线程没用”。更准确的说法是:CPython 多线程不适合纯 Python CPU 密集型并行计算,但适合 I/O 并发。

6. asyncio 适合解决什么问题?和多线程有什么区别?

参考答案:

asyncio 适合大量 I/O 等待场景,例如高并发 HTTP 请求、数据库访问、消息队列消费、WebSocket 服务等。它基于事件循环和协程,在单线程内通过协作式调度切换任务。

和多线程的区别:

  • 多线程由操作系统调度,可能涉及线程切换和锁竞争。
  • asyncio 由事件循环调度,任务需要主动 await 让出控制权。
  • 多线程更容易封装同步阻塞代码。
  • asyncio 在高并发 I/O 下通常资源开销更小。

常见坑:

  • 在协程里调用阻塞函数会卡住事件循环。
  • 忘记 await 会导致协程没有真正执行。
  • CPU 密集型任务不适合直接放在事件循环里跑。

7. Python 中如何做异常处理和资源管理?

参考答案:

异常处理使用 try / except / else / finally。资源管理优先使用上下文管理器 with,因为它能确保文件、连接、锁等资源被正确释放。

示例:

try:
    with open("data.txt", "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    content = ""
except UnicodeDecodeError as e:
    raise ValueError("文件编码错误") from e

常见原则:

  • 不要裸写 except:,容易吞掉关键错误。
  • 异常要带上下文,方便定位问题。
  • 业务异常和系统异常要区分。
  • 清理资源优先交给 with。

在 LangChain / LangGraph 项目中,工具调用、模型调用、检索服务都可能失败,因此异常要结构化处理,便于 Agent 判断是否重试、降级或转人工。

8. 场景题:Python 服务内存不断上涨,你会如何排查?

参考答案:

我会先确认是正常缓存增长、内存泄漏,还是请求量上升导致的内存压力。

排查步骤:

  1. 观察进程 RSS、对象数量、GC 情况和请求流量。
  2. 使用 tracemalloc、objgraph、memory_profiler 等工具定位大对象来源。
  3. 检查是否有全局 list、dict、缓存、闭包、单例对象不断持有引用。
  4. 检查连接池、文件句柄、模型客户端、向量库客户端是否未释放。
  5. 检查大文本、embedding、检索结果、对话历史是否无限累积。
  6. 对缓存设置容量、TTL 和淘汰策略。
  7. 在线上通过灰度、压测和监控确认修复效果。

如果是 LLM 应用,还要重点看 prompt 上下文、历史消息、文档 chunk、工具返回结果是否被长期保存在内存状态里。

9. LangChain 的核心组件有哪些?

参考答案:

LangChain 是用于构建 LLM 应用的框架,核心组件通常包括:

  • Models:统一调用不同模型供应商的聊天模型或文本模型。
  • Messages:用统一结构表达 system、human、AI、tool 等消息。
  • Prompts:管理提示词模板和变量填充。
  • Tools:把函数、API、数据库、搜索等能力暴露给模型或 Agent。
  • Output Parsers / Structured Output:把模型输出解析成 JSON、Pydantic 对象或业务结构。
  • Retrievers:根据查询返回相关文档,常用于 RAG。
  • Agents:让模型在工具循环中推理、选择工具、读取结果并完成目标。
  • Callbacks / Tracing:记录调用链路,便于调试、评估和观测。

面试回答可以补充:LangChain 更适合组件编排和快速接入生态;如果需要可控、可恢复、可持久化的复杂 Agent 工作流,可以结合 LangGraph。

10. LangChain 中 Chain、Agent、Tool 的区别是什么?

参考答案:

Chain 更像固定流程,步骤通常由开发者预先定义,例如“检索文档 -> 拼 prompt -> 调模型 -> 解析输出”。

Agent 更像动态决策器,它可以根据用户目标和中间结果决定是否调用工具、调用哪个工具、是否继续执行或结束。

Tool 是可被模型或 Agent 调用的外部能力,例如搜索、查数据库、发请求、执行代码、读文件等。

可以这样总结:

  • Chain:流程固定,适合稳定、可预测任务。
  • Agent:流程动态,适合开放式、多步骤任务。
  • Tool:Agent 连接外部世界的动作接口。

面试加分点:生产环境里不一定所有任务都要做成 Agent。对于强流程、高风险、规则明确的任务,固定 Chain 或 LangGraph 状态机往往更可靠。

11. LangChain 的 Tool Calling 需要注意哪些设计点?

参考答案:

Tool Calling 的关键是让模型能够准确理解工具用途,并生成合法参数。

设计要点:

  • 工具名称要清晰,避免多个工具语义重叠。
  • 工具描述要说明何时使用、何时不要使用。
  • 参数类型和字段含义要明确,尽量使用结构化 schema。
  • 返回值要稳定、简洁、可解析。
  • 对高风险工具增加人工确认,例如删除数据、发邮件、转账。
  • 工具内部要做参数校验、权限校验和异常处理。
  • 工具调用日志要可追踪,便于排查错误。

常见坑:

  • 工具太多导致模型选择混乱。
  • 工具描述过短导致误调用。
  • 返回大段无结构文本导致后续推理困难。
  • 工具失败后没有错误码,Agent 无法判断是否重试。

12. LangChain 如何做结构化输出?为什么它很重要?

参考答案:

结构化输出是指让模型返回满足固定结构的数据,例如 JSON、Pydantic 对象、TypedDict 或 JSON Schema。

它很重要,因为生产系统通常不能只接收自然语言文本,而需要稳定字段,例如:

{
  "intent": "refund",
  "confidence": 0.92,
  "need_human_review": true
}

常见用途:

  • 意图识别。
  • 信息抽取。
  • 表单填充。
  • 路由决策。
  • 工具参数生成。
  • 风险等级判断。

设计时要注意:

  • schema 不宜过度复杂。
  • 枚举值要明确。
  • 对模型输出仍要做服务端校验。
  • 低置信度或解析失败时要有兜底逻辑。

面试中可以强调:结构化输出让 LLM 从“聊天组件”变成“可被工程系统消费的模块”。

13. 如何用 LangChain 设计一个 RAG 问答系统?

参考答案:

典型 RAG 流程如下:

  1. 文档接入:读取 PDF、网页、Markdown、数据库、知识库等数据。
  2. 清洗切分:去噪、分段、保留标题和元数据。
  3. 向量化:使用 embedding 模型把文本转成向量。
  4. 索引存储:存入向量库,也可以结合关键词索引。
  5. 检索召回:根据用户问题召回相关文档片段。
  6. 重排序:用 reranker 或规则提升相关性。
  7. 答案生成:把问题和检索片段交给模型生成答案。
  8. 引用溯源:返回文档来源,方便用户验证。
  9. 评估优化:评估召回率、答案准确率、引用准确率和拒答质量。

高频追问:

  • chunk 太大召回不准,太小上下文不完整。
  • 只用向量检索可能漏掉关键词精确匹配,生产中常用混合检索。
  • 检索不到相关资料时,应明确说不知道或转人工,不能编造答案。

14. 场景题:RAG 回答经常不准确,你会如何优化?

参考答案:

我会按“数据质量 -> 切分策略 -> 检索召回 -> 重排序 -> 生成约束 -> 评估集”的顺序排查。

具体做法:

  1. 检查原始文档是否过期、重复、格式混乱或权限不一致。
  2. 优化 chunk 大小、重叠长度和元数据,例如标题、章节、时间、部门。
  3. 使用混合检索,把向量检索和 BM25 / 关键词检索结合。
  4. 加 reranker,减少无关片段进入上下文。
  5. 对多跳问题做 query rewrite 或问题拆解。
  6. 在 prompt 中要求答案必须基于检索片段,并标注引用。
  7. 检索置信度低时拒答或追问。
  8. 建立测试集,用真实问题评估召回和答案质量。

面试中可以补充:RAG 的问题不一定出在模型,也可能出在文档解析、索引、召回、权限过滤或评估缺失。

15. LangGraph 的核心概念是什么?

参考答案:

LangGraph 的核心是用图来编排有状态的 Agent 或工作流。最重要的概念包括:

  • State:共享状态,记录当前任务的输入、中间结果、消息、工具结果等。
  • Node:节点,本质上是 Python 函数,读取 state 并返回 state 更新。
  • Edge:边,决定下一个执行哪个节点。
  • Conditional Edge:条件边,根据状态动态路由。
  • START / END:图的开始和结束。
  • Reducer:控制多个节点对同一个状态字段的更新方式,例如覆盖或追加。
  • Checkpoint:把图执行状态保存下来,用于恢复、记忆、调试和人工介入。

一句话回答:LangGraph 适合把 Agent 从“自由循环”变成“有状态、可控、可恢复、可观测”的图工作流。

16. LangGraph 中 State 应该如何设计?

参考答案:

State 是 LangGraph 的核心数据结构,设计好坏会直接影响可维护性。

常见设计原则:

  • 只放任务必需的数据,不要无限塞上下文。
  • 字段命名清晰,例如 messages、query、documents、answer、error_count。
  • 对追加型字段使用 reducer,例如消息列表、日志列表、候选结果列表。
  • 对覆盖型字段保持简单,例如当前意图、最终答案、状态码。
  • 对敏感字段谨慎保存,避免进入日志或长期记忆。
  • 大对象不要直接塞进 state,可以存引用、文件路径或对象 ID。

示例:

from typing import Annotated
from typing_extensions import TypedDict
import operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    query: str
    retrieved_docs: list
    answer: str
    error_count: int

面试加分点:State 不是越全越好,而是要让每个节点的输入输出清晰,便于恢复、测试和调试。

17. LangGraph 中普通边、条件边和 Command 的区别是什么?

参考答案:

普通边用于固定流程,例如 A 执行完一定到 B。

条件边用于动态路由,例如根据分类结果决定进入“客服节点”“退款节点”或“人工审核节点”。

Command 可以在节点返回时同时完成两件事:更新 state,并指定下一步跳转到哪里。它适合“计算结果和路由决策强相关”的场景。

示例理解:

  • add_edge("a", "b"):固定从 a 到 b。
  • add_conditional_edges("router", route_fn):由 route_fn(state) 决定下一节点。
  • return Command(update={...}, goto="review"):节点自己更新状态并跳到 review。

注意点:同一个节点不要同时混用静态边和动态路由,否则可能导致多个路径都执行,使流程难以理解。

18. LangGraph 的 checkpoint / persistence 有什么作用?

参考答案:

Checkpoint 是把图在执行过程中的状态保存下来。它的作用包括:

  • 短期记忆:同一个 thread 可以保留多轮对话上下文。
  • 断点恢复:长任务失败后可以从上一次成功状态继续。
  • 人工介入:在关键步骤暂停,让人审批后继续。
  • 时间回溯:回放或分叉过去的执行状态,便于调试。
  • 容错执行:部分节点成功、部分节点失败时,可以减少重复计算。

开发环境可以使用内存型 checkpointer,生产环境应使用数据库等持久化方案。回答时可以强调:没有 checkpoint 的复杂 Agent 很难做到可靠恢复和人工审批。

19. 场景题:用 LangGraph 设计一个需要人工审批的 SQL Agent,你会怎么做?

参考答案:

我会把 SQL Agent 设计成一个带状态和审批节点的图,而不是让模型直接执行 SQL。

流程设计:

  1. 理解问题节点:解析用户问题、业务目标和查询范围。
  2. 生成 SQL 节点:让模型生成只读 SQL 或待执行 SQL。
  3. SQL 校验节点:检查语法、表权限、危险关键字、扫描范围和参数合法性。
  4. 影响评估节点:对写操作先转换成预览或 explain,展示影响行数和样例。
  5. 人工审批节点:对 DELETE、UPDATE、INSERT、导出敏感数据等操作触发 interrupt。
  6. 执行节点:审批通过后用最小权限账号执行。
  7. 结果总结节点:把结果转成用户可读答案。
  8. 审计节点:记录用户、SQL、审批结果、影响范围和执行时间。

关键控制:

  • 默认只允许只读查询。
  • 高风险 SQL 必须人工确认。
  • 禁止模型拼接未校验的用户输入。
  • 限制最大返回行数和执行时间。
  • 对敏感字段做脱敏。

面试加分点:LangGraph 的 checkpoint 可以保存审批前状态,审批通过后从同一个 thread 恢复执行。

20. 场景题:你要从 0 到 1 落地一个 Python + LangChain + LangGraph 的企业知识库 Agent,会怎么做?

参考答案:

我会分五个阶段推进:场景定义、RAG 基建、Agent 编排、安全控制、评估上线。

第一阶段:明确场景

选择高频、低风险、知识边界清晰的问题,例如制度问答、产品文档问答、内部流程咨询。定义成功指标:答案准确率、引用准确率、召回率、平均响应时间、人工转接率。

第二阶段:搭建 RAG

用 Python 接入文档源,进行解析、清洗、切分、embedding、向量索引和混合检索。保留文档标题、章节、更新时间、权限标签等元数据。

第三阶段:LangChain 组件化

使用模型接口、Prompt、Retriever、Tool、结构化输出等组件。把搜索知识库、查询工单、查询权限、创建反馈单等能力封装成工具。

第四阶段:LangGraph 编排

用 StateGraph 设计流程:

  1. 用户问题进入。
  2. 意图识别。
  3. 权限过滤。
  4. 检索文档。
  5. 判断是否足够回答。
  6. 生成答案和引用。
  7. 低置信度转人工或追问。
  8. 保存反馈和日志。

第五阶段:生产化

加入 checkpoint、日志、监控、错误重试、成本控制、限流、Prompt Injection 防护、灰度发布和评估集。上线后根据真实问题持续优化 chunk、检索、rerank、prompt 和工具。

一句话总结:Python 负责工程底座,LangChain 负责 LLM 组件生态,LangGraph 负责把复杂 Agent 流程变成可控、可恢复、可观测的状态图。

加分追问清单

  • Python 中 is 和 == 的区别是什么?
  • Python 的闭包会导致什么引用问题?
  • 什么时候用线程池,什么时候用进程池?
  • LangChain 的 Runnable 思想是什么?
  • Tool 描述怎么写才能降低误调用?
  • RAG 中 chunk size 如何选择?
  • 如何做 query rewrite 和 multi-query retrieval?
  • LangGraph 的 reducer 为什么重要?
  • LangGraph 循环如何设置终止条件?
  • 如何防止 Agent 无限调用工具?
  • 人工审批节点如何恢复执行?
  • 如何评估一个 Agent 的任务成功率?
  • 如何做 Prompt Injection 防护?
  • 如何控制 token 成本和响应延迟?
  • 什么时候不应该使用 Agent?

面试表达模板

回答这类综合场景题时,可以按这个顺序说:

  1. 业务目标:先说明要解决什么问题。
  2. Python 工程底座:并发、异常、日志、配置、测试、部署。
  3. LangChain 组件:模型、Prompt、Retriever、Tool、结构化输出。
  4. LangGraph 流程:State、Node、Edge、条件路由、checkpoint。
  5. 安全边界:权限、审批、脱敏、注入防护、审计。
  6. 评估指标:准确率、召回率、任务成功率、延迟、成本、用户满意度。

核心表达:面试官不只是在考会不会调用库,而是在看你能不能把 Python、LangChain 和 LangGraph 组合成稳定、可控、可上线的 AI 工程系统。

参考资料

  • LangChain 官方文档:Agents、Models、Tools、Human-in-the-loop。
  • LangGraph 官方文档:Graph API、StateGraph、Persistence、Interrupts、Workflows and agents。
  • Python 官方文档:数据模型、并发、异常处理、上下文管理器、标准库。