ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-04-08中級

Antigravity エージェント出力検証エラーと品質保証の対処法

Antigravityエージェントの出力が期待した形式にならない、バリデーションエラーが頻発する、品質が不安定という問題を解決。出力検証の実装パターン・プロンプト設計・フォールバック戦略を実例つきで解説します。

Antigravity338エージェント64出力検証品質保証6バリデーション2

Antigravity のエージェントを使ったシステムで「エージェントの出力が毎回微妙に違う形式になってしまう」「バリデーションエラーで後続処理が止まる」「出力の品質が安定しない」といった問題に悩んだことはないでしょうか。

AI エージェントの出力は確率的であり、常に期待通りの形式や品質を保証するわけではありません。ここではAntigravity エージェントの出力検証エラーに体系的に対処するための実装パターンをご紹介します。

エージェント出力検証エラーの分類

出力検証エラーは大きく3つのカテゴリに分類できます。

形式エラー(Format Errors):JSON が不正、必須フィールドが欠落、データ型が違う、など。後続システムがパースできないケースです。

品質エラー(Quality Errors):形式は正しいが内容が期待を満たしていません。回答が短すぎる、情報が不正確、タスクの要件を満たしていない、などが該当します。

整合性エラー(Consistency Errors):複数回実行した際に結果が大きく異なります。マルチエージェントシステムで各エージェントの出力が矛盾する、などです。

形式エラーへの対処:構造化出力の強制

プロンプトによる形式指定

エージェントへの指示でJSON形式を明示し、スキーマを提示することで形式エラーを減らせます。

def create_structured_prompt(task: str, schema: dict) -> str:
    """構造化出力を促すプロンプトを生成"""
    schema_str = json.dumps(schema, ensure_ascii=False, indent=2)
    return f"""
以下のタスクを実行し、必ず下記のJSONスキーマに従って出力してください。
 
タスク: {task}
 
出力スキーマ:
```json
{schema_str}

重要な注意事項:

  • 必ずJSONのみを出力してください(説明文は不要です)
  • すべての必須フィールドを含めてください
  • nullは使用せず、空の場合は空文字列または空配列を使用してください

JSON出力: """

使用例

schema = { "title": "string(必須)", "summary": "string(必須、100文字以内)", "key_points": ["string(必須、3〜5個)"], "confidence_score": "number(必須、0.0〜1.0)" }

prompt = create_structured_prompt("最新のAI動向を分析してください", schema)


### パースエラーのハンドリングと自動修復

