langchain-ai / langchain

πŸ¦œπŸ”— Build context-aware reasoning applications
https://python.langchain.com
MIT License
94.89k stars 15.37k forks source link

Message History not working with LLMSingleActionAgent #10783

Closed Daniel199438 closed 1 year ago

Daniel199438 commented 1 year ago

System Info

My systeminfo:

langchain 0.0.294 Python 3.11

Who can help?

Im not sure, maybe @hwchase17 and @agola11 can help

Information

Related Components

Reproduction

That is my code:

    openai.api_key = config.openai_api_key

    llm = ChatOpenAI(temperature=1, model="gpt-3.5-turbo-16k", max_tokens=1024)

    used_tools = []

    for tool in tools_to_use:
        vector_store = get_vector_store(tool.get("collection"))
        index = VectorStoreIndex.from_vector_store(vector_store=vector_store, service_context=service_context)

        vector_store_info = VectorStoreInfo(
            content_info=tool.get("description"),
            metadata_info=[]
        )
        retriever = VectorIndexAutoRetriever(index, vector_store_info=vector_store_info)

        used_tools.append(
            Tool(
                name=tool.get("name"),
                description=tool.get("description"),
                func=lambda q: str(retriever.retrieve(q)),
            )
        )

    message_history = PostgresChatMessageHistory(
        connection_string=f"postgresql://postgres:{postgres_str}", session_id=session_id, table_name="chat_history",
    )

    prompt = CustomPromptTemplate(template=get_prompt_template(), tools=used_tools,
                                  input_variables=["input", "intermediate_steps", "chat_history"])

    output_parser = CustomOutputParser()

    memory = ConversationBufferMemory(
        memory_key="chat_history", chat_memory=message_history
    )

    llm_chain = LLMChain(llm=llm, prompt=prompt)

    tool_names = [tool.name for tool in used_tools]

    agent = LLMSingleActionAgent(
        llm_chain=llm_chain,
        output_parser=output_parser,
        stop=["\nFinal Answer:"],  # Observation
        allowed_tools=tool_names,
        handle_parsing_errors=True,
    )

    agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=used_tools, verbose=debug,
                                                        memory=memory, return_intermediate_steps=True)

    response = agent_executor(user_prompt)

Expected behavior

