【LangChain】langchain_core.tools.tool 装饰器:创建自定义工具

langchain_core.tools.tool 装饰器详解

langchain_core.tools.tool 是 LangChain 框架中的核心组件,用于将 Python 函数转换为语言模型可调用的工具。本文详细介绍其功能、参数、使用方法、实际应用及注意事项,确保内容条理清晰、易于理解。

1. 概述

1.1 什么是 @tool 装饰器?

@tool 装饰器位于 langchain_core.tools.convert 模块,用于将 Python 函数或可运行对象转换为 BaseTool 对象,使其与 LangChain 的工具调用机制兼容。它通过分析函数签名和文档字符串,自动生成工具的名称、描述和参数模式,简化工具创建过程。该装饰器特别适合构建基于代理的系统、LangGraph 工作流或自定义链,允许模型调用外部功能并处理输出。

1.2 核心功能

  • 自动模式推断:从函数的类型提示和文档字符串生成工具模式。
  • 灵活配置:支持自定义工具名称、描述、参数模式和输出格式。
  • 工件支持:可返回工件(如图片、数据框)供下游使用,不暴露给模型。
  • 注入参数:结合 InjectedToolArg,隐藏敏感参数(如用户 ID)。
  • 版本要求:需 langchain-core>=0.2.14,工件支持需 >=0.2.19。

2. 使用方法

2.1 基本用法

@tool 应用于函数,自动生成工具:

from langchain_core.tools import tool

@tool
def add_numbers(a: int, b: int) -> int:
    """添加两个数字。"""
    return a + b

此代码创建一个名为“add_numbers”的工具,描述为“添加两个数字”,接受两个整数参数 ab,返回其和。

2.2 自定义用法

通过传递参数自定义工具属性:

@tool("custom_add", return_direct=True)
def add_numbers(a: int, b: int) -> int:
    """添加两个数字。"""
    return a + b

工具命名为“custom_add”,return_direct=True 确保输出直接返回,绕过代理处理。

2.3 直接函数转换

使用 tool 函数直接转换:

def divide(a: float, b: float) -> float:
    return a / b

divide_tool = tool(divide)

装饰器语法更简洁,适合大多数场景。

2.4 带工件的工具

支持返回工件,需设置 response_format="content_and_artifact"

@tool(response_format="content_and_artifact")
def generate_image(prompt: str) -> tuple[str, bytes]:
    """根据提示生成图片。"""
    image_data = some_image_generation_function(prompt)  # 假设的函数
    return f"图片生成:{prompt}", image_data

返回模型使用的字符串和下游使用的图片工件。

3. 参数详解

以下是 @tool 装饰器的所有参数,包括类型、默认值、描述和示例:

参数类型默认值描述
name_or_callableOptional[str | Callable]None工具名称或可调用对象。字符串时覆盖默认名称;可调用对象时指定转换目标。
runnableOptional[Runnable]None可运行对象,用于直接转换,通常在装饰器中不使用。
descriptionstr | NoneNone工具描述。优先级:参数 > 文档字符串 > 参数模式描述。
return_directboolFalse若为 True,工具输出直接返回,代理停止处理。
args_schematype[BaseModel] | dict[str, Any] | NoneNone参数模式,可为 Pydantic 模型或字典,提供验证或额外信息。
infer_schemaboolTrue若为 True,从函数签名推断模式,支持 run 方法接受字典输入。
response_formatLiteral[‘content’, ‘content_and_artifact’]‘content’输出格式:‘content’ 仅返回内容;‘content_and_artifact’ 返回内容和工件元组。
parse_docstringboolFalse若为 True,解析 Google 风格文档字符串以提取参数描述。
error_on_invalid_docstringboolTrue若为 True 且 parse_docstring=True,无效文档字符串抛出 ValueError。

3.1 参数示例

  1. name_or_callable

    @tool("custom_multiply")
    def multiply(a: int, b: int) -> int:
        """乘两个数字。"""
        return a * b
    

    工具名称设置为“custom_multiply”。

  2. runnable

    from langchain_core.runnables import RunnableLambda
    
    def func(x: str) -> str:
        return x.upper()
    
    tool_instance = tool(runnable=RunnableLambda(func), name="uppercase")
    
  3. description

    @tool(description="计算两数之和")
    def add_numbers(a: int, b: int) -> int:
        """添加两个数字。"""
        return a + b
    
  4. return_direct

    @tool(return_direct=True)
    def calculator(expression: str) -> str:
        """计算数学表达式。"""
        return str(eval(expression))  # 仅示例,实际需安全处理
    
  5. args_schema

    from pydantic import BaseModel
    
    class AddSchema(BaseModel):
        a: int
        b: int
    
    @tool(args_schema=AddSchema)
    def add_numbers(a: int, b: int) -> int:
        """添加两个数字。"""
        return a + b
    
  6. infer_schema

    @tool(infer_schema=True)  # 默认行为
    def multiply(a: int, b: int) -> int:
        """乘两个数字。"""
        return a * b
    
  7. response_format

    @tool(response_format="content_and_artifact")
    def process_data(data: str) -> tuple[str, dict]:
        """处理输入数据并生成报告。"""
        report = {"summary": data}
        return f"数据处理完成:{data}", report
    
  8. parse_docstring

    @tool(parse_docstring=True)
    def multiply(a: int, b: int) -> int:
        """
        乘两个数字。
    
        Args:
            a (int): 第一个数字。
            b (int): 第二个数字。
    
        Returns:
            int: a 和 b 的乘积。
        """
        return a * b
    
  9. error_on_invalid_docstring

    @tool(parse_docstring=True, error_on_invalid_docstring=False)
    def multiply(a: int, b: int) -> int:
        """乘两个数字。"""  # 无效文档字符串,未定义参数
        return a * b
    

