课本示例只捕获
ValueError、ConnectionError,生产远远不够 。大模型接口几乎不会抛出原生ConnectionError,大部分是langchain_core.exceptions自定义异常GitHub。
一、先区分 4 大类错误,对应不同策略
表格
错误类型
例子
处理策略
瞬时可重试错误
网络抖动、超时、429 限流、5xx 服务端报错
自动重试(指数退避 + 抖动),不要无限重试
不可重试业务错误
API Key 鉴权 401、上下文超长 ContextOverflow、内容被安全拦截
直接返回给用户,禁止重试
Agent 业务逻辑错误
工具调用异常、输出 JSON 解析失败、Graph 循环超限
包装错误消息丢回给 LLM,让 Agent 自己修复
程序 BUG
TypeError、变量 None、代码逻辑错误
记录完整日志,上报告警,不要暴露原始堆栈给前端
核心异常类(必须导入)
javascript
from langchain_core.exceptions import (
ModelTimeoutError,
ModelConnectionError,
RateLimitError,
ContextOverflowError,
AuthError,
PromptBlockedError,
)
from langgraph.errors import GraphRecursionError, NodeTimeoutError
二、底层 ChatModel 侧配置(model 初始化阶段,优先做)
ChatOpenAI(init_chat_model 底层)自带重试、超时配置,优先在模型实例配置,不要全部靠外层 try‑except稀土掘金。
ini
model = init_chat_model(
model="deepseek-chat",
timeout=30, # 单次http请求超时,防止无限阻塞
max_retries=2, # 瞬时错误内置重试2次,429/网络抖动自动重试
)
max_retries:只对可瞬时错误生效;鉴权、上下文溢出不会重试。timeout:流式也生效,避免长请求卡死。
三、invoke /stream 生产完整 try‑except 模板
stream 流式尤其坑:异常不一定在 for 循环外面抛出,可能迭代过程内部抛异常,try 必须包住整个迭代器循环。
1)普通 invoke(阻塞)
python
try:
resp = model.invoke([("user","你好")])
except RateLimitError as e:
# 429限流,配额耗尽
print(f"模型接口限流:{e}")
except AuthError as e:
# api‑key错误、鉴权失败,配置问题,不要重试
print(f"鉴权失败,请检查API_KEY:{e}")
except ContextOverflowError as e:
# 上下文窗口超限,业务错误
print(f"上下文长度超限:{e}")
except ModelTimeoutError as e:
print(f"模型调用超时:{e}")
except ModelConnectionError as e:
print(f"网络无法连接模型服务商:{e}")
except PromptBlockedError as e:
# 内容安全拦截
print(f"内容安全拦截:{e}")
except Exception as e:
# 所有其他异常:记录完整堆栈日志,不要把e直接返回前端
import traceback
traceback.print_exc()
print(f"未知异常:{e}")
2)stream 流式模板(高频踩坑!异常发生在迭代内部)
python
try:
stream = model.stream([("user","你好")])
for chunk in stream:
if chunk.content:
print(chunk.content, end="")
# ⚠️所有异常写在最外层,for循环迭代的时候才可能抛出
except RateLimitError as e:
print("\n【限流】")
except ModelTimeoutError as e:
print("\n【请求超时】")
except Exception as e:
import traceback
traceback.print_exc()
print(f"\n【未知错误】{e}")
四、LangGraph Agent 生产错误处理(重点)
Agent 有两层错误:
- LLM 调用本身异常;
- Graph 执行异常:工具报错、递归死循环、节点超时
GraphRecursionError、NodeTimeoutErrorLangChain。
① agent.stream () 完整捕获示例(你平时写的聊天流式)
python
from langgraph.errors import GraphRecursionError
try:
stream = agent.stream(
{"messages":[("user","你是谁")]},
stream_mode=["updates","messages"]
)
for mode, data in stream:
if mode == "messages":
chunk, _ = data
print(chunk.content, end="", flush=True)
except GraphRecursionError:
# Agent无限循环,工具来回调用,超过最大步骤
print("\nAgent执行循环超限")
except RateLimitError:
print("\n模型限流")
except ContextOverflowError:
print("\n上下文超限")
except Exception as e:
import traceback
traceback.print_exc()
print(f"\nAgent执行异常:{e}")
重要坑:Agent 流式迭代过程中随时可能抛异常,不能只包创建 stream 那一行,try 要包住整个 for 循环。
② Agent 节点级别重试策略(生产高级,不用自己写 try‑except)
RetryPolicy:给 Graph 节点配置,瞬时错误自动重跑节点,不用业务层捕获,langgraph>=1.2 支持LangChain。
ini
from langgraph.fault_tolerance import RetryPolicy
# 编译agent的时候配置节点重试
agent = create_agent(
model=model,
agent_node_name="model",
retry_policy=RetryPolicy(
max_attempts=3,
initial_interval=1.0,
backoff_factor=2.0
)
)
只对瞬时错误生效;鉴权、上下文溢出不会重试。
五、生产工程化几条硬性规范
- 日志要完整,禁止只打印
str(e)一定要打印堆栈traceback.print_exc(),或者日志库记录 exc_info=True;否则线上只看到报错文字,看不到堆栈,无法定位。
对外返回给前端,绝对不要把原始异常堆栈返回给用户,只返回友好提示文本。
-
区分:哪些错误可以重试,哪些绝对不能重试 ✅可以重试:
RateLimitError、ModelTimeoutError、ModelConnectionError❌禁止重试:AuthError、ContextOverflowError、PromptBlockedError、参数错误。 -
Agent 无限循环防护 捕获
GraphRecursionError,代表 agent 陷入工具死循环,需要告诉用户当前无法完成任务。 -
batch /abatch_as_completed 批量处理一定要开启
return_exceptions=True,单条失败不打断整个批量任务。results = agent.batch(inputs, return_exceptions=True)
遍历结果判断是否isinstance(res, Exception)
-
Checkpointer 生产不要用 MemorySaver,进程重启状态丢失,用 RedisSaver/PostgresSaver稀土掘金。
六、FastAPI Web 服务场景示例伪代码
前端打字机 sse 接口;异常捕获,SSE 向前端输出友好错误事件,不抛堆栈。
python
@app.get("/chat")
async def chat(q:str):
async def event_generator():
try:
async for mode, data in agent.astream(...):
... yield数据
except RateLimitError:
yield "event:error\ndata:模型访问限流,请稍后重试\n\n"
except ContextOverflowError:
yield "event:error\ndata:对话内容过长\n\n"
except Exception:
logger.exception("agent异常")
yield "event:error\ndata:服务内部异常\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")
七、新手常见踩坑回顾
- ❌只捕获原生
ConnectionError:LLM 库已经把网络错误封装成ModelConnectionError,原生 ConnectionError 抓不到。 - ❌stream 只把 try 写在创建迭代器,for 循环里面抛出异常逃逸。
- ❌不管什么错误全部重试:鉴权、上下文超限重试只会浪费额度。
- ❌把完整异常堆栈直接返回前端,泄露内部信息。
- ❌批量任务不开
return_exceptions=True,一条坏数据把整个批量任务搞崩。
如果你需要,我可以给一份完整复制即用的 agent.stream 生产模板,包含日志输出、友好错误提示、完整异常分支。