pythonlangchainvalueerrorpy-langchainlangchain-agents

ValueError: variable agent_scratchpad should be a list of base messages, got of type <class 'str'>


This is a very basic example how I am trying to use langchain to invoke a llm and find the tool to use:

import asyncio
import json
from langchain.agents import AgentExecutor, create_structured_chat_agent, Tool
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import AIMessage, ToolCall
from langchain_community.chat_models.fake import FakeMessagesListChatModel

# 1. Define a simple, predictable tool
def simple_tool_function(input: str) -> str:
    """A simple tool that returns a fixed string."""
    print(f"Tool called with input: '{input}'")
    return "The tool says hello back!"

tools = [
    Tool(
        name="simple_tool",
        func=simple_tool_function,
        description="A simple test tool.",
    )
]

# 2. Create responses that follow the structured chat format
responses = [
    # First response: Agent decides to use a tool
    AIMessage(
        content=json.dumps({
            "action": "simple_tool",
            "action_input": {"input": "hello"}
        })
    ),
    # Second response: Agent provides final answer after tool execution
    AIMessage(
        content=json.dumps({
            "action": "Final Answer",
            "action_input": "The tool call was successful. The tool said: 'The tool says hello back!'"
        })
    ),
]

# Use the modern FakeMessagesListChatModel
llm = FakeMessagesListChatModel(responses=responses)

# 3. Create the prompt using the standard structured chat prompt format
prompt = ChatPromptTemplate.from_messages([
    ("system", """Respond to the human as helpfully and accurately as possible. You have access to the following tools:

{tools}

Use a json blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).

Valid "action" values: "Final Answer" or {tool_names}

Provide only ONE action per $JSON_BLOB, as shown:

```
{{
  "action": $TOOL_NAME,
  "action_input": $INPUT
}}
```

Follow this format:

Question: input question to answer
Thought: consider previous and subsequent steps
Action:
```
$JSON_BLOB
```
Observation: action result
... (repeat Thought/Action/Observation as needed)
Thought: I know what to respond
Action:
```
{{
  "action": "Final Answer",
  "action_input": "Final response to human"
}}
```

Begin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:```$JSON_BLOB```then Observation"""),
    ("human", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

# 4. Create the agent and executor
agent = create_structured_chat_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,
    handle_parsing_errors=True,
    max_iterations=3
)

# 5. Run the agent
result = asyncio.run(agent_executor.ainvoke({"input": "call the tool"}))

Python requirements I am using:

langchain==0.3.27
langchain-community==0.3.27
langchain-core==0.3.74
langchain-aws==0.2.30
langchain-openai==0.3.29

Python version: 3.9

How do I get rid of the error ValueError: variable agent_scratchpad should be a list of base messages, got of type <class 'str'>?


Solution

  • The main issue here is that for structured chat agent objects, agent_scratchpad should be a string placeholder in a user prompt. So, instead of (shortened OP's system prompt for brevity)

    # case 1
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a helpful assistant."),
        ("human", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ])
    

    you should use

    # case 2
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a helpful assistant."),
        ("human", "{input}\n{agent_scratchpad}"),
    ])
    

    You can see that in the docs as well (check create_structured_chat_agent.__doc__).


    A very short explanation of an agent executor langchain.agents.AgentExecutor is that it is a loop that uses a list of messages in each iteration to generate an output. At each step, the output of the previous step is appended to the list of messages to generate the output of that step. How to append these intermediate steps differs depending on which agent object is used.

    For some agents, the intermediate steps are converted into messages and the initial list of messages are extended with these messages; so in any given step, the LLM uses [system_message, user_message, tool_message, ...] to generate an output. The placeholder to extend the list of messages within the workflow of an agent is MessagesPlaceholder; so that placeholder will be useful for these agents.

    For other agents, the intermediate steps are converted into a string and appended to the user prompt; so in any given step, the LLM uses only 2 messages [system_message, user_message] (sometimes just a single user_message) to generate an output. Structured chat agent is such an agent.

    Some common langchain agents that need agent_scratchpad as part of its user prompt:

    Some common langchain agents that need agent_scratchpad as a messages placeholder: