深入解析 LangGraph 智能体开发工作流:从概念到实践

LangGraph 通过图结构实现 ReAct 智能体工作流,让 LLM 能动态调用 NOAA 浮标 API 获取实时海洋天气数据。示例中,模型自主推理浮标 ID 并调用工具,展现“推理+行动”能力,代码简洁、扩展性强,为金融、医疗等需实时数据的场景提供可落地的智能体开发路径。

发布于2025年3月14日 02:34
编辑零重力瓦力
评论0
阅读85

Manus 再次让我们看到 LLM ReAct (Reasoning Act,推理+行动)模式的强大能力。其实,我们也可以自己通过 LangGraph 提供的智能体(Agent)构建工作流实现相似的功能。让 LLM(大语言模型)为我们完成更加复杂和实用的功能。

著名 AI 科普达人 New Machina,展示了如何使用 LangGraph 来搭建一个基于 ReAct 范式的智能体系统,该系统能够调用国家气象服务浮标 API,获取实时海洋天气数据,并将结果返回给用户。

整个流程的核心在于使用图数据结构(Graph Data Structure)来组织智能体的决策路径。每个节点代表一个状态或计算步骤,而边则定义了不同状态之间的转换逻辑。在 Python 代码的实现中,LangGraph 允许开发者以简洁的方式定义这些节点和边,使得整个工作流更加直观和易于管理。这种方式的好处在于,它不仅让智能体的行为逻辑更清晰,而且极大增强了系统的可扩展性。如果开发者需要增加更多工具或决策步骤,只需调整图的结构,而不必推倒重来。

在具体实现上,该智能体工作流的核心逻辑围绕 ReAct 模型展开。用户输入一个查询,比如 “圣克莱门特海岸附近的浪高是多少?”,LLM 首先进行推理,判断自身是否具备足够的知识来直接回答问题。如果发现训练数据不足,它会决定调用一个外部工具,例如浮标信息 API,来获取实时信息。这个过程中,LLM 还会推断出应该使用哪个浮标 ID,比如对于圣克莱门特,它会选择 46086 号浮标,而对于半月湾,则会选择 46214 号浮标。

这一点非常关键,因为它展示了 LLM 在一个结构化环境中的 “智能决策能力”。传统的 LLM 主要依赖自身的训练数据进行回答,而在 ReAct 工作流中,模型可以主动调用外部 API,填补知识空白,这使其在特定领域的应用能力大幅提升。例如,在金融、医疗、供应链等领域,类似的方法可以用于实时数据查询,提高 LLM 作为智能助手的实用性。

此外,New Machina 提到的 LangGraph 工具绑定机制也是一个亮点。通过 Python 装饰器 @tool,开发者可以将外部 API 直接注册到智能体系统中,使得 LLM 可以在推理过程中自然地调用这些工具。这种方式不仅简化了开发流程,还赋予了系统更高的透明性和可维护性。比如,如果未来国家气象服务 API 发生变化,开发者只需要修改工具函数,而不需要调整整个智能体逻辑。

从更宏观的角度来看,LangGraph 代表了一种新的 AI 应用范式。过去,我们主要依赖 LLM 进行 “静态推理”,也就是基于已有知识回答问题。而 ReAct 工作流的引入,则让智能体具备了“动态推理” 和 “主动执行” 的能力。这不仅扩展了 LLM 的应用边界,也让 AI 系统能够更加自然地融入实际业务流程。

当然,这种方法也有其挑战。比如,如何确保 LLM 在调用工具时不会误用 API?如何在多工具环境下优化决策逻辑?如何在不同任务之间高效管理智能体的状态?这些问题都值得进一步探索。但可以肯定的是,结合推理和行动的智能体将成为未来 AI 发展的重要方向,而 LangGraph 正在为这个未来提供一条清晰的路径。

完整示例代码

import certifi
import urllib3
import csv
from langchain_core.tools import tool
from typing_extensions import Literal
from langchain_openai import ChatOpenAI
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph import MessagesState
from langchain_core.messages import SystemMessage, HumanMessage, ToolMessage

class MarineForecast:
    def __init__(self):
        self.wave_height = 0  # 波高(单位:英尺)
        self.wave_period = 0  # 波浪周期(单位:秒)
        return

    def getHumanReadableStr(self):
        # 返回可读的天气信息
        return "The waves are " + str(self.wave_height) + " feet with period of " + str(self.wave_period) + " seconds."

# 初始化 LLM(GPT-4)
llm = ChatOpenAI(model="gpt-4", temperature=0)

@tool
def getMarineForecast(buoyId: str) -> str:
    """
    调用美国国家气象局(NWS)获取指定浮标(buoyId)附近的海洋天气预报。

    参数:
        buoyId (str): 浮标 ID,用于查询海洋天气信息。

    返回值:
        MarineForecast: 包含波高和周期信息的字符串。
    """
    # 获取海洋天气浮标数据
    http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())
    response = http.request('GET', 'https://www.ndbc.noaa.gov/data/realtime2/' + buoyId + '.txt')
    lines = response.data.decode("utf-8").splitlines()
    
    reader = csv.reader(lines)
    next(reader, None)  # 跳过第一行表头
    next(reader, None)  # 跳过第二行表头

    marine_forecast = MarineForecast()
    
    for row in reader:
        rowDatum = row[0]
        rowList = rowDatum.split()
        
        if rowList and rowList[8] != 'MM' and rowList[9] != 'MM':  # 确保数据有效
            marine_forecast.wave_height = round(float(rowList[8]) * 3.28084, 1)  # 转换单位(米 -> 英尺)
            marine_forecast.wave_period = rowList[9]
            break

    return marine_forecast.getHumanReadableStr()

