6月20日、MarkTechPostが「Cisco AI Introduces FAPO: Pipeline-Aware Prompt Optimization With Step-Level Failure Attribution and Claude Code Orchestration」と題した記事を公開した。この記事では、CiscoのAIチームがマルチステップLLMパイプラインを自動最適化するOSSフレームワーク「FAPO」を公開したことについて詳しく紹介されている。
「どのステップが失敗しているか」を特定してから直す
プロンプトエンジニアリングで最も厄介なのは、マルチステップのパイプラインでどこが壊れているかを特定することだ。最終出力が間違っていても、その原因が検索ステップにあるのか、推論ステップにあるのか、フォーマット処理にあるのかは、中間出力を手作業で掘り下げなければわからない。
FAPO(Fully Automated Prompt Optimization)はその作業を自動化する。GitHubリポジトリはApache 2.0で公開済みだ。なお、内部パッケージ名はhephaestus(ギリシャ神話の鍛冶神ヘパイストスに由来)であり、コード例やCLIコマンドではhephaestusとして登場するが、フレームワーク全体の名称はFAPOで統一されている。
FAPOのコアとなる仕組みがステップレベルの障害帰属(Step-Level Failure Attribution)だ。失敗ケースを以下の4クラスに分類する:
- Retrieval failure:検索ステップが空または無関係なコンテンツを返している
- Cascading failure:早いステップの空出力が後続ステップをすべて壊している
- Format failure:正しい答えが生成されているが、スコアラーが解析できない形式で出力されている
- Reasoning failure:入力は正しいが、推論ステップが誤った結論を出している
FormatとReasoningはプロンプト編集で対処可能。RetrievalとCascadeはパイプラインの構造変更が必要——この判断をFAPOが自動で下す。
3段階のエスカレーション構造
FAPOの最適化ループは6ステージのサイクルを繰り返す:
- Evaluate:パイプラインを実行し、ケースごとのスコアとステップ出力を収集
- Attribute:ルールベースヒューリスティック+LLM分析で失敗原因を分類
- Propose:主要な失敗クラスターを狙ったバリアントを生成
- Review:独立したエージェントがスコープ適合とデータ漏洩を確認
- Compare:前回ベストを上回った場合のみバリアントを採用
- Iterate:目標精度到達かバジェット枯渇まで繰り返す
このループを、Claude Code(またはCodex)エージェントがオーケストレーションする。
試みる変更にも優先順位がある。コストの低い順に、①プロンプトテキストの編集→②retrieval_kやtemperatureなどのパラメータ変更→③チェーントポロジーの変更(self-reflectionノードの追加やReActパターンへの切り替えなど)という3段階でエスカレーションし、低コストの手段を使い果たしてから次のレベルに進む。
GEPAとの比較:構造変更が刺さったベンチマークで+33.8pp
Ciscoは既存の有力なプロンプト最適化手法GEPA(Generalized Evolutionary Prompt Architecture)との比較評価を実施した。GEPAは遺伝的アルゴリズムを使った進化的サーチでプロンプトを最適化する手法で、プロンプト自動最適化の分野において近年注目されているベースラインのひとつだ。ただし、GEPAが変更できるのはプロンプトテキストのみであり、パイプラインのトポロジー変更には対応していない。FAPOのステップレベル障害帰属とエスカレーション構造は、まさにこのGEPAの限界を超えることを設計上の動機としている。
タスクモデルはGPT-4.1-mini、GPT-5.4-mini、Gemma 3-12Bの3種。オーケストレーターにはClaude Opus 4.6を使用。これらのモデル名は元記事に記載されているものをそのまま引用しており、一部は本稿執筆時点で広く知られているバージョンと異なる場合がある点に留意されたい。6ベンチマーク、計18モデル×ベンチマークペアで比較した結果が以下だ:
| ベンチマーク | ベースライン | GEPA | FAPO | GEPAとの差 |
|---|---|---|---|---|
| HoVer | 35.9 | 48.5 | 83.8 | +35.3pp |
| IFBench | 35.7 | 48.5 | 80.7 | +32.2pp |
| LiveBench-Math | 51.0 | 52.6 | 62.0 | +9.4pp |
| HotpotQA | 50.9 | 61.8 | 68.3 | +6.5pp |
| Papillon | 73.6 | 90.7 | 94.9 | +4.2pp |
| AIME | 16.7 | 16.0 | 12.9 | -3.1pp |
18ペア中15ペアでFAPOが上回り、平均ゲインは+14.1pp。HoVerとIFBenchではパイプライン構造変更にエスカレーションし、6ペア全勝、平均+33.8ppという結果になった。GEPAが上回ったのはAIMEのみで、差は3.1ppとサンプリングノイズの範囲内とされている。
過学習への対策
最適化ループが訓練データに過適合するリスクへの対策として、FAPOは以下の設計を取っている:
- 訓練スプリットのみ参照:最適化中はバリデーションセットとテストセットの集計スコアしか公開しない
- イミュータブルなバリアントファイル:既存のプロンプトファイルを上書きせず、常に新ファイルとして保存
- 独立したレビュアーエージェント:すべてのProposalを別エージェントが検証してから実行
試してみる
データセットはJSONL形式で、1行1ケース:
{"case_id": "1", "task_type": "qa", "context": {"question": "What is the capital of France?"}, "expected": {"answer": "Paris"}, "metadata": {}}
スコアラーはvalidate_caseとscore_caseを実装するクラスとして定義する。詳細なAPIリファレンスはGitHubリポジトリを参照してほしいが、最小構成の例を示す:
from hephaestus.scoring.scorer import Scorer as BaseScorer
class Scorer(BaseScorer):
def validate_case(self, case, scoring_profile):
assert "answer" in case.expected, "Missing 'answer' in expected"
def score_case(self, case, output_text, scoring_profile):
expected = case.expected["answer"].strip().lower()
predicted = output_text.strip().lower()
em = 100.0 if predicted == expected else 0.0
return {"composite_score": em, "score_breakdown": {"exact_match": em}}
ベースライン評価を確認してから最適化ループを起動する:
export OPENAI_API_KEY="sk-..."
python -m hephaestus.cli eval --config tenants/my_project/configs/eval.json
テナント(最適化プロジェクトの単位)のファイル群はClaude Codeにタスクを自然言語で説明すればスキャフォールドしてもらえる。各実行の成果物はすべてディスクに書き出されるため、ローカルのUIツール「FAPO Explorer」で事後に確認できる。
現時点の制約
元記事が明示している弱点を整理しておく。最適化品質はユーザーが用意するデータセットの質とカバレッジに上限が引かれる。また、デフォルトのループはClaude CodeまたはCodexというエージェント型コーディングツールに依存しており、単独で動くスタンドアロンの最適化エンジンではない。プロジェクト自体がまだ新しく、本番環境での独立した実績は限られている。
詳細はCisco AI Introduces FAPO: Pipeline-Aware Prompt Optimization With Step-Level Failure Attribution and Claude Code Orchestrationを参照していただきたい。




