LangGraph 生产环境跑了三个月,我的真实感受

我们团队从去年底开始在生产环境用 LangGraph 做 Agent 开发,到现在稳定运行了三个月。不吹不黑,聊聊实际体验。

为什么选 LangGraph

Agent 框架我们对比过 AutoGen、CrewAI,最终选了 LangGraph。不是它最好,而是最匹配我们的场景。

LangGraph 的核心优势是有状态、可编排,能可视化地管理复杂流程。我们的业务里有一个典型场景:用户下单后需要跑一串校验,状态流转必须稳定可靠。

python

python 复制代码
from typing import TypedDict, Annotated
from langchain_core.messages import BaseMessage
import operator

class OrderState(TypedDict):
    order_id: str
    user_id: str
    messages: Annotated[list[BaseMessage], operator.add]
    validation_results: dict
    current_step: str

如果你的需求只是简单问答,不建议用 LangGraph,太重了。

实际案例:一个客服 Agent 的完整链路

我们搭建的客服 Agent 大致流程:

text

复制代码
用户下单 → 验证库存 → 检查地址 → 计算运费 → 更新库存 → 发送通知

每一步都可能出错,一旦出错需要回滚到上一步。用 LangGraph 来实现非常自然:

python

python 复制代码
def validate_inventory(state: OrderState) -> OrderState:
    """检查库存"""
    order_id = state["order_id"]
    stock = check_stock(order_id)

    if stock < state["quantity"]:
        return {
            **state,
            "current_step": "insufficient_stock",
            "validation_results": {"inventory": False}
        }

    return {
        **state,
        "validation_results": {"inventory": True},
        "current_step": "check_address"
    }

def handle_insufficient_stock(state: OrderState) -> OrderState:
    """处理库存不足,回滚并通知用户"""
    notify_user(state["user_id"], "库存不足")
    return {
        **state,
        "messages": state["messages"] + [
            AIMessage(content="很抱歉,库存不足,请减少购买数量")
        ]
    }

流程图示意:

text

css 复制代码
[validate_inventory] → [check_address] → [calc_shipping]
      ↓                                       ↓
[handle_insufficient_stock] ← [rollback]

用图来管理流程比一堆 if-else 清晰太多了,这也是 LangGraph 最打动我们的地方。

工具调用的经验与坑

工具调用我们用了不少,但也踩过坑:

python

ini 复制代码
from langchain_community.tools import DuckDuckGoSearchRun

search = DuckDuckGoSearchRun()

常见问题:AI 会重复调用同一个工具,于是我们加了一个去重逻辑:

python

ini 复制代码
def deduplicate_tools(tools_called: list[str]) -> list[str]:
    seen = set()
    result = []
    for tool in tools_called:
        if tool not in seen:
            seen.add(tool)
            result.append(tool)
    return result

另外,工具描述(tool description)写得不够清晰时,AI 很容易乱调,这块需要在 Prompt 上调教到位。

生产环境踩过的三个坑

  1. 长对话导致内存持续上涨

    运行几天后发现内存一直涨,排查发现是 messages 没做截断。加了一个长度限制:

    python

    python 复制代码
    def trim_messages(messages: list[BaseMessage], max_len: int = 20) -> list[BaseMessage]:
        if len(messages) > max_len:
            return messages[-max_len:]
        return messages
  2. 并行执行几乎跑崩

    有一次让 AI 同时调用 5 个工具,结果两个超时、两个报错,AI 开始循环重试,差点把系统打崩。后面我们为所有工具调用都加了最大重试次数限制。

  3. K8s 多 Pod 间状态丢失

    在 Kubernetes 上跑的时候,不同 Pod 之间状态不共享。某个请求的后续调用被调度到另一个 Pod 上,状态直接丢了。后来改用 Redis 做状态持久化:

    python

    python 复制代码
    from redis import Redis
    import json
    
    redis_client = Redis(host='redis', port=6379)
    
    def save_state(session_id: str, state: OrderState):
        redis_client.setex(
            f"order_state:{session_id}",
            3600,  # 1 小时过期
            json.dumps(state)
        )

生产环境的三个建议

从三个月实战里浓缩出三条最重要的经验:

1. 监控必须上

LangGraph 没有内置监控,我们自己加上了 Prometheus 指标:

python

ini 复制代码
from prometheus_client import Counter, Histogram

tool_calls = Counter('agent_tool_calls_total', 'Total tool calls', ['tool_name'])
execution_time = Histogram('agent_execution_seconds', 'Agent execution time')

2. 异常兜底要全面

不要相信 AI 一定按你的流程走,必须给它兜底:

python

python 复制代码
try:
    result = graph.invoke(state)
except Exception as e:
    logger.error(f"Graph execution failed: {e}")
    route_to_human(state)  # 降级为人工处理

3. 日志要足够细

AI 的行为很难排查,日志不够详细的话,问题出现时只能干瞪眼。

到底适不适合你?

不是所有场景都需要 LangGraph,可以按复杂度对号入座:

  • 简单场景:对话机器人、FAQ 问答 → 用 RAG 就够了
  • 中等复杂度 :多步骤执行、需要状态管理 → LangGraph 正合适
  • 高复杂度:多 Agent 协作、复杂回滚逻辑 → AutoGen 或自研

我们的场景恰好卡在中等复杂度,使用 LangGraph 刚好够用。如果你也在类似的业务里,它值得一试。


如果还有任何问题,欢迎在评论区交流。

相关推荐
陈随易11 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
IT_陈寒13 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰14 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
用户83562907805114 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
小满zs15 小时前
Go语言第二章(小无相功)
后端·go
用户83562907805115 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
karry_k15 小时前
MyBatis批量insert-select踩坑:useGeneratedKeys=true 可能让PostgreSQL返回大量插入结果
java·后端
妙码生花15 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
贰先生15 小时前
Xiuno BBS X版 用户封禁系统
后端
karry_k15 小时前
PostgreSQL 在 MyBatis 中执行正常 SQL 失效:一次 DELETE USING 踩坑记录
java·后端