LangGraph 入门笔记
基于 LangChain + LangGraph 构建 AI Agent 的核心概念总结
一、第一次 LLM 调用
LangChain 提供统一的模型接口,可以无缝切换 OpenAI、Anthropic 等不同提供商:
from langchain.chat_models import init_chat_model
model = init_chat_model("openai:gpt-4o-mini")
response = model.invoke("什么是 LangGraph?")
response.pretty_print() # 格式化输出模型回复
要点:
init_chat_model("provider:model_name")统一入口,无厂商锁定.invoke()发送请求,返回AIMessage对象.pretty_print()格式化显示内容,比直接print更易读
二、消息(Messages)
消息是 LangChain 中对话的基本单元,分为四种类型:
| 类型 | 说明 |
|---|---|
SystemMessage |
设置模型行为的指令 |
HumanMessage |
用户输入 |
AIMessage |
模型回复 |
ToolMessage |
工具执行结果 |
from langchain.messages import HumanMessage, SystemMessage
messages = [
SystemMessage(content="你是一个简洁的技术助手。"),
HumanMessage(content="什么是 Agent?"),
]
response = model.invoke(messages)
# 多轮对话:把回复追加到历史,继续提问
messages.append(response)
messages.append(HumanMessage(content="举个例子?"))
response2 = model.invoke(messages)
要点: 把消息列表不断追加,就实现了多轮对话(模型能记住上下文)。
三、工具(Tools)
LLM 本身无法访问外部数据,@tool 装饰器让普通 Python 函数变成 LLM 可调用的工具:
from langchain_core.tools import tool
@tool
def get_weather(latitude: float, longitude: float) -> str:
"""获取指定坐标的天气信息。"""
# 调用天气 API...
return "晴天,22°C"
@tool
def search_movies(genre: str) -> str:
"""按类型搜索电影。"""
return "星际穿越, 降临, 银翼杀手2049"
将工具绑定给模型,模型会决定何时调用:
model_with_tools = model.bind_tools([get_weather, search_movies])
response = model_with_tools.invoke("北京天气怎么样?")
print(response.tool_calls) # 模型返回想调用的工具名+参数
工具调用完整流程:
用户提问
→ 模型返回 tool_calls(工具名 + 参数)
→ 执行工具获取结果
→ 把结果包装成 ToolMessage 传回模型
→ 模型综合输出最终回答
四、Agent:自动化工具调用循环
手动处理工具调用循环很繁琐,create_agent() 约 10 行代码搞定:
from langchain.agents import create_agent
agent = create_agent(
model=model,
tools=[get_weather, search_movies],
system_prompt="你是一个能查天气、推荐电影的助手。"
)
result = agent.invoke({
"messages": [HumanMessage(content="北京天气?推荐几部科幻电影。")]
})
for msg in result["messages"]:
msg.pretty_print()
Agent 自动完成:分析请求 → 并行调用多个工具 → 综合结果输出。
create_agent() vs 自定义 LangGraph:
create_agent() |
自定义 LangGraph | |
|---|---|---|
| 代码量 | ~10 行 | 30+ 行 |
| 流程 | 固定 ReAct 循环 | 完全自定义 |
| 适用场景 | 快速原型、简单问答 | 审批流、多 Agent、复杂业务 |
五、记忆(Memory)
默认每次调用都是独立的,加 checkpointer 实现跨轮记忆:
from langgraph.checkpoint.memory import MemorySaver
import uuid
checkpointer = MemorySaver()
agent_with_memory = create_agent(
model=model,
tools=[get_weather, search_movies],
system_prompt="你是一个有用的助手。",
checkpointer=checkpointer
)
# 用 thread_id 标识同一段对话
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
# 第一轮
agent_with_memory.invoke({"messages": [{"role": "user", "content": "我叫 Alice,喜欢科幻片。"}]}, config=config)
# 第二轮(Agent 记得上文)
result = agent_with_memory.invoke({"messages": [{"role": "user", "content": "我叫什么名字?"}]}, config=config)
要点:
- 同一个
thread_id= 同一段对话,共享记忆 - 不同
thread_id= 不同对话,互相隔离 thread_id可以用uuid.uuid4()或任意唯一字符串
六、流式输出(Streaming)
# 查看每个 Agent 步骤(适合调试)
for chunk in agent.stream({"messages": [...]}, stream_mode="updates"):
for node_name, data in chunk.items():
print(f"步骤: {node_name}")
# 逐 Token 流式输出(类似 ChatGPT 打字效果)
for token, metadata in agent.stream({"messages": [...]}, stream_mode="messages"):
if metadata.get("langgraph_node") == "model":
for block in token.content_blocks:
if block.get("type") == "text":
print(block["text"], end="", flush=True)
七、从零构建 ReAct Agent
理解 LangGraph 三大原语:State(状态)、Node(节点)、Edge(边)
State — 对话数据容器
from typing_extensions import TypedDict
from typing import Annotated, List
from langgraph.graph.message import AnyMessage, add_messages
class State(TypedDict):
# add_messages 是 reducer,表示新消息追加而非覆盖
messages: Annotated[List[AnyMessage], add_messages]
继承
TypedDict的原因:LangGraph 需要读取字段定义和 reducer 来管理状态更新。
Node — 处理逻辑单元
from langgraph.prebuilt import ToolNode
from langchain.messages import SystemMessage
# 工具节点:自动根据函数名匹配并执行工具
tools = [search_movies, get_weather]
tool_node = ToolNode(tools) # 内部建立 {"get_weather": fn, ...} 字典,按名字匹配执行
# 主助手节点
def assistant(state: State):
system_prompt = "你是一个能查天气、推荐电影的助手。"
all_messages = [SystemMessage(system_prompt)] + state["messages"]
response = model_with_tools.invoke(all_messages)
return {"messages": [response]}
Edge — 控制流转
def should_continue(state: State):
last_message = state["messages"][-1]
if last_message.tool_calls:
return "continue" # 有工具调用 → 去执行工具
else:
return "end" # 直接回答 → 结束
编译图
from langgraph.graph import StateGraph, START, END
builder = StateGraph(State)
# 添加节点
builder.add_node("assistant", assistant)
builder.add_node("tool_node", tool_node)
# 添加边
builder.add_edge(START, "assistant")
builder.add_conditional_edges(
"assistant",
should_continue,
{
"continue": "tool_node", # should_continue 返回 "continue" → 去 tool_node
"end": END, # should_continue 返回 "end" → 结束
}
)
builder.add_edge("tool_node", "assistant") # 工具执行后返回 LLM
agent = builder.compile(name="agent")
执行流程:
START → assistant → (有工具调用?) → tool_node → assistant → ... → END
↘ (直接回答) → END
小结
| 概念 | 作用 |
|---|---|
init_chat_model |
统一模型接口,支持多提供商 |
Messages |
对话历史的基本单元 |
@tool |
把 Python 函数变为 LLM 可调用工具 |
create_agent() |
快速创建 ReAct Agent |
MemorySaver |
基于 thread_id 的对话记忆 |
StateGraph |
自定义 Agent 的有向图框架 |
ToolNode |
自动匹配执行工具的预构建节点 |
| 条件边 | 根据运行时状态动态路由流程 |
浙公网安备 33010602011771号