You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将类成员函数作为LangGraph工具时遇TypeError问题求助

问题描述

使用LangChain和LangGraph开发智能体,希望工具仅能在本地目录内进行文件交互,因此将工具集实现为类的成员函数,通过类实例存储本地目录路径。但调用智能体触发工具时出现错误:

TypeError: StructuredTool._run() got multiple values for argument 'self'
错误原因

LangChain的@tool装饰器会将函数转换为StructuredTool对象,当直接装饰类的实例方法时,装饰器无法正确处理方法的self参数(类实例的引用)。调用工具时,会同时传递StructuredTool自身的self和类实例的self,导致参数冲突。

正确实现方式

方案一:手动创建Tool并绑定类实例

取消@tool装饰器,在get_tools方法中手动创建工具对象,将类实例的方法包装进去:

from langchain.tools import tool
from pathlib import Path

class FileInterface:
    def __init__(self):
        self.localdir = Path.cwd()

    def get_tools(self):
        return [
            # 手动创建工具,绑定当前实例的方法
            tool(
                func=self.read_file,
                name="read_file",
                description="Tool for reading file at path, restricted to local directory"
            ),
            # 其他工具同理
        ]
    
    def read_file(self, path: str) -> str:
        """读取指定路径的文件,仅允许访问本地目录内的文件"""
        target_path = Path(path).resolve()
        if not target_path.is_relative_to(self.localdir):
            raise ValueError(f"文件 {path} 位于允许目录 {self.localdir} 之外")
        return target_path.read_text()

方案二:继承BaseTool实现自定义工具类

为每个工具创建继承自BaseTool的类,将共享的本地目录作为类属性传入,这种方式扩展性更强:

from langchain_core.tools import BaseTool
from langchain_core.pydantic_v1 import BaseModel, Field
from pathlib import Path

# 定义工具输入参数模型
class ReadFileInput(BaseModel):
    path: str = Field(description="要读取的文件路径")

class ReadFileTool(BaseTool):
    name = "read_file"
    description = "读取指定路径的文件,仅允许访问本地目录内的文件"
    localdir: Path  # 共享的本地目录路径

    def _run(self, path: str) -> str:
        target_path = Path(path).resolve()
        if not target_path.is_relative_to(self.localdir):
            raise ValueError(f"文件 {path} 位于允许目录 {self.localdir} 之外")
        return target_path.read_text()

class FileInterface:
    def __init__(self):
        self.localdir = Path.cwd()

    def get_tools(self):
        return [
            ReadFileTool(localdir=self.localdir),
            # 其他工具可类似实现,如write_file等
        ]

方案三:使用functools.partial绑定实例

通过functools.partial将类实例绑定到工具方法,避免参数冲突:

from functools import partial
from langchain.tools import tool
from pathlib import Path

class FileInterface:
    def __init__(self):
        self.localdir = Path.cwd()

    def get_tools(self):
        # 使用partial绑定当前实例到方法
        bound_read_file = partial(self.read_file)
        # 为绑定后的方法添加工具装饰
        read_tool = tool(bound_read_file, name="read_file", description="读取本地目录内的文件")
        return [read_tool]
    
    def read_file(self, path: str) -> str:
        target_path = Path(path).resolve()
        if not target_path.is_relative_to(self.localdir):
            raise ValueError(f"文件 {path} 位于允许目录 {self.localdir} 之外")
        return target_path.read_text()
验证调用

修改后,智能体的初始化和调用代码保持不变即可正常运行:

file_interface = FileInterface()
agent = create_agent(
    model=init_model(...),
    state_schema=MyState,
    tools=file_interface.get_tools(),
    system_prompt="You are a helpful agent that can only interact with files in the local directory",
    checkpointer=InMemorySaver()
)

print(agent.invoke({"messages":[{"role":"human","content":"tell me the contents of file example.txt"}]}, context=context))

内容的提问来源于stack exchange,提问作者FLKR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 02:54:53