LangChain实战快速入门笔记(五)--LangChain使用之Tools

LangChain实战快速入门笔记(五)--LangChain使用之Tools

文章目录


一、Tools概述

1. 介绍

  要构建更强大的AI工程应用,只有生成文本这样的"纸上谈兵 "能力自然是不够的。工具Tools不仅仅是"肢体"的延伸,更是为"大脑"插上了想象力的"翅膀"。借助工具,才能让AI应用的能力真正具备无限的可能,才能从"认识世界 "走向"改变世界 "。

  Tools 用于扩展大语言模型(LLM)的能力,使其能够与外部系统、API 或自定义函数交互,从而完成

仅靠文本生成无法实现的任务(如搜索、计算、数据库查询等)。

特点:

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

库、运行代码等)

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

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

询工具)

LangChain 拥有大量第三方工具。请访问工具集成查看可用工具列表。

https://python.langchain.com/v0.2/docs/integrations/tools/

2. Tool 的要素

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

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

  • name :工具的名称

  • description :工具的功能描述

  • 该工具输入的JSON模式

  • 要调用的函数

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

实操步骤:

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

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

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

注意:

如果⼯具具有精心选择的名称、描述和JSON模式,则模型的性能将更好。

下⼀章内容我们可以看到⼯具的调⽤动作可以通过Agent⾃主接管。

二、自定义工具

1. 两种自定义方式

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

装饰器默认使用函数名称作为工具名称,但可以通过参数name_or_callable来覆盖此设置。

同时,装饰器将使用函数的文档字符串 作为工具的描述,因此函数必须提供文档字符串。

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

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

2. 几个常用属性

Tool由几个常用属性组成:

3. 具体实现

方式1:@tool 装饰器

举例1:
python 复制代码
from langchain.tools import tool

@tool
def add_number(a: int, b: int) -> int:
    """两个整数相加"""
    return a + b

print(f'name = {add_number.name}')
print(f'args = {add_number.args}')
print(f'description = {add_number.description}')
print(f'return_direct = {add_number.return_direct}')

res = add_number.invoke({"a":10, "b":20})
print(res)

说明:return_direct参数的默认值是False。当return_direct=False时,工具执行结果会返回给Agent,让Agent决定下一步操作;而return_direct=True则会中断这个循环,直接结束流程,返回结果给用户。

举例2:通过@tool的参数设置进行重置
python 复制代码
from langchain.tools import tool

@tool(name_or_callable="add_two_number", description="two number add", return_direct=True)
def add_number(a: int, b: int) -> int:
    """两个整数相加"""
    return a + b

print(f'name = {add_number.name}')
print(f'description = {add_number.description}')
print(f'args = {add_number.args}')
print(f'return_direct = {add_number.return_direct}')

res = add_number.invoke({"a":10, "b":20})
print(res)

补充:还可以修改参数的说明

python 复制代码
from langchain.tools import tool
from pydantic import BaseModel, Field

class FieldInfo(BaseModel):
    a: int = Field(description="第1个参数")
    b: int = Field(description="第2个参数")

@tool(name_or_callable="add_two_number", description="two number add", args_schema=FieldInfo, return_direct=True)
def add_number(a: int, b: int) -> int:
    """两个整数相加"""
    return a + b

print(f'name = {add_number.name}')
print(f'description = {add_number.description}')
print(f'args = {add_number.args}')
print(f'return_direct = {add_number.return_direct}')

res = add_number.invoke({"a":10, "b":20})
print(res)

方式2:StructuredTool的from_function()

StructuredTool.from_function 类方法提供了比**@tool**装饰器更多的可配置性,而无需太多额外的代

码。

举例1:

python 复制代码
from langchain_core.tools import StructuredTool

def search_function(query: str):
    return "LangChain"

search1 = StructuredTool.from_function(
    func=search_function,
    name="Search",
    description="useful for when you need to answer questions about current events"
)

print(f'name = {search1.name}')
print(f'description = {search1.description}')
print(f'args = {search1.args}')

search1.invoke("hello")

举例2:

python 复制代码
from langchain_core.tools import StructuredTool
from pydantic import Field, BaseModel

class FieldInfo(BaseModel):
    query: str = Field(description= "要检索的关键词")

def search_function(query: str):
    return "LangChain"

search1 = StructuredTool.from_function(
    func=search_function,
    name="Search",
    description= "useful for when you need to answer questions about current events",
    args_schema=FieldInfo,
    return_direct=True,
)

print(f'name = {search1.name}')
print(f'description = {search1.description}')
print(f'args = {search1.args}')
print(f'return_direct = {search1.return_direct}')

search1.invoke("hello")

4. 工具调用举例

