Skip to content

常见问题 FAQ

本篇汇总学习和使用 LangGraph 时最常踩的坑,以 Q&A 形式给出原因 + 解决。按主题分组,方便按需查阅。涉及的概念贯穿全教程,遇到问题先来这里查一遍,能省下大量排查时间。

一、安装与环境

Q1. pip install langgraph 后 import 报错 ModuleNotFoundError: No module named 'langgraph'

原因:装到了别的 Python 环境里,或当前用的是系统 Python 而非虚拟环境。

解决

bash
# 确认用的是哪个 python
python -c "import sys; print(sys.executable)"
# 建议用 venv
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install langgraph -i https://pypi.tuna.tsinghua.edu.cn/simple

Q2. 装完报 pydantic 版本冲突 ImportError: cannot import name 'BaseModel'

原因:langchain 生态已全面转向 Pydantic v2,但旧项目还依赖 v1,两版本混装冲突。

解决

bash
pip install --upgrade "pydantic>=2.7" langchain-core langchain-openai langgraph
# 强制重装避免残留
pip install --force-reinstall --no-cache-dir pydantic

检查

python -c "import pydantic; print(pydantic.VERSION)" 应输出 2.x.x

Q3. 国产镜像装包还是慢/超时

原因:某些包(如 psycopg)在国内镜像同步滞后,或用了 -i 但没配 trusted-host。

解决:换源并加 trusted-host,或用 uv(Rust 写的,速度快很多):

bash
pip install langgraph -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn
# 或用 uv
pip install uv
uv pip install langgraph

二、State 与消息

Q4. 我在节点里 return {"key": value},但 state 里这个字段没更新

原因:TypedDict 字段没用 Annotated[..., reducer],默认 reducer 是「整体覆盖」。若节点返回的值没包含该字段,state 不变;若你的 reducer 写错也会出问题。

解决:确认字段有正确的 reducer。消息列表用 add_messages

python
from typing import Annotated
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list, add_messages]  # ✅ 有 reducer 才会追加
    count: int                                # 默认覆盖

Q5. 第二轮对话模型「失忆」,不记得第一轮说了啥

原因:没用 checkpointer,或 invoke 时没传 thread_id,每轮都是全新 state。

解决:编译时加 checkpointer,调用时传 thread_id:

python
from langgraph.checkpoint.memory import MemorySaver
graph = builder.compile(checkpointer=MemorySaver())
# 第一轮
await graph.ainvoke({"messages":[HumanMessage("我叫张三")]},
                    config={"configurable":{"thread_id":"t1"}})
# 第二轮,同 thread_id 才能接上记忆
await graph.ainvoke({"messages":[HumanMessage("我叫啥")]},
                    config={"configurable":{"thread_id":"t1"}})

详见状态与持久化

Q6. 消息历史里混进了工具调用消息,导致 LLM 报错「unexpected tool message」

原因:上一轮工具调用没完成就被中断,state 里残留了孤立的 ToolMessageAIMessage(tool_calls=...) 没有对应的工具结果。

解决:在送入 LLM 前用 trim_messages 或手动校验消息序列完整性;或用 RemoveMessage 清理历史:

python
from langchain_core.messages import RemoveMessage
# 删除指定 id 的消息
return {"messages": [RemoveMessage(id=msg.id) for msg in bad_msgs]}

三、运行与控制流

Q7. RecursionError: Recursion limit of 25 reached

原因:图执行步数超过默认 25 步。要么真死循环(条件边成环),要么任务确实复杂。

解决

  1. 先排查是否死循环:打印每步节点名,看是否在两节点间反复横跳
  2. 确实需要更多步:config={"recursion_limit": 50}
  3. ReAct 智能体连续调工具不收敛:检查 prompt 和工具描述是否清晰

Q8. 条件边路由错误,跑到不该去的节点

原因:条件函数返回的字符串和 add_conditional_edges 里映射的 key 对不上,或用了 END/START 字面量没导入。

解决:条件函数返回值必须严格匹配映射 key;用 tools_condition 这种预置函数时别自己重写:

python
from langgraph.graph import END
# 返回值必须是 "tools" 或 END,和下面映射一致
builder.add_conditional_edges("chatbot", tools_condition, {"tools": "tools", END: END})
# 预置的 tools_condition 第二参可省,传字符串 "tools" 表示无映射时落到该节点

Q9. checkpointer 配了但 aget_state 拿不到历史

原因thread_id 每次都不同(如用了随机 UUID 没固定),或编译图时没传 checkpointer。

解决:确认 builder.compile(checkpointer=saver) 且每次 invoke 用同一 thread_idaget_state 要传和 invoke 时一样的 config。

Q10. thread_id 传了还是没有记忆

原因:config 结构写错,thread_id 必须嵌在 configurable 下:

python
# ❌ 错
config = {"thread_id": "t1"}
# ✅ 对
config = {"configurable": {"thread_id": "t1"}}

