Ciblage des configurations
Configurez les règles de ciblage pour les configurations afin de contrôler quelles variations sont servies à différents contextes. Fonctionne de la même manière en mode completion et agent.
Conditions préalables
- Compte LaunchDarkly avec AgentControl activé
- Token d'accès API avec permissions d'écriture
- Clé de projet et clé d'environnement
- Configuration existante avec variations (utilisez la skill
configs-create)
Détection de clé API
- Vérifier les variables d'environnement -
LAUNCHDARKLY_API_KEY,LAUNCHDARKLY_API_TOKEN,LD_API_KEY - Vérifier la config MCP - Claude:
~/.claude/config.json->mcpServers.launchdarkly.env.LAUNCHDARKLY_API_KEY - Demander à l'utilisateur - Seulement si la détection échoue
Concepts fondamentaux
Ordre d'évaluation
Les règles de ciblage s'évaluent dans cet ordre (identique aux feature flags) :
- Cibles individuelles - Clés de contexte spécifiques (priorité la plus haute)
- Règles de segment - Segments prédéfinis
- Règles personnalisées - Conditions basées sur les attributs (évaluées dans l'ordre)
- Règle par défaut - Fallback pour tous les autres
- Variation désactivée - Quand le ciblage est désactivé
API Semantic Patch
Le ciblage de configuration utilise les instructions semantic patch :
PATCH /api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting
Content-Type: application/json; domain-model=launchdarkly.semanticpatch
Concepts clés
- variationId : UUIDs, pas des clés. Récupérez toujours le ciblage en premier pour obtenir les IDs.
- Poids : Millièmes (50000 = 50%, 100000 = 100%)
- Logique des clauses : Plusieurs clauses = AND, plusieurs valeurs = OR
- Attributs nuls : Les règles avec attributs nuls/manquants sont ignorées
Flux de travail
Étape 1 : Récupérer le ciblage (avec IDs de variation)
curl -X GET "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \
-H "Authorization: {api_token}" \
-H "LD-API-Version: beta"
La réponse inclut un tableau variations avec _id (UUID) pour chaque variation.
Étape 2 : Modifier la règle par défaut
Modifiez la règle par défaut pour servir la variation que vous avez créée.
Important : L'instruction
turnTargetingOnne fonctionne pas pour les configurations. UtilisezupdateFallthroughVariationOrRolloutà la place.
# D'abord, obtenez les IDs de variation de la réponse de l'étape 1
# Puis définissez le fallthrough à la variation activée (par exemple, la variation « Default »)
curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \
-H "Authorization: {api_token}" \
-H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch" \
-H "LD-API-Version: beta" \
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": "your-enabled-variation-uuid"
}]
}'
Étape 3 : Ajouter des règles de ciblage
Règle basée sur les attributs :
curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \
-H "Authorization: {api_token}" \
-H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch" \
-H "LD-API-Version: beta" \
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "addRule",
"clauses": [{
"contextKind": "user",
"attribute": "selectedModel",
"op": "contains",
"values": ["sonnet"],
"negate": false
}],
"variation": 0
}]
}'
Déploiement en pourcentage :
curl -X PATCH "..." \
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "addRule",
"clauses": [{
"contextKind": "user",
"attribute": "tier",
"op": "in",
"values": ["premium"],
"negate": false
}],
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": "key",
"variations": [
{"variation": 0, "weight": 60000},
{"variation": 1, "weight": 40000}
]
}
}]
}'
Définir le fallthrough (règle par défaut) :
curl -X PATCH "..." \
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": "fallback-variation-uuid"
}]
}'
Implémentation Python
import requests
import os
from typing import Dict, List, Optional
class AIConfigTargeting:
"""Manager pour les règles de ciblage de configuration"""
def __init__(self, api_token: str, project_key: str):
self.api_token = api_token
self.project_key = project_key
self.base_url = "https://app.launchdarkly.com/api/v2"
def get_targeting(self, config_key: str) -> Optional[Dict]:
"""Récupère le ciblage actuel avec les IDs de variation."""
url = f"{self.base_url}/projects/{self.project_key}/ai-configs/{config_key}/targeting"
response = requests.get(url, headers={
"Authorization": self.api_token,
"LD-API-Version": "beta"
})
if response.status_code == 200:
return response.json()
print(f"[ERROR] {response.status_code}: {response.text}")
return None
def get_variation_id(self, config_key: str, variation_key: str) -> Optional[str]:
"""Cherche l'UUID de variation à partir de la clé ou du nom."""
targeting = self.get_targeting(config_key)
if targeting:
for var in targeting.get("variations", []):
if var.get("key") == variation_key or var.get("name") == variation_key:
return var.get("_id")
return None
def update_targeting(self, config_key: str, environment: str,
instructions: List[Dict], comment: str = "") -> Optional[Dict]:
"""Envoie les instructions semantic patch."""
url = f"{self.base_url}/projects/{self.project_key}/ai-configs/{config_key}/targeting"
payload = {"environmentKey": environment, "instructions": instructions}
if comment:
payload["comment"] = comment
response = requests.patch(url, headers={
"Authorization": self.api_token,
"Content-Type": "application/json; domain-model=launchdarkly.semanticpatch",
"LD-API-Version": "beta"
}, json=payload)
if response.status_code == 200:
return response.json()
print(f"[ERROR] {response.status_code}: {response.text}")
return None
def enable_config(self, config_key: str, environment: str,
variation_key: str = "default") -> bool:
"""
Active une configuration en définissant le fallthrough à une variation activée.
Note : turnTargetingOn ne fonctionne pas pour les configurations. À la place,
définissez le fallthrough de la variation désactivée (index 0) à une activée.
"""
variation_id = self.get_variation_id(config_key, variation_key)
if not variation_id:
print(f"[ERROR] Variation '{variation_key}' not found")
return False
return self.set_fallthrough(config_key, environment, variation_id)
def add_rule(self, config_key: str, environment: str,
clauses: List[Dict], variation: int,
description: str = "") -> bool:
"""Ajoute une règle de ciblage servant un index de variation spécifique."""
instruction = {
"kind": "addRule",
"clauses": clauses,
"variation": variation
}
if description:
instruction["description"] = description
result = self.update_targeting(config_key, environment,
[instruction], f"Add rule: {description}")
if result:
print(f"[OK] Rule added")
return True
return False
def add_rollout_rule(self, config_key: str, environment: str,
clauses: List[Dict],
weights: List[Dict],
bucket_by: str = "key") -> bool:
"""
Ajoute une règle de déploiement en pourcentage.
weights: [{"variation": 0, "weight": 50000}, {"variation": 1, "weight": 50000}]
"""
result = self.update_targeting(config_key, environment, [{
"kind": "addRule",
"clauses": clauses,
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": bucket_by,
"variations": weights
}
}], "Add percentage rollout")
if result:
print(f"[OK] Rollout rule added")
return True
return False
def set_fallthrough(self, config_key: str, environment: str,
variation_id: str) -> bool:
"""Définit la variation par défaut (fallthrough) par UUID."""
result = self.update_targeting(config_key, environment, [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": variation_id
}], "Set fallthrough")
if result:
print(f"[OK] Fallthrough set")
return True
return False
def target_individuals(self, config_key: str, environment: str,
context_keys: List[str], variation: int,
context_kind: str = "user") -> bool:
"""Cible des clés de contexte spécifiques."""
result = self.update_targeting(config_key, environment, [{
"kind": "addTargets",
"variation": variation,
"contextKind": context_kind,
"values": context_keys
}], f"Target {len(context_keys)} individuals")
if result:
print(f"[OK] Individual targets added")
return True
return False
def target_segment(self, config_key: str, environment: str,
segment_keys: List[str], variation: int) -> bool:
"""Cible un segment."""
result = self.update_targeting(config_key, environment, [{
"kind": "addRule",
"clauses": [{
"attribute": "segmentMatch",
"contextKind": "", # Laissez vide pour les segments
"op": "segmentMatch",
"values": segment_keys,
"negate": False
}],
"variation": variation
}], f"Target segments: {segment_keys}")
if result:
print(f"[OK] Segment targeting added")
return True
return False
def clear_rules(self, config_key: str, environment: str) -> bool:
"""Supprime toutes les règles de ciblage."""
result = self.update_targeting(config_key, environment,
[{"kind": "replaceRules", "rules": []}], "Clear all rules")
if result:
print(f"[OK] All rules cleared")
return True
return False
Référence des instructions
Note :
turnTargetingOnetturnTargetingOffne fonctionnent pas pour les configurations. Les configurations ont le ciblage activé par défaut. Pour « activer » une configuration, définissez le fallthrough à une variation activée en utilisantupdateFallthroughVariationOrRollout.
Règles
| Kind | Description |
|---|---|
addRule |
Ajoute une règle avec clauses et variation/déploiement |
removeRule |
Supprime par ruleId |
replaceRules |
Remplace toutes les règles |
reorderRules |
Change l'ordre d'évaluation |
updateRuleVariationOrRollout |
Met à jour ce qu'une règle sert |
Fallthrough
| Kind | Description |
|---|---|
updateFallthroughVariationOrRollout |
Définit la variation par défaut ou le déploiement |
Cibles individuelles
| Kind | Description |
|---|---|
addTargets |
Cible des clés de contexte spécifiques |
removeTargets |
Supprime des cibles spécifiques |
replaceTargets |
Remplace toutes les cibles |
Référence des opérateurs
| Opérateur | Description | Exemple |
|---|---|---|
in |
Valeur dans la liste | ["premium", "enterprise"] |
contains |
Contient une chaîne | ["sonnet"] |
startsWith |
Préfixe de chaîne | ["user-"] |
endsWith |
Suffixe de chaîne | [".edu"] |
matches |
Correspondance regex | ["^user-\\d+$"] |
greaterThan / lessThan |
Comparaison numérique | [100] |
before / after |
Comparaison de date | ["2024-12-31T00:00:00Z"] |
semVerEqual / semVerGreaterThan |
Comparaison de version | ["2.0.0"] |
segmentMatch |
Appartenance au segment | ["beta-testers"] |
Structure des clauses
{
"contextKind": "user",
"attribute": "email",
"op": "endsWith",
"values": [".edu"],
"negate": false
}
- Plusieurs clauses = AND (toutes doivent correspondre)
- Plusieurs valeurs = OR (n'importe quelle valeur peut correspondre)
negate: trueinverse l'opérateur
Types de déploiement
Déploiement en pourcentage manuel
{
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": "key",
"variations": [
{"variation": 0, "weight": 50000},
{"variation": 1, "weight": 50000}
]
}
}
Déploiement progressif
{
"progressiveRolloutConfig": {
"contextKind": "user",
"controlVariation": 1,
"endVariation": 0,
"steps": [
{"rolloutWeight": 1000, "duration": {"quantity": 4, "unit": "hour"}},
{"rolloutWeight": 5000, "duration": {"quantity": 4, "unit": "hour"}},
{"rolloutWeight": 10000, "duration": {"quantity": 4, "unit": "hour"}}
]
}
}
Déploiement gardé
{
"guardedRolloutConfig": {
"randomizationUnit": "user",
"stages": [
{"rolloutWeight": 1000, "monitoringWindowMilliseconds": 17280000},
{"rolloutWeight": 5000, "monitoringWindowMilliseconds": 17280000}
],
"metrics": [{
"metricKey": "error-rate",
"onRegression": {"rollback": true},
"regressionThreshold": 0.01
}]
}
}
Modèles courants
Routage de modèle par attribut
# Route basé sur l'attribut de contexte selectedModel
targeting.add_rule(
config_key="model-selector",
environment="production",
clauses=[{
"contextKind": "user",
"attribute": "selectedModel",
"op": "contains",
"values": ["sonnet"],
"negate": False
}],
variation=0, # Index de variation Sonnet
description="Route sonnet requests"
)
Variation basée sur le tier
targeting.add_rule(
config_key="chat-assistant",
environment="production",
clauses=[{
"contextKind": "user",
"attribute": "tier",
"op": "in",
"values": ["premium", "enterprise"],
"negate": False
}],
variation=0 # Variation du modèle premium
)
Ciblage de segment
targeting.target_segment(
config_key="chat-assistant",
environment="production",
segment_keys=["beta-testers"],
variation=1 # Variation expérimentale
)
Gestion des erreurs
| Statut | Cause | Solution |
|---|---|---|
| 400 | Semantic patch invalide | Vérifiez le format de l'instruction, les ops doivent être en minuscules |
| 403 | Permissions insuffisantes | Vérifiez le token API |
| 404 | Configuration non trouvée | Vérifiez projectKey et configKey |
| 422 | Variation invalide | Utilisez l'index (0, 1, 2...) ou l'UUID de la réponse de ciblage |
Prochaines étapes
Après avoir configuré le ciblage :
- Fournir l'URL de configuration :
https://app.launchdarkly.com/projects/{projectKey}/ai-configs/{configKey} - Surveiller les performances avec
built-in-metrics - Ajouter des judges avec
online-evals - Configurer des déploiements gardés pour la détection automatique des régressions
Skills associées
configs-create- Créer des configurations avec variationsconfigs-variations- Gérer les variationsonline-evals- Ajouter des judgessegments- Créer des segments pour le ciblage