エージェントの失敗とループへの対処
タイムアウト時間、最大反復回数、エラー回復用のプロンプトを設定し、エージェントが無限ループしたり、壊れたツールを繰り返し呼び出したりするのを防ぎます。
「エージェントの失敗とループへの対処」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。
エージェントが失敗してループする理由
エージェントが失敗ループに陥る理由はいくつかあります。壊れたツールが、エージェントには抜け出し方の分からないエラーを返す、モデルが不正なアクション構文を繰り返し生成する、利用可能なツールでは達成できないタスクである、あるいは異なる結果を期待して、エージェントが少しずつ変えながら同じツールを呼び出し続ける、といった場合です。安全策がなければ、API予算を消費し続け、問題は解決しません。
最大反復回数の制限
最も簡単な保護策は、Thought/Action/Observationサイクルの回数に上限を設けることです。LangChainのAgentExecutorはmax_iterationsパラメーターを受け取ります。上限に達すると、エグゼキューターはループを停止し、エージェントがタスクを完了できなかったことを示すメッセージを返します。
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=10, # Hard stop after 10 steps
max_execution_time=30.0, # Also stop after 30 wall-clock seconds
early_stopping_method='generate', # Ask the model for a partial answer at the limit
verbose=True
)早期停止:最終回答を強制する
エージェントが反復回数の上限に達すると、early_stopping_method='generate'はモデルに対して、「ステップ数の上限に達しました。ここまでに得た情報に基づいて、最善の最終回答を提示してください」と最後に1回だけプロンプトを送ります。空のレスポンスを返したりクラッシュしたりするよりも、ユーザーに役立つ情報を提供できます。
# The 'generate' early_stopping_method adds this system instruction
# when max_iterations is reached:
#
# 'You have {N} steps remaining but the task is not complete.
# Give your best final answer based on the information gathered so far.'
#
# Contrast with 'force' which abruptly terminates without generating an answer.
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=7,
early_stopping_method='generate'
)解析エラーの適切な処理
モデルがThought/Action形式に一致しない出力(アクションキーワードの欠落、誤ったツール名、自由形式のテキストなど)を生成すると、エージェントはOutputParserExceptionを発生させます。handle_parsing_errors=Trueを設定すると、エラーをObservationとしてモデルにフィードバックし、自己修正させることができます。
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
handle_parsing_errors=True,
# Custom error message fed back to the model:
# handle_parsing_errors='Please format your response as Thought/Action/Action Input.'
)
# When a parse error occurs, the executor automatically adds:
# Observation: Could not parse LLM output. Please follow the format:
# Thought: ...
# Action: tool_name
# Action Input: ...反復ループの検出と中断
よくあるループのパターンは、エージェントがsearch('same query')を3回連続で呼び出し、そのたびに同じ役に立たない結果を得ることです。最近の(ツール、入力)のペアを追跡してループを検出します。同じ組み合わせが2回を超えて繰り返されたら、別の方法を提案するObservationを挿入してください。
from collections import Counter
class LoopDetector:
def __init__(self, max_repeats: int = 2):
self.max_repeats = max_repeats
self.call_counts = Counter()
def check(self, tool_name: str, tool_input: str) -> bool:
key = f'{tool_name}:{tool_input}'
self.call_counts[key] += 1
if self.call_counts[key] > self.max_repeats:
return True # Loop detected
return False
def get_warning(self) -> str:
return ('You have called this tool with the same input multiple times. '
'Try a different approach, different search terms, or a different tool.')ツールレベルのエラー処理
堅牢なエージェントには、堅牢なツールが必要です。すべてのツールは自身の例外を捕捉し、Python例外を発生させるのではなく、構造化されたエラーメッセージを返すべきです。エラーの種類と、再試行すべきか、方法を変えるべきか、上位にエスカレーションすべきかをエージェントが判断できる提案を含めてください。
from langchain_core.tools import tool
import requests
@tool
def get_company_data(company_name: str) -> str:
'''Retrieve company information from the business database.
Input: company name as a string.
'''
try:
resp = requests.get(
f'https://api.example.com/companies/{company_name}',
timeout=5
)
if resp.status_code == 404:
return f'No company found with name "{company_name}". Try the exact legal name or ticker symbol.'
if resp.status_code == 429:
return 'Rate limit exceeded. Wait 60 seconds before trying again.'
resp.raise_for_status()
return resp.json().get('summary', 'No summary available.')
except requests.Timeout:
return 'The database is not responding. Try searching the web instead.'API障害時の指数バックオフ
ツールが外部APIを呼び出す場合、一時的な障害はよく発生します。ツール関数内に指数バックオフ付きの再試行ロジックを追加し、待機時間を増やしながら最大3回まで再試行してください。これにより、エージェントが再試行を意識しなくても、レート制限や短時間の障害に透過的に対処できます。
import time
import requests
from langchain_core.tools import tool
@tool
def reliable_search(query: str) -> str:
'''Search with automatic retry on failure. Input: search query string.'''
max_retries = 3
for attempt in range(max_retries):
try:
resp = requests.get(
'https://api.duckduckgo.com/',
params={'q': query, 'format': 'json'},
timeout=10
)
resp.raise_for_status()
data = resp.json()
return data.get('AbstractText', 'No results found.')
except requests.RequestException as e:
if attempt < max_retries - 1:
wait = 2 ** attempt # 1s, 2s, 4s
time.sleep(wait)
else:
return f'Search failed after {max_retries} attempts: {str(e)}'エージェントレベルのタイムアウト予算
個々のツールの再試行は有効ですが、エージェント実行全体にも合計の実時間タイムアウトが必要です。タスクがSLAで許容される時間(たとえば30秒)を超えたら、ループを停止して、機能を縮小した適切な応答を返します。LangChainのmax_execution_timeパラメーターで、エグゼキューターレベルのこの処理を行えます。
import asyncio
async def run_with_timeout(user_input: str, timeout_seconds: float = 30.0) -> str:
try:
result = await asyncio.wait_for(
agent_executor.ainvoke({'input': user_input}),
timeout=timeout_seconds
)
return result['output']
except asyncio.TimeoutError:
return ('I am taking longer than expected to answer this question. '
'Please try again with a simpler question, or check back later.')分析のための失敗ログ
エージェントの失敗はすべてデータになります。ユーザー入力、すべての中間ステップ、失敗理由、使用した反復回数を含む完全なトレースを、データベースまたは可観測性プラットフォームに記録してください。失敗パターンを分析すると、信頼性の低いツール、エージェントが処理できない質問の種類、最も頻繁に発生するループが明らかになります。
import logging
import json
logger = logging.getLogger('agent')
def run_and_log(user_input: str) -> str:
try:
result = agent_executor.invoke(
{'input': user_input},
return_intermediate_steps=True
)
if not result.get('output'):
logger.warning('Agent returned empty output', extra={
'input': user_input,
'steps': len(result.get('intermediate_steps', []))
})
return result['output']
except Exception as e:
logger.error('Agent failed with exception', extra={
'input': user_input,
'error': str(e),
'error_type': type(e).__name__
})
return 'I encountered an error. Please try rephrasing your question.'プロンプトへの復旧ヒントの注入
失敗パターンを検出したら、次のプロンプトに復旧手順を動的に注入できます。たとえば検索ツールが失敗し続けている場合は、「現在、Web検索ツールは安定していません。このクエリではナレッジベースツールを優先してください」のようなヒントを追加します。これにより、ハードコードされたフォールバックロジックを使わずに、エージェントを機能する解決策へ誘導できます。
失敗シナリオのテスト
失敗シナリオ専用のテストスイートを構築してください。すべてのツールがエラーを返す場合、モデルがmax_iterationsに達した場合、入力に回答可能な質問が含まれていない場合、モデルが存在しないツールを呼び出した場合の動作をテストします。どれほど敵対的な状況でも、エージェントは常に妥当なメッセージを返し、アプリケーションをクラッシュさせないようにしてください。
クイックチェック
エージェントの失敗を処理し、ループを防ぐ方法についての理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、max_iterationsとmax_execution_timeによってエージェントの実行時間に厳格な上限を設定できること、handle_parsing_errorsによって形式上の誤りをモデルにフィードバックし自己修正させられること、そしてツールは例外を捕捉し、例外を発生させるのではなく説明的なエラー文字列を返すべきであることを学びました。次は、構造化されたツール統合のためのOpenAIのネイティブなfunction calling機能を学びます。
よくある質問
「エージェントの失敗とループへの対処」レッスンは無料ですか?
はい。「エージェントの失敗とループへの対処」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。
「エージェントの失敗とループへの対処」で何を学びますか?
タイムアウト時間、最大反復回数、エラー回復用のプロンプトを設定し、エージェントが無限ループしたり、壊れたツールを繰り返し呼び出したりするのを防ぎます。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Engineering Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「エージェントの失敗とループへの対処」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Engineering Academyレッスンでコードを書いて実行できますか?
はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。