2025, Oct 16 05:36
LangChain structured chat एजेंट में agent_scratchpad त्रुटि (ValueError) को ठीक करने का तरीका
LangChain structured chat एजेंट में agent_scratchpad को MessagesPlaceholder रखने से ValueError आती है। प्रॉम्प्ट में स्ट्रिंग जोड़कर इसे कैसे ठीक करें, जानें.
LangChain में एक structured chat एजेंट जोड़ते समय, एक दिखने में छोटी-सी बात ऐसा अपवाद फेंक सकती है जो आपके कोड से असंबंधित लगता है: ValueError: variable agent_scratchpad should be a list of base messages, got of type <class 'str'>. असल कारण यह है कि एजेंट अपने मध्यवर्ती तर्क को प्रॉम्प्ट के माध्यम से किस तरह जोड़ा जाने की अपेक्षा करता है। यदि आप structured chat एजेंट के लिए agent_scratchpad को messages placeholder के रूप में रखते हैं, तो यह विफल हो जाएगा।
समस्या को दोहराना
निम्नलिखित न्यूनतम सेटअप एक नकली LLM को कॉल करता है, उसे एक साधारण टूल चलाने को कहता है, और फिर अंतिम उत्तर लौटाता है। प्रॉम्प्ट structured chat एजेंट के लिए बनाया गया है, लेकिन agent_scratchpad को गलत तरह से messages placeholder के रूप में दिया गया है।
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
from langchain_community.chat_models.fake import FakeMessagesListChatModel
# 1. एक पूर्वानुमेय टूल परिभाषित करें
def echo_utility(text: str) -> str:
    print(f"Tool called with input: '{text}'")
    return "The tool says hello back!"
utility_catalog = [
    Tool(
        name="simple_tool",
        func=echo_utility,
        description="A simple test tool.",
    )
]
# 2. structured chat फ़ॉर्मैट के अनुरूप प्रतिक्रियाएँ
mock_outputs = [
    AIMessage(
        content=json.dumps({
            "action": "simple_tool",
            "action_input": {"input": "hello"}
        })
    ),
    AIMessage(
        content=json.dumps({
            "action": "Final Answer",
            "action_input": "The tool call was successful. The tool said: 'The tool says hello back!'"
        })
    ),
]
fake_llm = FakeMessagesListChatModel(responses=mock_outputs)
# 3. प्रॉम्प्ट: agent_scratchpad का गलत स्थान
broken_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. एजेंट और एग्ज़िक्यूटर
structured_agent = create_structured_chat_agent(fake_llm, utility_catalog, broken_prompt)
runner = AgentExecutor(
    agent=structured_agent,
    tools=utility_catalog,
    verbose=True,
    handle_parsing_errors=True,
    max_iterations=3,
)
# 5. कॉल/इनवोक करें
result = asyncio.run(runner.ainvoke({"input": "call the tool"}))
उपयोग की निर्भरताएँ: 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 संस्करण: 3.9.
वास्तव में क्या गलत होता है
AgentExecutor एक लूप चलाता है जहाँ हर इटरेशन पिछली स्टेप के आउटपुट पर आधारित होता है। अलग-अलग एजेंट उन मध्यवर्ती चरणों को अलग तरह से जोड़ते हैं। कुछ एजेंट intermediate steps को संदेशों में बदलकर बातचीत में जोड़ते हैं। अन्य एजेंट इन्हें एक स्ट्रिंग में बदलकर यूज़र प्रॉम्प्ट से जोड़ते हैं। एक structured chat एजेंट दूसरी श्रेणी में आता है: यह उम्मीद करता है कि agent_scratchpad को यूज़र संदेश में एक स्ट्रिंग की तरह इंजेक्ट किया जाए, न कि संदेशों की सूची की तरह। agent_scratchpad के लिए MessagesPlaceholder देने पर एग्ज़िक्यूटर स्ट्रिंग को बेस मैसेजेस की सूची मानने की कोशिश करता है, जिससे ValueError ट्रिगर हो जाती है।
यह भेद structured chat एजेंट के लिए प्रलेखित है। व्यवहार में इसका मतलब है कि इस एजेंट के लिए आप agent_scratchpad को सीधे human प्रॉम्प्ट में रखते हैं। इसके विपरीत, वे एजेंट जो संदेश-आधारित मध्यवर्ती चरणों पर निर्भर हैं, MessagesPlaceholder का उपयोग करते हैं।
स्पष्ट तौर पर, structured_chat_agent, react_agent, self_ask_with_search_agent, जब agent_type निर्दिष्ट नहीं होता तब डिफ़ॉल्ट sql_agent, और xml_agent चाहते हैं कि agent_scratchpad यूज़र प्रॉम्प्ट का हिस्सा एक स्ट्रिंग के रूप में हो। वहीं, json_chat_agent, openai_tools_agent, जब agent_type को "tool-calling" पर सेट किया जाता है तब sql_agent, और tool_calling_agent अपेक्षा करते हैं कि agent_scratchpad एक messages placeholder हो।
समाधान
प्रॉम्प्ट को इस तरह समायोजित करें कि agent_scratchpad messages placeholder की जगह human संदेश का हिस्सा बने। नियंत्रण प्रवाह या टूल सेटअप में और किसी बदलाव की आवश्यकता नहीं है।
import asyncio
import json
from langchain.agents import AgentExecutor, create_structured_chat_agent, Tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import AIMessage
from langchain_community.chat_models.fake import FakeMessagesListChatModel
# 1. टूल की परिभाषा समान रहती है
def echo_utility(text: str) -> str:
    print(f"Tool called with input: '{text}'")
    return "The tool says hello back!"
