configs-targeting について
LaunchDarkly AgentControl の設定にターゲティングルールを構成するスキルです。個別ターゲット、セグメント、属性ルール、各種ロールアウトを扱います。
主な機能
- 01個別およびセグメントのターゲット管理
- 02属性ルールの追加と並べ替え
- 03フォールスルーのバリエーション設定
- 04割合およびガード付きロールアウト
- 05多様な属性演算子の利用
活用シーン
- 01ユーザー階層ごとのバリエーション割り当て
- 02テストセグメントへの設定ターゲティング
- 03バリエーションの段階的な公開
- 04モデル属性による設定の振り分け
MCP 対応
認証とターゲティング操作には LaunchDarkly MCP サーバーのツールを優先します。MCP に相当するツールがない手順では REST API を使用できます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ launchdarkly/ ai-tooling --skill configs-targetingインストール後、Claude Code で/configs-targetingを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
設定のターゲティング
設定のターゲティングルールを構成して、さまざまなコンテキストにどのバリエーションを配信するかを制御します。完了モードとエージェントモードの両方で同じように動作します。
前提条件
- AgentControl が有効な LaunchDarkly アカウント
- 書き込み権限を持つ API アクセストークン
- プロジェクトキーと環境キー
- バリエーションを持つ既存の設定(
configs-createスキルを使用)
API アクセス
LaunchDarkly MCP サーバーのツールを優先してください。これらのツールは OAuth で認証されるため、トークンは不要です。MCP に相当するものがない手順があり、REST API を直接呼び出す必要がある場合は、このセッション用の API アクセストークンを貼り付けるようユーザーに依頼し、以下の例の {api_token} をそれに置き換えてください。認証情報を環境変数、.env ファイル、エージェント/MCP 設定ファイルから検索しないでください。
基本概念
評価順序
ターゲティングルールは次の順序で評価されます(フィーチャーフラグと同じです)。
- 個別ターゲット - 特定のコンテキストキー(最優先)
- セグメントルール - 事前定義されたセグメント
- カスタムルール - 属性ベースの条件(順番に評価)
- デフォルトルール - その他すべてに対するフォールスルー
- オフバリエーション - ターゲティングが無効な場合
セマンティックパッチ API
設定のターゲティングではセマンティックパッチ命令を使用します。
PATCH /api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting
Content-Type: application/json; domain-model=launchdarkly.semanticpatch
主な概念
- variationId: キーではなく UUID です。常に最初にターゲティングを取得して ID を入手してください。
- 重み: 1000分の1単位(50000 = 50%、100000 = 100%)
- 句のロジック: 複数の句 = AND、複数の値 = OR
- null 属性: null/欠落した属性を持つルールはスキップされます
ワークフロー
ステップ 1: ターゲティングを取得する(バリエーション ID を含む)
curl -X GET "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \
-H "Authorization: {api_token}" \
-H "LD-API-Version: beta"
レスポンスには、各バリエーションの _id(UUID)を含む variations 配列が含まれます。
ステップ 2: デフォルトルールを編集する
作成したバリエーションを配信するようにデフォルトルールを編集します。
重要:
turnTargetingOn命令は設定では機能しません。代わりにupdateFallthroughVariationOrRolloutを使用してください。
# First, get variation IDs from Step 1 response
# Then set fallthrough to the enabled variation (e.g., "Default" variation)
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"
}]
}'
ステップ 3: ターゲティングルールを追加する
属性ベースのルール:
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
}]
}'
パーセンテージロールアウト:
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}
]
}
}]
}'
フォールスルー(デフォルトルール)を設定する:
curl -X PATCH "..." \
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": "fallback-variation-uuid"
}]
}'
Python 実装
import requests
import os
from typing import Dict, List, Optional
class AIConfigTargeting:
"""Manager for config targeting rules"""
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]:
"""Get current targeting with variation IDs."""
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]:
"""Look up variation UUID from key or name."""
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]:
"""Send semantic patch instructions."""
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:
"""
Enable a config by setting fallthrough to an enabled variation.
Note: turnTargetingOn doesn't work for configs. Instead, set the
fallthrough from the disabled variation (index 0) to an enabled one.
"""
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:
"""Add targeting rule serving a specific variation index."""
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:
"""
Add percentage rollout rule.
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:
"""Set default (fallthrough) variation by 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:
"""Target specific context keys."""
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:
"""Target a segment."""
result = self.update_targeting(config_key, environment, [{
"kind": "addRule",
"clauses": [{
"attribute": "segmentMatch",
"contextKind": "", # Leave blank for 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:
"""Remove all targeting rules."""
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
命令リファレンス
注記:
turnTargetingOnとturnTargetingOffは設定では機能しません。設定はデフォルトでターゲティングが有効になっています。設定を「有効化」するには、updateFallthroughVariationOrRolloutを使用してフォールスルーを有効なバリエーションに設定してください。
ルール
| Kind | 説明 |
|---|---|
addRule | 句とバリエーション/ロールアウトを持つルールを追加する |
removeRule | ruleId で削除する |
replaceRules | すべてのルールを置き換える |
reorderRules | 評価順序を変更する |
updateRuleVariationOrRollout | ルールが配信する内容を更新する |
フォールスルー
| Kind | 説明 |
|---|---|
updateFallthroughVariationOrRollout | デフォルトのバリエーションまたはロールアウトを設定する |
個別ターゲット
| Kind | 説明 |
|---|---|
addTargets | 特定のコンテキストキーをターゲットにする |
removeTargets | 特定のターゲットを削除する |
replaceTargets | すべてのターゲットを置き換える |
演算子リファレンス
| 演算子 | 説明 | 例 |
|---|---|---|
in | 値がリストに含まれる | ["premium", "enterprise"] |
contains | 文字列が含まれる | ["sonnet"] |
startsWith | 文字列のプレフィックス | ["user-"] |
endsWith | 文字列のサフィックス | [".edu"] |
matches | 正規表現の一致 | ["^user-\\d+$"] |
greaterThan / lessThan | 数値の比較 | [100] |
before / after | 日付の比較 | ["2024-12-31T00:00:00Z"] |
semVerEqual / semVerGreaterThan | バージョンの比較 | ["2.0.0"] |
segmentMatch | セグメントのメンバーシップ | ["beta-testers"] |
句の構造
{
"contextKind": "user",
"attribute": "email",
"op": "endsWith",
"values": [".edu"],
"negate": false
}
- 複数の句 = AND(すべてが一致する必要があります)
- 複数の値 = OR(いずれかが一致すればよい)
negate: trueは演算子を反転させます
ロールアウトの種類
手動パーセンテージロールアウト
{
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": "key",
"variations": [
{"variation": 0, "weight": 50000},
{"variation": 1, "weight": 50000}
]
}
}
プログレッシブロールアウト
{
"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"}}
]
}
}
ガード付きロールアウト
{
"guardedRolloutConfig": {
"randomizationUnit": "user",
"stages": [
{"rolloutWeight": 1000, "monitoringWindowMilliseconds": 17280000},
{"rolloutWeight": 5000, "monitoringWindowMilliseconds": 17280000}
],
"metrics": [{
"metricKey": "error-rate",
"onRegression": {"rollback": true},
"regressionThreshold": 0.01
}]
}
}
一般的なパターン
属性によるモデルルーティング
# Route based on selectedModel context attribute
targeting.add_rule(
config_key="model-selector",
environment="production",
clauses=[{
"contextKind": "user",
"attribute": "selectedModel",
"op": "contains",
"values": ["sonnet"],
"negate": False
}],
variation=0, # Sonnet variation index
description="Route sonnet requests"
)
ティアベースのバリエーション
targeting.add_rule(
config_key="chat-assistant",
environment="production",
clauses=[{
"contextKind": "user",
"attribute": "tier",
"op": "in",
"values": ["premium", "enterprise"],
"negate": False
}],
variation=0 # Premium model variation
)
セグメントターゲティング
targeting.target_segment(
config_key="chat-assistant",
environment="production",
segment_keys=["beta-testers"],
variation=1 # Experimental variation
)
エラー処理
| ステータス | 原因 | 解決策 |
|---|---|---|
| 400 | 無効なセマンティックパッチ | 命令の形式を確認してください。ops は小文字である必要があります |
| 403 | 権限が不足しています | API トークンを確認してください |
| 404 | 設定が見つかりません | projectKey と configKey を確認してください |
| 422 | 無効なバリエーション | インデックス(0、1、2...)またはターゲティング応答の UUID を使用してください |
次のステップ
ターゲティングを構成した後:
- 設定 URL を指定します:
https://app.launchdarkly.com/projects/{projectKey}/ai-configs/{configKey} built-in-metricsでパフォーマンスを監視しますonline-evalsでジャッジをアタッチします- 自動回帰検出のためにガード付きロールアウトを設定します
関連スキル
configs-create- バリエーションを含む設定を作成しますconfigs-variations- バリエーションを管理しますonline-evals- ジャッジをアタッチしますsegments- ターゲティング用のセグメントを作成します