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

LangChain-4-工具调用

Tools概述

Tools 用于扩展大语言模型(LLM)的能力,使其能够与外部系统、API 或自定义函数交互,从而完成仅靠文本生成无法实现的任务(如搜索、计算、数据库查询等)。

LangChain通过提供统一框架集成功能的具体实现。在框架内,每个功能被封装成一个工具,具有自己的输入输出及处理方法。代理接收任务后,通过大模型推理选择适合的工具处理任务。一旦选定,LangChain将任务输入传递给该工具,工具处理输入生成输出。输出经过大模型推理,可用于其他工具的输入或作为最终结果返回给用户。

特点:

增强 LLM 的功能 :让 LLM 突破纯文本生成的限制,执行实际操作(如调用搜索引擎、查询数据 库、运行代码等)

支持智能决策 :在Agent 工作流中,LLM 根据用户输入动态选择最合适的 Tool 完成任务。

模块化设计 :每个 Tool 专注一个功能,便于复用和组合(例如:搜索工具 + 计算工具 + 天气查 询工具)

Tool 的要素

Tools 本质上是封装了特定功能的可调用模块,是Agent、Chain或LLM可以用来与世界互动的接口。

Tool 通常包含如下几个要素:

name :工具的名称

description :工具的功能描述

该工具输入的 JSON模式

要调用的函数

return_direct :是否应将工具结果直接返回给用户(仅对Agent相关)

实操步骤:

步骤1:将name、description 和 JSON模式作为上下文提供给LLM

步骤2:LLM会根据提示词推断出 需要调用哪些工具 ,并提供具体的调用参数信息

步骤3:用户需要根据返回的工具调用信息,自行触发相关工具的回调

示列:

import os from langchain_community.tools import TavilySearchResults os.environ['TAVILY_API_KEY'] = '' tool = TavilySearchResults(top_k_results=1, doc_content_chars_max=100) print("name:", tool.name) print("description:", tool.description) print("args:", tool.args) print("return_direct:", tool.return_direct) print("langchain:", tool.run({"query":"langchain"})) print(tool.run("langchain"))

两种自定义Tool方式

第1种:使用@tool装饰器(自定义工具的最简单方式)

装饰器默认使用函数名称作为工具名称,但可以通过参数 name_or_callable 来覆盖此设置。 同时,装饰器将使用函数的 文档字符串 作为 工具的描述 ,因此函数必须提供文档字符串。

第2种:使用StructuredTool.from_function类方法

这类似于 @tool 装饰器,但允许更多配置和同步/异步实现的规范。

几个常用属性

Tool由几个常用属性组成

案例1:

from langchain.tools import tool from langchain_core.tools import StructuredTool @tool(name_or_callable="add", description="计算两个数字的和", return_direct=True) def add(a,b): return a+b print(add.name) print(add.description) print(add.args) print(add.return_direct) resp1 = add.invoke({"a":1, "b":2}) print(resp1)

案例2:

from langchain.tools import tool from langchain_core.tools import StructuredTool def search(keyword): return f"检索{keyword}结果" search_tool = StructuredTool.from_function(func=search, name="search", description="一个可以进行网络搜索的工具") print(search_tool.name) print(search_tool.description) print(search_tool.args) print(search_tool.return_direct) resp2 = search_tool.invoke("狗") print(resp2)

工具调用

bind_toolsagent是构建智能代理系统时常用的功能,bind_tools可用于将工具绑定到特定的组件上,而agent则是一个智能实体,它可以根据输入和可用的工具来决定如何采取行动以实现目标。下面将详细介绍如何使用bind_toolsagent来调用工具。

bind_tools

LangChain里,bind_tools是一种将工具绑定到链(Chain)或模型(LLM)上的方法,目的是让模型能够自动调用这些工具来完成特定任务。它主要用于简化工具调用的流程,使得模型在处理输入时可以直接利用绑定的工具进行信息查询或其他操作。

import os from langchain_community.tools import TavilySearchResults from langchain_core.prompts import ChatPromptTemplate from langchain_core.tools import tool from model.deepseek import deepseek_llm # 搜索工具 os.environ["TAVILY_API_KEY"] = '' search_tool = TavilySearchResults(max_results=5) # 定义几个计算工具 from pydantic import BaseModel class CalculatorArgs(BaseModel): operation: str operand1: float operand2: float @tool("Calculator", return_direct=True, args_schema=CalculatorArgs) def calculator(operation, operand1, operand2): """ 计算器工具,支持加减乘除四种基本运算。 参数: operation (str): 运算类型,可选值为 'add', 'subtract', 'multiply', 'divide'。 operand1 (float): 第一个操作数。 operand2 (float): 第二个操作数。 返回: float: 运算结果。 异常: ValueError: 如果运算类型不支持或除数为零。 """ if operation == "add": return operand1 + operand2 elif operation == "subtract": return operand1 - operand2 elif operation == "multiply": return operand1 * operand2 elif operation == "divide": if operand2 == 0: raise ValueError("Cannot divide by zero.") return operand1 / operand2 else: raise ValueError(f"Unsupported operation: {operation}") tools = [search_tool, calculator] model_with_tools = deepseek_llm.bind_tools(tools) prompt_template = ChatPromptTemplate.from_messages( [ ("system", "你是一个助手,请根据用户输入提供准确的回答。"), ("user", "{input}") ] ) chain = prompt_template | model_with_tools # 示例:调用工具的逻辑 def invoke_tool_example(user_input): # 调用模型并传递工具 res = chain.invoke({"input": user_input}) # 解析返回结果 if res.response_metadata["finish_reason"] == 'tool_calls': # 处理工具调用 for tool_call in res.tool_calls: tool_name = tool_call['name'] tool_args = tool_call['args'] # 根据工具名称调用相应的工具 print(f"Tool name: {tool_name}, Args: {tool_args}") if tool_name == 'Calculator': result = calculator.invoke({"input": tool_args}) print(f"Calculator result: {result}") elif tool_name == 'tavily_search_results_json': result = search_tool.invoke(tool_args['query']) print(f"search tool: {result}") else: print(res.content) # 执行示例函数 while True: user_input = input("请输入你的问题(输入 'exit' 退出):") if user_input.lower() == 'exit': break invoke_tool_example(user_input)