If i print the params, it shows my chat history (so it's successfully loaded into code and into the agent).

{'intermediate_steps': [], 'stop': ['\nFinal Answer:'], 'input': 'What was the last thing I said?', 'chat_history': 'Human: ....?\nAI:....']

It should also process the chat history correctly. But I always get this answer to my prompt:

Since the previous chat history is not available, I can't tell what you said last. Please give me more information or ask your question again so I can help you further.
dosubot[bot] commented 1 year ago

πŸ€–

Hello,

Thank you for providing detailed information about your issue. Based on the code you've shared and the context provided, it seems like you're having trouble with the LLMSingleActionAgent not processing the chat history correctly.

From the context provided, there are a few similar issues that have been solved in the LangChain repository. Here are some potential solutions based on those issues:

  1. Check the keys used in your inputs and outputs dictionaries and ensure that the add_user_message and add_ai_message methods are correctly adding the messages to the agent's memory. You can refer to these issues for more details: initialize_agent not saving and returning messages in memory and Initialize_agent not storing messages when memory is present.

  2. Add more clarity to your prompt to distinguish between new input and chat history. This was the solution provided in this issue: Agent + Memory causing issues with tool interaction. The prompt should clearly differentiate between the previous chat history and the new input.

Regarding the PostgresChatMessageHistory and ConversationBufferMemory classes, the PostgresChatMessageHistory class handles the storage and retrieval of chat message history in a PostgreSQL database. It retrieves all messages associated with the current session_id from the PostgreSQL database, ordered by their id. It also appends new messages to the record in the PostgreSQL database. However, the context does not provide any information about the ConversationBufferMemory class or how it interacts with the PostgresChatMessageHistory class.

The LLMSingleActionAgent class handles chat history and memory through the intermediate_steps parameter in its plan and aplan methods. These steps represent the history of actions taken by the language model and their corresponding observations. The plan and aplan methods use this chat history to decide what to do next.

I hope this information helps you in resolving your issue. If you need further assistance, please provide more details about the specific error messages you're encountering or the unexpected behavior you're observing.

Best, Dosu

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a πŸ‘ if this is helpful and πŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

Daniel199438 commented 1 year ago

@dosu-bot

I checked the input and output keys and printed it out. Also the Postgres DB saved all messages like it should.

Thats the suffix of my prompt template:

Start.

Previous chat history:

{chat_history}

End of the previous chat history

Question: {input} 

{agent_scratchpad}

So I think that distinguishes enough between my other parts and the chat history too.

Do you have other solutions or do you know how can I test if the LLMSingleActionAgent really exchanged the chat_history variable with the chat history?

dosubot[bot] commented 1 year ago

πŸ€–

Hello,

Thank you for providing a detailed description of your issue. Based on the context provided, it seems like you've already done a good job of setting up your LLMSingleActionAgent and ensuring that your chat history is being saved correctly in the Postgres DB.

From the similar issues you've found in the LangChain repository, it seems that the problem might be related to how the save_context method in the ConversationBufferMemory class is functioning. This method is responsible for saving the context of the model run to memory. It retrieves the input and output strings from the inputs and outputs dictionaries, respectively, and then calls the add_user_message and add_ai_message methods to add the user and AI messages to the agent's memory.

If the inputs and outputs dictionaries do not contain the expected keys or if the add_user_message and add_ai_message methods are not functioning as expected, the agent might not store any messages in memory. In your case, you need to ensure that the keys used in self._get_input_output(inputs, outputs) correctly correspond to the keys used to store the input and output strings in the inputs and outputs dictionaries. Additionally, you need to ensure that the add_user_message and add_ai_message methods are correctly adding the messages to the agent's memory.

As for testing if the LLMSingleActionAgent is correctly exchanging the chat_history variable with the actual chat history, you can try to print out the agent_scratchpad after each interaction with the agent. The agent_scratchpad should contain a list of BaseMessage objects that represents the agent's thought process, which includes the chat history. If the agent_scratchpad is not being updated correctly, then there might be an issue with how the LLMSingleActionAgent is handling the exchange of the chat_history variable.

I hope this helps! If you have any other questions or need further clarification, please don't hesitate to ask.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a πŸ‘ if this is helpful and πŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

Daniel199438 commented 1 year ago

@dosu-bot

I printed the agent_scratchpad how you suggested and checked the methods and everything works as expected. The agent also remembers last topics if asked indirectly but if I ask directly tell me about my last message or smth like that. He always tells me that he can not tell me about it, bc he doesnt have access to the chat history.

Maybe the error is at my prompt template: So here is a part of it:

To get more information, you have access to the following tools:

{tools}

Use the following format:

Question: the input question you need to answer.

Thought: Begin with an assessment of the question or task.

Action: the name of the tool to be used. Must be one of [{tool_names}]. Nothing else. If no action is required and none of the existing tools are eligible, then simply enter a 'None' here.

Action Input: Specific keywords to search the tool with to get the desired information.

Observation: The result of the action.... Check if the required information is available, if not repeat it. Keep in mind that each answer should be as detailed as possible across all topics. (This Thought/Action/Action Input/Observation cycle can be repeated as needed).

Thought: Summarize the key findings. Ensure that the input selection is accurate and factual. Evaluate both advantages and disadvantages of the solution or answer. Inform the user if speculated or predicted, and cite all sources cited.

Final Answer: Provide a final, well-organized, factual answer and is as comprehensive as possible with all information found. Always include the URL (if included) and other meta data of the source. Ask the user if further assessment is desired.

Begin.

Previous chat history consisting of messages between human and AI:

{chat_history}

End of previous chat history

Question: {input} 

{agent_scratchpad}
dosubot[bot] commented 1 year ago

πŸ€–

Hello,

Thank you for providing a detailed description of your issue. Based on the context provided, it seems like you're facing an issue with the LLMSingleActionAgent not processing the chat history correctly.

From the similar issues found in the LangChain repository, it appears that the problem might be related to how the save_context method in the ConversationBufferMemory class is functioning. The save_context method is responsible for saving the context of the model run to memory. It retrieves the input and output strings from the inputs and outputs dictionaries, respectively, and then calls the add_user_message and add_ai_message methods to add the user and AI messages to the agent's memory.

If the inputs and outputs dictionaries do not contain the expected keys or if the add_user_message and add_ai_message methods are not functioning as expected, the agent might not store any messages in memory. In your case, you need to ensure that the keys used in self._get_input_output(inputs, outputs) correctly correspond to the keys used to store the input and output strings in the inputs and outputs dictionaries. Additionally, you need to ensure that the add_user_message and add_ai_message methods are correctly adding the messages to the agent's memory.

Regarding the LLMSingleActionAgent, it interacts with the chat history through the intermediate_steps parameter in its plan and aplan methods. The intermediate_steps parameter is a list of tuples, where each tuple contains an AgentAction and an observation. The AgentAction represents the action taken by the agent, and the observation is the response from the language model. The LLMSingleActionAgent uses these intermediate steps to decide the next action.

In the plan and aplan methods, the LLMSingleActionAgent uses the intermediate_steps to create the full inputs for the LLMChain. This is done in the get_full_inputs method, where the LLMSingleActionAgent constructs a scratchpad that lets the agent continue its thought process. The scratchpad is constructed by iterating over the intermediate_steps and appending the log of each action and the corresponding observation.

I hope this helps! If you have any other questions or need further clarification, please let me know.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a πŸ‘ if this is helpful and πŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

Daniel199438 commented 1 year ago

@dosu-bot Thank you for your help. For anyone else struggling with similar issues:

I used this notebook and set up a memory overview tool for the agent to use when needed.

See here: https://python.langchain.com/docs/modules/agents/how_to/sharedmemory_for_tools

dosubot[bot] commented 1 year ago

πŸ€–

Hello,

Based on the information you've provided, it seems like the LLMSingleActionAgent might not be processing the chat history correctly due to a mismatch between the memory_key used in the ZepMemory instance and the key used in the agent's prompt template. The memory_key is the key used for the memory and it should match the key used in the agent's prompt template.

Here is an example of how to initialize the ZepMemory:

memory = ZepMemory(
    session_id=session_id,  # Identifies your user or a user's session
    url=ZEP_API_URL,        # Your Zep server's URL
    api_key=<your_api_key>, # Optional
    memory_key="history",   # Ensure this matches the key used in
                            # chain's prompt template
    return_messages=True,   # Does your prompt template expect a string
                            # or a list of Messages?
)
chain = LLMChain(memory=memory,...) # Configure your chain to use the ZepMemory instance

The memory overview tool can help resolve this issue by providing a visual representation of the memory usage and allowing you to inspect the keys used in the memory. This can help you identify if there is a mismatch between the memory_key and the key used in the agent's prompt template.

The LLMSingleActionAgent in the LangChain framework is a subclass of BaseSingleActionAgent and is responsible for calling the language model and deciding the action to be taken. This is driven by an LLMChain, which is a sequence of language model calls. The LLMSingleActionAgent uses the LLMChain to decide the next action based on the current state of the conversation.

The LLMSingleActionAgent interacts with the chat history through the intermediate_steps parameter in its plan and aplan methods. The intermediate_steps parameter is a list of tuples, where each tuple contains an AgentAction and an observation. The AgentAction represents the action taken by the agent, and the observation is the response from the language model. The LLMSingleActionAgent uses these intermediate steps to decide the next action.

In the plan and aplan methods, the LLMSingleActionAgent uses the intermediate_steps to create the full inputs for the LLMChain. This is done in the get_full_inputs method, where the LLMSingleActionAgent constructs a scratchpad that lets the agent continue its thought process. The scratchpad is constructed by iterating over the intermediate_steps and appending the log of each action and the corresponding observation.

In the return_stopped_response method, the LLMSingleActionAgent uses the intermediate_steps to generate a final response when the agent has been stopped due to max iterations. If the early_stopping_method is "generate", the LLMSingleActionAgent constructs a scratchpad similar to the plan and aplan methods, and then makes a final prediction using the LLMChain.

I hope this helps! If you have any other questions, feel free to ask.

Best, Dosu

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a πŸ‘ if this is helpful and πŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.