チャットUIには、すべての応答の下に小さな「AI生成」バッジが表示されています。それは良いことです。しかし、あるパートナーチームがバッチジョブから/summarizeエンドポイントを呼び出し、その出力をデータベースに書き込み、顧客向けのレポート内でレンダリングした場合、そのバッジは誰の役にも立ちません。
これがAI開示が陥りがちな落とし穴です。開示はUIの決定として設計されるため、自身のフロントエンドの範囲で止まってしまいます。機械のコンシューマは何の情報も得られず、モデルからの応答だと見分けることができないため、彼らこそ最もそれを必要としているのです。
2026年8月2日以降、EU AI Actの第50条は、多くのチームにとってこれを具体的なものにしました。Anthropicのようなモデルプロバイダはモデルレベルで出力をマークしますが、AIを扱っていることを人々に伝える義務は、システムをデプロイする側にかかっています。もしあなたのAPIがその間に位置するなら、呼び出し側がコンプライアンスを遵守できるかどうかはあなた次第です。
ここでは、開示をインターフェースではなく契約に組み込む方法を紹介します。何を返すか、どこに配置するか、どのように文書化するか、そして次回のコード修正にも耐えうるようにどのようにテストするか、です。Apidogは、その設計、ドキュメント、テストの側面を一つにまとめます。
応答に含めるべき内容
3つの項目があり、それぞれ異なる質問に答えます。
これは生成されたものか? 真偽値、あるいはより良いのはEnumです。ai_generated: trueは良い出発点ですが、generation: "synthetic" | "assisted" | "human"の方がより役立ちます。なぜなら、「Claudeが人間の下書きを修正した」と「Claudeが全て書き上げた」は根本的に異なり、第50条の免除規定もそれらを異なるものとして扱っているからです。
誰によって生成されたか? ベンダーとモデルIDです。呼び出し側は独自のモデルポリシーを持っている場合があり、フォールバックによってモデルを切り替えると、出力の利用方法が変わる可能性があります。
実際に何が分かっているか? 確認した場合のプロベナンス(来歴)ステータスです。「これを生成したのは私たちだ」はあなたが持つ事実であり、「C2PAマニフェストを検証した」はあなたが行った観察であるため、生成フラグとは別に保ちましょう。
有効な形式は以下の通りです。
{
"id": "sum_4f81a2",
"content": "The incident affected two regions for 41 minutes...",
"ai": {
"generation": "synthetic",
"vendor": "anthropic",
"model": "claude-opus-5",
"human_review": false,
"generated_at": "2026-08-11T09:14:22Z"
},
"provenance": {
"status": "unchecked",
"standard": null
}
}
2つの詳細について説明する価値があります。
human_reviewは、第50条(4)がそれに依拠しているため存在します。公共の利益に関する情報を一般に公開するAI生成テキストは開示されなければなりませんが、人間のレビューまたは編集責任者が編集管理を行った場合は免除されます。プラットフォームが人間が下書きを承認したことを記録している場合、その事実は応答に含めるべきです。なぜなら、それが呼び出し側がラベルを必要とするかしないかの違いとなるからです。
provenance.statusには2つ以上の状態があります。verified、absent、invalid、uncheckedはすべて異なる意味を持ち、これらを真偽値にまとめることは有用な情報を捨て去ることになります。検証サービスの停止が、クリーンな結果と同一に見えるべきではありません。
ヘッダーかボディか?
消費者によって異なりますが、両方です。
ボディが真実を伝えます。 ボディは保存され、ログに記録され、リプレイされ、ダウンストリームに渡されます。呼び出し側が解析されたJSONのみを保持する場合、開示情報はそこに含まれる必要があります。
ヘッダーはエッジで役立ちます。 プロキシ、ゲートウェイ、またはボディを解析しないロギング層でも、ヘッダーに基づいてルーティングしたり、記録したりすることができます。また、プレーンテキストやバイナリのエンドポイントのようにJSONではない応答における開示の唯一の合理的な場所でもあります。
HTTP/1.1 200 OK
Content-Type: application/json
X-AI-Generated: synthetic
X-AI-Model: anthropic/claude-opus-5
ヘッダーに関する2つのルール。すべてのエンドポイントで一貫性を保ちましょう。なぜなら、一部のルートにのみ表示されるヘッダーは、まったく表示されないヘッダーよりも悪いからです。そして、ボディとヘッダーが矛盾する場合、ヘッダーを権威あるものとして扱わないでください。どちらを規範とするかを決め、文書化し、テストでそれを強制するようにしましょう。
ストリーミング応答の場合、開示は最初のイベントまたは応答ヘッダーに含めます。最初のトークンをレンダリングし始める呼び出し側は、何をレンダリングしているかを知るためにトレーラーを待つべきではありません。ヘッダー設計全般に慣れていない場合は、HTTPヘッダーとは何かで基本を学ぶことができます。
仕様に記載する
OpenAPI定義にない開示フィールドは「慣習」であり、慣習は腐敗します。再利用可能なスキーマとして定義し、すべてのAIバックエンドエンドポイントが同じ形式を使用するようにしましょう。
components:
schemas:
AiDisclosure:
type: object
required: [generation]
properties:
generation:
type: string
enum: [synthetic, assisted, human]
description: >
synthetic = 人間による作成がなく、モデルによって生成されたもの。
assisted = 人間がコンテンツを作成し、モデルが編集、翻訳、または要約したもの。
human = モデルの関与がないもの。
vendor:
type: string
example: anthropic
model:
type: string
example: claude-opus-5
human_review:
type: boolean
description: >
応答が返される前に人間が結果をレビューし、
特定可能な当事者が編集責任を負う場合にTrue。
generated_at:
type: string
format: date-time
そしてそれをすべての場所で参照し、モデルの出力を含む可能性のあるすべての応答でaiを必須プロパティにします。必須であることが重要です。オプションのフィールドは、呼び出し側が防御的なコードを書く必要があり、ほとんどの呼び出し側はそうしないでしょう。
2つの副次的な利点があります。生成されたドキュメントは、誰もWikiページを書くことなく、すべての消費者にフィールドを説明します。そして、仕様の検証は、実際に発生するであろう、フィールドが消滅する日を捕捉します。OpenAPI仕様を検証する方法は検証の側面をカバーし、CIで破壊的変更をブロックするためのOpenAPI diffは、誰かがこっそりオプションに変更した場合を捕捉します。
人々が忘れがちなパス
誰もが意識しないルートでは、開示フィールドが欠落しがちです。特に確認すべき4つの点があります。
キャッシュされた応答。 開示が添付される前にボディを保存するキャッシュ層は、TTLが続く限り、マークされていない出力を提供します。モデルの出力と再構築するラッパーをキャッシュするのではなく、完全な応答をキャッシュしましょう。
エラー応答と部分的な応答。 部分的なサマリーを返すタイムアウトであっても、それはモデルの出力を返しています。エラーエンベロープの形式が異なる場合でも、そのフィールドが必要です。
バッチおよびウェブフックのペイロード。 非同期配信では、異なるコードで構築されたよりスリムなスキーマが使用されることがよくあります。これは、フィールドが最も頻繁に欠落する場所です。
フォールバックパス。 プライマリモデルが失敗してフォールバックする場合、model値もそれに従う必要があります。開示ブロック内のハードコードされたモデル文字列は、いずれ嘘になる可能性を秘めています。
これら4つすべての解決策は同じです。モデルの出力が応答オブジェクトに入る時点で開示を添付し、ハッピーパスをシリアル化する時点ではないようにしましょう。
保証のようにテストする
開示フィールドは、呼び出し側への約束です。テストされていない約束は、単なる文書に過ぎません。
5つのアサーションでほとんどのカバーが可能で、これらは通常のAPIテストです。
1. すべてのAIバックエンドルートにフィールドが存在すること。
const body = pm.response.json();
pm.test("response carries AI disclosure", function () {
pm.expect(body).to.have.property("ai");
pm.expect(body.ai.generation).to.be.oneOf(["synthetic", "assisted", "human"]);
});
2. ヘッダーとボディが一致すること。
pm.test("header and body agree", function () {
pm.expect(pm.response.headers.get("X-AI-Generated")).to.eql(body.ai.generation);
});
3. 報告されたモデルが実際に呼び出したものと一致すること。 これは、サイレントフォールバックを捕捉するものです。出力にウォーターマークが付与されるかどうかはモデルIDに依存します。そのため、ClaudeのAPIウォーターマーキングは、モデルの固定をパフォーマンスではなくコンプライアンスの詳細にしています。
4. キャッシュされたパスでも開示されること。 2回呼び出し、キャッシュから返された2番目の応答が、最初の応答と同じ開示を持っていることを確認します。
5. エラーパスでも開示されること。 タイムアウトまたはダウンストリームの障害を強制し、エンベロープがまだフィールドを保持していることを確認します。
これらをテストシナリオにまとめ、OpenAPI定義に対するスキーマ検証を追加し、CIでapidog-cliから実行します。
apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
-t "$DISCLOSURE_SCENARIO_ID" -e "$APIDOG_ENV_ID" -r cli,html
アサーションが失敗すると非ゼロで終了するため、フィールドが削除されたマージは、デプロイされる代わりにビルドが失敗します。完全なパイプラインの設定はGitHub ActionsでのAPIテストの自動化にあり、一般的なアサーションパターンはAPIアサーションに記載されています。Apidogをダウンロードして、自身のエンドポイントに対してシナリオを構築しましょう。
呼び出し側が見る場所に文書化する
2つの対象者、2つの場所。
リファレンスに。 スキーマの説明が適切に書かれていれば、その大部分をカバーします。抽象的ではなく、あなたの製品においてassistedが何を意味するかを述べましょう。ラベルが必要かどうかを判断する呼び出し側は、法的な決定を下すためにその文章を読んでいます。
短いポリシーページに。 モデルの出力が返される可能性のあるエンドポイント、使用するモデル、人間によるレビューが行われるかどうか、そしてそれが何を意味するか、あなたが保証することとしないことを網羅する1つのページを作成します。リファレンスからリンクし、バージョン管理しましょう。
制限について具体的に述べましょう。Claudeの出力をそのまま渡す場合、テキストには自分で検証できない埋め込みウォーターマークが含まれており、Anthropicは検出方法を公開していません。検証能力がないのにそれをほのめかすよりも、その事実を伝える方が良いです。その理由はClaudeのウォーターマークを検出する方法にあります。
インタラクティブなドキュメントは、ここでは通常よりも役立ちます。なぜなら、呼び出し側は表を信用するだけでなく、ライブ応答で開示フィールドを見ることができるからです。試用コンソール付きのインタラクティブなAPIドキュメントのホスティングでその設定について解説しています。
よくある質問
X-AI-Generatedヘッダーは標準ですか? いいえ。AI開示のための標準化されたヘッダーはまだありません。名前を決め、文書化し、一貫性を保ち、契約の一部として扱いましょう。
開示はヘッダーとボディのどちらに含めるべきですか? 両方です。ボディは保存され、伝達されるものです。ヘッダーはプロキシ、ゲートウェイ、ログ、および非JSON応答に対応します。もし両者が矛盾することがあれば、どちらが規範であるかを文書化しましょう。
これを法的に行う義務がありますか? あなたの役割とコンテンツによります。第50条の義務はプロバイダとデプロイヤで異なり、50条(4)はディープフェイクと公共の利益に関するテキストに限定され、人間の編集管理による免除があります。API開発者のためのEU AI Act第50条で詳しく解説しています。法的な判断はあなたの弁護士の仕事ですが、実装はあなたの仕事です。
プロバイダはすでにその出力にウォーターマークを付けています。それだけでは不十分ですか? いいえ。ウォーターマークは、呼び出し側が現在のところテキストでは読み取れない機械可読信号であり、デプロイヤとしてのあなたの開示義務を満たすものではありません。それは代替ではなく補完です。
ストリーミング応答についてはどうですか? 開示を応答ヘッダーまたは最初のイベントに含めます。呼び出し側はトークンが到着するにつれてレンダリングするため、最後まで待つべきではありません。
生成後に人間が編集したコンテンツはどのように扱いますか? そのためにassistedとhuman_reviewがあります。第50条(4)には編集責任を伴う人間のレビュー下にあるコンテンツに対する免除があるため、それを正確に記録することは単一の真偽値よりも価値があります。
このフィールドはバージョン管理すべきですか? 応答スキーマの一部であるため、他の部分と全く同じようにバージョン管理してください。Enum値を追加することは、呼び出し側に通知する必要がある変更であり、CIの仕様差分がそれを教えてくれるでしょう。
まとめ
AI開示はUI機能としては失敗し、契約としては機能します。応答に必須フィールドを配置し、ヘッダーにミラーリングし、OpenAPI仕様で一度定義し、キャッシュされたパス、エラーパス、バッチパス、および常に欠落しがちなフォールバックパスでそれをアサートしましょう。
これはおそらく午後の作業ですが、マーケティングでの主張を、呼び出し側が信頼して構築でき、テストが強制できるものに変換します。