4. 技术细节

  • 实现:装饰器将函数转换为 BaseTool 对象,继承自 Runnable 接口,支持 LangChain 的工具调用机制。
  • 模式影响
    • 输入模式get_input_schema().schema()):包含所有参数,包括注入参数。
    • 工具调用模式tool_call_schema.schema()):排除注入参数,模型仅生成非注入参数。
  • 版本要求:引入于 langchain-core 0.2.14,工件支持需 >=0.2.19。
  • 函数要求:支持多参数函数,推荐包含文档字符串和类型提示以提高模式准确性。

5. 实际应用

@tool 装饰器适用于以下场景:

  • 代理系统:为代理提供工具执行任务,如计算、搜索或数据更新。
  • 自定义工作流:在 LangGraph 或链中实现模块化功能,输出反馈给模型或下游组件。
  • 工件处理:生成供下游使用的工件,如图片、数据框或报告。

示例:结合注入参数

from langchain_core.tools import tool, InjectedToolArg
from typing import Annotated, List

@tool
def update_favorite_pets(pets: List[str], user_id: Annotated[str, InjectedToolArg]) -> None:
    """更新用户的收藏宠物。"""
    user_to_pets[user_id] = pets

user_id 由运行时注入,模型仅生成 pets

6. 最佳实践

  • 命名与文档:使用描述性名称和详细 Google 风格文档字符串。
  • 类型提示:包含类型注解以确保模式推断准确。
  • 限定范围:为特定任务设计工具,增强清晰度和性能。
  • 版本检查:确保安装 langchain-core>=0.2.14,工件支持需 >=0.2.19,通过 pip install -qU langchain
  • 错误处理:设置 error_on_invalid_docstring=False 以避免无效文档字符串引发错误。

7. 注意事项与限制

  • 类方法支持:在类方法上使用可能导致错误,建议在类外定义或使用 StructuredTool.from_function
  • 文档字符串格式:若 parse_docstring=True,需正确格式化 Google 风格文档字符串,否则可能抛出错误。
  • 版本依赖:部分功能(如工件支持)需特定版本。
  • 工件格式:工件需为可序列化对象(如字典、字节),以便下游处理。

8. 结论

langchain_core.tools.tool 装饰器是 LangChain 中创建自定义工具的强大工具。其自动模式推断、工件支持和灵活配置使其适合构建复杂代理系统和自定义工作流。开发者应遵循最佳实践,利用类型提示和最新版本以充分发挥其潜力。

9. 参考资料

