グラウンドトゥルース: AIエージェントを現実につなぎとめる
> AIエージェントは自信満々にハルシネーションを起こします。グラウンドトゥルースは、バージョン管理され、スコープが明確な事実であり、エージェントの振る舞いを現実につなぎとめます。私たちがどのようにそれを構築し、運用しているかを紹介します。
この記事の数値は公開時点(2026年1月)のシステムを反映しています。最新の数値はチームページをご覧ください。
AIエージェントは驚くほど高い能力を持っています。推論し、統合し、生成することができます。しかし根本的な弱点が1つあります。事実を作り出してしまうのです。悪意からではなく、自信満々に。エージェントは、存在しないAPIパラメータをでっち上げたり、一度も定義されたことのない設定を参照したり、実際のアーキテクチャと矛盾する、学習データ由来のパターンを適用したりすることがあります。
定番の対策は「エージェントにもっとコンテキストを与える」ことです。しかしコンテキスト自体が矛盾していることもあります。ドキュメントは実装から乖離していきます。コメントは嘘をつきます。コードでさえ、意図を理解せずに読めば誤解を招くことがあります。
私たちには、もっと明示的な何かが必要でした。無視することも誤解することもできない何か。エージェントを検証可能な現実につなぎとめる何かです。
私たちはそれをグラウンドトゥルースと呼んでいます。
グラウンドトゥルースとは何か
グラウンドトゥルースとは、エージェントが尊重しなければならない、明示的かつバージョン管理された事実の記述です。ドキュメントではありません。コメントでもありません。システムにおける第一級のエンティティであり、次の要素を備えています:
- 一意の識別子(
GT-MAG-015やGT-MAG-036のような) - ライフサイクルステータス(current、tentative、deprecatedのいずれか)
- スコープ(プラットフォーム全体、パッケージ固有、ドメイン限定のいずれか)
- エビデンス(その記述を裏付けるファイルパス、URL、参照)
- エージェント向けガイダンス(明示的な「すべきこと/避けるべきこと」の指示)
私たちのコードインテリジェンスプラットフォームMaguyvaからの例を示します:
- id: GT-MAG-015
status: current
scope: package
statement: |
Fuzzy symbol matching is opt-in via `find_similar=true`.
Default behavior returns empty results for non-existent symbols;
`exact_match=true` enforces strict matching and disables all fuzzy fallbacks.
rationale: |
Deterministic defaults prevent agents from receiving misleading results.
Typos should fail explicitly rather than silently returning unrelated symbols.
evidence:
- "packages/maguyva/server/src/maguyva/services/code_analysis_service.py"
- "packages/maguyva/server/docs/quick_reference/parameters.md"
last_verified: "2026-01-25"
tags:
- product
- ai_first
- principle
これは文章ではありません。契約です。エージェントがこのグラウンドトゥルースに遭遇したとき、次のことがわかります:
- デフォルトは決定的である(あいまいな推測ではなく、空の結果を返す)
- 定義済みの挙動を持つ特定のパラメータ(
find_similar、exact_match)が存在する - 検証可能な特定のファイルにエビデンスが存在する
- この記述は特定の日付に検証済みである
グラウンドトゥルースレジストリの構造
グラウンドトゥルースは、ai_assets/reference/ground_truths.yaml配下のYAMLレジストリに格納されます。各パッケージやドメインは、それぞれ独自のレジストリを持つことができます。その構造は次の通りです:
metadata:
title: "Maguyva Ground Truths"
summary: "Foundational constraints and principles that guide Maguyva."
last_updated: "2026-01-26"
owner: "maguyva"
render:
include_statuses: [current, tentative]
show_deprecated: true
groups:
- title: "Product Principles"
tags: [product, principle, brand]
- title: "Architecture & Boundaries"
tags: [architecture, boundaries, cqrs]
statements:
- id: GT-MAG-001
status: current
scope: package
statement: "Maguyva is read-only with respect to user repositories..."
...
レジストリには、コレクション自体に関するメタデータ、ドキュメント生成のためのレンダー設定、そして記述そのものが含まれます。それぞれの記述は、Pydanticモデルによって検証される厳格なスキーマに従います:
class GroundTruthStatement(BaseModel):
id: str
status: GTStatus # current, tentative, deprecated
source: GTSource | None # claude-code, orkestra, discipline
scope: GTScope # platform, package, domain
statement: str
rationale: str | None
evidence: list[str]
last_verified: str | None
tags: list[str]
agent_guidance: AgentGuidance | None
エージェントはグラウンドトゥルースにどうアクセスするか
グラウンドトゥルースは複数のチャネルを通じて公開されています:
1. レンダリングされたドキュメント
orkestra syncコマンドは、YAMLレジストリを読みやすいMarkdownへ変換します:
uv run orkestra sync
これにより、エージェントのコンテキストに組み込まれるGROUND_TRUTHS.mdファイルが生成されます。レンダリングされた出力は、記述をステータスとカテゴリー別にグループ化します:
## Current
### Product Principles
- Maguyva is read-only with respect to user repositories... (GT-MAG-001)
- Design tool responses for AI agents first... (GT-MAG-009)
### Architecture & Boundaries
- Pipeline and Maguyva boundaries are intentional... (GT-MAG-006)
2. CLI検索
シェルアクセスを持つエージェントは、グラウンドトゥルースをプログラム的に検索できます:
uv run orkestra context ground-truths search "embedding"
uv run orkestra context ground-truths search --tag security
uv run orkestra context ground-truths list --status current
検索機能は、複数のフィールドにまたがるマッチを重み付きの関連度でスコアリングします:
def truth_fields(gt: GroundTruthStatement) -> list[FieldSpec]:
return [
FieldSpec(name="id", weight=6, values=[gt.id]),
FieldSpec(name="statement", weight=5, values=[gt.statement]),
FieldSpec(name="rationale", weight=4, values=[gt.rationale] if gt.rationale else []),
FieldSpec(name="tags", weight=3, values=gt.tags or []),
FieldSpec(name="evidence", weight=2, values=gt.evidence or []),
]
3. コンテキストの構成
エージェントがYAML定義からレンダリングされる際、そのコンテキストはグラウンドトゥルースレジストリを参照できます:
context_composition:
domain_knowledge:
- packages/maguyva/ai_assets/reference/ground_truths.yaml
これにより、エージェントが作業を始める前に、関連するグラウンドトゥルースが確実に読み込まれます。
グラウンドトゥルースの分類
私たちのレジストリ全体を見渡すと、グラウンドトゥルースはいくつかのパターンにまとまっていきます:
プロダクト原則
プロダクトが何であり、何でないかについての制約です:
「Maguyvaはユーザーのリポジトリに対して読み取り専用である。再構築不可能な唯一のアセットは、有料の埋め込みキャッシュである。」(GT-MAG-001)
アーキテクチャの境界
責務がどこにあり、なぜそこにあるのかです:
「パイプラインとMaguyvaの境界は意図的なものである。パイプラインは再利用可能であり、Maguyvaはコード固有のロジックを保持し、CQRSはステージの書き込みとサーバーの読み取りを分離する。」(GT-MAG-006)
ハルシネーション防止ルール
ツールの契約を、推測ではなく決定的なものに保つための明示的な規定です:
「あいまいなシンボルマッチングは
find_similar=trueを介したオプトインである。デフォルトの挙動は、存在しないシンボルに対して空の結果を返す。exact_match=trueは厳格なマッチングを強制し、あいまいなフォールバックをすべて無効化する。」(GT-MAG-015)
品質ゲート
維持されなければならない基準です:
「共有インフラ(post_filters.py、関係抽出器、共有ハンドラー)への変更は、コミット前にフルマニフェスト生成を通じて、サポートするすべての言語に対して検証されなければならない。共有コードに対して単一言語での検証だけでは不十分である。」(GT-MAG-036)
コードパターン
実装上の要件です:
「非同期コンテキストにおけるCPUバウンドな処理には
asyncio.to_thread()を使用する。非推奨のloop.run_in_executor()パターンは新規コードで使用してはならない。」(GT-MAG-018)
グラウンドトゥルースのライフサイクル
グラウンドトゥルースは静的なものではありません。定義されたライフサイクルを通じて進化していきます:
Tentative(暫定)
評価中の、提案された真実です。記述は記録されますが、変更される可能性があります:
- id: GT-MAG-044
status: tentative
statement: |
get_file with include_metadata=false may still return metadata in the
response because middleware may re-inject it for AI agent disambiguation.
Current(有効)
エージェントが尊重しなければならない、検証済みの真実です。エビデンスは検証済みです:
- id: GT-MAG-017
status: current
last_verified: "2026-01-26"
evidence:
- "packages/maguyva/server/src/maguyva/services/supabase.py"
Deprecated(廃止)
もはや適用されない真実です。何に置き換えられたかへのポインタとともに、歴史的な参照として保持されます:
- id: GT-MAG-099
status: deprecated
superseded_by: GT-MAG-015
notes: "Replaced when we moved to explicit matching behavior"
なぜドキュメントだけではだめなのか
ドキュメントは異なる目的に奉仕します。説明します。教えます。あいまいであってもよく、「一般的に」や「通常は」といった限定語を使うこともできます。
グラウンドトゥルースはあいまいであってはなりません。それは断定です。適用されるか、されないかのどちらかです。
その違いを見てみましょう:
ドキュメント: 「APIは、シンボルが見つからない場合、一般的には空の結果を返しますが、設定によってはあいまいマッチングが有効になっている場合もあります。」
グラウンドトゥルース: 「デフォルトの挙動は、存在しないシンボルに対して空の結果を返す。exact_match=trueは厳格なマッチングを強制し、あいまいなフォールバックをすべて無効化する。」
前者はシステムを学ぼうとする人間にとって有用です。後者は、判断を下すエージェントにとって実行可能なものです。
エージェント向けガイダンス:すべきこと・避けるべきこと
一部のグラウンドトゥルースには、明示的なエージェント向けガイダンスが含まれています:
- id: GT-MAG-022
statement: |
Accuracy fixes must happen at extraction time via production code,
never via validator filters.
agent_guidance:
do:
- "Fix extraction bugs in YAML config, handlers, or tree-sitter queries"
- "Add test cases at the layer where the fix lives"
avoid:
- "Adding validator filters to mask production bugs"
- "Creating test-only workarounds for extraction issues"
これによりあいまいさが排除されます。これを読んだエージェントは、何が真実であるかだけでなく、その真実がどのような行動を意味するのかも理解できます。
検証とメンテナンス
グラウンドトゥルースにはメンテナンスが必要です。私たちは次を追跡しています:
- last_verified:誰かがその記述が今も成り立っていることを確認した日時
- evidence:その記述を裏付けるファイル(存在確認が可能)
- source:その真実がどこから生まれたか(CLIによる調査、アーキテクチャレビュー、インシデント後の学び)
検証日が古くなっていたり、エビデンスへのリンクが壊れていたりするグラウンドトゥルースは、調査すべきサインです。その真実がまだ有効で再検証が必要なのか、それとも現実が変わってしまいその真実を更新する必要があるのか、どちらかです。
本番環境からの実例
セキュリティ境界
- id: GT-MAG-014
statement: |
Maguyva queries are search patterns, not executable code.
SQL injection prevention is handled by PostgREST parameterization;
application-layer SQL keyword blocking must never be added.
rationale: |
Blocking SQL keywords breaks legitimate code search. Users search FOR
code containing patterns like 'DROP TABLE', they don't execute them.
このグラウンドトゥルースは、プロダクトを壊してしまうであろう、見当違いの「セキュリティ改善」の一群を未然に防ぎます。
抽出時点での精度
- id: GT-MAG-022
statement: |
Accuracy fixes must happen at extraction time via production code
(YAML config, handlers, queries), never via validator filters.
rationale: |
Validator filters only run during tests. They can hide extractor bugs
while production responses remain wrong.
これは痛い経験から生まれたルールです。エージェントは、失敗している言語パックに対して、テストハーネスをより「グリーン」に見せかけるだけのバリデータ限定フィルタを追加してパッチを当てていました。その一方で、実際に稼働しているMaguyvaの抽出器は、依然として誤ったエッジを出力し続けていたのです。このルールは、修正を本来あるべき本物の経路 ―― YAML設定、クエリ、あるいはハンドラー ―― へ強制的に差し戻します。
多層フィルタリング
- id: GT-MAG-023
statement: |
Language engine uses three-tier filtering: external_method_patterns
(builtins/stdlib), allowlists (legitimate idioms), and expected_call_targets
(validation-time deduplication). Each tier serves a distinct purpose.
rationale: |
Conflating filter purposes leads to either over-filtering (missing real
relationships) or under-filtering (noise).
これにより、エージェントが誤った場所にフィルタを追加してしまうという、精度の退行を引き起こしがちなよくあるミスを防ぎます。
オーケストレーションシステムとの統合
グラウンドトゥルースは、より広いコンテキストシステムにおける1つのレイヤーです:
- アーキテクチャ上の意思決定(ADR) ―― なぜアプローチAをBより選んだのかを記録する
- グラウンドトゥルース ―― 今この瞬間、確定的に真実であることを述べる
- ドメインパターン ―― 正しい進め方を説明する
- アンチパターン ―― 何を避けるべきか、なぜかを説明する
このシステムの中で作業するエージェントは、この4つすべてにアクセスできます。グラウンドトゥルースが事実の錨(いかり)を提供し、意思決定が歴史を説明し、パターンが実装を導き、アンチパターンが落とし穴を警告します。
効果の測定
グラウンドトゥルースを導入して以来、私たちは次のような変化を観測しています:
- 「ハルシネーションによる修正を、さらに修正する」サイクルの減少
- 事実が明確なときの、エージェントによるより自信を持った意思決定
- 期待値が明示的であることによる、PRレビューの質の向上
- 新しいエージェント(そして人間)のオンボーディング時間の短縮
グラウンドトゥルースを維持するための投資は、デバッグ時間の削減と、より明確なシステム境界という形で報われます。
はじめに
あなたのシステムにグラウンドトゥルースを追加するには:
- パッケージの
ai_assets/reference/ディレクトリにground_truths.yamlを作成する - メタデータとレンダー設定を定義する
- スキーマに従って記述を追加する
uv run orkestra syncを実行してドキュメントを生成する- エージェントのコンテキスト構成にレジストリを組み込む
もっとも混乱を招く事実や、もっとも頻繁に破られる制約から始めましょう。それらが、あなたにとって最も価値の高いグラウンドトゥルースです。
結論
AIエージェントはハルシネーションを起こします。それがその本質です。しかし私たちは、ハルシネーションが制約された環境、特定の事実が交渉の余地なく確定している環境、エージェントが自らの前提を検証済みの現実と照らし合わせて確認できる環境を作ることができます。
グラウンドトゥルースは完全な解決策ではありません。メンテナンスが必要です。古くなることもあります。開発プロセスにオーバーヘッドを加えます。
しかし、価値あるものを提供してくれます。人間とエージェントの両方が信頼できる、事実についての共有語彙です。エージェントがソフトウェア開発にますます参加するようになる世界において、その共有された基盤は不可欠なものになっていきます。
その代替案は、エージェントが自信満々に間違いを犯し、人間がそれを訂正し続けるという終わりのないサイクルです。グラウンドトゥルースは、その訂正を明示的かつ永続的なものにすることで、そのサイクルを断ち切ります。
あなたのエージェントには、何が真実かを知る資格があります。それを、教えてあげましょう。
関連記事
Maguyva開発ログのその他の記事
コード検索をvoyage-4-largeへアップグレードした理由_
私たちはコード埋め込みをvoyage-4-largeへ移行しました ―― 現在、公開RTEBコード検索リーダーボードのトップに立つモデルです。正直に言うと:私たちが受け入れているトレードオフ、実際に何をインデックス化しているか、そしてなぜプレミアムな埋め込みにお金を払うのか。
言語の再帰的自己改善:約280言語にわたるコードインテリジェンスの磨き上げ_
私たちは約280言語のコードインテリジェンスに対応しています。人間の手でそのすべてを監査することはできません。そこで私たちは、言語の再帰的自己改善ループ ―― 抜き取り検査、LLM-as-judge、1点修正、再検証 ―― を構築し、抽出が単に「グリーン」であるだけでなく実際に正しくなるまで、隔離されたエージェント群でこれを回し続けています。
マルチモーダル・フュージョン検索:あらゆるクエリに最適な検索エンジンを選ぶ_
「parseConfigはどこで定義されているか」のようなクエリと「認証はどう動いているか」のようなクエリでは、求められる検索の種類が異なります。Maguyvaは意図を分類し、それに応じて4つの検索モダリティに重みを付け、重み付き相互順位融合で結果を統合します。