```python
import json
import re
from typing import Optional, Any

def parse_agent_output(raw_output: str, schema: dict) -> Optional[dict]:
    """
    エージェントの出力をパースし、形式エラーを自動修復する
    """
    # 1. まずそのままパースを試みる
    try:
        return json.loads(raw_output)
    except json.JSONDecodeError:
        pass

    # 2. マークダウンコードブロックを除去してパース
    code_block_pattern = r'```(?:json)?\s*([\s\S]*?)\s*```'
    match = re.search(code_block_pattern, raw_output)
    if match:
        try:
            return json.loads(match.group(1))
        except json.JSONDecodeError:
            pass

    # 3. JSON部分を抽出してパース(前後の余分なテキストを除去)
    json_pattern = r'\{[\s\S]*\}'
    match = re.search(json_pattern, raw_output)
    if match:
        try:
            return json.loads(match.group())
        except json.JSONDecodeError:
            pass

    # 4. パース失敗 - None を返して上位でハンドリング
    return None

def validate_output(parsed: dict, schema: dict) -> tuple[bool, list[str]]:
    """
    パース済み出力のスキーマ検証
    Returns: (is_valid, list of error messages)
    """
    errors = []

    for field, field_type in schema.items():
        if field not in parsed:
            errors.append(f"必須フィールドが欠落: {field}")
            continue

        value = parsed[field]

        if "string" in str(field_type) and not isinstance(value, str):
            errors.append(f"型エラー: {field} は文字列である必要があります(実際: {type(value).__name__})")
        elif "number" in str(field_type) and not isinstance(value, (int, float)):
            errors.append(f"型エラー: {field} は数値である必要があります")
        elif "array" in str(field_type) or isinstance(field_type, list):
            if not isinstance(value, list):
                errors.append(f"型エラー: {field} はリストである必要があります")

    return len(errors) == 0, errors

リトライによる自動修復

from antigravity import Agent  # 仮のAntigravity SDK
 
async def get_validated_output(
    agent: Agent,
    task: str,
    schema: dict,
    max_retries: int = 3
) -> Optional[dict]:
    """
    バリデーションが通るまで自動リトライする
    """
    for attempt in range(max_retries):
        prompt = create_structured_prompt(task, schema)
        raw_output = await agent.run(prompt)
 
        # パース試行
        parsed = parse_agent_output(raw_output)
        if parsed is None:
            if attempt < max_retries - 1:
                # リトライ用プロンプトで修正を依頼
                task = f"""
前回の出力がJSONとして正しくパースできませんでした。
前回の出力: {raw_output[:500]}
 
修正してください: {task}
"""
                continue
            return None
 
        # スキーマ検証
        is_valid, errors = validate_output(parsed, schema)
        if is_valid:
            return parsed
 
        if attempt < max_retries - 1:
            # エラーを伝えて修正を依頼
            error_list = "\n".join(f"- {e}" for e in errors)
            task = f"""
前回の出力に以下の問題がありました:
{error_list}
 
修正してください: {task}
"""
        else:
            print(f"バリデーション失敗 (最終試行): {errors}")
            return None
 
    return None

品質エラーへの対処:セルフチェックパターン

AI エージェントに自己評価をさせることで、品質エラーを事前にフィルタリングできます。

QUALITY_CHECK_PROMPT = """
以下のエージェント出力を品質評価してください。
 
タスク: {task}
出力: {output}
 
以下の基準で評価し、JSONで返してください:
{{
  "meets_requirements": true/false,
  "quality_score": 0.0〜1.0,
  "issues": ["問題点のリスト"],
  "needs_revision": true/false,
  "revision_guidance": "修正が必要な場合の指示"
}}
 
評価基準:
1. タスクの要件をすべて満たしているか
2. 情報が具体的で実用的か
3. 内容に矛盾や誤りはないか
4. 必要な情報量が含まれているか
"""
 
async def get_quality_checked_output(
    primary_agent: Agent,
    checker_agent: Agent,
    task: str,
    schema: dict,
    min_quality_score: float = 0.7
) -> Optional[dict]:
    """セルフチェック付きの出力生成"""
 
    for attempt in range(3):
        # プライマリエージェントで出力生成
        output = await get_validated_output(primary_agent, task, schema)
        if output is None:
            continue
 
        # チェッカーエージェントで品質評価
        check_prompt = QUALITY_CHECK_PROMPT.format(
            task=task,
            output=json.dumps(output, ensure_ascii=False)
        )
        check_raw = await checker_agent.run(check_prompt)
        check_result = parse_agent_output(check_raw, {})
 
        if check_result is None:
            # チェック自体が失敗した場合は出力をそのまま使用
            return output
 
        quality_score = check_result.get("quality_score", 0)
        needs_revision = check_result.get("needs_revision", False)
 
        if not needs_revision and quality_score >= min_quality_score:
            return output
 
        if attempt < 2:
            # 修正指示を追加してリトライ
            guidance = check_result.get("revision_guidance", "品質を改善してください")
            issues = check_result.get("issues", [])
            task = f"{task}\n\n改善指示:\n{guidance}\n問題点: {', '.join(issues)}"
        else:
            # 最終試行でも品質不足の場合は低品質フラグを付けて返す
            output["_quality_warning"] = {
                "score": quality_score,
                "issues": check_result.get("issues", [])
            }
            return output
 
    return None

整合性エラーへの対処:アグリゲーションパターン

複数回の実行や複数エージェントの出力が矛盾する場合、投票・アグリゲーションで整合性を確保します。

from collections import Counter
from typing import List
 
async def get_consensus_output(
    agent: Agent,
    task: str,
    num_samples: int = 3,
    schema: dict = None
) -> Optional[dict]:
    """
    複数回実行して多数決で最終出力を決定する
    (確率的な揺れを抑制する)
    """
    outputs = []
 
    for _ in range(num_samples):
        output = await get_validated_output(agent, task, schema or {})
        if output:
            outputs.append(output)
 
    if not outputs:
        return None
 
    if len(outputs) == 1:
        return outputs[0]
 
    # 文字列フィールドは最も多く出現した値を採用
    consensus = {}
    all_keys = set().union(*[o.keys() for o in outputs])
 
    for key in all_keys:
        if key.startswith("_"):  # 内部フィールドはスキップ
            continue
 
        values = [str(o.get(key, "")) for o in outputs if key in o]
 
        if not values:
            continue
 
        if isinstance(outputs[0].get(key), (int, float)):
            # 数値は平均値を使用
            numeric_values = [o[key] for o in outputs if key in o and isinstance(o[key], (int, float))]
            consensus[key] = sum(numeric_values) / len(numeric_values)
        elif isinstance(outputs[0].get(key), list):
            # リストは出現頻度の高いアイテムを優先
            all_items = [item for o in outputs for item in o.get(key, [])]
            item_counts = Counter(all_items)
            consensus[key] = [item for item, _ in item_counts.most_common()]
        else:
            # 文字列は最頻値を使用
            consensus[key] = Counter(values).most_common(1)[0][0]
 
    return consensus

出力検証のモニタリング

本番環境では、バリデーションエラーの発生率を継続的に監視する点が肝心です。

import time
from dataclasses import dataclass, field
from collections import defaultdict
 
@dataclass
class ValidationMetrics:
    total_attempts: int = 0
    format_errors: int = 0
    quality_errors: int = 0
    success_count: int = 0
    retry_counts: list = field(default_factory=list)
    error_details: list = field(default_factory=list)
 
    @property
    def success_rate(self) -> float:
        return self.success_count / self.total_attempts if self.total_attempts > 0 else 0
 
    @property
    def avg_retries(self) -> float:
        return sum(self.retry_counts) / len(self.retry_counts) if self.retry_counts else 0
 
    def alert_if_needed(self):
        if self.success_rate < 0.8:
            print(f"⚠️ 出力検証成功率が低下: {self.success_rate:.1%}")
        if self.avg_retries > 1.5:
            print(f"⚠️ 平均リトライ回数が高い: {self.avg_retries:.1f}回")
 
metrics = ValidationMetrics()

全体を振り返って

Antigravity エージェントの出力検証エラーへの対処は、形式エラー(パースエラーの自動修復・リトライ)、品質エラー(セルフチェックパターン)、整合性エラー(複数実行でのアグリゲーション)の3層で考えるとわかりやすくなります。完璧な出力を毎回保証することは難しいですが、適切な検証と回復戦略を組み合わせることで、実用的なレベルの品質と安定性を実現できます。困っている方のお役に立てれば幸いです。

個人開発12年の現場で実感したこと

線引きするときの3つの判断軸

  • 失敗時の影響が金銭やユーザー体験にどれだけ波及するか
  • 復旧オペレーションが明文化されているか
  • 観測ログから人間が再現できる粒度に整っているか
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Agents & Manager2026-06-29
Antigravity のエージェントが開く PR の説明が「Update files」のままになる問題と、レビューできる要約を強制するゲート
Antigravity のエージェントが自動で開く PR は、説明が「Update files」のように空疎になりがちです。差分からリスクを見積もり、空疎な説明を弾いてレビューできる要約を強制する検証ゲートを、動くコードとともにまとめます。
Agents & Manager2026-06-29
Antigravity に書かせたテストが「通るだけ」になっていないか — ミューテーションで実効性を測る
Antigravity のエージェントに書かせたテストは、通っても肝心のバグを捕まえられないことがあります。ミューテーションテストで実効性を測り、生存ミュータントを潰してから採用する運用を、動くコードとともにまとめます。
Agents & Manager2026-07-17
エージェントに渡した参照メモの7割は届いていませんでした — head で切る運用の限界を測った記録
定期実行のエージェントに参照メモを cat と head で渡していたところ、肝心な行が黙って落ちていました。切り取り位置を実測し、行数ではなくセクション単位の契約に置き換えるまでの記録です。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →