在这里插入图片描述

  【个人主页:玄同765

大语言模型(LLM)开发工程师中国传媒大学·数字媒体技术(智能交互与游戏设计)

深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调

技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️

工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案 

     

「让AI交互更智能,让技术落地更高效」

欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!

当你开发大模型应用时,是否曾遇到这些挑战:

  • 如何让模型与外部系统进行交互?
  • 如何管理和组织各种工具函数?
  • 如何让模型智能地选择和使用工具?
  • 如何处理工具调用的错误和异常?

LangChain v1.0+的tools模块为这些问题提供了优雅的解决方案。本文将全面解析LangChain v1.0+中tools模块的核心功能、使用方法和最佳实践,帮助你构建更加智能、强大的大模型应用。


一、LangChain v1.0+ Tools模块核心概念

1. Tool:工具的基本抽象

核心用途:Tool是LangChain中工具的基本抽象,它封装了一个可执行函数,并提供了名称、描述和参数等元数据,使模型能够理解和使用这个工具。

代码示例

from langchain_core.tools import Tool

def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    weather_data = {
        "北京": "晴,25℃",
        "上海": "多云,23℃",
        "广州": "阴,28℃"
    }
    return weather_data.get(city, "未知城市")

# 创建工具实例
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息,参数为城市名称"
)

适用场景:封装各种外部功能,如API调用、数据库查询、文件操作等,使模型能够使用这些功能。

2. StructuredTool:结构化工具

核心用途:StructuredTool是Tool的扩展,它支持结构化的输入参数,使用Pydantic模型来定义参数结构,使工具调用更加类型安全。

代码示例

from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

# 定义参数结构
class WeatherRequest(BaseModel):
    city: str = Field(description="要查询天气的城市名称")
    days: int = Field(default=1, description="要查询的天数")

def get_weather_detailed(city: str, days: int = 1) -> str:
    """获取指定城市的详细天气信息"""
    weather_data = {
        "北京": ["晴,25℃", "多云,23℃", "阴,22℃"],
        "上海": ["多云,23℃", "阴,22℃", "小雨,20℃"],
        "广州": ["阴,28℃", "小雨,26℃", "多云,27℃"]
    }
    if city in weather_data:
        return "\n".join(weather_data[city][:days])
    return "未知城市"

# 创建结构化工具
weather_tool = StructuredTool.from_function(
    func=get_weather_detailed,
    name="get_weather_detailed",
    description="获取指定城市的详细天气信息",
    args_schema=WeatherRequest
)

适用场景:需要复杂参数结构的工具,如多参数API调用、数据库查询等。

3. Toolkit:工具集合

核心用途:Toolkit是一组相关工具的集合,它提供了一种组织和管理多个工具的方式,使工具的使用更加模块化和可维护。

代码示例

from langchain_core.tools import Toolkit
from langchain_community.tools import YouTubeSearchTool, WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper

class InformationToolkit(Toolkit):
    """信息查询工具集合"""

    def __init__(self):
        self.youtube_tool = YouTubeSearchTool()
        self.wikipedia_tool = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

    def get_tools(self):
        """获取工具列表"""
        return [self.youtube_tool, self.wikipedia_tool]

# 使用工具集合
toolkit = InformationToolkit()
tools = toolkit.get_tools()

适用场景:组织相关的工具,如信息查询工具集、数据分析工具集等,使工具的管理更加清晰。


二、LangChain v1.0前后工具开发对比

1. v1.0之前的工具开发

在LangChain v1.0之前,工具的开发和使用方式与现在有较大差异:

核心差异

  • 模块结构:工具类分布在不同模块,导入路径复杂
  • 接口设计:没有统一的Runnable接口,工具调用方式不一致
  • 参数处理:参数验证机制不够完善,类型安全不足
  • 集成方式:与Agent的集成较为复杂,需要更多样板代码

v1.0之前的代码示例

# v1.0之前的工具开发
from langchain.tools import Tool
from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI

# 定义工具函数
def get_weather(city):
    """获取天气信息"""
    return f"{city}的天气是晴天"

# 创建工具
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息"
)

