AI の時代のために構築されたフィーチャーフラグ
2026-04-17 | Rohan Mukherjee、Abhishek Kankani | 6 分で読める
AI がこれまで以上にコードを書いている
AI による支援を受けたコントリビューションは、プラットフォーム全体の新しいコードの急速に増加するシェアを占めるようになりました。OpenCode や Claude Code のようなエージェント型コーディングツールは、数分でフィーチャー全体を出荷しています。本番環境に入る AI 生成コードは加速し続けるだけです。
しかし、より大きな変化は単なるスピードではなく、自律性です。今日、AI エージェントがコードを書き、人間がレビュー、マージ、デプロイします。明日は、エージェントがそのすべてを自分で行います。問題は次のようになります:エージェントがすべてのセーフティネットを削除することなく、本番環境に出荷することをどのように許可しますか?
フィーチャーフラグが答え
エージェントはフラグの背後に新しいコードパスを書き、デプロイします。フラグはオフなので、ユーザーには何も変わりません。その後、エージェントはフラグを自分自身または小さなテストコホートに対して有効にし、本番環境でフィーチャーを実行し、結果を観察します。メトリクスが良好に見える場合は、ロールアウトをランプアップします。何か壊れた場合は、フラグを無効にします。人間はすべてのステップでループに入る必要はありません。彼らは境界を設定し、フラグが爆発半径を制御します。
これは、フィーチャーフラグが常に構築していたワークフローです:デプロイメントをリリースから分離するだけでなく、出荷プロセスのすべてのステージから人間の注意を分離することです。エージェントはフラグが高速に移動することを安全にするため、高速に移動します。
Flagship の発表
本日、Cloudflare のネイティブフィーチャーフラグサービスである Flagship を発表します。これは OpenFeature(フィーチャーフラグ評価の CNCF オープンスタンダード)上に構築されています。Workers、Node.js、Bun、Deno、ブラウザなど、どこでも動作しますが、Cloudflare ネットワーク内でフラグが評価される Workers で最も高速です。
Flagship バインディングと OpenFeature を使用した統合は次のようになります:
await OpenFeature.setProviderAndWait(
new FlagshipServerProvider({
binding: env.FLAGS
})
);
Flagship は現在クローズドベータで利用可能です。
Workers でのフィーチャーフラグの問題
多くの Cloudflare 開発者は実用的な回避策に頼ってきました:フラグロジックを Workers に直接ハードコーディングすることです。正直なところ、最初はうまく機能します。Workers は数秒でデプロイされるため、コード内のブール値を反転して本番環境にプッシュすることは、ほとんどの状況では十分に高速です。
しかし、シンプルなままではいません。1 つのハードコーディングされたフラグが 10 になります。10 が 50 になり、異なるチームが所有し、何がオンまたはオフであるかの中央ビューがありません。監査証跡がありません。何か壊れた場合、git blame を検索して誰がトグルを切ったかを把握しています。
外部サービスへのネットワーク呼び出し
Workers で使用される別の一般的なパターンは、次のように外部サービスに HTTP リクエストを行うことです:
const response = await fetch("https://flags.example-service.com/v1/evaluate", {
body: JSON.stringify({
flagKey: "new-checkout-flow",
context: { },
}),
});
const { value } = await response.json();
if (value === true) {
return handleNewCheckout(request);
}
return handleLegacyCheckout(request);
そのアウトバウンドリクエストは、すべてのユーザーリクエストの重要なパスに位置します。ユーザーがフラグサービスのリージョンからどれだけ離れているかに応じて、かなりのレイテンシを追加する可能性があります。これは奇妙な状況です。アプリケーションはエッジで実行され、ユーザーから数ミリ秒離れています。しかし、フィーチャーフラグチェックは、何をレンダリングするかを決定する前に、インターネット全体を別の API に戻すことを強制します。
ローカル評価が問題を解決しない理由
一部のフィーチャーフラグサービスは「ローカル評価」SDK を提供しています。リモート API をすべてのリクエストで呼び出す代わりに、SDK はフラグルールの完全なセットをメモリにダウンロードし、ローカルで評価します。評価ごとのアウトバウンドリクエストはなく、フラグの決定はインプロセスで発生します。
Workers では、これらの仮定のいずれも成立しません。長時間存在するプロセスはありません:Worker アイソレートは作成され、リクエストを処理し、1 つのリクエストと次のリクエストの間に削除される可能性があります。新しい呼び出しは、SDK をゼロから再初期化することを意味する可能性があります。
サーバーレスプラットフォームでは、エッジに既にある配布プリミティブが必要です。キャッシングが管理され、読み取りがローカルで、物事を最新に保つために永続的な接続が不要な場所です。Cloudflare KV はこれに最適なプリミティブです!
Flagship の仕組み
Flagship は Cloudflare のインフラストラクチャ全体(Workers、Durable Objects、KV)上に構築されています。外部データベース、サードパーティサービス、評価パス内の集中型オリジンサーバーはありません。
フラグを作成または更新すると、コントロールプレーンは変更を Durable Object にアトミックに書き込みます。Durable Object は SQLite でサポートされた、グローバルに一意のインスタンスで、そのアプリのフラグ構成と変更ログの信頼できるソースとして機能します。
数秒以内に、更新されたフラグ構成は Workers KV(Cloudflare のグローバルに分散されたキー値ストア)に同期され、Cloudflare のネットワーク全体に複製されます。
リクエストがフラグを評価すると、Flagship はエッジの KV からフラグ構成を直接読み取ります。これは、リクエストを既に処理している同じ Cloudflare の場所です。評価エンジンはそこでアイソレート内で実行されます:リクエストコンテキストをフラグのターゲティングルールと照合し、ロールアウト率を解決し、バリエーションを返します。データとロジックの両方がエッジに存在します。他の場所に送信されて評価されることはありません。
Flagship の使用:Worker バインディング
Cloudflare Workers を実行しているチームの場合、Flagship は Workers ランタイム内でフラグを評価するダイレクトバインディングを提供します。HTTP ラウンドトリップなし、SDK オーバーヘッドなし。バインディングを wrangler.jsonc に追加すると、Worker が接続されます:
{
"flagship": [
{
"binding": "FLAGS",
"app_id": "<APP_ID>"
}
]
}
それだけです。アカウント ID は Cloudflare アカウントから推測され、app_id はバインディングを特定の Flagship アプリに結び付けます。
Worker では、フラグ値を要求するだけです:
export default {
async fetch(request: Request, env: Env) {
const showNewUI = await env.FLAGS.getBooleanValue('new-ui', false, {
userId: 'user-42',
plan: 'enterprise',
});
const details = await env.FLAGS.getStringDetails('checkout-flow', 'v1', {
userId: 'user-42',
});
},
};
バインディングは、すべてのバリエーションタイプに対して型付きアクセサーをサポートしています。getBooleanValue()、getStringValue()、getNumberValue()、getObjectValue() に加えて、解決された値、マッチしたバリエーション、および選択された理由を返す *Details() バリエーションがあります。
評価エラーでは、デフォルト値が適切に返されます。型の不一致では、バインディングは例外をスローします。これは一時的な障害ではなく、コード内のバグです。
SDK:OpenFeature ネイティブ
ほとんどのフィーチャーフラグ SDK には、独自のインターフェースと評価パターンが付属しています。時間が経つにつれて、それらはコードベースに深く組み込まれます。プロバイダーを切り替えることは、すべての呼び出しサイトを書き直すことを意味します。
私たちは別のものを構築したくありませんでした。Flagship は OpenFeature(フィーチャーフラグ評価の CNCF オープンスタンダード)上に構築されています。OpenFeature は、言語とプロバイダー全体でフラグ評価の共通インターフェースを定義します。これは、OpenTelemetry が可観測性に対して持つ関係と同じです。標準に対して評価コードを一度書き、単一の構成行を変更することでプロバイダーを交換します。
import { OpenFeature } from '@openfeature/server-sdk';
import { FlagshipServerProvider } from '@cloudflare/flagship/server';
await OpenFeature.setProviderAndWait(
new FlagshipServerProvider({
appId: 'your-app-id',
accountId: 'your-account-id',
authToken: 'your-cloudflare-api-token',
})
);
const client = OpenFeature.getClient();
const showNewCheckout = await client.getBooleanValue(
'new-checkout-flow',
false,
{
targetingKey: 'user-42',
plan: 'enterprise',
country: 'US',
}
);
Workers で Flagship バインディングを実行している場合は、OpenFeature プロバイダーに直接渡すことができます。バインディングは既にアカウントコンテキストを保持しているため、構成するものはありません。認証は暗黙的です。
import { OpenFeature } from '@openfeature/server-sdk';
import { FlagshipServerProvider } from '@cloudflare/flagship/server';
let initialized = false;
export default {
async fetch(request: Request, env: Env) {
if (!initialized) {
await OpenFeature.setProviderAndWait(
new FlagshipServerProvider({
binding: env.FLAGS
})
);
initialized = true;
}
const client = OpenFeature.getClient();
const showNewCheckout = await client.getBooleanValue(
'new-checkout-flow',
false,
{
targetingKey: 'user-42',
plan: 'enterprise',
}
);
},
};
評価コードは変わりません。OpenFeature インターフェースは同じです。しかし、内部では、Flagship は HTTP ではなくバインディングを通じてフラグを評価します。標準の移植性とバインディングのパフォーマンスを得られます。
クライアント側プロバイダーもブラウザで利用可能です。指定したフラグをプリフェッチし、構成可能な TTL でキャッシュし、そのキャッシュから同期的に評価を提供します。
Flagship でできること
Flagship は、フィーチャーフラグサービスから期待するパターンと、AI 生成コードが毎日本番環境に着地するときに重要になるパターンをサポートしています。
フラグ値
フラグ値は、ブール値、文字列、数値、または完全な JSON オブジェクトです。構成ブロック、UI テーマ定義、または別のコードパスを維持することなく、ユーザーを異なる API バージョンにルーティングするのに役立ちます。
ターゲティングルール
各フラグは複数のルールを持つことができ、優先度順に評価されます。最初にマッチするルールが勝ちます。ルールは以下で構成されます:
- 特定のコンテキストにルールが適用されるかどうかを決定する条件
- ルールがマッチするときに提供するフラグバリエーション
- パーセンテージベースの配信のためのオプションのロールアウト
- 複数のルールが存在する場合の評価順序を決定する優先度(数値が低い = 優先度が高い)
ネストされた論理条件
条件は AND/OR ロジックを使用して構成でき、最大 5 レベルまでネストできます。単一のルールは次のようなことを表現できます:
(plan == "enterprise" AND region == "us") OR (user.email.endsWith("@cloudflare.com")) = serve ("premium")
ルールのトップレベルでは、複数の条件は暗黙的な AND で結合され、ルールがマッチするにはすべての条件が渡される必要があります。各条件内では、より複雑なロジックのために AND/OR グループをネストできます。
パーセンテージ別フラグロールアウト
段階的なデプロイメント(Worker の異なるアップロードされたバージョン間でトラフィックを分割する)とは異なり、フィーチャーフラグを使用すると、100% のトラフィックを提供している単一バージョン内でパーセンテージ別に動作をロールアウトできます。
すべてのルールにはパーセンテージロールアウトを含めることができます。条件にマッチするすべてのユーザーにバリエーションを提供する代わりに、それらのパーセンテージに提供します。
ロールアウトは指定されたコンテキスト属性で一貫性のあるハッシュを使用します。同じ属性値(例えば userId)は常に同じバケットにハッシュされるため、リクエスト全体でバリエーション間でフリップしません。5% から 10% から 50% から 100% のユーザーにランプアップできるため、既にロールアウトに含まれている人は含まれたままです。
次に来るものに向けて構築
AI 生成コードが本番環境に入ることは加速し続けるだけです。エージェント型ワークフローはそれをさらに推し進めます。本番環境でコードを自律的にデプロイ、テスト、反復するエージェント。
この世界で繁栄するチームは、最も高速に出荷するチームではありません。高速に出荷でき、ユーザーが見るものに対する制御を維持し、何か壊れたときに数秒でロールバックでき、新しいコードパスを自信を持って段階的に公開できるチームです。
それが Flagship が構築されたものです:
- 地球全体のリージョン全体での評価、KV を使用してグローバルにキャッシュされます
- 完全な監査証跡。すべてのフラグ変更はフィールドレベルの差分で記録されるため、誰が何をいつ変更したかがわかります
- ダッシュボード統合。チーム上の誰でも、フラグを作成、更新、ロールアウトできます