langchain-ai / langchain

🦜🔗 Build context-aware reasoning applications
https://python.langchain.com
MIT License
92.39k stars 14.77k forks source link

early_stopping_method parameter of AgentExecutor doesn’t work in expected way #16374

Closed Aaalexyyy closed 7 months ago

Aaalexyyy commented 7 months ago

Checked other resources

Example Code

tools = [get_news, solve_math_problem]

agent = ZeroShotAgent()
agent_executor = AgentExecutor.from_agent_and_tools(
            agent=agent,
            tools=tools,
            verbose=False,
            max_iterations=1
            early_stopping_method="generate",
            return_intermediate_steps=True,
            handle_parsing_errors=True,
)
result = agent_executor.invoke(
                input={
                    "input": user_query,
                },
)

Description

We find that if the agent reaches the maximum steps, but it still wants to use tools to solve question, then the final answer will become the input for the next step, rather than a real final answer. This problem cannot be solved just by setting the right parameters.

e.g. Input: News Tesla? and root of 18376?

Output:

('Action: solve_math_problem\nAction Input: square root of 18376',
 [{'input': 'Tesla',
   'output': "Tesla CEO Elon Musk has expressed ...",
   'tool': 'get_news'}])

We set max_iteration=1 just because of easily reproducing this error.

System Info

We check the function for generating the final answer and printed out the input and output.

image

new_inputs:

{
'agent_scratchpad': 
'Thought: The question has two parts: one is about the latest news on Tesla, and the other is about the root of 18376. I can use the get_news tool to find the latest news about Tesla, and the solve_math_problem tool to find the square root of 18376.\n
Action: get_news \nAction Input: Tesla\n
Observation: {
  \'input\': \'Tesla\', 
  \'output\': "Tesla\'s CEO Elon Musk has sparked speculation about his ownership stake in the company after expressing 
  his reluctance to develop Tesla into a leader in artificial intelligence (AI) and robotics …", 
}\n
Thought:\n\nI now need to return a final answer based on the previous steps:', 
'stop': ['\nObservation:', '\n\tObservation:']
}

full_output:

: Action: solve_math_problem Action Input: root of 18376

My guess is that in agent_scratchpad prompt has clear information that The question has two parts ... and doesn’t include the actual user query News Tesla? and root of 18376? Therefore, LLM may be confused about the meaning of final answer. Is final answer for initial user query or for previous steps?

Please review this issue. Thank you!

Related Components

dosubot[bot] commented 7 months ago

🤖

Hello @Aaalexyyy! I'm Dosu, a friendly bot here to help you with your LangChain repository issues. Rest assured, I'm here to assist in debugging, answering questions, and maybe even nudging you towards becoming a contributor. While waiting for a human maintainer, I'll be your first line of assistance. Let me dive right into your issue and I'll get back to you with a comprehensive answer in a jiffy!

hwchase17 commented 7 months ago

I believe this is an issue with the prompt engineering done here.

When using generate for the early_stopping_method, it appends a string to the prompt that says "I now need to return a final answer based on the previous steps". The model is not abiding by this though

What model are you using? its possible that with worse models this doesnt work

A more explicit fix would be to modify the execution logic. There's a few ways to do this. One would be to subclass the Agent class and modify how this is handled. Another would be to submit a PR with this change. A final (our preferred) would be to replace the agent executor with LangGraph (https://github.com/langchain-ai/langgraph/blob/main/examples/agent_executor/base.ipynb). LangGraph was specifically designed to make it easy to modify the looping logic

dosubot[bot] commented 7 months ago

🤖

Thank you for the detailed issue report. It seems like the issue is indeed related to the early_stopping_method parameter of the AgentExecutor class.

The early_stopping_method parameter is used to determine the behavior of the agent when it has been stopped due to reaching the maximum number of iterations or time limit. There are two possible values for early_stopping_method: "force" and "generate".

If early_stopping_method is set to "force", the agent simply returns a constant string indicating that it has been stopped due to reaching the maximum number of iterations or time limit.

If early_stopping_method is set to "generate", the agent does one final forward pass, generates a final prediction based on the previous steps, and tries to extract a final answer. If it can extract a final answer, it returns it. If it can extract an answer but the tool is not the final tool, it returns the full output. If it cannot extract an answer, it raises a ValueError.

From your description, it seems like the agent is not able to extract a final answer when early_stopping_method is set to "generate", and thus it returns the full output, which becomes the input for the next step. This could be due to the way the return_stopped_response method is implemented in the Agent class.

To fix this issue, you might need to check the implementation of the return_stopped_response method in the Agent class. Make sure it correctly handles the early_stopping_method parameter and returns the appropriate output when the agent is stopped prematurely.

You can find the relevant code in the Agent class and the AgentExecutorIterator class in the LangChain codebase.

I hope this helps! If you have any further questions, feel free 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.

Aaalexyyy commented 7 months ago

@hwchase17 Thanks for your reply. I used gpt-4-32k but it still has this problem. We took your first suggestion and rewrote a chain to get the final answer. And we also notived another issue. We are migrating our application to latest langchain version where we used create_react_agent and AgentExecutor to create ReAct agent. However, it doesn't support "generate" early_stopping_method. In langchain code it seems that not every agent implements two stopping methods.

https://github.com/langchain-ai/langchain/blob/54fcd476bb3ce089eac92aa1e6838ac31215150a/libs/langchain/langchain/agents/agent.py#L255

https://github.com/langchain-ai/langchain/blob/54fcd476bb3ce089eac92aa1e6838ac31215150a/libs/langchain/langchain/agents/agent.py#L114