
langchain 代理在调用自定义工具时意外传入 `arg1` 参数,导致 `typeerror`,根本原因是工具签名未被正确识别——使用 `basetool` 子类时未声明 `args_schema`,而 langchain v0.1+ 默认采用 pydantic 模型解析参数,需显式定义输入结构。
在 LangChain(尤其是 v0.1.x 及以上版本)中,当 Agent 执行工具调用时,它不再简单地将字典解包为位置参数,而是基于工具的输入 schema 进行结构化解析。若你继承 BaseTool 但未定义 args_schema,LangChain 会 fallback 到一个默认行为:将传入的单个参数字典(如 {'arg1': '...'})强行映射为名为 arg1 的关键字参数,从而引发 _run() 方法接收未声明参数的错误。
✅ 正确做法:为 BaseTool 显式声明 args_schema
你需要使用 Pydantic BaseModel 定义输入结构,并将其赋值给 args_schema 类属性:
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
class SQLFilterInput(BaseModel):
query_input: str = Field(..., description="用户自然语言查询,例如 '2023年8月计算机设备的平均温度'")
class SQLFilterTool(BaseTool):
name = "filter_user_query"
description = "根据用户自然语言问题生成结构化SQL过滤条件(用于后端数据筛选)"
args_schema: type[BaseModel] = SQLFilterInput # ← 关键!必须显式声明
def _run(self, query_input: str) -> str:
return sql_filter_vanna(query_input)
async def _arun(self, query_input: str) -> str:
# 注意:_arun 应为 async def,且返回 awaitable 或使用 asyncio.to_thread(如需同步函数)
return await asyncio.to_thread(sql_filter_vanna, query_input)⚠️ 注意事项:args_schema 必须是 pydantic.BaseModel 的子类,字段名需与 _run 方法参数名严格一致(此处为 query_input);若 _run 接收多个参数(如 query_input: str, db_name: str),则 SQLFilterInput 中需对应定义全部字段;async def _arun 的签名也应与 _run 保持语义一致(参数名可不同,但逻辑输入应匹配);
✅ 更简洁方案:优先使用 @tool 装饰器(推荐)
正如答案中所示,@tool 是 LangChain 官方推荐的轻量级工具定义方式,它自动推导 schema(基于类型注解 + docstring),无需手动管理 BaseModel:
from langchain.agents import tool
@tool
def filter_user_query(query_input: str) -> str:
"""根据用户自然语言问题生成SQL过滤条件。
例如输入:"2023年8月计算机设备的平均温度" → 输出:"WHERE device_type = 'computer' AND month = 8 AND year = 2023"
"""
return sql_filter_vanna(query_input)该方式自动注册为 Tool 实例,支持多参数、类型校验、描述提取,且与最新 Agent(如 OpenAIToolsAgent、ReactAgent)完全兼容。
? 补充说明:为什么之前能运行,现在报错?
- 你提到“几天前代码正常”,大概率是升级了 LangChain 版本(如从 0.0.x 升至 0.1.0+);
- 旧版 LangChain 对 BaseTool 的参数解析较宽松,新版强化了 schema 驱动机制以提升可靠性与可调试性;
- @tool 装饰器在各版本中行为更稳定,是生产环境首选。
✅ 总结
| 方案 | 是否推荐 | 关键要求 |
|---|---|---|
| BaseTool 子类 | ⚠️ 仅需高度定制时用 | 必须实现 args_schema,字段名与 _run 参数严格对齐 |
| @tool 装饰器 | ✅ 强烈推荐 | 使用类型注解 + docstring,零配置即用 |
选择 @tool 可大幅降低维护成本,避免隐式参数映射陷阱。如需扩展功能(如异步支持、自定义序列化),再考虑 BaseTool 并严格遵循 schema 规范。










