AI実装解決ナビ .jp
🤖 AIエージェント 2026-04-09 公開 • 12分で読める

【解決済】LangChain Agentの
「Could not parse LLM output」
エラーを完全攻略

LangChain Agentで最も頻出する「ValueError: Could not parse LLM output」エラーの根本原因と、5つの実践的な解決策を詳しく解説します。

❌ 問題症状

LangChain Agentを実行すると以下のエラーが発生:

ValueError: Could not parse LLM output: `Assistant, how can I help you today?`
  • 非OpenAIモデル(Flan-T5、Bloomなど)使用時に頻発
  • GPT-3.5-turboでも発生することがある
  • GitHub Issue: 124👍 | 82💬 - LangChainで最も議論されたエラー
  • エラーが出ても実際には正しいレスポンスが生成されている

🔍 問題の背景:なぜこのエラーが発生するのか

1. LangChain Agentが期待する出力フォーマット

LangChain の conversational-react-description Agentは、LLMに対して以下の形式での出力を期待しています:

Thought: Do I need to use a tool? Yes
Action: the action to take, should be one of [tool_names]
Action Input: the input to the action
Observation: the result of the action

Thought: Do I need to use a tool? No
AI: [your response here]

2. 非OpenAIモデルが失敗する理由

💡 核心的な違い

  • Flan-T5やBloom:言語モデリング用に学習されている(指令追従能力が低い)
  • GPT-3.5/GPT-4:指令追従(Instruction Following)に特化して微調整されている
  • 非OpenAIモデルは期待される形式で出力を生成できず、パース処理が失敗する

3. エラー発生のメカニズム

LangChainの内部処理:

  1. LLMに対してプロンプトを送信
  2. LLMが応答を返す(例:"Assistant, how can I help you today?"
  3. Agentが応答から "Action:" または "AI:" を探す
  4. どちらも見つからない → ValueError が発生
# LangChain内部のパース処理(簡略版)
if "Action:" in llm_output:
    # ツールを使用するケース
    action = extract_action(llm_output)
elif "AI:" in llm_output:
    # 直接応答するケース
    return extract_response(llm_output)
else:
    # どちらも見つからない
    raise ValueError(f"Could not parse LLM output: `{llm_output}`")

✅ 解決策一覧

💡 推奨度別の対処法

方法 推奨度 難易度 適用ケース
① OpenAI系モデル使用 ⭐⭐⭐⭐⭐ 簡単 本番環境
② try-except で処理 ⭐⭐⭐ 簡単 応急処置
③ カスタムOutputParser ⭐⭐⭐⭐ 中級 非OpenAIモデル使用時
④ リトライ機構 ⭐⭐⭐⭐ 中級 信頼性向上
⑤ Few-shot プロンプト ⭐⭐⭐ 中級 非OpenAIモデル最適化

📋 解決策① OpenAI系モデルの使用(最も確実)

最もシンプルで確実な解決方法は、指令追従に特化したモデルを使用することです。

from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent
from langchain.memory import ConversationBufferMemory

# ❌ 問題が発生するコード
llm = HuggingFaceHub(repo_id="google/flan-t5-xl")

# ✅ 解決策:OpenAI系モデルを使用
llm = ChatOpenAI(
    model_name="gpt-3.5-turbo",  # または gpt-4
    temperature=0
)

agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent="conversational-react-description",
    memory=ConversationBufferMemory(memory_key="chat_history"),
    verbose=True
)

💰 コスト最適化のヒント

  • gpt-3.5-turbo: 高速・低コスト(推奨)
  • gpt-4: 高精度だがコスト高
  • gpt-4o-mini: 2026年新モデル、コストパフォーマンス最高

📋 解決策② try-except で応答を抽出(応急処置)

エラーメッセージ内に実際の応答が含まれているため、それを抽出する方法:

try:
    response = agent_chain.run(input=query)
except ValueError as e:
    response = str(e)
    if not response.startswith("Could not parse LLM output: `"):
        raise e  # 別のエラーの場合は再度raise
    # エラーメッセージから実際の応答を抽出
    response = response.removeprefix("Could not parse LLM output: `").removesuffix("`")

print(response)  # "Assistant, how can I help you today?"
⚠️ 注意:この方法は一時的な対処法です。本番環境では他の解決策を強く推奨します。

📋 解決策③ カスタムOutputParserの実装

独自のパーサーを実装することで、様々な出力形式に対応できます:

import re
from langchain.schema import BaseOutputParser
from typing import Any