<think>好的,用户之前问过如何开发一个基于DeepSeek的校园助手应用,现在他们又询问如何使用LangChain框架开发。我需要先回顾之前的对话,确保这次回答能衔接上。用户可能已经对校园助手应用有基本了解,现在想深入技术实现,特别是LangChain的应用。 首先,我应该介绍LangChain是什么,以及为什么在开发AI应用时使用它。用户可能不太清楚LangChain的作用,需要简明扼要的解释。比如,LangChain可以帮助集成各种AI模型,管理数据流,处理提示词等。 接下来,要结合之前的校园助手应用场景,说明LangChain如何具体应用。例如,之前提到的课程管理、校园服务、智能问答等功能,如何用LangChain来实现。可能需要分模块讲解,比如数据连接、处理流程、与DeepSeek的集成等。 用户可能需要具体的代码示例,这样他们能更直观地理解。比如,用LangChain调用DeepSeek的API,处理用户查询,访问学校数据库等。需要确保代码示例简单易懂,同时指出需要注意的地方,比如API密钥的安全性。 另外,用户可能关心开发步骤和架构设计。之前回答中提到了技术栈和系统架构,这里需要补充LangChain在其中的位置。比如,如何在后端使用LangChain来协调AI模型和其他服务,如何管理对话链和记忆模块。 还要考虑潜在的问题,比如数据隐私、处理复杂查询的效率、多步骤任务的处理等。需要给出解决方案,比如使用LangChain的Agent和Tools来分解任务,或者使用缓存机制优化性能。 最后,应该总结使用LangChain的优势,并邀请用户进一步提问,确保他们如果有更具体的问题可以得到帮助。同时,提醒用户注意合规性和安全性,与之前回答中的建议保持一致。</think>以下是使用LangChain框架开发的系统化指南,结合其核心模块和典型应用场景: --- ### 一、LangChain基础架构 #### 1. **核心组件** | 模块 | 功能描述 | |-----------------|--------------------------------------------------------------------------| | **Models** | 对接大语言模型(如DeepSeek/OpenAI) | | **Prompts** | 管理提示词模板(动态生成高质量query) | | **Chains** | 构建任务流水线(多步骤逻辑串联) | | **Memory** | 维护对话状态(短期记忆+长期记忆存储) | | **Indexes** | 连接外部数据(文档加载/向量数据库) | | **Agents** | 动态决策工具调用(如计算器/API调用) | #### 2. **典型工作流** ``` 用户输入 → [Prompt模板加工] → [LLM推理] → [工具调用] → [记忆更新] → 输出响应 ``` --- ### 二、校园助手开发实战 #### 1. **环境准备** ```python # 安装核心库 pip install langchain langchain-community langchain-core # 对接DeepSeek需要额外安装适配器(假设存在) pip install langchain-deepseek ``` #### 2. **基础问答实现** ```python from langchain_community.llms import DeepSeek from langchain_core.prompts import PromptTemplate # 初始化模型 llm = DeepSeek(api_key="YOUR_KEY", temperature=0.3) # 创建课程咨询模板 prompt = PromptTemplate.from_template( "你是一个校园助手,根据用户专业:{major}和年级:{grade}," "用中文回答关于{course}的问题。当前问题:{question}" ) # 构建链式调用 chain = prompt | llm # 执行查询 response = chain.invoke({ "major": "计算机科学", "grade": "大三", "course": "数据结构", "question": "本周实验课要准备哪些材料?" }) print(response) ``` #### 3. **工具扩展(图书馆查询)** ```python from langchain.agents import Tool, AgentExecutor from langchain.agents import create_react_agent # 自定义图书馆API工具 def search_library(query: str) -> str: # 模拟调用学校图书馆接口 return "《算法导论》可借阅,馆藏位置:A区3层CS书架" tools = [ Tool( name="LibrarySearch", func=search_library, description="用于查询图书馆藏书信息" ) ] # 创建Agent agent = create_react_agent(llm, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools) # 执行工具调用 result = agent_executor.invoke({ "input": "帮我找《算法导论》的借阅信息" }) ``` --- ### 三、关键功能实现模式 #### 1. **课程提醒系统** ```python from langchain.chains import LLMChain from langchain.memory import ConversationBufferMemory # 带记忆的对话链 memory = ConversationBufferMemory() chain = LLMChain( llm=llm, prompt=PromptTemplate.from_template( "作为课程助手,根据用户过往选课记录:{history}," "用亲切的中文风格回答:{input}" ), memory=memory ) # 模拟多轮对话 chain.invoke({"input": "我这学期选了哪些专业课?"}) chain.invoke({"input": "哪门课最近有作业要提交?"}) ``` #### 2. **文档问答系统** ```python from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain_deepseek import DeepSeekEmbeddings # 加载学生手册PDF loader = PyPDFLoader("student_handbook.pdf") pages = loader.load() # 文档处理 text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000) docs = text_splitter.split_documents(pages) # 创建向量库 embeddings = DeepSeekEmbeddings() db = FAISS.from_documents(docs, embeddings) # 构建检索链 retriever = db.as_retriever() qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever ) # 查询宿舍管理条例 qa_chain.invoke("宿舍晚上几点关门?") ``` --- ### 四、性能优化技巧 #### 1. **缓存策略** ```python from langchain.cache import SQLiteCache import langchain # 启用SQLite缓存 langchain.llm_cache = SQLiteCache(database_path=".langchain.db") ``` #### 2. **流式输出** ```python # 实现逐字输出效果 for chunk in chain.stream({"input": "解释牛顿第三定律"}): print(chunk.content, end="", flush=True) ``` #### 3. **验证与测试** ```python # 使用Pytest编写测试用例 def test_course_query(): response = chain.invoke({ "major": "物理", "question": "下周的电磁学实验地点" }) assert "实验楼B栋" in response ``` --- ### 五、部署方案 #### 1. **API服务化** ```python from fastapi import FastAPI from langserve import add_routes app = FastAPI() add_routes(app, chain, path="/course-assistant") ``` #### 2. **监控指标** | 指标 | 监控方式 | |-----------------|--------------------------| | 响应延迟 | Prometheus + Grafana | | API调用错误率 | Sentry异常捕获 | | Token消耗 | 自定义中间件统计 | --- ### 六、典型问题解决方案 1. **长上下文处理** - 使用`LongContextReorder`优化文档检索顺序 - 采用Map-Reduce策略分割长文本 2. **多模态扩展** ```python from langchain_community.document_loaders import ImageCaptionLoader # 处理校园地图图片 loader = ImageCaptionLoader("campus_map.jpg") img_description = loader.load() ``` 3. **权限控制** ```python # 添加角色验证装饰器 def require_student(func): def wrapper(user_role, *args, **kwargs): if user_role != "student": raise PermissionError("仅限学生访问") return func(*args, **kwargs) return wrapper ``` 如果需要具体场景的完整代码实现(如课程表同步Agent),可以提供更详细的需求说明!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彬彬侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值