AI Feature Flagging & Model Rollout Playbook
Deploying Large Language Models (LLMs) in production environments introduces unique risks: non-deterministic responses, structural output drift, API timeouts, and token price variations. Traditional feature flagging is no longer just for toggling UI buttons; it is the core mechanism for executing safely gated AI releases, progressive model migrations, and real-world shadow evaluations.
๐ 1. Request Lifecycle & Gateway Architecture
An enterprise gateway intercepts user requests and resolves feature flag states (model target, prompt version, tool permissions) prior to invoking model endpoints.
๐ 2. AI-Specific Rollout Patterns
Modern AI engineering decouples deployments from releases across four operational layers:
- Prompt Rollout: Dynamic prompt templates are served as flag variables. Prompt engineers can deploy adjustments (Prompt V2) to a targeted cohort without redeploying code.
- Model Rollout: Percentage splits are defined at the gateway (e.g.,
90%togpt-4o-miniand10%toclaude-3-5-haiku) to test quality, latency, and costs on live user traffic. - Agent Rollout: Routing users to different execution engines (e.g., shifting beta cohorts from a single model call to a stateful, multi-agent LangGraph workflow).
- Tool Rollout: Gating high-risk agent capabilities (e.g., write permissions to production databases or automatic email dispatches) by binding tool access rights to target feature flags.
Progressive AI Rollout Stages
To minimize impact during updates, follow this progressive rollout framework:
[Internal Dev/QA] โ [Beta Segment (10%)] โ [Canary (5% Live)] โ [Progressive (25%/50%/75%)] โ [General Availability (100%)]- Stage 1: Internal: Enabled for internal developers and QA teams. Focuses on code integration correctness, logging verification, and basic error checks.
- Stage 2: Beta: Released to a selected subset of early-access users. Validates UI compatibility and gathers initial user feedback.
- Stage 3: Canary (5% Live): Exposed to a small fraction of real production traffic. Monitored strictly for latency anomalies, cost spikes, and schema violations.
- Stage 4: Progressive (25% โ 50% โ 75%): Incremental rollouts over several days. Verifies scalability, database connection pooling, and downstream API rate limits.
- Stage 5: General Availability (GA): 100% traffic. The old model/prompt is archived.
๐ ๏ธ 3. Technology Evaluation Matrix
Choosing the right flagging infrastructure depends on your latency budgets and deployment topologies:
| Dimension | LaunchDarkly | Unleash | OpenFeature |
|---|---|---|---|
| Core Focus | Commercial SaaS flag management | Open-source enterprise flagging | Vendor-neutral API standard |
| Vendor Lock-in | High | Medium (Self-hostable) | None (Allows switching backends) |
| Edge Execution | Yes (via Cloudflare / Vercel integrations) | Yes (Unleash Edge proxy) | Dependent on selected provider |
| Best For | Enterprise-wide feature rollouts | Self-hosted backend flag controls | Decoupling SDK syntax from vendor choice |
๐ 4. Code Integrations & Provider Setups
OpenFeature Provider Neutrality
OpenFeature separates application logic from the flagging vendor. Developers interact with the OpenFeature SDK, making it easy to swap providers (e.g., from LaunchDarkly to Unleash) by updating the client registration step.
LaunchDarkly Python Integration
import ldclient
from ldclient.config import Config
# Initialize LaunchDarkly Client
ldclient.set_config(Config(sdk_key="your-sdk-key"))
ld_client = ldclient.get()
def get_ld_model_variant(user_id: str, plan_tier: str) -> str:
user_context = {
"key": user_id,
"custom": {"tier": plan_tier}
}
# Evaluate model routing variant
return ld_client.variation("ai_model_selection", user_context, "gpt-4o-mini")Unleash Python Integration
from UnleashClient import UnleashClient
# Initialize Unleash Client
unleash_client = UnleashClient(
url="https://unleash-server.com/api",
app_name="genai-gateway",
custom_headers={"Authorization": "your-api-key"}
)
unleash_client.initialize_client()
def get_unleash_prompt_template(user_id: str) -> str:
context = {"userId": user_id}
# Retrieve dynamic prompt template string
variant = unleash_client.get_variant("prompt_version_flag", context)
return variant["payload"]["value"] if variant["enabled"] else "default_prompt_v1"๐ฏ 5. Case Study: GPT-4o to Claude 3.5 Sonnet Migration
Migrating core models requires structured safety gates to prevent regressions in user experience.
Step-by-Step Migration Guide
- Deploy behind Shadow Flag: Run Claude 3.5 Sonnet in shadow mode on 10% of traffic. Validate that latencies, token consumption, and output formatting meet requirements without exposing outputs to users.
- Canary Test (5%): Switch the flag to route 5% of users to Claude. Monitor user engagement, error logs, and cost metrics.
- Progressive Rollout: Incrementally scale the flag values (
25%โ50%โ100%) over a 5-day window. - Automated Rollback: If Claudeโs API returns rate limits (
429) or formatting exceptions, the gateway automatically switches traffic back to GPT-4o.
๐ป 6. Shadow Deployment Pipeline (FastAPI)
Shadow deployments run the candidate model in the background, comparing its speed and accuracy against the primary model without delaying the response to the client.
import os
import time
import asyncio
from fastapi import FastAPI, BackgroundTasks
from pydantic import BaseModel
import openai
app = FastAPI(title="GenAI Feature Flag Gateway")
client = openai.AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
class ChatRequest(BaseModel):
user_id: str
prompt: str
# Retrieve variant (e.g. from OpenFeature / local cache)
def get_flag_variant(user_id: str) -> str:
# 20% shadow rollout simulation
return "shadow_launch" if hash(user_id) % 5 == 0 else "control"
async def execute_shadow_inference(prompt: str, primary_output: str, primary_time: float):
"""Asynchronously runs the shadow model and compares metrics."""
start = time.time()
try:
response = await client.chat.completions.create(
model="gpt-4o", # Shadow model
messages=[{"role": "user", "content": prompt}],
timeout=5.0
)
shadow_output = response.choices[0].message.content
shadow_time = time.time() - start
# Log comparison metrics
print(f"[SHADOW EVAL] Primary Latency: {primary_time:.2f}s | Shadow Latency: {shadow_time:.2f}s")
print(f"[SHADOW EVAL] Size Delta: {len(shadow_output) - len(primary_output)}")
except Exception as e:
print(f"[SHADOW ERROR] Shadow inference failed: {str(e)}")
@app.post("/chat")
async def chat_endpoint(request: ChatRequest, background_tasks: BackgroundTasks):
flag_variant = get_flag_variant(request.user_id)
# 1. Run primary model
start_time = time.time()
primary_res = await client.chat.completions.create(
model="gpt-4o-mini", # Primary model
messages=[{"role": "user", "content": request.prompt}]
)
primary_output = primary_res.choices[0].message.content
elapsed_time = time.time() - start_time
# 2. Trigger shadow execution in the background
if flag_variant == "shadow_launch":
background_tasks.add_task(
execute_shadow_inference,
request.prompt,
primary_output,
elapsed_time
)
return {"response": primary_output, "variant": flag_variant}๐ 7. Client State Propagation (Next.js & Server Components)
Evaluating flags inside edge middleware avoids layout shifts (FOUC) and ensures server-rendered components receive the correct flag context.
import { OpenFeature } from '@openfeature/server-sdk';
import { NextRequest, NextResponse } from 'next/server';
const openFeatureClient = OpenFeature.getClient();
export async function middleware(req: NextRequest) {
const userId = req.cookies.get('user_id')?.value || 'anonymous';
// Resolve the flag state at the Edge before rendering begins
const flagContext = { targetingKey: userId };
const modelVariant = await openFeatureClient.getStringValue(
'llm_routing_variant',
'gpt-4o-mini',
flagContext
);
const response = NextResponse.next();
// Inject the resolved variant into headers for Server Components
response.headers.set('x-llm-variant', modelVariant);
return response;
}๐ 8. Observability & OpenTelemetry Span Tagging
Attributing token cost and performance metrics to active feature variants in OpenTelemetry allows observability dashboards to analyze variations dynamically.
Span Tagging Semantic Conventions
We will set standard feature_flag attributes to record active variants, models, and costs:
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
tracer = trace.get_tracer("genai.gateway")
def invoke_model_with_flag_tracing(prompt: str, flag_key: str, variant: str) -> str:
with tracer.start_as_current_span("model_invocation") as span:
# Standard OpenTelemetry feature flag semantic conventions
span.set_attribute("feature_flag.key", flag_key)
span.set_attribute("feature_flag.variant", variant)
# LLM system configurations
span.set_attribute("model.name", "gpt-4o-mini")
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
# Record Token costs
usage = response.usage
input_cost = (usage.prompt_tokens / 1_000_000) * 0.15
output_cost = (usage.completion_tokens / 1_000_000) * 0.60
total_cost = input_cost + output_cost
span.set_attribute("token.cost", total_cost)
span.set_status(Status(StatusCode.OK))
return response.choices[0].message.content
except Exception as e:
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise๐จ 9. Rollback Playbook for Failed Model Deployments
When launching a new model or prompt configuration, establish automated rollback triggers:
Metrics Thresholds
- TTFT Spike: Average Time to First Token exceeds
1.5 secondsover a 3-minute window. - Rate Limits: Client receives
429errors on more than 2% of requests. - Inference Failures: API returns
5xxserver codes on more than 1% of transactions. - Validation Errors: Pydantic output validation checks fail on more than 3% of responses.
Rollback Execution Checklist
- De-escalate Flag: Set the feature flag percentage split to
0%for the new variant in the management dashboard (LaunchDarkly/Unleash). - Verify Rollback: Confirm the traffic distribution logs return to 100% control model baseline.
- Trace Investigation: Identify the error cause (e.g., rate limit exhaustion, payload format drift) using OTel Trace IDs and error spans.
๐ ๏ธ 10. Troubleshooting Guide
- Layout Shift (FOUC): Occurs when the client browser resolves feature flags after page hydration.
- Mitigation: Pre-evaluate flags in Edge middleware and inject flag states directly into page props or server headers.
- Latency Overhead: Evaluating remote feature flags adds network hops.
- Mitigation: Enable local flag evaluation (bootstrap from a local JSON cache or run regional Unleash proxies next to your gateway).
- Flag Synchronization Lag: Outdated flag states cached on edge nodes.
- Mitigation: Set short TTL bounds (e.g., 5 seconds) on edge worker flag state cache caches.