测试

agent

可以理解为一个智能决策者,它基于大语言模型(LLM),根据输入的问题和工具的描述,决定调用哪些工具以及如何使用它们来生成答案

from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.tools import tool from pydantic import Field, BaseModel from model.zhipu import zhipu_llm class AddInput(BaseModel): num1: int = Field(description="计算的第一个数字") num2: int = Field(description="计算的第二个数字") @tool("add_num", args_schema=AddInput, description="求两个数字的和") def add_num(num1: int, num2: int) -> int: """求两个数字的和""" print(f"工具被调用:num1: {num1}, num2: {num2}") return num1 + num2 prompt = ChatPromptTemplate.from_messages( [ ("system", "你是一个智能助手,尽可能的调用工具回答用户的问题"), MessagesPlaceholder(variable_name="chat_history", optional=True), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad", optional=True), ] ) agent = create_tool_calling_agent(zhipu_llm, [add_num], prompt) executor = AgentExecutor(agent=agent, tools=[add_num]) result = executor.invoke({"input": "我昨天赚了100,今天赚了200, 总共赚了多少?"}) print(result)

bind_toolsAgent的对比

1.Agent概述

AgentLangChain中一种更高级的机制,它可以根据输入动态地决定是否调用工具、调用哪个工具以及如何使用工具的输出。Agent通常包含一个决策逻辑,能够根据模型的输出和任务的需求进行智能决策。

2. 优点对比

  • bind_tools
    • 代码简单,适合初学者和简单任务。
    • 工具调用流程固定,易于调试和理解。
  • Agent
    • 自主性强:能够根据任务的复杂性和输入内容动态地决定是否调用工具以及调用哪个工具,更适合处理复杂任务。
    • 适应性好:可以处理多步推理和复杂决策的任务,能够根据工具的输出进一步调整处理流程。

3. 缺点对比

  • bind_tools
    • 缺乏自主性,不能根据情况动态调整工具调用。
    • 对于复杂任务的处理能力有限。
  • Agent
    • 代码复杂:需要配置决策逻辑、工具选择策略等,代码编写和调试的难度较大。
    • 性能开销大:由于需要进行额外的决策和推理,Agent的运行时间和资源消耗可能会更高。

综上所述,bind_tools适合简单任务,追求代码简洁和快速实现;而Agent则更适合复杂任务,需要模型具备智能决策和多步推理能力的场景。

http://www.jsqmd.com/news/472456/

相关文章:

  • Boost电路CCM模式下的参数设计与MATLAB仿真验证
  • 告别账号切换折磨,让矩阵运营更轻松
  • 告别复杂依赖:用ONNX和NoSMPL轻松实现3D人体姿态可视化
  • .NetCore3.1 升级实战:解决ANCM启动超时与HostingModel配置陷阱
  • windows下OpenClaw 一键彻底卸载清理脚本
  • 程序员效率跃迁:精选在线工具集,一站式解决开发与日常难题
  • CES 2026 的 Micro LED 真相:不是在拼亮度,而是在拼谁先把「抗突波」想清楚
  • 监督对比学习(SupCon)在图像分类中的实战应用与优化策略
  • FPGA高速通信中Aurora64B/66B协议的性能优化与实战调优
  • CODESYS开发实战:从零完成控制器与IO模块的集成配置
  • 从恢复余数法到非恢复余数法:Verilog除法器的核心算法实现与优化
  • 深入解析CAN总线字节序:Motorola与Intel格式的实战对比
  • 基于uCOS-III的STM32多任务系统搭建实战指南
  • Win10系统下VS2019与CMake集成编译flann_1.9.1的完整指南
  • SpringBoot集成阿里云身份证核验:从API购买到业务落地的全流程解析
  • 谷歌开源SynthID:AI生成文本水印技术的实战解析
  • 芯片设计-信号完整性 SI 实战 1.2.2 -- 时序裕量(Margin)在高速接口中的关键作用
  • 【GESP】C++四级考试必备:异常处理机制实战解析
  • 从流体动力学到拓扑场论:Chern-Simons形式在三维流形中的几何实现
  • Photoshop 批量图片优化脚本:高效处理JPG与PNG格式
  • MATLAB R2024b 高效部署与性能调优实战:从安装到加速的完整攻略
  • 拆解Libevent:从统一接口到系统后端的核心数据流
  • 告别数据孤岛:基于infini-cloud(原TeraCLOUD)WebDAV协议,构建Zotero全平台文献同步生态
  • 无监督深度学习在图像拼接中的应用:《Reconstructing Stitched Features to Images》核心技术解析
  • Windows系统下cuDNN与CUDA的版本匹配及安装指南
  • 等保2.0实战:Windows系统关机与登录缓存中的剩余信息清除
  • 企业协同文档工具(WebOffice)选型指南:从微软、金山到开源封装的全面解析
  • Verilog数据组织实战:从标量到存储器的精准建模与高效访问
  • 探究电阻变化对二极管直流电压与交流电流影响的仿真实验
  • 傻子嵌入式图解——位带