LangChain:创建工具Ⅰ

1.创建工具

在 LangChain 中,工具是实现特定功能的可调用单元,供大模型在需要时调用。创建工具的核心,是为模型提供清晰的工具信息,包括工具名称、描述、参数,让模型知道有什么工具、能做什么、怎么用

1.1 使用 @tool 装饰器创建工具

@tool 装饰器是定义工具最简单的方式,它会自动从函数中提取工具信息。

工具需要的核心属性

为什么这些属性必不可少?

  1. 工具名称:让 LLM 知道可以调用哪些工具。
  2. 工具描述:作为提示词的一部分,告诉模型工具的能力与用途。
  3. 工具参数:定义输入数据的结构,让模型知道如何传参。

这些信息会被整理成 tool schema,LLM 会基于这个 Schema 来决定是否调用工具、如何调用工具。


模式 1:依赖 Pydantic 类

如果使用 @tool 定义工具时,函数没有提供文档字符串(docstring),运行会直接报错:

复制代码
ValueError: Function must have a docstring if description not provided.

这是因为 @tool 会自动从 docstring 中提取工具描述,没有 docstring 就无法生成完整的工具 Schema。

此时可以通过 Pydantic 类配合 args_schema 参数,手动定义工具参数的描述:

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

class AddInput(BaseModel):
    """两数相加"""
    a: int = Field(..., description="第一个整数")
    b: int = Field(..., description="第二个整数")

@tool(args_schema=AddInput)
def multiply(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

print(multiply.invoke({"a": 2, "b": 3}))  # 输出:6
  • args_schema 会告诉 @tool 从 Pydantic 类中提取参数描述,自动完成数据校验。
  • Field(..., description="xxx") 会为每个参数添加描述,让模型理解参数含义。

模式 2:依赖 Annotated

也可以通过 typing_extensions.Annotated 直接在参数上添加描述,无需额外定义 Pydantic 类:

python 复制代码
from langchain_core.tools import tool
from typing_extensions import Annotated

@tool
def add(
    a: Annotated[int, ..., "First integer"],
    b: Annotated[int, ..., "Second integer"]
) -> int:
    """Add two integers."""
    return a + b

@tool
def multiply(
    a: Annotated[int, ..., "First integer"],
    b: Annotated[int, ..., "Second integer"]
) -> int:
    """Multiply two integers."""
    return a * b

print(add.invoke({"a": 2, "b": 3}))  # 输出:5
print(multiply.invoke({"a": 2, "b": 3}))  # 输出:6

Annotated 会直接把参数描述传递给工具 Schema,实现和 Pydantic 类类似的效果,代码更简洁。


1.2 使用 StructuredTool 类创建工具

StructuredTool 是 LangChain 提供的更灵活的工具定义方式,支持从函数创建工具,还能自定义更多细节。核心方法是 from_function,其定义如下:

python 复制代码
@classmethod
def from_function(
    func: Callable | None = None,
    coroutine: Callable[..., Awaitable[Any]] | None = None,
    name: str | None = None,
    description: str | None = None,
    args_schema: type[BaseModel] | dict[str, Any] | None = None,
    infer_schema: bool = True,
    *,
    response_format: Literal["content", "content_and_artifact"] = "content",
    parse_docstring: bool = False,
    error_on_invalid_docstring: bool = False,
    **kwargs: Any,
) -> "StructuredTool":

关键参数说明:

参数 说明
func 要设置的工具函数
coroutine 要设置的异步工具函数
name 工具名称,默认取函数名
description 工具描述,默认取函数的 docstring
args_schema 工具输入参数的 Schema,默认自动推断
response_format 工具响应格式,默认 content

1.2.1 示例 1:常规用法

最基础的用法,直接从函数创建工具:

python 复制代码
from langchain_core.tools import StructuredTool

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

calculator_tool = StructuredTool.from_function(func=multiply)
print(calculator_tool.invoke({"a": 2, "b": 3}))  # 输出:6

此时工具的名称、描述、参数信息,都会自动从函数和 docstring 中提取。


1.2.2 示例 2:加入配置,依赖 Pydantic 类

同样的,让工具函数不提供描述、文档字符串等需要传递给工具 Schema 的内容,如下所示:

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

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

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

calculator_tool = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="两数相乘",
    args_schema=CalculatorInput
)

