LangChain ReAct Agent 的无限循环与解析失败(基于 Qwen LLM)

在构建基于 LangChain Agent 的应用时,遇到了一个令人头疼的问题: Agent 陷入无限循环。在我的一个项目中,Agent 不仅循环,还不断抛出 Invalid Format: Missing 'Action:' after 'Thought:' 的错误。通过深入 LangChain 源码和对 LLM 输出的调试,我最终锁定了问题的根源:Qwen LLM 对 ReAct 提示词的匹配不严格


🧐 一:发现问题与初步诊断

我的 Agent 使用了 LangChain 的 ReAct 框架,并配置了自定义工具,同时使用了 agent_executor.stream() 进行流式输出。

初始现象

Agent 在执行完一个工具调用并收到 Observation 后,没有继续下一步的 Action,而是陷入循环,并在日志中反复出现以下错误:

1
2
Action: _Exception
Action Input: "Invalid Format: Missing 'Action:' after 'Thought:'"

并且,这个错误信息被错误地注入到 messages 历史中,加剧了循环。如下:

1
2
{'steps': [AgentStep(action=AgentAction(tool='_Exception', tool_input="Invalid Format: Missing 'Action:' after 'Thought:'", log='此处省略我的工具输出内容,以上为全部用户列表。部分用户未
填写昵称和邮箱信息。'), observation="Invalid Format: Missing 'Action:' after 'Thought:'")], 'messages': [HumanMessage(content="Invalid Format: Missing 'Action:' after 'Thought:'", additional_kwargs={}, response_metadata={})]}

初步怀疑点

  1. 1.

    Memory 污染(循环的直接原因): 中间步骤(Observation_Exception)被错误地当作 HumanMessage 写入了对话历史。

  2. 2.

    Tool异常导致Langchain异常:Tool抛出异常,Langchain错误的将Tool输出作为HumanMessage。

  3. 3.

    LLM 格式化失败(错误的根源): LLM 的输出不符合 ReAct 格式。

我决定从根源入手,确认 LLM 的输出到底出了什么问题。


🛠️ 二:深入源码定位解析失败点

逐个排除,首先停用Memory,在停用后发现问题依旧

为了找出 Agent 解析器在哪里“卡住”了,我定位到 LangChain 负责 ReAct 解析的核心文件:langchain/agents/output_parsers/react_single_input.py 中的 ReActSingleInputOutputParser 类。

核心代码分析

parse 方法中,解析逻辑是按顺序检查 LLM 输出 text 的格式:

  1. 1.

    检查 **Action** + **Action Input** (首要匹配):

    Python

    1
    2
    3
    4
    regex = r"Action\s*\d*\s*:[\s]*(.*?)[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
    action_match = re.search(regex, text, re.DOTALL)
    if action_match:
    # 成功解析 Action,返回 AgentAction
  2. 2.

    检查 **Final Answer**:

    Python

    1
    2
    if includes_answer:
    # 成功解析 Final Answer,返回 AgentFinish
  3. 3.

    检查是否存在 **Action** 标记 (我的异常点):

    Python

    1
    2
    3
    4
    5
    6
    7
    8
    if not re.search(r"Action\s*\d*\s*:[\s]*(.*?)", text, re.DOTALL):
    msg = f"Could not parse LLM output: `{text}`"
    raise OutputParserException(
    msg,
    observation=MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE, # <-- 触发了这个错误信息
    llm_output=text,
    send_to_llm=True,
    )

调试发现

通过调试,我发现当工具返回长篇 Markdown 表格数据作为 Observation 后,LLM 的下一段输出(即进入 parse(self, text: str)text 变量)内容如下:

1
'【我的工具返回的数据】\n\n以上是系统中的用户列表,共20位用户。更多用户信息可进一步查询。'

而正常的应该类似如下:

1
2
Thought: 从 `xxx` 表中未查询到有效数据,而从 `yyy` 表中已获取到用户信息。因此可以确认当前系统中的用户主要存储在 `yyy` 表中。\n\nFinal Answer: 当前系统中存在的用户如下表 
所示(共20条记录):\n\n【我的工具返回的数据】\n\n注:以上为系统中部分用户列表,共计20位用户,状态均为“active”(启用)。

从以上对比可以看出,错误响应的信息如下:

  • 没有 **Thought:** 标记。也没有Final Answer标记。

由于 text 变量中既没有 Action: 也没有 Final Answer:,它直接掉入了第三个检查,导致了 Missing 'Action:' after 'Thought:' 异常。

真相大白: Qwen 大模型 在处理完复杂的 Observation 后,认为任务已经完成,直接给出了总结性的自然语言回答没有严格遵循 ReAct 提示词要求在答案前加上 **Final Answer:** 标记。


✅ 三:解决方案——加固提示词(Prompt Engineering)

既然问题是 LLM 的输出格式不严格,那么解决办法就是加固 ReAct 框架的提示词,强制 Qwen LLM 严格遵守输出要求。

关键调整点

在 Agent 的 System Prompt 或 Instruction 部分,我对格式要求进行了以下修改,增加了清晰的措辞、分隔符和强调

  1. 1.

    明确格式要求(尤其针对 Final Answer): 将原来Langchain官方给出的React提示词进行调整,要求”输出必须严格按照如下格式”

  2. 2.

    检查Instruction部分的提示词,确保没有任何提示词与格式要求混淆

示例 Prompt 片段(强调部分):

Markdown

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Answer the following questions as best you can. You have access to the following tools:

{tools}

输出必须严格按照如下格式:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should 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!

Question: {input}
Thought:{agent_scratchpad}

📢经过以上调整,问题缓解,多次尝试暂无出现类似的错误。


结论

通过将 LLM 的行为偏差与 LangChain 解析器的源码逻辑相结合,成功定位并解决了 Agent 循环和解析失败的问题。

核心经验是:

  1. 1.

    不要相信 LLM 会自然遵循格式。 即使提供了示例,也必须通过强有力的措辞和格式化在 Prompt 中进行约束。

  2. 2.

    调试 Agent 循环,一定要从 LLM 的原始输出(**log** 字段)开始,结合 OutputParser 的源码,才能真正理解 LLM 在哪个环节“失控”了。

在调整提示词后,Qwen LLM 的输出格式变得稳定,Agent 成功地从工具返回的数据跳转到 Final Answer: 步骤,流程顺畅,循环问题也随之消失。希望这段经验能帮助遇到类似 Agent 问题的开发者!🙏