未来的改进方向有很多:设计更精准的提示词、接入睡眠/心率等更多数据源、加入用户反馈闭环。但最重要的是,这些改进都可以在现有图形化架构上渐进式地完成。

你是否曾为设计一个复杂的 AI 工作流而头疼?想让 AI 根据情况动态决定下一步,而不是机械地走完固定流程?

如果你也有这样的痛点,那么今天介绍的 LangGraph,可能就是你在寻找的答案。

过去两年,从智能客服到自动化助手,从语音机器人到内部流程自动化,几乎所有我构建的、需要“思考”的 AI 应用,核心都离不开 LangGraph。它不仅是我个人实验项目的首选,更频繁出现在客户的生产系统中。

在深入新特性和更优雅的 API 之前,我们先搞清楚 LangGraph 为何而生。

一、LangGraph 核心:让 AI 工作流“活”起来

简单说,LangGraph 是一个专注于为 LLM 应用提供显式控制流的库。

传统的 AI 流水线通常是 有向无环图 (DAG):一路向前,永不回头。这能满足许多需求,但当你想要一个能迭代、重新评估、动态决定下一步的系统时,它就力不从心了。

LangGraph 的核心突破在于允许图中存在循环。节点可以被重复访问,决策可以基于结果反复调整。这使得构建能够规划、执行、观察结果并持续运行直至满足停止条件的智能体成为可能。

图片

理解这三个概念,就理解了 LangGraph

  1. 状态:智能体的“记忆”
    这是一个贯穿整个图的共享数据结构。每个节点都能读取当前状态,并返回更新。它包含了对话历史、决策结果、工具输出等所有需要跨步骤保留的信息。
  2. 节点:专注的“行为单元”
    每个节点只做一件事:调用 LLM、执行工具、转换数据或做出路由决策。保持节点小巧、专注,能让智能体更易测试和迭代。
  3. 边:清晰的“控制流”
    边定义了执行如何从一个节点转移到下一个节点。它们编码了代理的控制流,可以是:
  • 顺序(始终移动到下一个节点)
  • 条件式(根据状态选择下一个节点)
  • 循环(返回到上一个节点)

LangGraph 通过显式定义边,使控制流在图中清晰可见,而不是将其隐藏在提示逻辑中。这使得理解代理何时循环、何时分支以及何时终止变得更加容易。

理论说完了,让我们动手。接下来,我们将一步步构建一个基于 Strava 的智能训练教练,看看如何用状态、节点和边,打造一个能根据真实训练数据自动调整计划的 AI 智能体。

二、手把手实战:构建你的 Strava 训练教练

第一步:将目标拆解为清晰步骤

首先,我们要把“自动训练教练”这个大目标,拆解成一个个清晰的、可执行的节点

想象一下这个智能体的工作流:

  1. 连接到 Strava 帐户并查看最近的活动(跑步、越野跑等)。
  2. 了解你的目标(比赛距离/日期、目标配速/完赛目标、海拔变化情况)
  3. 生成简洁的一周训练计划,并遵守进度上限和减量训练计划。
  4. 对比计划工作与已完成工作,以发现错过/额外/困难的工时和超负荷风险。
  5. 当出现风险信号时,调整接下来一周的计划,并解释发生了哪些变化以及原因。
  6. 如果设置了 SMTP,则通过电子邮件发送计划;如果未设置,则在日志/终端中预览。

这个过程可以清晰地映射为下图中的节点和流向:

图片图片

graph LR
    A[开始] --> B[同步 Strava 活动]
    B --> C[汇总近期训练]
    C --> D[评估进度 vs 目标]
    D --> E[生成下周计划]
    E --> F{推荐策略?}
    F -- keep/保持 --> G[撰写周报邮件]
    F -- adjust or deload/调整或减载 --> H[调整计划 & 添加警告]
    H --> G
    G --> I[发送邮件]
    I --> J[结束]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

第二步:定义每个节点的职责

每个节点需要什么?产出什么?我们将其分为三类:

  • 数据节点:从外部获取信息。如同步 Strava 活动,它需要 API 密钥,产出近期活动列表。
  • LLM 节点:进行分析、推理和生成。如评估进度 vs 目标,它需要活动汇总和目标,产出状态评估和风险提示。
  • 行动节点:与外部世界交互。如发送邮件,它需要邮件内容和地址,完成发送动作。

第三步:设计共享“状态”(State)

节点之间如何传递信息?靠状态。状态是智能体的共享内存。

对于训练教练,状态需要包含:

  • 原始 Strava 活动
  • 训练汇总数据
  • 用户目标和约束
  • 评估结果和风险标识
  • 生成的训练计划
  • 最终邮件内容

我们用 TypedDict 来定义它,确保结构清晰:

from typing import TypedDict, Literal, List, Dict

