mcpField
C
configs-targeting

configs-targeting

github.com/launchdarkly开发281.8k 次安装1 天前更新
代码仓库

关于 configs-targeting

LaunchDarkly AgentControl 配置的定向规则管理技能,适用于按上下文向不同对象提供配置变体。涵盖目标、细分、属性规则及多种发布方式。

主要功能

  1. 01管理个体目标与细分规则
  2. 02添加和排序属性规则
  3. 03设置默认变体或渐进发布
  4. 04配置百分比及受保护发布
  5. 05支持多种属性条件运算符

适用场景

  1. 01按用户层级分配配置变体
  2. 02将配置定向到测试细分
  3. 03逐步发布变体
  4. 04按模型属性路由配置

MCP 相关

优先使用 LaunchDarkly MCP 服务的工具进行身份验证和定向操作;没有对应工具的步骤可通过 REST API 完成。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/launchdarkly/ai-tooling --skill configs-targeting

安装后在 Claude Code 中输入/configs-targeting确认已加载。

附带文件README.md

详细介绍

配置定向

配置配置定向规则,以控制在不同上下文中提供哪些变体。补全模式和 Agent 模式的工作方式相同。

前提条件

  • 已启用 AgentControl 的 LaunchDarkly 账户
  • 具有写入权限的 API 访问令牌
  • 项目键和环境键
  • 已有包含变体的配置(使用 configs-create skill)

API 访问

优先使用 LaunchDarkly MCP 服务工具:它们通过 OAuth 进行身份验证,无需令牌。如果某个步骤没有对应的 MCP 工具,且必须直接调用 REST API,请让用户为本次会话粘贴 API 访问令牌,并在以下示例中用该令牌替换 {api_token}。请勿在环境变量、.env 文件或 Agent/MCP 配置文件中搜索凭据。

核心概念

评估顺序

定向规则按以下顺序评估(与功能标志相同):

  1. 单独定向 - 特定上下文键(优先级最高)
  2. 细分受众群规则 - 预定义的细分受众群
  3. 自定义规则 - 基于属性的条件(按顺序评估)
  4. 默认规则 - 适用于其他所有情况的回退规则
  5. 关闭变体 - 定向处于禁用状态时使用
语义补丁 API

配置定向使用语义补丁指令:

PATCH /api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting
Content-Type: application/json; domain-model=launchdarkly.semanticpatch
关键概念
  • variationId:UUID,而非键。务必先获取定向信息以取得 ID。
  • 权重:千分之一单位(50000 = 50%,100000 = 100%)
  • 子句逻辑:多个子句表示 AND,多个值表示 OR
  • 空属性:属性为空或缺失时,会跳过相关规则

工作流

步骤 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"

响应包含 variations 数组,其中每个变体都有 _id(UUID)。

步骤 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 将回退规则设为已启用的变体。

规则
类型说明
addRule添加包含子句和变体/渐进发布的规则
removeRule按 ruleId 移除规则
replaceRules替换所有规则
reorderRules更改评估顺序
updateRuleVariationOrRollout更新规则提供的内容
回退
类型说明
updateFallthroughVariationOrRollout设置默认变体或渐进发布
单独定向
类型说明
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语义补丁无效检查指令格式,操作必须使用小写字母
403权限不足检查 API 令牌
404未找到配置验证 projectKey 和 configKey
422变体无效使用索引(0、1、2……)或定向响应中的 UUID

后续步骤

配置定向后:

  1. 提供配置 URL:
    https://app.launchdarkly.com/projects/{projectKey}/ai-configs/{configKey}
    
  2. 使用 built-in-metrics 监控性能
  3. 使用 online-evals 附加评估器
  4. 设置受保护的渐进发布,以自动检测回归

相关技能

  • configs-create - 创建包含变体的配置
  • configs-variations - 管理变体
  • online-evals - 附加评估器
  • segments - 创建用于定向的细分

其他资源

评论

支持 Markdown