我们通过大模型分析用户需求,判断是否需要调用指定工具。

举例1:大模型分析调用工具

python 复制代码
#1.导入相关依赖
from langchain_community.tools import MoveFileTool
from langchain_core.messages import HumanMessage
from langchain_core.utils.function_calling import convert_to_openai_function
import os
import dotenv
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["OPENAI_BASE_URL"] = os.getenv("OPENAI_BASE_URL")

#2.定义LLM模型
chat_model = ChatOpenAI(model="gpt-4o-mini",temperature=0)

#3.定义工具
tools = [MoveFileTool()]

#4.这里需要将工具转换为openai函数,后续再将函数传入模型调用
functions = [convert_to_openai_function(t) for t in tools]
#print(functions[0])

#5.提供大模型调用的消息列表
messages = [HumanMessage(content="将文件a移动到桌面")]

#6.模型使用函数
response = chat_model.invoke(
    input = messages,
    functions=functions
)

print(response)

模型绑定工具,调用模型,传入Message对象。

作为对照,修改代码:

python 复制代码
response = chat_model.invoke(
    [HumanMessage(content="今天的天气怎么样?")],
    functions=functions
)

print(response)


调用工具说明

两种情况:

情况1:大模型决定调用工具

如果模型认为需要调用工具(如 MoveFileTool ),返回的 message 会包含:

  • content : 通常为空(因为模型选择调用工具,而非生成自然语言回复)。

  • additional_kwargs : 包含工具调用的详细信息:

python 复制代码
AIMessage(
    content="",  # 无自然语言回复
    additional_kwargs={
        'function_call': {
            'name': 'move_file',  # 工具名称
            'arguments': 
                '{"source_path": "a", "destination_path": "/Users/YourUsername/Desktop/a"}'  # 工具参数
        }
    }
)
情况2:大模型不调用工具

如果模型认为无需调用工具(例如用户输入与工具无关),返回的message 会是普通文本回复:

python 复制代码
AIMessage(
    content="我没有找到需要移动的文件。",  # 自然语言回复
    additional_kwargs={"refusal": None}  # 无工具调用
)
举例2:确定工具并调用
python 复制代码
# 定义LLM模型
chat_model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 定义工具
tools = [MoveFileTool()]

# 将工具转换为openai函数
functions = [convert_to_openai_function(t) for t in tools]

# 提供消息列表
messages = [HumanMessage(content="将本目录下的abc.txt文件移动到C:\\Users\\shkst\\Desktop")]

# 模型调用
response = chat_model.invoke(
    input=messages,
    functions=functions
)

print(response)
(1) 检查是否需要调用工具
python 复制代码
import json

if "function_call" in response.additional_kwargs:
    tool_name = response.additional_kwargs["function_call"]["name"]
    tool_args = json.loads(message.additional_kwargs["function_call"]["arguments"])
    print(f"调用工具: {tool_name}, 参数: {tool_args}")
else:
    print("模型回复: ", response.content)
(2) 实际执行工具调用
python 复制代码
from langchain.tools import MoveFileTool

if "move_file" in response.additional_kwargs["function_call"]["name"]:
    tool = MoveFileTool()
    result = tool.run(tool_args)  # 执行工具
    print("工具执行结果: ", result)

大模型与 Agent 的核心区别:是否涉及到工具的调用

针对大模型:仅能分析出要调用的工具,但是此工具(或函数)不能真正的执行

针对 Agent:除了分析出要调用的工具之外,还可以执行具体的工具(或函数)

总结

记得关注么么哒

相关推荐
Zhao-Jichao9 小时前
AI Prompting for Everyone 课程笔记 - P21 总结 Conclusion
人工智能·笔记
欢欢李9 小时前
【LTE L3 笔记 05】LTE同步信号
笔记·无线通信·物理层·lte·空口协议
La Pulga11 小时前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
蒸蒸yyyyzwd11 小时前
秋招学习笔记 day106
笔记·学习
小李不想当小白12 小时前
WDG看门狗(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
欢欢李12 小时前
【LTE L3 笔记 04】LTE帧结构
笔记·无线通信·物理层·lte·空口协议
Liangwei Lin14 小时前
Exchange Server 2019 部署手册
microsoft
終不似少年遊*14 小时前
【安全业务Agent】从场景到编排
python·react.js·ai·langchain·agent·安全架构·工作流
Zhao-Jichao15 小时前
AI Prompting for Everyone 课程笔记 - P20 实验与期末项目 Lab and Final Project
前端·人工智能·笔记
Z21-X15 小时前
云原生运维实战笔记:企业网站综合上云部署与云运维服务全景解析
运维·笔记·学习·云原生