# 初始化Agent
llm = ChatOpenAI(temperature=0)
agent = initialize_agent(
    tools=[weather_tool],
    llm=llm,
    agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# 执行
result = agent.run("北京的天气怎么样?")

2. v1.0之后的工具开发

LangChain v1.0+引入了全新的架构和接口,使工具开发更加简洁、灵活和类型安全:

核心改进

  • 统一接口:所有组件实现Runnable接口,支持invoke、batch、stream等统一方法
  • 模块化设计:工具类集中在langchain_core.tools模块,导入路径清晰
  • 结构化参数:StructuredTool支持Pydantic模型,提供类型安全的参数处理
  • 简化集成:与Agent的集成更加简化,支持工具绑定和自动调用
  • 异步支持:原生支持异步工具和并发执行

v1.0之后的代码示例

# v1.0之后的工具开发
from langchain_core.tools import Tool
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

# 定义工具函数
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    return f"{city}的天气是晴天"

# 创建工具
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息,参数为城市名称"
)

# 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini")

# 创建Agent(推荐方式)
agent = create_agent(
    model=llm,
    tools=[weather_tool],
    system_prompt="你是一个助手,需要根据用户请求选择合适的工具来完成任务。"
)

# 执行(使用消息列表格式)
result = agent.invoke({
    "messages": [("human", "北京的天气怎么样?")]
})
print("最终结果:", result["messages"][-1].content)

三、Tools模块核心功能实现

1. 工具调用机制

核心用途:LangChain的工具调用机制允许模型根据用户输入智能地选择和使用工具,实现模型与外部系统的交互。

代码示例

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langchain_core.tools import Tool

def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    weather_data = {
        "北京": "晴,25℃",
        "上海": "多云,23℃",
        "广州": "阴,28℃"
    }
    return weather_data.get(city, "未知城市")

def calculate(expression: str) -> str:
    """计算数学表达式,如'1+1'、'2*3'等"""
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except:
        return "计算错误"

# 创建工具列表
tools = [
    Tool(
        name="get_weather",
        func=get_weather,
        description="获取指定城市的天气信息,参数为城市名称"
    ),
    Tool(
        name="calculate",
        func=calculate,
        description="计算数学表达式,参数为数学表达式字符串"
    )
]

# 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini")

# 构建带工具调用的链
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个助手,需要根据用户请求选择合适的工具来完成任务。"),
    ("human", "{input}")
])

# 绑定工具到模型
tool_llm = llm.bind_tools(tools)

# 构建完整链
chain = prompt | tool_llm

# 执行
response = chain.invoke({"input": "北京今天的天气怎么样?"})
print(response)

适用场景:需要模型根据上下文智能选择工具的场景,如智能助手、客服系统等。

2. Agent与Tools集成

核心用途:将Tools模块与Agent框架集成,使Agent能够根据任务需求智能地使用工具。

推荐方法(1.0+):使用create_agent

代码示例

from langchain.agents import create_agent
from langchain_core.tools import Tool
from langchain_openai import ChatOpenAI

def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    weather_data = {
        "北京": "晴,25℃",
        "上海": "多云,23℃",
        "广州": "阴,28℃"
    }
    return weather_data.get(city, "未知城市")

def calculate(expression: str) -> str:
    """计算数学表达式,如'1+1'、'2*3'等"""
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except:
        return "计算错误"

# 创建工具列表
tools = [
    Tool(
        name="get_weather",
        func=get_weather,
        description="获取指定城市的天气信息,参数为城市名称"
    ),
    Tool(
        name="calculate",
        func=calculate,
        description="计算数学表达式,参数为数学表达式字符串"
    )
]

# 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini")

# 创建Agent(推荐方式)
agent = create_agent(
    model=llm,
    tools=tools,
    system_prompt="你是一个助手,需要根据用户请求选择合适的工具来完成任务。"
)

# 执行(使用消息列表格式)
result = agent.invoke({
    "messages": [("human", "北京今天的天气怎么样?另外,请计算3+5*2的结果。")]
})
print("最终结果:", result["messages"][-1].content)
传统方法:使用create_tool_calling_agent和AgentExecutor

代码示例

from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import Tool
from langchain_openai import ChatOpenAI

# 定义工具函数(同上)
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    weather_data = {
        "北京": "晴,25℃",
        "上海": "多云,23℃",
        "广州": "阴,28℃"
    }
    return weather_data.get(city, "未知城市")

# 创建工具列表(同上)
tools = [
    Tool(
        name="get_weather",
        func=get_weather,
        description="获取指定城市的天气信息,参数为城市名称"
    )
]

# 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini")

# 定义Agent提示词
agent_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个助手,需要根据用户请求选择合适的工具来完成任务。"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}")
])

# 创建Agent
agent = create_tool_calling_agent(llm, tools, agent_prompt)

