AI Agent 从入门到落地:用 LangGraph 搭建能调用工具的任务型代理
本文为原创技术分享,仅用于技术学习交流。
适用场景:想搭建能调用工具的 AI Agent,网上讲原理的多,真正给你完整可运行代码实例教程少,本文手把手带你做一个能查询天气、计算的工具调用 Agent。
一、痛点场景:Agent 开发,你是否也卡在这里?
大语言模型 Agent 现在很火,大家都想做一个能自己调用工具完成任务的智能代理。比如:
-
用户问"北京今天天气热吗",Agent 知道调用天气 API 查询
-
用户问"399 的 85 折是多少钱",Agent 知道调用计算器算出来
但是网上教程大多在讲 LangGraph 原理,什么状态机、循环、节点,看完原理还是不知道怎么写出一个能跑通的实例。
这篇文章就带你从 0 到 1,用 LangGraph 搭建一个支持多工具调用的任务型 Agent,代码完整可运行,看完你就能照着改出自己的工具调用 Agent。
二、最终效果展示
最终我们要实现这样的效果:
用户: 北京今天天气多少度?帮我算一下,如果开 26 度空调,一天耗电多少度?
Agent:
-> 调用 get_weather(city="北京") 获取天气
-> 得到结果: 北京今天 28 度
-> 调用 calculate(expression="(26 * 1.5 * 12)") 计算耗电
-> 得到结果: 468 度电
-> 生成最终回答: 北京今天 28°C,开 26 度空调预计耗电 468 度。
Agent 会自己判断需要调用哪些工具、按什么顺序调用,最后整合结果回答用户。本文实现的结构支持任意扩展工具,你只需要写工具函数,剩下的交给 LangGraph 调度。
三、实战代码:完整可运行
环境依赖安装
pip install langchain langgraph openai python-dotenv
完整代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LangGraph 工具调用 Agent 完整示例
支持多工具顺序调用,自动判断需要调用什么工具
"""
import operator
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import BaseMessage, ToolMessage
from langchain_core.runnables import Runnable
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph
from langgraph.prebuilt import ToolNode
from openai import OpenAI
import json
import os
# ============ 配置 ============
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "your-api-key")
OPENAI_API_BASE = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
MODEL_NAME = "gpt-3.5-turbo"
# ============ 定义工具 ============
def get_weather(city: str) -> str:
"""查询城市今日天气
Args:
city: 城市名称
"""
# 这里替换成你自己的天气 API 调用
# 示例返回,实际项目对接真实接口
fake_data = {
"北京": "28°C,晴朗",
"上海": "26°C,多云",
"广州": "32°C,晴天",
"深圳": "31°C,阴天",
}
return fake_data.get(city, f"未找到{city}天气数据")
def calculate(expression: str) -> str:
"""计算数学表达式结果
Args:
expression: 数学表达式,比如 "399 * 0.85"
"""
try:
result = eval(expression)
return f"{result}"
except Exception as e:
return f"计算错误: {str(e)}"
# 工具列表,在这里注册你所有的工具
tools = [get_weather, calculate]
# ============ 定义 Agent 状态 ============
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]
# ============ 构建 Graph ============
def build_agent():
# 初始化 LLM
llm = ChatOpenAI(
model=MODEL_NAME,
openai_api_key=OPENAI_API_KEY,
openai_api_base=OPENAI_API_BASE,
temperature=0,
).bind_tools(tools)
# 判断是否需要继续调用工具
def should_continue(state: AgentState):
messages = state["messages"]
last_message = messages[-1]
# 如果最后一条消息有工具调用,继续
if getattr(last_message, "tool_calls", None):
return "continue"
# 否则结束
return END
# 调用 LLM 生成回复
def call_llm(state: AgentState):
messages = state["messages"]
response = llm.invoke(messages)
return {"messages": [response]}
# 构建工作流
workflow = StateGraph(AgentState)
# 节点:LLM 推理
workflow.add_node("agent", call_llm)
# 节点:工具调用
tool_node = ToolNode(tools)
workflow.add_node("tools", tool_node)
# 入口
workflow.set_entry_point("agent")
# 条件边:LLM 输出后,如果要调用工具,走工具节点,否则结束
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "tools",
END: END,
},
)
# 工具调用完回到 LLM 整合结果
workflow.add_edge("tools", "agent")
# 编译得到可运行的 Agent
app = workflow.compile()
return app
# ============ 运行对话 ============
def run_agent(app, user_query: str):
from langchain_core.messages import HumanMessage
inputs = {"messages": [HumanMessage(content=user_query)]}
output = []
for chunk in app.stream(inputs, stream_mode="updates"):
for node, update in chunk.items():
output.append((node, update))
print(f"\n--- 节点: {node} ---")
if "messages" in update:
last_msg = update["messages"][-1]
if hasattr(last_msg, "tool_calls") and last_msg.tool_calls:
for tc in last_msg.tool_calls:
print(f"调用工具: {tc['name']} 参数: {tc['args']}")
# 拿到最终回复
final_state = chunk[-1][1]
last_message = final_state["messages"][-1]
return last_message.content
if __name__ == "__main__":
app = build_agent()
print("Agent 已启动,输入问题即可开始(输入 quit 退出)")
while True:
try:
user_input = input("\n你: ")
if user_input.lower() in ["quit", "exit", "q"]:
break
answer = run_agent(app, user_input)
print(f"\nAgent: {answer}")
except KeyboardInterrupt:
break
print("\n再见!")
四、原理解释:LangGraph Agent 工作流程
本文的 Agent 工作流程非常清晰,就三个节点:
用户提问 → [agent节点] → LLM 判断是否需要调用工具
↓
是 → [tools节点] → 执行工具调用 → 回到 [agent节点]
↓
否 → 结束 → 输出最终回答
节点说明
|
节点 |
作用 |
|---|---|
|
agent |
调用大模型,根据当前对话生成下一个动作(回答或调用工具) |
|
tools |
执行工具调用,把工具结果放回对话 |
|
条件判断 |
决定继续调用工具还是结束 |
为什么要用 LangGraph?
-
显式控制流程:比 LangChain 的 Agent 更可控,哪里出问题方便调试
-
支持循环:可以多次调用工具,工具结果回来再让 LLM 判断
-
结构化状态:状态管理清晰,方便扩展复杂场景
五、避坑指南:我踩过的这些坑
坑 1:工具参数不匹配
问题: LLM 调用工具参数格式不对,解析报错。
解决:
-
使用 bind_tools 方法绑定工具,LangChain 会自动给 LLM 正确的工具描述
-
工具函数一定要写好 docstring,说明每个参数含义,LLM 才能理解
-
参数一定要加类型标注,比如 city: str,不要省略
坑 2:state 维护错误
问题: 工具调用结果没有正确加到对话历史里,LLM 看不到工具返回结果。
解决: LangGraph 状态用 Annotated[Sequence[BaseMessage], operator.add] ,这样每次更新是追加不是替换,工具结果会正确保留在对话里。
坑 3:temperature 设置太高
问题: Agent 总是乱调用工具,不需要调用也非要调用。
解决: Agent 调度推理需要确定性,把 temperature=0,输出稳定很多,不要开高温。
坑 4:忘记导 operator.add
问题: 运行直接报错 name 'operator' is not defined。
解决: 开头一定要 import operator,state 定义需要 operator.add。
坑 5:工具调用完不回到 LLM
问题: 工具执行完就结束了,LLM 不会整合结果回答用户。
解决: 一定要加 workflow.add_edge("tools", "agent"),工具执行完必须回到 agent 节点让 LLM 看工具结果生成最终回答。
六、使用示例
运行代码之后:
Agent 已启动,输入问题即可开始(输入 quit 退出)
你: 北京今天天气多少度?帮我算一下,如果开 26 度空调,一天耗电多少度?
--- 节点: agent ---
调用工具: get_weather 参数: {'city': '北京'}
--- 节点: tools ---
--- 节点: agent ---
调用工具: calculate 参数: {'expression': '26 * 1.5 * 12'}
--- 节点: tools ---
--- 节点: agent ---
Agent: 北京今天温度是28°C,天气为晴朗。如果一天开空调12小时,按每小时1.5度计算,总耗电量为 26 × 1.5 × 12 = 468 度电。
完美!Agent 自动判断需要两次工具调用,按顺序执行,最后整合结果回答用户。
七、总结
这个方案非常清晰,完整代码不到 200 行,就能跑起来一个支持多工具调用的 Agent:
-
✅ 自动判断是否需要调用工具
-
✅ 支持多次工具顺序调用
-
✅ 方便扩展新工具,只需要添加工具函数
-
✅ 代码结构清晰,方便调试,哪里出问题改哪里
如果你想学习 LangGraph Agent 开发,又找不到完整可运行的实例,这个示例正好适合你。照着这个结构,把你的工具加进去就能用了。
更多推荐



所有评论(0)