四、工具与智能体

Q11. 定义了工具但模型不调用

原因:模型没 bind_tools,或工具描述太模糊模型不知道何时用,或用了不支持 function calling 的模型/供应商。

解决

python
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)  # 必须 bind_tools

检查工具 @tool 装饰器的 docstring 是否清晰说明「何时用」。国产模型需确认供应商支持 OpenAI 兼容的 tools 接口,见国产模型集成

Q12. 工具函数抛异常,整个图崩了

原因:工具函数没 try/except,异常向上冒泡终止图执行。

解决:工具内部捕获异常,返回错误字符串而非抛出:

python
@tool
def search(query: str) -> str:
    try:
        return do_search(query)
    except Exception as e:
        return f"搜索失败:{e}"  # 让模型知道失败,自己决定下一步

五、部署与调试

Q13. Studio 连不上本地 Server

原因langgraph dev 没起来、端口不对、防火墙拦了。

解决:确认终端里看到 Server started at http://127.0.0.1:2024;Studio 桌面版填的 URL 要带 http:// 和端口;公司网络可能拦 2024 端口,换 --port 8080

Q14. SSE 接口不流式,前端等几秒一次性收到全部

原因:中间有代理(nginx/CDN)缓冲了响应。

解决:nginx 加 proxy_buffering off;,响应头加 X-Accel-Buffering: no。详见流式 API 与 SSE

Q15. 序列化错误 Object of type XXX is not JSON serializable

原因:state 里塞了不可序列化对象(数据库连接、自定义类实例、datetime 没转字符串)。

解决:state 只放基础类型和 dict/list;datetime 转 ISO 字符串;自定义对象转 dict。checkpointer 落库和 Studio 传输都依赖 JSON 序列化。

六、异步与并发

Q16. 同步 invoke 和异步 ainvoke 能混用吗

原因:想在一个 async 函数里调同步 invoke 省事。

解决:尽量别混用。在 async 上下文里调同步 invoke 会阻塞事件循环,导致其他协程卡死。async 函数里统一用 ainvoke/astream。必须调同步代码用 asyncio.to_thread

python
result = await asyncio.to_thread(graph.invoke, inputs, config)

Q17. RuntimeError: asyncio.run() cannot be called from a running event loop

原因:已经在 async 环境里(如 Jupyter、FastAPI 端点)又调了 asyncio.run

解决:Jupyter 里直接 await graph.ainvoke(...)(Jupyter 顶层支持 await);FastAPI 端点里也直接 await,别套 asyncio.run

七、模型与供应商

Q18. Pydantic v1/v2 冲突导致工具定义失败

原因:旧版 langchain 还用 pydantic v1 的 BaseModel,新版用 v2,混装时 @tool 装饰器报错。

解决:全量升级到 v2:

bash
pip install --upgrade "langchain>=0.3" "langchain-core>=0.3" "langgraph>=0.2" "pydantic>=2.7"

工具参数用 v2 风格 BaseModel

python
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
    query: str = Field(description="搜索关键词")

Q19. 国产模型(通义/智谱/DeepSeek)工具调用失败或参数乱

原因:部分国产模型对 OpenAI tools 协议兼容不完整,或参数 schema 解析有差异;temperature 过高导致输出格式不稳。

解决

  1. 用官方 SDK 的 bind_tools,别手搓 function calling JSON
  2. temperature=0 提高格式稳定性
  3. 工具描述用中文且简洁,避免歧义
  4. 部分 SDK 需指定 tool_choice="auto" 或强制调用

详见国产模型集成

Q20. OpenAI 报 RateLimitError 或超时

原因:QPS 超 OpenAI 限额,或网络到 OpenAI 不稳定(国内直连常见)。

解决

  1. 加重试:ChatOpenAI(max_retries=3)
  2. 用代理/中转 base_url:ChatOpenAI(base_url="https://your-proxy/v1")
  3. 限流:业务层控制 QPS,用 slowapi 或令牌桶
  4. 切国产模型降低对 OpenAI 依赖

八、其他

Q21. 怎么调试「为什么模型这么回答」

解决:开 LangSmith 追踪,看每步输入输出;或在节点里 print(state);或用 LangGraph Studio 可视化逐步看 state。这是排查智能体行为的第一利器。

Q22. 图能跑但很慢,怎么优化

解决

  1. 用异步 ainvoke/astream 不阻塞
  2. 大模型换小模型做简单任务
  3. 长历史用 trim_messages 裁剪
  4. 重复请求加缓存(set_llm_cache
  5. 多请求用 asyncio.gather 并发

详见生产最佳实践性能优化一节。


遇到本 FAQ 没覆盖的问题,建议:先开 LangSmith 看 trace → 检查 state 序列化 → 查 API 速查表 确认用法 → 到官方 GitHub issues 搜索。多数问题在前三步就能定位。