class FlexibleAgentOutputParser(BaseOutputParser):
    """柔軟な出力形式に対応するカスタムパーサー"""
    
    def get_format_instructions(self) -> str:
        return """Output format:
{
  "action": "tool_name",
  "action_input": "input_for_tool"
}
OR
{
  "final_answer": "your response"
}"""
    
    def parse(self, text: str) -> Any:
        cleaned_output = text.strip()
        
        # JSON形式を試みる
        action_pattern = r'"action":\s*"([^"]*)"'
        action_input_pattern = r'"action_input":\s*"([^"]*)"'
        
        action_match = re.search(action_pattern, cleaned_output)
        action_input_match = re.search(action_input_pattern, cleaned_output)
        
        if action_match and action_input_match:
            return {
                "action": action_match.group(1),
                "action_input": action_input_match.group(1)
            }
        
        # final_answerを試みる
        final_answer_pattern = r'"final_answer":\s*"([^"]*)"'
        final_answer_match = re.search(final_answer_pattern, cleaned_output)
        
        if final_answer_match:
            return {"output": final_answer_match.group(1)}
        
        # フォールバック:テキスト全体を返す
        return {"output": cleaned_output}

# 使用例
from langchain.agents import AgentExecutor, LLMSingleActionAgent

output_parser = FlexibleAgentOutputParser()

# Agentにカスタムパーサーを設定
agent = LLMSingleActionAgent(
    llm_chain=llm_chain,
    output_parser=output_parser,
    stop=["\nObservation:"],
    allowed_tools=[tool.name for tool in tools]
)

agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent, 
    tools=tools, 
    verbose=True
)

📋 解決策④ リトライ機構の実装

パースエラー時にLLMを再呼び出しする方法:

from langchain.callbacks.base import BaseCallbackHandler

class RetryOnParseErrorCallback(BaseCallbackHandler):
    """パースエラー時に再試行するコールバック"""
    
    def __init__(self, max_retries=3):
        self.max_retries = max_retries
        self.retry_count = 0
    
    def on_agent_action(self, action, **kwargs):
        self.retry_count = 0  # 成功時にリセット
    
    def on_tool_error(self, error, **kwargs):
        if "Could not parse LLM output" in str(error):
            if self.retry_count < self.max_retries:
                self.retry_count += 1
                print(f"⚠️ パースエラー検出。リトライ {self.retry_count}/{self.max_retries}")
                return True  # リトライ
            else:
                print(f"❌ 最大リトライ回数に達しました")
                raise error
        raise error

# 使用例
callback = RetryOnParseErrorCallback(max_retries=3)

agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent="conversational-react-description",
    callbacks=[callback],
    verbose=True
)

📋 解決策⑤ Few-shot プロンプトの最適化

非OpenAIモデルに正しい出力形式を学習させる方法:

from langchain.prompts import PromptTemplate

# Few-shot 例を含むプロンプトテンプレート
few_shot_template = """You are a helpful AI assistant. 
When you need to use a tool, respond in this exact format:

Example 1:
Human: What's the weather today?
Thought: I need to use the weather tool
Action: get_weather
Action Input: today

Example 2:
Human: Hello!
Thought: This is a greeting, no tool needed
AI: Hello! How can I help you today?

Now, respond to the following:
Human: {input}
"""

prompt = PromptTemplate(
    input_variables=["input"],
    template=few_shot_template
)

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

📊 各解決策の比較

解決策 成功率 実装工数 ランニングコスト
① OpenAIモデル 95-99% 5分 中〜高
② try-except 60-70% 5分 変動なし
③ カスタムParser 80-90% 2-4時間 変動なし
④ リトライ機構 85-95% 1-2時間 やや増加
⑤ Few-shot 70-80% 30分-1時間 変動なし

🎓 まとめ

✅ 推奨アプローチ

本番環境の場合:

  1. 第一選択:OpenAIモデル(gpt-4o-mini または gpt-3.5-turbo)を使用
  2. 信頼性向上:リトライ機構を併用
  3. コスト削減が必須:カスタムOutputParser + 非OpenAIモデル

開発・テスト環境の場合:

  • try-except で応急処置しつつ、他の解決策を検討
  • Few-shot プロンプトで非OpenAIモデルの挙動を改善

🔗 参考リンク

💡 この記事が役立ちましたか?

AI実装解決ナビでは、LangChain、Dify、AutoGPTなどAIエージェント開発の最新情報と実践的な解決策を発信しています。