[tool_name] is not a valid tool, try one of [tool_name]
Labels: name: area: agent, name: area: vector store, name: auto:bug

### Issue you'd like to raise.

I am using Opensearch as vector database in langchain to store the documents and using tools to integrate it with agent to look for the information when we pass any query and to use GPT model to get the enhanced response.

I am facing tool not valid issue while running the code. Any suggestions to fix the error.

Error: Observation:[faq] is not a valid tool, try one of [faq].

Code:

import re
from langchain import OpenAI, PromptTemplate, VectorDBQA, LLMChain
from langchain.agents import Tool, initialize_agent, AgentExecutor, AgentOutputParser, LLMSingleActionAgent
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import ConversationChain, RetrievalQA
from langchain.chains.conversation.memory import ConversationBufferMemory, ConversationSummaryBufferMemory,
    CombinedMemory
import pypdf
from langchain.prompts import StringPromptTemplate
from langchain.schema import HumanMessage, AgentAction, AgentFinish
from langchain.text_splitter import CharacterTextSplitter
from langchain.tools import BaseTool
from langchain.memory import ConversationBufferWindowMemory
import os
from typing import List, Union, Optional
from langchain.memory import ConversationSummaryBufferMemory
from langchain.vectorstores import Chroma, OpenSearchVectorSearch

os.environ['OPENAI_API_KEY'] = "api_key"


embeddings = OpenAIEmbeddings()
llm = OpenAI(temperature=0.7)
docsearch = OpenSearchVectorSearch(
    index_name="customer_data",
    embedding_function=embeddings,
    opensearch_url="host_url",
)

qa = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=docsearch.as_retriever(),
)


tools = [
    Tool(
        name="faq",
        func=qa.run(),
        description="Useful when you have to answer FAQ's"
    )]

template = """Your are a support representative, Customers reaches you for queries. refer the tools and answer.
You have access to the following tools to answer the question. 
{tools}


Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, can be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question.

Begin!
Previous conversation history:
{history}

New Question: {input}
{agent_scratchpad}"""



# Set up a prompt template
class CustomPromptTemplate(StringPromptTemplate):
    # The template to use
    template: str
    # The list of tools available
    tools: List[Tool]

    def format(self, **kwargs) -> str:
        # Get the intermediate steps (AgentAction, Observation tuples)
        # Format them in a particular way
        intermediate_steps = kwargs.pop("intermediate_steps")
        thoughts = ""
        for action, observation in intermediate_steps:
            thoughts += action.log
            thoughts += f"\nObservation: {observation}\nThought: "
        # Set the agent_scratchpad variable to that value
        kwargs["agent_scratchpad"] = thoughts
        # Create a tools variable from the list of tools provided
        kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
        # Create a list of tool names for the tools provided
        kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
        return self.template.format(**kwargs)


prompt = CustomPromptTemplate(
    template=template,
    tools=tools,
    # This omits the `agent_scratchpad`, `tools`, and `tool_names` variables because those are generated dynamically
    # This includes the `intermediate_steps` variable because that is needed
    input_variables=["input", "intermediate_steps", "history"]
)


# Custom Output Parser. The output parser is responsible for parsing the LLM output into AgentAction and AgentFinish. This usually depends heavily on the prompt used. This is where you can change the parsing to do retries, handle whitespace, etc


class CustomOutputParser(AgentOutputParser):

    def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
        # Check if agent should finish
        if "Final Answer:" in llm_output:
            return AgentFinish(
                # Return values is generally always a dictionary with a single `output` key
                # It is not recommended to try anything else at the moment :)
                return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
                log=llm_output,
            )
        # Parse out the action and action input
        regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
        match = re.search(regex, llm_output, re.DOTALL)
        print(match)
        if not match:
            raise ValueError(f"Could not parse LLM output: `{llm_output}`")
        action = match.group(1).strip()
        action_input = match.group(2)
        # Return the action and action input
        return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)


output_parser = CustomOutputParser()

# Set up LLM !

llm = OpenAI(temperature=0, model_name='gpt-3.5-turbo')

# Define the stop sequence. This is important because it tells the LLM when to stop generation. This depends heavily on the prompt and model you are using. Generally, you want this to be whatever token you use in the prompt to denote the start of an Observation (otherwise, the LLM may hallucinate an observation for you).

# Set up the Agent


# LLM chain consisting of the LLM and a prompt
llm_chain = LLMChain(llm=llm, prompt=prompt)

tool_names = [tool.name for tool in tools]

agent = LLMSingleActionAgent(
    llm_chain=llm_chain,
    output_parser=output_parser,
    stop=["\nObservation:"],
    allowed_tools=tool_names
)

# Agent Executors take an agent and tools and use the agent to decide which tools to call and in what order.



convo_memory = ConversationBufferMemory(
    memory_key="chat_history_lines",
    input_key="input"
)

summary_memory = ConversationSummaryBufferMemory(llm=llm, memory_key="chat_history", input_key="input")

memory = CombinedMemory(memories=[convo_memory, summary_memory], memory_key="story")

agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent,
    tools=tools,
    verbose=True,
    memory=memory
)

si = input("Human: ")
agent_executor.run({'history': memory, 'input': si})

### Suggestion:

_No response_