class StravaTrainingAgentState(TypedDict):
    activities: List[Dict] | None           # 原始活动数据
    training_summary: Dict | None           # 训练汇总
    goal: Dict                              # 用户目标
    sessions_per_week: int                  # 每周训练次数约束
    evaluation: Dict | None                 # 评估结果
    next_week_plan: List[Dict] | None       # 下周计划
    weekly_email: str | None                # 生成的邮件
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

第四步:用代码实现每个节点

节点就是一个普通的 Python 函数:接收状态,返回要更新的部分。

以最核心的 生成下周计划 节点为例:

def generate_next_week_plan(state: StravaTrainingAgentState) -> dict:
    """LangGraph 节点:生成下周训练计划"""
    llm = LLMService() # 一个封装好的 LLM 调用服务
    goal = state["goal"]
    summary = state["training_summary"]
    sessions = state["sessions_per_week"]
    recommendation = state["evaluation"]["recommendation"] # 来自上一步的评估

    # 系统提示词:设定角色和规则
    system_prompt = """
    你是一名跑步教练。请只返回有效的 JSON 格式:
    一个包含以下字段的会话列表:星期几、描述、时长(分钟)、强度。
    严格遵守每周训练次数限制。除非是减载周,否则进度增幅不超过10%。
    """

    # 用户提示词:注入具体上下文
    user_prompt = f"""
    目标:{goal}
    近期训练汇总:{summary}
    当前建议:{recommendation}
    每周训练次数:{sessions}
    """

    # 调用 LLM 生成计划
    plan_json = llm.structured_completion(system_prompt, user_prompt)
    return {"next_week_plan": json.loads(plan_json)}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

这个节点完全由状态驱动,职责单一,非常容易测试和优化。

第五步:将节点“组装”成智能体

这是让智能体“活”起来的关键——定义控制流。

from langgraph.graph import StateGraph, START, END

# 1. 创建图
graph = StateGraph(StravaTrainingAgentState)

# 2. 添加所有节点
graph.add_node("sync_strava", sync_strava_activities)
graph.add_node("summarize", summarize_recent_training)
graph.add_node("evaluate", evaluate_progress_vs_goal)
graph.add_node("generate_plan", generate_next_week_plan)
graph.add_node("adjust_plan", adjust_plan_add_warnings)
graph.add_node("compose_email", compose_weekly_email)
graph.add_node("send_email", send_email)

# 3. 添加边(定义执行顺序)
graph.add_edge(START, "sync_strava")
graph.add_edge("sync_strava", "summarize")
graph.add_edge("summarize", "evaluate")
graph.add_edge("evaluate", "generate_plan")

# 4. 关键!添加“条件边”,实现智能路由
graph.add_conditional_edges(
    "generate_plan", # 从哪个节点开始分支
    # 路由函数:根据状态中的“推荐策略”决定下一步
    lambda state: state["evaluation"]["recommendation"],
    {
        "keep": "compose_email",      # 若策略为“保持”,直接去写邮件
        "adjust": "adjust_plan",      # 若为“调整”,先去调整计划
        "deload": "adjust_plan",      # 若为“减载”,也去调整计划
    }
)
graph.add_edge("adjust_plan", "compose_email")
graph.add_edge("compose_email", "send_email")
graph.add_edge("send_email", END)

# 5. 编译图,获得可执行的应用
app = graph.compile()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

至此,一个具备判断和循环能力的 AI 智能体就构建完成了!运行 app,它就会按照你设计的逻辑自动执行。

第六步:运行与部署

在本地测试成功后,你可以轻松地将其自动化。由于它只需每周运行一次,使用 GitHub Actions 的定时任务(cron job)是简单又免费的绝佳选择。将密钥保存在 GitHub Secrets 中,即可实现全自动每周训练计划生成与发送。

写在最后

这个教程的目的,不是构建最复杂的训练系统,而是展示 LangGraph 如何让复杂智能体的构建变得清晰、可维护

通过“图”的思维方式——用状态共享记忆,用小节点分解任务,用显式的边描述流程——你构建出的智能体,其行为将是可预测、可调试的,同时又能灵活适应各种输入。

这种模式的应用远不止于此:客户支持助手、数据分析智能体、内部审批工具……任何需要“推理-行动-循环”的场景,都是 LangGraph 的用武之地。

未来的改进方向有很多:设计更精准的提示词、接入睡眠/心率等更多数据源、加入用户反馈闭环。但最重要的是,这些改进都可以在现有图形化架构上渐进式地完成

如果你能学会将一个复杂问题分解成节点,精心设计状态,并有意地连接它们,那么你就掌握了使用 LangGraph 构建强大、自适应 AI 智能体的核心能力。

文章来自:51CTO

Loading

作者 yinhua

发表回复