失业一年了,天天想着怎么翻身。前两课把State、Node、Edge这些基础概念讲得差不多,大家反馈“终于知道LangGraph是怎么跑的了”。这节课我们直接上手做一个真正实用的单Agent——写作助手Agent。它能帮用户搜索资料、起草文章、最后润色输出。代码会比前两课稍长,但我依然每一段都写得超级慢、注释超级详细,零基础也能一步步跟上。

本课目标

  • 构建一个完整的、可实际使用的单Agent工作流
  • 掌握多工具绑定 + 条件循环 + 最终输出控制
  • 学会用LangGraph的add_conditional_edges实现“思考→工具→思考→结束”的完整循环
  • 理解如何让Agent在合适的时候停止并给出最终答案

环境准备

pip install -U langgraph langchain langchain-deepseek langchain-core tavily-python

(我们会使用Tavily搜索工具,如果你没有Tavily API Key,可以先用模拟工具,后面我也会给出模拟版本)

设置环境变量:

import os
os.environ["DEEPSEEK_API_KEY"] = "sk-你的key"
os.environ["TAVILY_API_KEY"] = "tvly-你的key"   # 如无Tavily可暂时注释

核心代码实战

代码段1:定义State、工具和LLM(准备阶段)

from typing import Annotated, TypedDict, Literal
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_core.messages import AnyMessage, HumanMessage, AIMessage
from langchain_deepseek import ChatDeepSeek
from langchain_core.tools import tool
from langgraph.prebuilt import ToolNode
from tavily import TavilyClient   # 真实搜索工具

# ==================== 1. 定义状态 ====================
class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]
    # 可以后续扩展其他字段,如 next_action、draft 等

# ==================== 2. 定义工具 ====================
tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))

@tool
def search_web(query: str) -> str:
    """使用Tavily搜索网页并返回总结结果"""
    response = tavily_client.search(query, max_results=3)
    results = "\n\n".join([f"标题: {r['title']}\n内容: {r['content']}" for r in response['results']])
    return results

@tool
def write_draft(topic: str, info: str) -> str:
    """根据主题和搜索到的信息,撰写初稿"""
    return f"关于《{topic}》的初稿已生成(长度适中)。"

tools = [search_web, write_draft]

# ==================== 3. 准备LLM并绑定工具 ====================
llm = ChatDeepSeek(model="deepseek-chat", temperature=0.7)
llm_with_tools = llm.bind_tools(tools)

代码段2:定义Agent节点和路由函数

# ==================== Agent思考节点 ====================
def agent_node(state: State):
    # 把历史消息传入LLM,让它决定下一步(搜索、写初稿还是直接回答)
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}

# ==================== 路由函数:决定下一步去哪 ====================
def should_continue(state: State) -> Literal["tools", "end"]:
    last_msg = state["messages"][-1]
    
    # 如果LLM发出了工具调用请求
    if last_msg.tool_calls:
        return "tools"
    
    # 否则认为可以给出最终答案,进入结束流程
    return "end"

代码段3:构建完整写作助手图(核心部分)

# 创建工具执行节点
tools_node = ToolNode(tools)

# 开始构建图
workflow = StateGraph(State)

# 添加节点
workflow.add_node("agent", agent_node)
workflow.add_node("tools", tools_node)

# 添加边
workflow.add_edge(START, "agent")

# 条件边:从agent出来后判断
workflow.add_conditional_edges(
    "agent",
    should_continue,
    {
        "tools": "tools",   # 需要调用工具 → 去tools节点
        "end": END          # 可以结束 → 直接结束
    }
)

# 工具执行完后回到agent继续思考
workflow.add_edge("tools", "agent")

# 编译图
graph = workflow.compile()

# ==================== 测试运行 ====================
user_input = "帮我写一篇关于'2026年AI Agent发展趋势'的800字文章"

result = graph.invoke({
    "messages": [HumanMessage(content=user_input)]
})

print("\n=== 最终输出 ===")
print(result["messages"][-1].content)

运行结果说明(典型执行路径):

  1. Agent 第1次调用 → 决定先搜索资料 → 调用 search_web
  2. Tools 执行搜索 → 返回相关网页内容
  3. Agent 第2次调用 → 拿到搜索结果,决定写初稿 → 调用 write_draft
  4. Tools 执行写初稿 → 返回草稿
  5. Agent 第3次调用 → 基于草稿进行润色或直接输出最终文章
  6. 没有工具调用 → should_continue 返回 “end” → 图结束

最终输出是一篇相对完整的文章。

小练习(正好2道)

  • 练习1(基础)
    把上面的 write_draft 工具改成真正的LLM调用版本(让LLM根据搜索结果生成初稿,而不是返回固定字符串)。修改工具函数并测试。

  • 练习2(进阶)
    在State中增加一个字段 draft: str,让Agent在调用write_draft后把初稿保存到State里,后续节点可以直接读取这个draft进行润色。修改State定义和对应节点代码。

本课小结
本课我们成功构建了第一个实用单Agent图:写作助手。它通过 agent_node + ToolNode + conditional_edges 实现了“思考→调用工具→继续思考→结束”的完整循环。关键在于:

  • should_continue 精准控制什么时候结束
  • 工具执行完必须回到agent,让LLM基于新信息继续决策
  • 整个流程完全由你通过边来掌控,而不是靠LLM自己乱猜

掌握这个单Agent模式,后面多Agent协作就有了坚实基础。

下节预告
第4课:多 Agent 协作基础(Crew / Team 模式)
我们会把多个专门的Agent(研究员、写手、审稿人)组成团队,让它们真正协作完成复杂任务。下节开始进入多智能体时代!

如果觉得这篇有用,欢迎点赞和关注,一起玩转 LangGraph!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