utility_catalog = [
    Tool(
        name="simple_tool",
        func=echo_utility,
        description="A simple test tool.",
    )
]
# 2. मॉक LLM आउटपुट समान रहते हैं
mock_outputs = [
    AIMessage(
        content=json.dumps({
            "action": "simple_tool",
            "action_input": {"input": "hello"}
        })
    ),
    AIMessage(
        content=json.dumps({
            "action": "Final Answer",
            "action_input": "The tool call was successful. The tool said: 'The tool says hello back!'"
        })
    ),
]
fake_llm = FakeMessagesListChatModel(responses=mock_outputs)
# 3. सही स्थान: agent_scratchpad यूज़र प्रॉम्प्ट में जोड़ा गया है
fixed_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}\n{agent_scratchpad}"
    ),
])
structured_agent = create_structured_chat_agent(fake_llm, utility_catalog, fixed_prompt)
runner = AgentExecutor(
    agent=structured_agent,
    tools=utility_catalog,
    verbose=True,
    handle_parsing_errors=True,
    max_iterations=3,
)
result = asyncio.run(runner.ainvoke({"input": "call the tool"}))
यह बारीकी क्यों मायने रखती है
AgentExecutor प्रॉम्प्ट को क्रमिक रूप से संयोजित करता है। यदि एजेंट की डिजाइन मानती है कि मध्यवर्ती चरणों को यूज़र संदेश में स्ट्रिंग के रूप में जोड़ा जाएगा, तो messages placeholder उस मान्यता को तोड़ देता है और एग्ज़िक्यूटर प्रकारों का सामंजस्य नहीं करा पाता। यह जानना कि कौन-से एजेंट संदेश जोड़ते हैं और कौन-से स्ट्रिंग जोड़ते हैं, नाज़ुक प्रॉम्प्ट वायरिंग से बचाता है, उलझाने वाली टाइप त्रुटियों से दूर रखता है, और आपके टूल-कॉलिंग लूप्स को पूर्वानुमेय बनाए रखता है।
व्यावहारिक निष्कर्ष
structured chat एजेंट के लिए, agent_scratchpad को यूज़र संदेश के अंदर रखें। अगर आप ऐसे एजेंट पर स्विच करते हैं जो संदेश सूची को बढ़ाते हैं, तो agent_scratchpad को MessagesPlaceholder में ले जाएँ। यदि ऊपर बताई गई वही त्रुटि सामने आए, तो पहले प्रॉम्प्ट वायरिंग की जाँच करें—अधिकतर मामलों में समाधान एक ही पंक्ति का परिवर्तन होता है।
यह लेख StackOverflow पर प्रश्न (लेखक: hitesh) और cottontail के उत्तर पर आधारित है।