langgraph 构建一个带工具调用的简单 Agent 工作流
HumanMessage(content='今天上海的天气怎么样?', additional_kwargs={}, response_metadata={}, id='ef338c50-e6bf-4726-887e-7c4ad8699726')LangChain 的。

LangChain 的 bind_tools 依赖模型能输出符合 OpenAI Tool Calling 格式的响应(即包含 tool_calls 字段的消息)。
from langgraph.graph import StateGraph, END, START, MessagesState
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from langchain_core.messages import ToolMessage
from langgraph.checkpoint.memory import MemorySaver
llm = ChatOllama(model="qwen3:8b", base_url="http://localhost:11434")
@tool
def search_tool(input: str):
"""支持查询北京和上海的天气"""
if "上海" in input.lower():
return "晴天,气温27度"
elif "北京" in input.lower():
return "晴转多云,气温20度"
tools = [search_tool]
model = llm.bind_tools(tools)
def call_model(state: MessagesState):
message = state["messages"]
respone = model.invoke(message)
return {"messages": [respone]}
def tool_node(state: MessagesState):
last_msg = state['messages'][-1]
tool_call = last_msg.tool_calls[0]
tool_name = tool_call["name"]
args = tool_call["args"]
input = args.get("input", "")
# 找到对应的工具函数
tool_func = {t.name: t for t in tools}[tool_name]
# 直接调用工具函数(不是 model!)
result = tool_func.invoke(input) # ✅ 正确调用方式
return {"messages": [ToolMessage(content=str(result),
tool_call_id=tool_call["id"])]}
# 定义路由函数,决定是否走哪条边
def should_continue(state: MessagesState):
messages = state['messages']
last_message = messages[-1]
# 判断LLM是否需要调用工具
if last_message.tool_calls:
return "tool"
# 否则,结束
return END
workflow = StateGraph(MessagesState)
workflow.add_node("tool", tool_node)
workflow.add_node("agent", call_model)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, ["tool", END])
workflow.add_edge("tool", "agent")
graph = workflow.compile()
graph.get_graph().draw_mermaid_png(output_file_path="1.png")
inputs = {"messages": [('human', "今天上海的天气怎么样?")]}
res = graph.invoke(inputs)
print(res["messages"][-1].content)
打断点:

分析如下:

state:

其中0(HumanMessage)如下:
HumanMessage(content='今天上海的天气怎么样?', additional_kwargs={}, response_metadata={}, id='ef338c50-e6bf-4726-887e-7c4ad8699726')
其中1(AIMessage)如下:

content='' additional_kwargs={} response_metadata={'model': 'qwen3:8b', 'created_at': '2025-12-25T03:14:28.9946579Z', 'done': True, 'done_reason': 'stop', 'total_duration': 26736100700, 'load_duration': 231792600, 'prompt_eval_count': 143, 'prompt_eval_duration': 656036400, 'eval_count': 95, 'eval_duration': 25769589900, 'model_name': 'qwen3:8b'} id='run--490413d4-2667-4b50-814f-96ad29447c5f-0' tool_calls=[{'name': 'search_tool', 'args': {'input': '上海'}, 'id': 'd41df242-af88-4aa9-a9ad-d48a3be63649', 'type': 'tool_call'}] usage_metadata={'input_tokens': 143, 'output_tokens': 95, 'total_tokens': 238}
最终传给model的如下:state状态更新


[HumanMessage(content='今天上海的天气怎么样?', additional_kwargs={}, response_metadata={}, id='da68f03c-cd51-4350-9937-02b9c2be027a'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'qwen3:8b', 'created_at': '2025-12-25T03:26:07.8786592Z', 'done': True, 'done_reason': 'stop', 'total_duration': 40361880100, 'load_duration': 213874600, 'prompt_eval_count': 143, 'prompt_eval_duration': 680992200, 'eval_count': 136, 'eval_duration': 39304178100, 'model_name': 'qwen3:8b'}, id='run--9204a268-0a5a-45ac-8009-21e57b6cfb4e-0', tool_calls=[{'name': 'search_tool', 'args': {'input': '上海'}, 'id': '183d70bd-f0e1-4c21-aa89-b58329873cbb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 143, 'output_tokens': 136, 'total_tokens': 279}), ToolMessage(content='晴天,气温27度', id='4c5a8c6a-fbbb-4c05-8c1c-2ad3582506b2', tool_call_id='183d70bd-f0e1-4c21-aa89-b58329873cbb')]
输出结果:

[respone]:
[AIMessage(content='上海今天天气晴朗,气温27摄氏度,适合外出活动哦!', additional_kwargs={}, response_metadata={'model': 'qwen3:8b', 'created_at': '2025-12-25T03:35:40.1167725Z', 'done': True, 'done_reason': 'stop', 'total_duration': 55149192000, 'load_duration': 16352963400, 'prompt_eval_count': 182, 'prompt_eval_duration': 3931605900, 'eval_count': 120, 'eval_duration': 34648799800, 'model_name': 'qwen3:8b'}, id='run--75a75fd4-f91e-44c2-9b01-80ebef675a39-0', usage_metadata={'input_tokens': 182, 'output_tokens': 120, 'total_tokens': 302})]

更多推荐

所有评论(0)