# 创建Agent执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 执行
result = agent_executor.invoke({"input": "北京今天的天气怎么样?"})
print("最终结果:", result["output"])

适用场景:复杂任务需要多个工具协作完成的场景,如多步骤信息查询、综合分析等。

3. 自定义工具开发

核心用途:开发自定义工具,封装特定领域的功能,满足特定业务需求。

代码示例

from langchain_core.tools import Tool
import requests

def search_wikipedia(query: str) -> str:
    """搜索维基百科获取信息"""
    try:
        url = f"https://zh.wikipedia.org/api/rest_v1/page/summary/{query}"
        response = requests.get(url, headers={"Accept": "application/json"})
        if response.status_code == 200:
            data = response.json()
            return data.get("extract", "未找到相关信息")
        return "搜索失败"
    except Exception as e:
        return f"错误:{str(e)}"

# 创建自定义工具
wikipedia_tool = Tool(
    name="search_wikipedia",
    func=search_wikipedia,
    description="搜索维基百科获取指定主题的信息,参数为搜索关键词"
)

# 使用工具
result = wikipedia_tool.run("LangChain")
print(result)

适用场景:特定领域的功能需求,如特定API调用、内部系统集成等。


四、LangChain内置工具集

LangChain提供了丰富的内置工具,涵盖了各种常见的功能需求。这些工具可以直接使用,大大减少了开发工作量。

1. 常用内置工具

信息查询工具

  • WikipediaQueryRun:搜索维基百科获取信息
  • YouTubeSearchTool:搜索YouTube视频
  • DuckDuckGoSearchRun:使用DuckDuckGo搜索引擎

文件操作工具

  • ReadFileTool:读取文件内容
  • WriteFileTool:写入文件内容
  • ListDirectoryTool:列出目录内容

数据处理工具

  • PythonREPLTool:执行Python代码
  • CalculatorTool:执行数学计算
  • JSONTool:处理JSON数据

API集成工具

  • RequestsTool:发送HTTP请求
  • ShellTool:执行Shell命令

2. 如何使用内置工具

代码示例

from langchain_community.tools import WikipediaQueryRun, DuckDuckGoSearchRun
from langchain_community.utilities import WikipediaAPIWrapper

# 初始化维基百科工具
wikipedia_tool = WikipediaQueryRun(
    api_wrapper=WikipediaAPIWrapper(lang="zh")
)

# 初始化搜索引擎工具
search_tool = DuckDuckGoSearchRun()

# 使用工具
wiki_result = wikipedia_tool.run("LangChain")
search_result = search_tool.run("LangChain 最新特性")

print("维基百科结果:", wiki_result)
print("\n搜索结果:", search_result)

3. 查找更多内置工具

要查找LangChain提供的更多内置工具,可以通过以下方式:

  1. 官方文档:访问 LangChain官方文档 查看完整的工具列表和使用示例
  2. GitHub仓库:浏览 LangChain GitHub仓库 中的 libs/community/tools 目录,了解所有社区贡献的工具
  3. Python包索引:使用 pip list | grep langchain 查看已安装的LangChain相关包,然后通过 python -c "from langchain_community.tools import *; print(dir())" 查看可用的工具类
  4. 集成指南:访问 LangChain Integrations 页面,了解与各种服务和API的集成工具

五、Tools模块高级特性

1. 工具参数验证

核心用途:使用Pydantic模型对工具参数进行验证,确保参数的类型和格式正确,减少错误。

代码示例

from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field, field_validator

# 定义带验证的参数模型
class CalculateRequest(BaseModel):
    expression: str = Field(description="要计算的数学表达式")

    @field_validator('expression')
    def validate_expression(cls, v):
        # 简单的表达式验证
        allowed_chars = set("0123456789+-*/() ")
        if not all(c in allowed_chars for c in v):
            raise ValueError("表达式只能包含数字、运算符和括号")
        return v

def calculate(expression: str) -> str:
    """计算数学表达式"""
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except Exception as e:
        return f"计算错误:{str(e)}"

# 创建结构化工具
calculate_tool = StructuredTool.from_function(
    func=calculate,
    args_schema=CalculateRequest,
    description="计算数学表达式"
)

适用场景:需要确保工具参数正确性的场景,如金融计算、数据处理等。

2. 工具调用缓存

核心用途:缓存工具调用的结果,减少重复计算,提高系统性能。

代码示例

from langchain_core.tools import Tool
from functools import lru_cache