print(calculator_tool.name)        # 输出:Calculator
print(calculator_tool.description) # 输出:两数相乘
print(calculator_tool.invoke({"a": 2, "b": 3}))  # 输出:6
  • name:自定义工具名称,覆盖默认的函数名。
  • description:自定义工具描述,覆盖默认的 docstring。
  • args_schema:通过 Pydantic 类定义参数 Schema,提供更详细的参数说明。

1.2.3 示例 3:加入 response_format 配置

response_format 支持两种模式:

  • content(默认):工具仅返回 ToolMessagecontent 属性(文本结果)。
  • content_and_artifact:工具同时返回 contentartifact,前者给大模型使用,后者保存原始数据,方便后续日志、分析、调试。

比如调用搜索工具时,content 是给模型看的摘要信息,artifact 可以是完整的搜索结果(包含链接、原文等)。

下面是 content_and_artifact 的示例:

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

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

def multiply(a: int, b: int) -> Tuple[str, List[int]]:
    """Multiply two numbers and return content and artifact."""
    nums = [a, b]
    content = f"{a} 与 {b} 相乘的结果是 {a * b}"
    return content, nums

calculator_tool = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="两数相乘",
    args_schema=CalculatorInput,
    response_format="content_and_artifact"
)

# 直接调用时,返回 (content, artifact) 元组
print(calculator_tool.invoke({"a": 2, "b": 3}))  
# 输出:('2 与 3 相乘的结果是 6', [2, 3])

如果是大模型调用工具,工具会返回一个 ToolMessage,包含 contentartifact 属性:

python 复制代码
# 模拟大模型调用工具的流程
from langchain_core.messages import ToolCall, ToolMessage

tool_call = ToolCall(name="Calculator", args={"a": 2, "b": 3}, id="123")
result = calculator_tool.invoke(tool_call)

print(isinstance(result, ToolMessage))  # True
print(result.content)    # 2 与 3 相乘的结果是 6
print(result.artifact)   # [2, 3]

💡 注意:artifact 是不直接给大模型使用的,主要是为了后续的日志、分析、调试,比如保存 API 返回的原始数据、链接等,方便排查问题。

相关推荐
geovindu9 小时前
python:Coroutines Pattern
开发语言·python·设计模式·协程模式
A.说学逗唱的Coke9 小时前
【运维专题】playbooks保姆级使用指南
运维·开发语言·python
2601_961845159 小时前
2026四级作文预测题|英语四级写作押题+提纲PDF
java·c语言·数据库·c++·python·pdf·php
高洁019 小时前
用知识图谱重构搜索引擎
人工智能·python·数据挖掘·virtualenv·知识图谱
广州灵眸科技有限公司9 小时前
3Tops NPU + 4核高性能架构:灵眸科技EASY-EAI-PI2开发板,为边缘AI开启“easy模式”
服务器·前端·人工智能·python·科技·深度学习·架构
RS&9 小时前
DAHITI水位数据产品批量下载(python)
python
27669582929 小时前
逆向视角解决:wsgsig dd03/dd05算法生成
python·滴滴出行·dd03·dd05·wsgsig·wsgsig算法·wsgsig逆向
AC赳赳老秦9 小时前
技术文章素材收集自动化:用 OpenClaw 自动爬取行业资讯、技术热点、优质文章
运维·开发语言·python·自动化·wpf·deepseek·openclaw
SilentSamsara9 小时前
模型评估与超参调优:交叉验证、Optuna 与模型选择策略
人工智能·python·深度学习·机器学习·青少年编程
叫我:松哥9 小时前
基于LSTM与ARIMA的城市空气质量分析与预测系统
人工智能·python·rnn·算法·机器学习·flask·lstm