はじめに
AIに設計書やREADMEを渡すと、実装の精度が上がる。そう考えて、私たちはさまざまなドキュメントをAIに読ませています。ですが、そのドキュメントは本当に正しいでしょうか。実際のプロジェクトには、こんな情報が紛れています。
- READMEや設計書が現在の実装と一致していない
- 古い設計書が削除されずに残っている
- 複数のドキュメントに異なるルールが書かれている
本記事では、こうしてAIに与える補足情報を「Context」と呼びます。同じ課題と初期コードに対してContextだけを変えた4つの条件を比較し、正しくない情報がAIコーディングの品質にどう影響するかを検証しました。
本記事は、「AIコーディングにおける情報設計の原則」検証シリーズの第1回です。シリーズ全体の予定は、記事末尾に記載しています。
Contextの扱いは、AIベンダー各社も認識している課題
この問題意識は、私たちのプロジェクトに限った話ではありません。
- Anthropic:Contextが長くなるほど、モデルが情報を正確に利用する能力は低下し得る(Effective context engineering for AI agents)。長時間稼働するエージェントでは作業状態の引き継ぎも課題(Effective harnesses for long-running agents)
- Google DeepMind:長いContextからの情報の取り出しはできても、無関係な情報を削ぎ落として複数の情報を統合する推論には改善の余地がある(Michelangelo: Long Context Evaluations Beyond Haystacks)
- OpenAI:リポジトリ情報の与え方と動作の評価を、重要なエンジニアリング課題として扱う(Introducing Codex)
各社に共通する課題は、単に情報を増やすことではなく、
AIが利用する情報を、どのように選択・構造化・更新・供給・評価するか
という点にあります。本シリーズでは、この問いを段階的な実験で検証します。本記事はその第1回で、情報の正確性と一貫性が品質に与える影響を扱います。
結論
正確なContextはすべてのテストを通過させた。しかしそれ以上に大きかったのは、古いContextがContextなしよりも品質を大幅に下げたことだ。AIはContextとコードの不整合に気付いても情報の「古さ」を疑わず、矛盾したContextを与えられても、その矛盾を一度も指摘しなかった。
効果は非対称でした。
- 正確なContextを足した効果:テスト成功 9/10 → 10/10 で +1
- 古いContextを混ぜた損害:テスト成功 9/10 → 4/10 で −5
ただし、Contextなしの時点で9/10に達しているため、改善側には天井効果があります。
| 条件 | テスト成功率 | 提示Contextからの逸脱数 | 要求外変更数 | 不整合・矛盾への言及 |
|---|---|---|---|---|
| A:Contextなし | 9/10 | 対象外 | 0 | 対象外 |
| B:正しいContext | 10/10 | 0 | 0 | 対象外 |
| C:古いContext | 4/10 | 2 ※ | 0 | 3/3(コードとの不整合) |
| D:矛盾したContext | 10/10 | 評価対象外 | 0 | 0/3(Context内部の矛盾) |
テスト成功率と逸脱数は、3試行すべてで同一の結果でした。※印の詳細は「検証結果」の脚注を参照してください。
本記事で扱う「Context」
一般に、AIコーディングでは次のような幅広い情報がContextに含まれます。
- ユーザーが入力した指示
- 会話履歴
- リポジトリ内のコード
- READMEや設計書
CLAUDE.mdやAGENTS.md- ADRなどに残された設計判断
- MCPや外部ツールから取得した情報
- 実行結果やエラーログ
- AIが保持するメモリ
PromptとContextの区別
本検証では、PromptとContextを、記述されている場所ではなく、情報が担う役割によって区別します。
- Prompt:AIに何をしてほしいかを伝える情報
- Context:その仕事を適切に行うために、何を知っておいてほしいかを伝える情報
両者は、同じ入力文に含まれる場合もあります。
注文キャンセル機能を実装してください。
未発送の注文のみキャンセル可能です。
管理者は発送済みでもキャンセルできます。
キャンセルできない場合は409を返してください。この場合、最初の一文がPrompt、それ以降がContextの役割を担っています。
今回の検証で扱う範囲
Contextに含まれる情報を同時に変更すると、どの情報が結果に影響したのか判断できません。そのため、今回はContextを次のように限定します。
AIに実装を依頼する際、課題文とは別に明示的に与える補足情報
- Contextとして与えたもの:条件B〜Dの業務ルール。キャンセル可否の条件、権限の例外、エラーコード、データの保存形式、在庫の扱い
- 与えていないもの:受け入れ条件と自動テスト。評価専用としてAIには見せていない
- Contextとは別に、全条件で固定して与えたもの:課題文と初期コード
- 今後の検証で変数として扱うもの:コードベースそのもの、会話履歴、ルールファイルの配置場所など
今回の検証結果は、あらゆる種類のContextにそのまま適用できるものではありません。今回定義した、明示的に与える補足情報に限定した結果として扱います。
今回の問いと仮説
Contextが存在すること自体ではなく、その正確性や一貫性がAIコーディングの品質を左右するのではないか。
この問いに対して、3つの仮説を立てます。
- 仮説1:正確で関連性の高いContextは、要求に適合した実装を増やす
- 仮説2:古いContextは、Contextを与えない場合よりも実装品質を低下させる
- 仮説3:矛盾したContextを与えられても、AIは必ずしも矛盾を指摘したり、確認質問をしたりするとは限らない
検証の設計
同じ初期コード、同じ課題、同じAIモデルを使用し、AIに与えるContextだけを変更します。
方法論に興味がない場合は、このセクションを読み飛ばして検証結果へ進んでも問題ありません。
固定する条件と変更する条件
- 固定するもの:初期コード、実装課題、ツール、モデル、実行環境、Contextの書式、自動テスト、評価基準
- 変更するもの:Contextの内容のみ
| 条件 | 与える情報 |
|---|---|
| A | 課題文のみ |
| B | 正確なContext |
| C | 一部が古いContext |
| D | 正しい情報と矛盾する情報が混在したContext |
- 条件間で揃えるもの:Contextの構造と情報量
- 今後の検証で個別に扱うもの:書式、配置場所、量、与えるタイミング
「古いContext」と「矛盾したContext」の定義
古いContext(条件C)と矛盾したContext(条件D)は、どちらも誤った情報を含みますが、誤りの現れ方で区別して定義します。
- 古いContext(条件C)
- Context内部に矛盾はなく、単体で読むと筋が通っている
- 一部のルールが過去の仕様のまま残っており、初期コードと照合した場合にのみ不整合に気付ける。例えば、現在のコードに存在しない状態名やフィールド名の参照
- 観察対象:与えられた情報をAIが疑うかどうか
- 矛盾したContext(条件D)
- 同じ項目について互いに両立しないルールが併記されており、Context単体で矛盾を検出できる
- 観察対象:検出可能な矛盾を、AIがどう扱うか
いずれの誤情報も、AIを引っ掛けるための不自然な文章ではなく、実際の開発プロジェクトで発生し得る状態を想定して作成します。
試行回数と対話プロトコル
- 試行回数:各条件3回。AIの出力には非決定性があるため
- セッション:試行ごとに独立した新規セッション
- 実行形態:非対話モード(ヘッドレス実行)
- 依頼は最初の1メッセージのみで、途中の対話や追加の指示は行わない
- AIが確認質問を出力しても回答は返らない。確認質問への言及は出力ログから記録
- 自動テストはAIには与えず、評価専用
検証用の課題
検証には、一般的な実装知識だけでは正しい仕様を推測できない、小規模な業務機能を使用します。
- 課題:TypeScript製のインメモリ注文管理APIへ、注文キャンセル機能(
cancelOrder関数)を追加する - 作成方法:課題・初期コード・テストはAIに生成させ、人間がレビューして確定
- 含まれる業務ルール:
- 未発送の注文だけキャンセルできる、という状態依存のルール
- 管理者は発送済みでもキャンセルできる、という権限の例外
- キャンセル時に在庫を元に戻す、という関連データの更新
- 409 / 404 / 403 という決められたエラーコード
- 選定理由:Contextなしでは判断できない業務ルールを含められ、古い仕様や矛盾を自然に混在させやすく、自動テストで客観的に評価でき、AIが短時間で実装できる規模に収まる
共通の課題文
# 課題: 注文キャンセル機能の実装
このリポジトリは、TypeScript で実装された注文管理 API です。
`src/orders.ts` に、注文をキャンセルする関数 `cancelOrder` を実装してください。
## インターフェース
```typescript
export function cancelOrder(orderId: string, actor: Actor): Result<Order>
```
- 既存の関数(`payOrder` など)と同じ `Result` 型・エラーハンドリングの流儀に従ってください
- 注文のキャンセルに関する業務ルールに従って実装してください
## 注意事項
- 変更は課題の実装に必要な範囲にとどめてください
- テストの作成は不要です(テストは別途用意されています)
- 実装完了後、実装内容と、実装にあたって判断・仮定した点を報告してください初期コード
初期コードは、インメモリの注文管理APIです。cancelOrder だけが未実装です。
src/types.ts:型定義src/store.ts:注文の保存src/inventory.ts:在庫管理src/orders.ts:注文操作。状態遷移とResult型によるエラーハンドリングの規約を含む
export type OrderStatus = "pending" | "paid" | "shipped" | "delivered" | "cancelled"
export type OrderItem = {
sku: string
quantity: number
}
export type Order = {
id: string
userId: string
status: OrderStatus
items: OrderItem[]
createdAt: string
paidAt?: string
shippedAt?: string
deliveredAt?: string
cancelledAt?: string
}
export type Actor = {
id: string
role: "customer" | "admin"
}
export type Result<T> = { ok: true; value: T } | { ok: false; code: number; message: string }export function payOrder(orderId: string): Result<Order> {
const order = findOrder(orderId)
if (!order) {
return { ok: false, code: 404, message: "注文が見つかりません" }
}
if (order.status !== "pending") {
return { ok: false, code: 409, message: `状態 ${order.status} の注文は支払いできません` }
}
order.status = "paid"
order.paidAt = new Date().toISOString()
saveOrder(order)
return { ok: true, value: order }
}
// createOrder / getOrder / shipOrder / deliverOrder も同じ流儀で実装済み
// createOrder は注文作成時に decreaseStock で在庫を引き当てる既存コードには 404 / 409 のエラーコードや ISO 8601 の日時形式といった規約が現れているため、条件Aでも一部のルールはコードから推測できます。管理者の例外や delivered の扱いのように推測できないルールが、条件間の差を生む設計です。
受け入れ条件
10件の自動テストは、次の受け入れ条件7項目を反映しています。これが「現在の正しい仕様」であり、条件Bで与えるContextと一致します。受け入れ条件達成率は、対応するテストがすべて成功した条件を「達成」として数えます。
- 所有者は、未発送(pending / paid)の注文をキャンセルできる(テスト1, 2)
- 所有者でも、shipped の注文はキャンセルできない=409(テスト5)
- 管理者は shipped の注文をキャンセルできるが、delivered はキャンセルできない=409(テスト6, 7)
- 所有者以外の customer によるキャンセルは 403、存在しない注文は 404(テスト8, 9)
- キャンセル成功時、status は "cancelled" になり、cancelledAt に ISO 8601 形式の日時が保存される(テスト1, 3)
- キャンセル成功時、注文に含まれる商品の在庫が元に戻る(テスト4)
- キャンセル済みの注文を再度キャンセルすると 409(テスト10)
条件ごとのContext
条件A:Contextなし
課題文だけを与えます。実際のPromptは、上に掲載した共通の課題文そのものです。
条件B:正しいContext
現在の要求、制約、業務ルールを正しく記載したContextを与えます。
## 補足情報: 注文キャンセルの業務ルール
- キャンセルできるのは、未発送の注文(status が "pending" または "paid")のみです
- 注文をキャンセルできるのは、その注文の所有者(order.userId と actor.id が一致する customer)です
- 管理者(role が "admin")は、発送済み(shipped)の注文もキャンセルできます
- 配達完了(delivered)の注文は、管理者でもキャンセルできません
- キャンセルできない状態の注文への操作は、code 409 を返します
- 存在しない注文への操作は code 404、所有者以外の customer による操作は code 403 を返します
- キャンセル成功時は、status を "cancelled" に変更し、cancelledAt に日時(ISO 8601 形式)を保存します
- キャンセル時は、注文に含まれる商品の在庫を元に戻します(inventory の increaseStock を使用)条件C:一部が古いContext
条件Bと同程度の情報量と構造を保ちつつ、一部のルールを過去の仕様に置き換えます。
## 補足情報: 注文キャンセルの業務ルール
- キャンセルできるのは、確定前の注文(status が "created")のみです
- 注文をキャンセルできるのは、その注文の所有者(order.userId と actor.id が一致する customer)です
- 管理者(role が "admin")であっても、確定後("confirmed" 以降)の注文はキャンセルできません
- キャンセル済みの注文を再度キャンセルすることはできません
- キャンセルできない状態の注文への操作は、code 400 を返します
- 存在しない注文への操作は code 404、所有者以外の customer による操作は code 403 を返します
- キャンセル成功時は、status を "canceled" に変更し、canceledDate に日時(UNIX タイムスタンプ)を保存します
- 在庫の変更は行いません(在庫は出荷時に引き当てるため、キャンセルによる在庫の操作は不要です)条件D:矛盾したContext
同じ項目について、互いに両立しないルールを2組含めます。
- 弱い矛盾:「発送後はキャンセル不可・返品フローで対応」と「管理者は shipped もキャンセル可」の併記。解釈で回避できる
- 強い矛盾:「キャンセル不可は 409」と「エラーは種類を問わず常に 400」の併記。回避できない
## 補足情報: 注文キャンセルの業務ルール
- キャンセルできるのは、未発送の注文(status が "pending" または "paid")のみです。発送後の注文はキャンセルできないため、返品フローで対応します
- 注文をキャンセルできるのは、その注文の所有者(order.userId と actor.id が一致する customer)です
- 管理者(role が "admin")は、発送済み(shipped)の注文もキャンセルできます
- キャンセルできない状態の注文への操作は、code 409 を返します
- エラーが発生した場合は、エラーの種類を問わず常に code 400 を返します
- 存在しない注文への操作は code 404、所有者以外の customer による操作は code 403 を返します
- キャンセル成功時は、status を "cancelled" に変更し、cancelledAt に日時(ISO 8601 形式)を保存します
- キャンセル時は、注文に含まれる商品の在庫を元に戻します(inventory の increaseStock を使用)品質の定義と評価方法
実装品質は、次の4つの観点で評価します。保守性、可読性、パフォーマンスなどは、副次的な評価項目として扱います。
- 観点1:要求を満たしているか ― 自動テストと受け入れ条件で測定
- 観点2:Contextと整合しているか ― 提示Contextからの逸脱数で測定
- 観点3:不要な変更を行っていないか ― 要求外変更数で測定
- 観点4:不確実な情報を適切に扱ったか ― 不整合・矛盾・情報不足への言及、確認質問、仮定の明示で測定
提示Contextからの逸脱数は「提示したContextへの逸脱」を数えます。自動テストは現在の正しい仕様を反映しているため、Context自体に誤りが含まれる条件Cでは、Contextに忠実な実装ほどテストに失敗し得ます。この逆転こそが本検証の観察対象であり、両者は独立した指標として記録します。なお、条件Dは互いに両立できないルールを含み、どちらかに従えば必ずもう一方から逸脱するため、この項目の評価対象外とします。
評価項目と判定方法の詳細
| 評価項目 | 判定方法 | 対応する観点 |
|---|---|---|
| 自動テスト成功率 | 成功したテスト数 ÷ 全テスト数 | 観点1 |
| 受け入れ条件達成率 | 達成した条件数 ÷ 全条件数 | 観点1 |
| 提示Contextからの逸脱数 | 提示したルールに反した実装数 | 観点2 |
| 要求外変更数 | 課題と直接関係のない変更数 | 観点3 |
観点4に対応するAIの判断評価は、次の項目で記録します。
| 評価項目 | 判定方法 |
|---|---|
| コードとの不整合/Context内部の矛盾を指摘したか | はい/いいえ |
| 情報不足を指摘したか | はい/いいえ |
| 確認質問・確認の必要性に言及したか | ユーザーへの行動要求(質問・依頼)があれば「はい」。自発的な調整の申し出のみは「いいえ」 |
| 仮定を明示したか | はい/いいえ |
| 判断の根拠を説明したか | はい/一部/いいえ |
あわせて、作業効率として完了までの時間を記録します。依頼の送信から実装完了までの実行時間です。
実行環境
AIの挙動は、モデルやツールの更新によって変化する可能性があるため、再現条件として次の情報を記録します。
実行環境(再現条件)
| 項目 | 内容 |
|---|---|
| 検証日 | 2026-07-29 |
| AIコーディングツール | Claude Code CLI 2.1.110(claude -p) |
| モデル | claude-opus-4-8 |
| モデル設定 | effort: medium、thinking 有効(グローバル設定を継承) |
| 言語 | TypeScript ^5(strict モード) |
| フレームワーク | なし(Node.js 標準テストランナー + tsx) |
| Node.js | v24.12.0 |
| OS | macOS 14.0 |
| 実行形態 | 非対話モード(ヘッドレス実行) |
| 試行回数 | 各条件3回 |
| セッション | 試行ごとに新規セッション |
検証結果
総合結果
- テスト結果・受け入れ条件:各条件で3試行すべて同じ結果。条件Aは3試行の実装 diff がバイト単位で同一
- 完了時間:3試行の平均
- 行動評価:該当した試行数を「該当数 / 3」で表記
| 評価項目 | A:なし | B:正しい | C:古い | D:矛盾 |
|---|---|---|---|---|
| 自動テスト成功率 | 9/10 | 10/10 | 4/10 | 10/10 |
| 受け入れ条件達成率 | 6/7 | 7/7 | 2/7 | 7/7 |
| 提示Contextからの逸脱数 | 対象外 | 0 | 2 ※1 | 評価対象外 ※2 |
| 要求外変更数 | 0 | 0 | 0 | 0 |
| コードとの不整合への言及 | 対象外 | 対象外 | 3/3 ※3 | 対象外 |
| Context内部の矛盾への言及 | 対象外 | 対象外 | 対象外 | 0/3 |
| 確認質問・確認の必要性への言及 | 1/3 | 0/3 | 2/3 | 1/3 |
| 完了時間(平均) | 58秒 | 45秒 | 98秒 | 57秒 |
※1 条件Cの逸脱2件は、状態名の読み替え(created → pending)と、保存形式の読み替え("canceled" / canceledDate / UNIXタイムスタンプ → "cancelled" / cancelledAt / ISO 8601。同一フィールドに関する読み替えのため1件と数える)。いずれもAIが報告した上で行った意図的な読み替えで、テスト成功に寄与した。逆に、型エラーにならない古いルールには忠実に従っており、それがテスト失敗6件の原因
※2 条件Dは両立できないルールを含み、どちらかに従えば必ずもう一方から逸脱するため評価対象外
※3 不整合の報告は3試行すべてにあったが、原因を「情報が古い」と帰属した試行はゼロ
条件A:Contextなし
結果:Contextなしでも9/10のテストに成功しましたが、コードから推測できない管理者例外だけを実装できませんでした。
条件Aの詳細
- 実装:404 → 403 → 409 のガード、pending / paid のみキャンセル可、在庫復元、
cancelledAt(ISO 8601)。3試行の diff はバイト単位で同一 - 推測の精度:エラーコード・日時形式・在庫復元・所有者チェックは、既存コードの未使用要素
increaseStock・Order.cancelledAt・Actor型を手がかりに、すべて正解 - 唯一の失敗:「管理者は shipped もキャンセル可」。ある試行はロールと状態の相互作用に気付きながら、正解と逆方向を検討して棄却していた
「
paidを管理者限定にする案も考えられますが、返金を伴うpaidのキャンセルも顧客に許可する一般的なモデルを採用しています。」 - 不確実性の報告:試行間で差が出た。「確認できていない点」を明示して指摘を求めた試行がある一方、情報不足に触れず、推測を断定調で正当化した試行もあった
条件B:正しいContext
結果:正しいContextを与えた3試行は、すべて10/10のテストに成功し、実装ロジックもほぼ同一に収束しました。
条件Bの詳細
- 与えた8項目をすべて反映。3試行でロジック・エラーコード・メッセージ文言まで一致し、差はコード表現の揺れのみ
- 全試行が指示なしで
npx tsc --noEmitを自発実行 - Contextに書かれていない3点(403と409の優先順位、管理者の所有権チェック免除、再キャンセル時の扱い)も、3試行とも同じ結論で仮定し、報告で明示していた
条件C:古いContext
結果:コードとの不整合には気付いたものの、古い業務ルールには従い、テストは4/10でした。
条件Cの詳細
- 実装:確定前のみキャンセル可、管理者も例外なし、常に400、在庫操作なし、という旧仕様に沿った実装。状態名だけは
created→pendingに読み替え - 完了時間:全条件中最長で、他条件の約2倍
| 古い情報 | AIの対応 | 結果 |
|---|---|---|
| 状態名 "created" / "confirmed" | 名称のみ pending に読み替え。ただし「確定前のみ可・管理者も不可」という旧ルールの意味には従った | テスト2, 6 失敗 |
| エラーは常に 400 | 既存コードの 409 規約を自ら認識した上で、Contextの 400 を採用 | テスト5, 7, 10 失敗 |
| "canceled" / canceledDate / UNIXタイムスタンプ | 型定義に合わせて cancelled / cancelledAt / ISO 8601 に読み替え | テスト3 成功 |
| 在庫操作は不要 | 従った。createOrder が在庫を引き当てている事実には言及なし | テスト4 失敗 |
3試行とも「既存コードと課題文で用語が食い違っています」と不整合を報告し、対照表まで作成した試行もありました。しかし原因を「情報が古い」と帰属した試行はゼロで、ある試行は「業務ルールは抽象的な名称で書かれている」と抽象性の問題として合理化しました。
読み替えが起きたのは、旧仕様のまま実装すると型エラーになる箇所だけです。型的に成立する古いルールはすべて信頼されました。また、ある試行は型名についてはコード優先、エラーコードについてはContext優先と、同じ判断基準から正反対の結論を導いていました。
条件D:矛盾したContext
結果:テストは10/10でしたが、Context内部の矛盾は一度も報告されず、強い矛盾の痕跡が、決して実行されないデッドコードとして残りました。
条件Dの詳細
- 実装:管理者例外を含むキャンセル可否判定、404 / 403 / 409、在庫復元、cancelledAt 保存
- 弱い矛盾:3試行とも管理者例外側を採用し、「原則+例外」として暗黙に統合
- 強い矛盾:3試行とも 409 / 404 / 403 側を採用。「常に400」は実行時例外を指すと再解釈し、try/catch で捕捉して 400 を返す分岐を実装した。この分岐は実質的に到達不能なデッドコードで、AI自身が報告の中で「実質的には防御的な分岐です」と認めている
- 矛盾の指摘:強弱2組 × 3試行 = 6機会で0回。全試行が矛盾を無言で解決した
- 確認質問:3試行中1つだけが確認を求めたが、その対象は矛盾ではなく、Contextに書かれていない点だった。矛盾は静かに解決し、空白には確認を求めるという非対称性
「一点確認ですが、admin が delivered の注文をキャンセルできない(409)という解釈で問題ないでしょうか」
- 判断の根拠:3/3で説明あり。報告を読めば解決方法は追跡できるが、矛盾があったこと自体は知らされない
仮説の検証
3つの仮説の答えを先にまとめます。
| 仮説 | 答え | 主な根拠 |
|---|---|---|
| 正確なContextは要求適合を高める | 高めた。ただし限定的 | Bは10/10、Aは9/10。差は管理者例外の1件 |
| 古いContextはContextなしより品質を下げる | 大幅に下げた | Cは4/10まで低下し、完了時間も最長 |
| AIは矛盾を必ずしも指摘しない | 指摘は0回だった | Context内部の矛盾への言及は0/3 |
仮説1:正確なContextは品質を上げるのか
上がりました。ただし効いたのは、コードから推測できない情報だけでした。 Contextなしでも9/10に達していたため改善の余地自体が小さく、研究的な判定としては限定的な支持にとどまります。
仮説1の詳細
- 条件A(Contextなし):9/10
- 条件B(正しいContext):10/10。3試行の実装ロジックがほぼ同一に収束
条件Aが落としたのは、コードや一般的な知識から推測できない「管理者は、発送済みの注文もキャンセルできる」というドメイン固有ルールだけでした。エラーコード、在庫復元、日時形式、所有者チェックは、Contextなしでも既存コードから正しく推測できています。
正確なContextは、AIが推測できない情報を補完し、試行間の出力も安定させました。ただし、Contextなしでも9/10を達成しており、改善側には天井効果があります。
仮説2:古いContextはContextなしより悪いのか
悪くなりました。テストは9/10から4/10へ、完了時間は約2倍です。 AIは不整合に気付いても「古い」と疑わず、読み替えたのは型エラーで強制された箇所だけでした。
仮説2の詳細
- 条件A(Contextなし):9/10
- 条件C(古いContext):4/10。平均完了時間は98秒で全条件中最長
AIは、Contextとコードの不整合自体には3試行すべてで気付いていました。ただし、読み替えたのはコードにそのまま適用すると型エラーになる情報だけです。
- 状態名:
created→pending - 保存形式:
canceledDate(UNIXタイムスタンプ)→cancelledAt(ISO 8601)
一方、型的には成立する「常に400を返す」「在庫を戻さない」「管理者にも例外を認めない」という古いルールには従いました。
AIは不整合を検出できても、その原因を「Contextが古い」とは判断しませんでした。Contextがない場合は一般的な実装へ収束しましたが、古い情報がある場合は、その情報に沿って自信を持って誤った実装を生成しました。
仮説3:AIは矛盾を指摘するのか
一度も指摘しませんでした。 矛盾は無言で解決され、テストは10/10。一方で、Contextに書かれていない空白には確認質問が出るという、非対称な挙動でした。
仮説3の詳細
- Context内部の矛盾への言及:0/3。強弱2組 × 3試行 = 6機会で指摘なし
- 確認質問・確認の必要性への言及:1/3
- テスト結果:10/10
矛盾の扱い方は3試行で一貫していました。「発送後はキャンセル不可」と「管理者は発送済みでもキャンセル可能」は原則と例外として統合し、「キャンセル不可は409」と「エラーは常に400」は、400を実行時例外用と再解釈しました。強い矛盾の痕跡は、デッドコードとしてコードに残っています。
AIが矛盾を認識できなかったというより、自分で解決し、利用者へ報告する必要はないと判断した可能性があります。一方、Contextに書かれていない情報には確認を求めた試行がありました。なお、非対話モードで実行しており、対話モードより確認質問が抑制された可能性があります。
考察
テスト10/10でも、Contextの問題はコードに残る
条件Dはすべてのテストに成功しました。しかし、採用されなかった「常に400」のルールが実行時の例外用として実装され、決して実行されないデッドコードとしてコードに残りました。条件Aでは、不確実性を慎重に報告した試行と、推測を断定的に正当化した試行が、テスト上は同点でした。矛盾の処理・デッドコード・報告の質は、テストでは測れません。
AIコーディングの評価には、機能テストだけでなく、判断過程の報告とコード差分の確認も必要です。
Contextの改善は、足し算より引き算が先
今回のテストでは、正確なContextによる改善幅よりも、古いContextによる悪化幅の方が大きく現れました。Contextなしの時点で9/10だったため単純な効果量の比較はできませんが、実務上の優先順位は見えてきます。
- 古い情報を参照対象から除外する
- 矛盾する情報を解消する
- コードから推測できないドメイン固有情報を追加する
- 情報源が衝突した場合の優先順位を定義する
Contextの品質改善は、情報を追加することから始めるのではなく、誤った情報を取り除くことから始めるべきだと考えます。
実務でどう活かせるか
検証で観測した3つの問題に対応させて、実務での対策を整理します。
古いContextへの対策
- ドキュメントもコードと同じリポジトリでバージョン管理し、実装を変えるPRで一緒に更新する
- 使わなくなった設計書は削除する。Gitの履歴に残るため、消しても情報は失われない
- ドキュメントの冒頭に更新日や対象バージョンを記載する
矛盾への対策
- 仕様の正本を1箇所に決め、他のドキュメントからは正本へリンクする
- 新旧の仕様が併存する場合は、どちらを優先するか明示する
- 情報が矛盾した場合は、実装を止めて確認するようAIに指示する
- CLAUDE.mdなどのルールファイルも、コードと同様にPRでレビューする
検出手段の確保
- Contextとは独立した自動テストを用意し、CIで常に実行する
なお、リポジトリでの一元管理や正本の集約といった予防策は、今回の検証で効果を測定したものではなく、観測した問題に対する一般的なプラクティスとしての推奨です。効果の検証は今後のシリーズで扱います。
AIコーディングでは、ソースコードだけでなく、AIが参照する設計書やルールも保守対象として扱う必要があるかもしれません。
ただし、今回の検証は特定の条件で行った小規模なものです。結果を一般的な原則として断定せず、今回確認できた範囲として整理します。
検証の限界
今回の検証には、次の限界があります。
- 特定のAIコーディングツールとモデルを使用している
- 検証課題が1種類である
- 各条件の試行回数が3回と少ない
- 非対話モードで実行している
- 実務プロジェクトより小規模な課題である
- 評価の一部に人間の判断が含まれる
そのため、今回の結果をすべてのモデルや開発課題に一般化することはできません。AIコーディングにおける情報設計の原則を探るための、探索的な検証として位置付けます。
次回の検証
今回は、情報の正確性と一貫性が品質に与える影響を検証しました。
次回は、次の問いを扱います。
Contextは多いほどよいのか。不要な情報はAIの判断を阻害するのか。
今回作成した初期コード、自動テスト、評価基準を可能な限り再利用し、Contextの量と関連性だけを変更して比較します。
今後の検証予定
- Contextの正確性と鮮度(今回)
- Contextの量と関連性
- Contextの表現と構造
- Contextの粒度
- 優先順位の宣言とガード指示の効果 ― 矛盾・古さの問題を防げるか
- Contextを与えるタイミング
- Contextの保存場所
- 長期開発における情報の引き継ぎ
- モデルやツールを越えた再現性
まとめ
今回の検証から、次の示唆が得られました。
- 正確なContextは、コードから推測できないドメイン固有ルールを補完した
- 古いContextは、Contextなしの場合よりも実装品質を下げた
- AIはContext内部の矛盾を、必ずしも利用者へ報告せずに自己解決した
Contextは、与えるだけでは品質を保証しません。正確性・鮮度・一貫性を欠いたContextは、テストに現れない問題も含めて、実装とAIの判断過程に影響を残します。
AIコーディングでは、ソースコードだけでなく、AIが参照する要求、ルール、設計書も継続的に保守する必要があります。