gosia
gosia

Reputation: 69

When creating LangChain custom tool, how can I add new property

I want to create a custom tool class with an additional property, let's say number. How can I change this code so that it doesn't throw an error?

Code:

from langchain.tools import BaseTool


class MyTool(BaseTool):
    name = "Whatever"
    description = "Whatever"
    
    def __init__(self):
        self.number = 123
    
    def _run(self):
        pass
    
    def _arun(self):
        pass


tool = MyTool()

Error:

ValueError: "MyTool" object has no field "number"

Upvotes: 2

Views: 2627

Answers (4)

DIMKA_4621
DIMKA_4621

Reputation: 51

I was able to solve this problem for myself! You need to define a custom class property and give it a value in __init__. Class property must be public!

from typing import Type
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun, CallbackManagerForToolRun

from .my_vector_search_class import MyVectorSearchClass


class VectorSearchSchema(BaseModel):
    query: str = Field(description="Search question or thesis")


class VectorSearchTool(BaseTool):
    name = "VectorSearch"
    description = "Use this when you need to find information from the documentation or FAQ."
    args_schema: Type[BaseModel] = VectorSearchSchema
    my_vector_search_property: MyVectorSearchClass = None

    def __init__(self):
        super().__init__()
        self.my_vector_search_property = MyVectorSearchClass()

    def _run(
        self, query: str, run_manager: CallbackManagerForToolRun = None
    ) -> str:
        context = self.my_vector_search_property.run(query)
        return context

    async def _arun(
        self, query: str, run_manager: AsyncCallbackManagerForToolRun = None
    ) -> str:
        raise NotImplementedError("VectorSearchTool does not support async")
langchain==0.2.13

Upvotes: 0

Mark Collins
Mark Collins

Reputation: 408

This worked for me

from langchain.tools import BaseTool
from langchain.pydantic_v1 import Extra

class MyTool(BaseTool):
    name = "Whatever"
    description = "Whatever"

    class Config:
      extra = Extra.allow
    
    def __init__(self, number):
      super().__init__(number=number)
      self.number = number # not needed but helps with type hinting
    
    def _run(self):
      return self.number
    
    def _arun(self):
      return self.number

tool = MyTool()

Related: https://github.com/langchain-ai/langchain/discussions/17232

Upvotes: 2

Luca Calomeni
Luca Calomeni

Reputation: 11

Try this:

from langchain.tools import BaseTool


class MyTool(BaseTool):
    name = "Whatever"
    description = "Whatever"
    number: int
        
    def __init__(self, number: int = 123):
        super(MyTool, self).__init__(number=number)
       
    def _run(self):
        print("run:", self.number)
    
    def _arun(self):
        print("arun:", self.number)
        

tool_1 = MyTool()
tool_2 = MyTool(number=321)

Upvotes: 1

ZKS
ZKS

Reputation: 2866

Please find solution below

    from langchain import LLMMathChain
    from langchain.agents import AgentType, initialize_agent
    from langchain.chat_models import ChatOpenAI
    from langchain.tools import BaseTool
    from typing import  Any

    class MyTool(BaseTool):
        name = "Custom Tool"
        description = "This tool multiplies a number by itself"

        def _run(self, number: str) -> Any:
            return float(number) * float(number)

    # Press the green button in the gutter to run the script.
    if __name__ == '__main__':

        llm = ChatOpenAI(temperature=0)
        llm_math_chain = LLMMathChain(llm=llm, verbose=True)

        tools = [MyTool()]

        agent = initialize_agent(
            tools, 
            llm, 
            agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, 
            verbose=True, max_iterations=3,
            early_stopping_method='generate'
        )

        agent(
            "Result of 5"
        )

Upvotes: 0

Related Questions