🤖
AIエージェント開発で踏んだ5つの地雷(コード付き)
「AIエージェントは一度作れば回り続ける」と思われがちですが、実運用は逆です。
壊れる前提で設計しないと、ある日まとめて止まります。
この記事では、本プロジェクト の実装と運用ログをもとに、
実際に踏みやすい失敗を5つに分解して解説します。
対象読者:
- AIエージェントを実運用している個人開発者
- 複数エージェントの自走パイプラインを回したいエンジニア
- 「動くけど不安定」な状態から抜けたい人
失敗事例① ハルシネーション連鎖(幻覚の地獄)
症状
- 1つ目の誤情報を別エージェントが正しい前提として継承し、数ステップで全体判断が崩壊する。
- 「それっぽいが根拠がない」説明がログに残り、後から原因追跡しづらい。
原因
- 不確実情報に「わからない」を返すルールが弱い。
- 出力の根拠確認(URL妥当性、許可ドメイン確認)が後段のみ。
再現
- 参照先URLが曖昧なまま要約を生成。
- 次段の評価エージェントが要約を事実として採用。
- 実行系が誤前提で投稿・通知まで進む。
対策
- 安全レビューで URL 妥当性と許可ドメインを必須チェック。
- 「根拠不明なら不確実と明示」のプロンプトを全戦略で統一。
// 根拠URLの検証例
function validateSources(content: string): { isValid: boolean; reason?: string } {
const urls = extractUrls(content);
const allowedDomains = ['note.com', 'github.com', 'zenn.dev', 'x.com'];
for (const url of urls) {
const domain = new URL(url).hostname;
if (!allowedDomains.some(d => domain.includes(d))) {
return { isValid: false, reason: `許可外ドメイン: ${domain}` };
}
}
return { isValid: true };
}
再発防止
-
scripts/auto-review.tsの安全チェック(秘匿情報・URL検証)を通らない投稿は自動却下。 - 根拠URLのない主張をそのまま外部出力しない運用ルールを固定。
失敗事例② 無限ループ(レビュー修正戦争)
症状
- 修正→再レビュー→再修正が終わらず、タスクが完了しない。
- API呼び出しと通知だけが増えて成果物が出ない。
原因
- 終了条件(最大回数・承認条件)の不在。
- 人間レビューと自動レビューの責務が曖昧。
再現
- レビュー基準を曖昧なまま自動チェックを有効化。
- 軽微な文言差分で毎回差し戻し。
- キュー滞留が増え、次タスクを押し出す。
対策
- 2名投票(安全/品質)+ 承認条件を明文化。
- レビューキューの滞留検知を監視対象に追加。
// レビューループ防止の実装例
const MAX_REVIEW_CYCLES = 3;
async function reviewWithLimit(content: string, cycle = 0): Promise<ReviewResult> {
if (cycle >= MAX_REVIEW_CYCLES) {
return { status: 'MANUAL_REQUIRED', reason: 'レビュー上限到達' };
}
const result = await autoReview(content);
if (result.status === 'APPROVED') return result;
const fixed = await applyFixes(content, result.issues);
return reviewWithLimit(fixed, cycle + 1);
}
再発防止
-
scripts/self-run-check.tsでレビューキュー放置(6時間超)をDEGRADEDとして検知。 -
scripts/auto-review.tsを定期実行して再審査を自動化。
失敗事例③ コンテキスト溢れ(長い会話の健忘症)
症状
- 最初の制約(件数、言語、禁止事項)が後半で抜ける。
- 出力フォーマットが途中で崩れ、下流の処理が失敗する。
原因
- 長い会話をそのまま渡し続ける設計。
- 入力の要約層がなく、重要制約が埋もれる。
再現
- 連続で追記指示を与える。
- 過去の重要制約が文脈後方へ追いやられる。
- 形式違反や件数超過が発生。
対策
- コンテキストは「要約JSON + 重要制約」を固定フォーマットで渡す。
- 実行前にスキーマ検証し、違反時は実行しない。
// コンテキスト圧縮と制約保持の例
interface StrategyContext {
constraints: {
maxCount: number;
language: string;
forbidden: string[];
};
history: string; // 要約済み過去文脈
currentTask: string;
}
function compressContext(fullHistory: Message[]): StrategyContext {
return {
constraints: extractConstraints(fullHistory[0]), // 最初の指示を固定
history: summarize(fullHistory.slice(1, -5)),
currentTask: fullHistory[fullHistory.length - 1].content,
};
}
再発防止
- 戦略
execute()のメタデータ契約を共通化(action/blockingReasons/artifacts)。 - 形式違反はレビュー段階で自動的に弾く。
**
詳細版は note の有料版で公開しています: https://note.com/agent_workshop
Discussion