# 使用lru_cache缓存函数结果
@lru_cache(maxsize=128)
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    print(f"调用天气API获取{city}的天气")
    weather_data = {
        "北京": "晴,25℃",
        "上海": "多云,23℃",
        "广州": "阴,28℃"
    }
    return weather_data.get(city, "未知城市")

# 创建工具
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息,参数为城市名称"
)

# 第一次调用(会执行函数)
print(weather_tool.run("北京"))

# 第二次调用(会使用缓存)
print(weather_tool.run("北京"))

适用场景:工具调用开销较大的场景,如API调用、复杂计算等。

3. 异步工具

核心用途:开发异步工具,支持异步执行,提高系统的并发处理能力。

代码示例

from langchain_core.tools import Tool
import asyncio
import aiohttp

async def async_get_weather(city: str) -> str:
    """异步获取指定城市的天气信息"""
    async with aiohttp.ClientSession() as session:
        # 模拟异步API调用
        await asyncio.sleep(0.5)
        weather_data = {
            "北京": "晴,25℃",
            "上海": "多云,23℃",
            "广州": "阴,28℃"
        }
        return weather_data.get(city, "未知城市")

# 创建异步工具
async_weather_tool = Tool(
    name="async_get_weather",
    func=async_get_weather,
    description="异步获取指定城市的天气信息,参数为城市名称"
)

# 异步执行
async def main():
    result = await async_weather_tool.arun("北京")
    print(result)

asyncio.run(main())

适用场景:高并发场景,如多个工具调用并行执行、Web应用等。


六、MCP工具与LangChain工具的区别

1. 概念与定位

LangChain工具

  • 是LangChain框架的核心组件之一,专为大模型应用设计
  • 提供了统一的工具接口和调用机制
  • 与LangChain的其他组件(如Agent、Chain)深度集成
  • 支持结构化参数、异步执行、缓存等高级特性

MCP工具

  • MCP (Model Context Protocol) 工具是一种更通用的模型工具协议
  • 专注于定义模型与工具交互的标准接口
  • 不依赖于特定框架,可跨框架使用
  • 更注重工具的标准化和互操作性

2. 使用方法对比

LangChain工具使用

from langchain_core.tools import Tool
from langchain_openai import ChatOpenAI

# 定义工具函数
def get_weather(city: str) -> str:
    """获取天气信息"""
    return f"{city}的天气是晴天"

# 创建工具
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息"
)

# 绑定工具到模型
llm = ChatOpenAI(model="gpt-4o-mini")
tool_llm = llm.bind_tools([weather_tool])

# 执行
response = tool_llm.invoke("北京的天气怎么样?")

MCP工具使用

from mcp import Tool
from mcp.server import Server

# 定义工具函数
def get_weather(city: str) -> str:
    """获取天气信息"""
    return f"{city}的天气是晴天"

# 创建工具
weather_tool = Tool(
    name="get_weather",
    description="获取指定城市的天气信息",
    parameters={
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "城市名称"
            }
        },
        "required": ["city"]
    }
)

# 注册工具
server = Server()
server.register_tool(weather_tool, get_weather)

# 启动服务器
server.start()

3. 撰写方法对比

LangChain工具撰写

  • 使用Python类和函数定义工具
  • 支持装饰器和Pydantic模型
  • 工具描述使用自然语言,注重模型理解
  • 集成到LangChain的工作流中

MCP工具撰写

  • 使用JSON Schema定义工具参数
  • 更注重工具的标准化描述
  • 支持远程调用和跨平台使用
  • 独立于特定框架运行

4. 适用场景对比

LangChain工具

  • 适用于构建基于LangChain的大模型应用
  • 适合需要与LangChain其他组件深度集成的场景
  • 适合快速开发和原型设计

MCP工具

  • 适用于需要跨框架、跨平台工具调用的场景
  • 适合构建标准化的工具服务
  • 适合企业级应用和多系统集成

七、Tools模块最佳实践

1. 工具描述编写

核心用途:编写清晰、准确的工具描述,使模型能够正确理解和使用工具。

最佳实践

  • 描述工具的功能和用途
  • 说明参数的含义和格式
  • 提供使用示例
  • 说明返回值的格式和含义

示例

weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息。参数:city(城市名称,如'北京'、'上海')。返回值:天气描述字符串,如'晴,25℃'。示例:get_weather('北京')"
)

2. 错误处理

核心用途:为工具添加错误处理机制,确保工具调用失败时能够优雅地处理,提供有用的错误信息。

