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 返回的原始数据、链接等,方便排查问题。

相关推荐
eqwaak02 小时前
PyTorch张量操作全攻略:从入门到精通
开发语言·人工智能·pytorch·python
A懿轩A2 小时前
Ghostty:告别 Mac 毛坯终端,打造 2026 最丝滑的 Ghostty AI 开发驾驶舱——Claude Code 团队也在用
python·macos·策略模式
Chasing Aurora2 小时前
python 安装依赖和导入模块 详解
开发语言·python·虚拟环境·import·pyenv·requirements
念恒123062 小时前
Python(for循环)
python·学习
咱那飘逸的长发2 小时前
Trae java项目配置全局maven和jdk
java·python·maven
码界筑梦坊2 小时前
116-基于Flask的健身房会员锻炼数据可视化分析系统
python·信息可视化·数据分析·flask·毕业设计
wcy_10112 小时前
QCoder智能生成Excel数据清洗与可视化代码
python·excel
财经资讯数据_灵砚智能3 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年5月2日
人工智能·python·信息可视化·自然语言处理·ai编程
skiy3 小时前
SpringBoot项目中读取resource目录下的文件(六种方法)
spring boot·python·pycharm