# 为 LLM 增强工具功能
tools = [getMarineForecast]
tools_by_name = {tool.name: tool for tool in tools}
llm_with_tools = llm.bind_tools(tools)

# 定义对话节点
def llm_call(state: MessagesState):
    """LLM 处理用户请求"""

    return {
        "messages": [
            llm_with_tools.invoke(
                [
                    SystemMessage(
                        content="你是一个帮助用户查询海洋天气的智能助手。"
                                "以下是查询海洋天气信息的指南:"
                                "" +
                                "如果要查询加利福尼亚州圣克莱门特(San Clemente)的海洋天气,请检查浮标 ID 46086。" +
                                "如果要查询加利福尼亚州康塞普西翁角(Point Conception)的海洋天气,请检查浮标 ID 46054。" +
                                "如果要查询加利福尼亚州使命湾(Mission Bay)的海洋天气,请检查浮标 ID 46258。" +
                                "如果要查询加利福尼亚州洛马角(Point Loma)的海洋天气,请检查浮标 ID 46232。" +
                                "如果要查询加利福尼亚州圣塔莫尼卡湾(Santa Monica Bay)的海洋天气,请检查浮标 ID 46221。" +
                                "如果要查询加利福尼亚州半月湾(Half Moon Bay)的海洋天气,请检查浮标 ID 46214。" +
                                "如果要查询加利福尼亚州 Mavericks 的海洋天气,请检查浮标 ID 46214。" +
                                ""
                    )
                ]
            ),
            state["messages"]
        ]
    }

def tool_node(state: dict):
    """执行 LLM 生成的工具调用"""
    
    result = []
    
    for tool_call in state["messages"][-1].tool_calls:
        tool = tools_by_name[tool_call["name"]]
        observation = tool.invoke(tool_call["args"])
        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    
    return {"messages": result}

# 判断是否需要调用工具
def should_continue(state: MessagesState) -> Literal["environment", END]:
    """决定是否继续调用工具或结束对话"""
    
    messages = state["messages"]
    last_message = messages[-1]
    
    # 如果 LLM 生成了工具调用,则执行工具调用
    if last_message.tool_calls:
        return "Action"
    
    # 否则,直接结束对话(回复用户)
    return END

# 构建对话流程
agent_builder = StateGraph(MessagesState)

# 添加节点
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("environment", tool_node)

# 连接节点
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
    "llm_call",
    should_continue,
    {
        # should_continue 的返回值 -> 下一个要访问的节点
        "Action": "environment",
        END: END,
    },
)

agent_builder.add_edge("environment", "llm_call")

# 编译智能代理
agent = agent_builder.compile()

# 运行查询示例
# messages = [HumanMessage(content="Mavericks in Half Moon Bay 的波高和周期是多少?")]
# messages = [HumanMessage(content="Santa Monica 的波高和周期是多少?")]
messages = [HumanMessage(content="San Clemente 的波高和周期是多少?")]

messages = agent.invoke({"messages": messages})

# 输出结果
for m in messages["messages"]:
    m.pretty_print()

相关文章

Google 搜索变身全天候智能体:Information Agents 上线,你的数据终于开始替你干活了
AI 产品工具
2026年6月15日
0 条评论
零重力瓦力

Google 搜索变身全天候智能体:Information Agents 上线,你的数据终于开始替你干活了

Google 推出 Information Agents 功能,面向 AI Ultra 订阅用户开放。该功能将搜索从被动查询转变为主动监测,智能体可 7×24 小时追踪用户需求并推送变化信息。其底层依托 Personal Intelligence 战略,通过整合 Gmail、Photos 等跨应用数据实现个性化推理。尽管存在隐私与准确性挑战,但凭借二十年数据积累,Google 正推动 AI 助手从对话工具向自主代理进化,重塑“信息找人”的交互范式。

#Google#智能体
阅读全文
Kimi Work 上线:300 个子智能体在你的电脑上同时干活,个人 Agent 之战正式开打
AI 产品工具
2026年6月14日
0 条评论
零重力瓦力

Kimi Work 上线:300 个子智能体在你的电脑上同时干活,个人 Agent 之战正式开打

6 月首周,月之暗面、微软、Google 及 Databricks 密集发布智能体产品,标志着 AI 正从对话助手转向持续行动系统。其中 Kimi Work 主打本地桌面运行,支持多智能体并行与浏览器接管;Microsoft Scout 定位永远在线的个人助理;Google 推出 24 小时信息追踪智能体;Databricks 开源 Omnigent 实现跨智能体互操作。行业共识逐渐形成,智能体将具备自主调度、任务拆解及持续运行能力。

#智能体框架#智能体
阅读全文
电脑自己动起来了?Windows 版 Codex 迎来功能更新
AI 产品工具
2026年6月13日
0 条评论
小创

电脑自己动起来了?Windows 版 Codex 迎来功能更新

Windows 版 Codex 新增计算机操控与移动端访问功能。AI 可直接接管电脑屏幕和光标,自动操作桌面软件及浏览器多标签页任务,简化繁琐工作流程。用户只需在设置中开启相关选项并添加设备即可使用。同时,该更新打通手机端,支持通过 iOS 或 Android 端 ChatGPT 应用扫码绑定,实现远程查看任务进度及发起新的电脑操控指令,大幅提升跨设备协作效率与自动化体验。

#Codex#智能体
阅读全文
互动讨论

评论区

围绕《深入解析 LangGraph 智能体开发工作流:从概念到实践》展开交流,未登录用户可浏览评论,登录后可参与讨论。

评论数
0
登录后参与评论
支持发表观点与回复一级评论,互动后将同步到消息中心。
登录后评论
暂无评论,欢迎成为第一个参与讨论的人。