最佳实践

  • 使用try-except捕获异常
  • 提供清晰的错误信息
  • 避免工具调用崩溃整个系统

示例

def safe_calculate(expression: str) -> str:
    """安全计算数学表达式"""
    try:
        # 验证表达式安全性
        if any(c in expression for c in ["__", "import", "exec", "eval"]):
            return "表达式不安全"
        result = eval(expression)
        return f"计算结果:{result}"
    except Exception as e:
        return f"计算错误:{str(e)}"

3. 工具模块化

核心用途:将工具组织成模块化的结构,提高代码的可维护性和可重用性。

最佳实践

  • 使用类和模块组织相关工具
  • 为工具提供清晰的接口
  • 避免工具之间的紧耦合

示例

class WeatherTools:
    """天气相关工具集合"""

    @staticmethod
    def get_current_weather(city: str) -> str:
        """获取当前天气"""
        pass

    @staticmethod
    def get_weather_forecast(city: str, days: int) -> str:
        """获取天气预报"""
        pass

    @classmethod
    def get_tools(cls):
        """获取工具列表"""
        return [
            Tool(
                name="get_current_weather",
                func=cls.get_current_weather,
                description="获取指定城市的当前天气"
            ),
            Tool(
                name="get_weather_forecast",
                func=cls.get_weather_forecast,
                description="获取指定城市的天气预报"
            )
        ]

八、常见问题与解决方案

1. 工具调用失败

问题:模型调用工具失败,可能是因为工具描述不清楚或参数格式不正确。

解决方案

  • 编写更清晰、详细的工具描述
  • 使用结构化工具和Pydantic模型定义参数
  • 提供工具使用示例

示例

# 改进前
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取天气"
)

# 改进后
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="获取指定城市的天气信息。参数:city(城市名称,字符串类型)。返回值:天气描述字符串。示例:get_weather('北京')"
)

2. 工具参数错误

问题:工具参数类型错误或格式不正确,导致工具执行失败。

解决方案

  • 使用StructuredTool和Pydantic模型进行参数验证
  • 在工具函数中添加参数检查
  • 提供明确的参数格式说明

示例

from pydantic import BaseModel, Field

class WeatherRequest(BaseModel):
    city: str = Field(..., description="城市名称,不能为空")
    days: int = Field(1, ge=1, le=7, description="预报天数,1-7天")

weather_tool = StructuredTool.from_function(
    func=get_weather,
    args_schema=WeatherRequest,
    description="获取天气信息"
)

3. 工具调用性能问题

问题:工具调用开销较大,影响系统性能。

解决方案

  • 使用缓存减少重复调用
  • 开发异步工具提高并发能力
  • 优化工具函数的执行效率

示例

from functools import lru_cache

@lru_cache(maxsize=100)
def expensive_tool(query: str) -> str:
    # 复杂计算或API调用
    import time
    time.sleep(1)  # 模拟耗时操作
    return f"结果:{query}"

九、总结:LangChain v1.0+ Tools模块的价值

LangChain v1.0+的Tools模块为大模型应用开发带来了以下价值:

  1. 扩展模型能力:通过工具集成,使模型能够使用外部功能,突破模型本身的能力限制。
  2. 标准化接口:提供了统一的工具接口和调用机制,简化了工具的开发和使用。
  3. 类型安全:通过StructuredTool和Pydantic模型,实现了类型安全的工具调用。
  4. 模块化设计:支持工具的模块化组织,提高了代码的可维护性和可重用性。
  5. 智能集成:与Agent框架无缝集成,使模型能够智能地选择和使用工具。
  6. 丰富的内置工具:提供了大量开箱即用的工具,涵盖信息查询、文件操作、数据处理等多个领域。
  7. 版本兼容性:v1.0+的架构设计更加现代化,提供了更好的开发者体验和更强大的功能。
  8. 最佳实践:提供了丰富的最佳实践,如工具描述编写、错误处理、性能优化等。

LangChain v1.0+的Tools模块不仅是一个工具管理系统,更是大模型应用与外部世界交互的桥梁。通过掌握Tools模块的使用,你可以构建更加智能、强大、实用的大模型应用,将AI的能力真正落地到实际业务中。

无论你是开发简单的信息查询工具,还是复杂的多Agent系统,LangChain v1.0+的Tools模块都能为你提供强大的支持。现在就开始使用这些功能,开启你的大模型应用开发之旅吧!

参考链接

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