当前位置: 首页 > news >正文

【LLM LangChain】 模型绑定工具+调用工具(手动调用/LangGraph/AgentExecutor)+相关注意事项

模型绑定工具

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool# 定义一个工具
@tool
def add_numbers(input: str) -> str:"""Add two numbers together. 输入格式: 'a,b'"""a, b = map(int, input.split(","))return str(a + b)# 初始化模型
model = ChatOpenAI(model= "qwen-plus",api_key= "sk-0cff369a69e1474d9a308f19370373f1",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1") # ChatOpenAI(model="gpt-4o", temperature=0)# 给模型绑定工具
model_with_tools = model.bind_tools([add_numbers])# 传入对话消息
result = model_with_tools.invoke([{"role": "user", "content": "帮我计算 123 + 456"}
])print(result)

输出

content='' additional_kwargs={'tool_calls': [{'id': 'call_407dc2ba39074f34a319c2', 'function': {'arguments': '{"input": "123,456"}', 'name': 'add_numbers'}, 'type': 'function', 'index': 0}], 'refusal': None} response_metadata={'token_usage': {'completion_tokens': 25, 'prompt_tokens': 162, 'total_tokens': 187, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-24d6004f-53c9-4362-ade0-1ec3d09f1f5b', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None} id='run--12c2fe5b-0b2c-4f05-9102-c20b73c93737-0' tool_calls=[{'name': 'add_numbers', 'args': {'input': '123,456'}, 'id': 'call_407dc2ba39074f34a319c2', 'type': 'tool_call'}] usage_metadata={'input_tokens': 162, 'output_tokens': 25, 'total_tokens': 187, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}

关键字段说明

  • content=''

    • 空字符串,因为这次回答不是自然语言,而是“我要调用工具”。
  • additional_kwargs.tool_calls

    • 模型生成的工具调用请求。

    • 这里包含:

      {"id": "call_407dc2ba39074f34a319c2","function": {"arguments": "{\"input\": \"123,456\"}","name": "add_numbers"},"type": "function","index": 0
      }
      
      • name: 工具名称 → "add_numbers"
      • arguments: 工具的参数 → {"input": "123,456"}
      • 这就是模型想让你执行的函数调用。
  • response_metadata.finish_reason='tool_calls'

    • 表示这次生成 不是回答,而是“请求调用工具”。
  • tool_calls

    • 更直观地列出了工具调用:

      [{'name': 'add_numbers', 'args': {'input': '123,456'}, ...}]
      
  • usage_metadata / response_metadata.token_usage

    • 记录了这次请求的 token 用量(输入 162,输出 25)。

工具执行

  • 拿到了 工具调用请求 (tool_calls),接下来就有几种执行方式。
  • 手动执行:最灵活,适合简单场景或需要自己管理工具调用逻辑。
  • LangGraph + ToolNode:推荐 👍,适合生产级、多工具、复杂工作流。
  • AgentExecutor:入门快,写起来简洁,但定制性差。

方法 1:手动执行工具

  • 自己解析 tool_calls,调用对应函数,再把结果交回模型。
from langchain_core.messages import AIMessage, ToolMessage# 1. 模型返回的工具调用请求
ai_message = result  # 就是你拿到的对象
tool_call = ai_message.tool_calls[0]
tool_name = tool_call["name"]
tool_args = tool_call["args"]# 2. 执行工具
tool_result = add_numbers.invoke(tool_args)  # -> "579"# 3. 把工具的结果传回模型
final_result = model_with_tools.invoke([ai_message,ToolMessage(content=tool_result, tool_call_id=tool_call["id"])
])print(final_result.content)  # 实际输出:最终答案: 123 加 456 等于 579。

方法 2:用 LangGraph 的 ToolNode

  • LangGraph 专门为这种场景做了封装,你只要把工具交给 ToolNode,它会自动检测 tool_calls → 执行 → 把结果再反馈给模型。
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode# 定义工具节点
tools = [add_numbers]
tool_node = ToolNode(tools)# 定义模型节点
def call_model(state: MessagesState):response = model_with_tools.invoke(state["messages"])return {"messages": [response]}  # 必须返回 dict# 定义工作流
workflow = StateGraph(MessagesState)
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
workflow.add_edge(START, "agent")# 条件判断:模型是否要调用工具
def should_continue(state: MessagesState):last_msg = state["messages"][-1]return "tools" if getattr(last_msg, "tool_calls", None) else ENDworkflow.add_conditional_edges("agent", should_continue, ["tools", END])
workflow.add_edge("tools", "agent")graph = workflow.compile()# 执行
result = graph.invoke({"messages": [("user", "帮我计算 123+456")]})
print("最终答案:", result["messages"][-1].content)
# 最终答案: 123 + 456 = 579
  • 旧版本 LangGraph Python里使用MessagesAnnotation:
from langgraph.prebuilt import ToolNode
from langgraph.graph import StateGraph, MessagesAnnotation, START, END# 1. 定义工具节点
tools = [add_numbers]
tool_node = ToolNode(tools)# 2. 定义模型节点
def call_model(state: MessagesAnnotation.State):return {"messages": [model_with_tools.invoke(state["messages"])]}# 3. 定义图
workflow = StateGraph(MessagesAnnotation)
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)# 4. 逻辑:模型调用工具 → 工具执行 → 回到模型
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent",lambda state: "tools" if state["messages"][-1].tool_calls else END,["tools", END],
)
workflow.add_edge("tools", "agent")graph = workflow.compile()# 5. 执行
result = graph.invoke({"messages": [("user", "帮我计算 123+456")]})
print(result["messages"][-1].content)

方法 3:用 AgentExecutor

  • LangChain 有 AgentExecutor,可以自动处理工具调用,尤其是想要 “让模型自由选择工具” 时。开箱即用,逻辑封装好,适合快速跑 demo,但灵活度不如 LangGraph。
  • 支持多个工具也更简单:tools = [add_numbers, subtract_numbers];agent = create_openai_functions_agent(llm, tools)
  • agent 会打印执行轨迹(调用了哪个工具、返回了什么),用于调试。
from langchain.agents import initialize_agent, AgentTypeagent = initialize_agent(tools=[add_numbers],llm=model,agent_type=AgentType.OPENAI_FUNCTIONS
)result = agent.invoke({"input": "帮我计算 123+456"})
print(result["output"])

注意事项

如果没有tool_calls

  • AgentExecutor:直接输出 Final Answer。
  • LangGraph:你要在条件分支里处理这种情况。
  • 手动执行工具:需要自己判断 tool_calls 是否为空。

调用报错

  • 正确的情况
    在这里插入图片描述

  • 错误的情况:

    • 工具参数定义是 input: str,模型就可能输出 "123,456"'123,456'、甚至 {"input": "'123,456'"}。Agent 里最常见,因为它全自动调用工具,最容易出脏数据。

    • ValueError: invalid literal for int() with base 10: "'123",模型返回的参数带了引号,input.split(“,”) 得到的是 [“'123”, “456’”],转 int报错:
      在这里插入图片描述

修复方法

方法 1:在工具里清理参数
@tool
def add_numbers(input: str) -> str:"""Add two numbers together. 输入格式: 'a,b'"""# 去掉可能的引号和空格cleaned = input.strip().replace("'", "").replace('"', "")a, b = map(int, cleaned.split(","))return str(a + b)
方法 2:直接用 结构化参数
from langchain_core.tools import StructuredTool
from pydantic import BaseModelclass AddInput(BaseModel):a: intb: intdef add_numbers(a: int, b: int) -> str:"""Add two numbers together"""return str(a + b)add_tool = StructuredTool.from_function(func=add_numbers,args_schema=AddInput,name="add_numbers",description="Add two numbers together"
)

预定义工具

  • 自带工具:https://python.langchain.com/docs/integrations/tools/
  • https://js.langchain.ac.cn/docs/integrations/tools/duckduckgo_search/
  • https://python.langchain.com/docs/integrations/tools/tavily_search/
http://www.dtcms.com/a/394132.html

相关文章:

  • 图神经网络(GNN)入门:用PyG库处理分子结构与社会网络
  • 【C++】编码表 STL简介:STL是什么,版本,六大组件,重要性以及学习方法总结
  • show_interrupts函数的进一步解析及irq_desc结构体
  • Kafka面试精讲 Day 19:JVM调优与内存管理
  • 10.vector容器
  • Linux系统介绍
  • MFC中的CMFCDynamicLayout类的介绍
  • UniScene 统一驾驶场景 | 生成语义占据 | 生成多视角视频 | 生成激光点云 CVPR2025
  • Git 简明教程:从原理到实战
  • 【设计模式】中介者模式
  • nginx添加modsecurity插件
  • 代码上传Github:SSH法
  • 【iOS】AFNetworking初步了解及使用
  • JVM实战-G1参数调优
  • 超简单的视频分割脚本
  • 基于51单片机电子钟闹钟12/24小时制LCD显示( proteus仿真+程序+设计报告+讲解视频)
  • 在 Windows 系统上安装官方 Codex CLI 教程
  • Redis 配置与优化全攻略
  • 二分查找左右边界写法
  • Oracle体系结构-Large Pool详解
  • Elasticsearch面试精讲 Day 19:磁盘IO与存储优化
  • 【AI智能体】Dify 搭建数据分析应用实战操作详解
  • Nginx localtion / 、/a、/a/ 的区别
  • 【C++】string的使用与模拟实现
  • 新手向 算法 希尔排序-yang
  • 如何用RAG增强的动态能力与大模型结合打造企业AI产品?
  • 黑马头条_SpringCloud项目阶段五:openFeign服务接入以及接入腾讯云内容安全服务实现文章提交违规信息自动审核
  • Spring、SpringBoot框架核心流程详解
  • 195. Java 异常 - finally 块:Java 中的“兜底侠”
  • C语言底层学习(2.指针与数组的关系与应用)(超详细)