mcpField
M
migrate

migrate

github.com/launchdarkly開発281.8k 回インストール今日更新
リポジトリ

migrate について

ハードコードされた LLM のプロンプトや設定を LaunchDarkly AgentControl に移すための段階的なスキルです。コード監査、設定、ツール移行、トラッキング、評価を案内し、各段階で確認を求めます。

主な機能

  1. 015段階の移行ワークフロー
  2. 02読み取り専用のコード監査
  3. 03LaunchDarkly 設定の案内
  4. 04ツールスキーマの移行
  5. 05リクエスト指標のトラッキング
  6. 06評価器の設定案内

活用シーン

  1. 01プロンプトとモデル設定の外部化
  2. 02ツール定義の設定への移行
  3. 03リクエスト単位の利用状況追跡
  4. 04オフラインまたはオンライン評価の設定

MCP 対応

環境にリモートの LaunchDarkly MCP サーバーが必要ですが、このスキル自体は MCP ツールを直接使用しません。

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/migrateを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
references/
agent-graph-reference.md
agent-mode-frameworks.md
before-after-examples.md
fallback-defaults-pattern.md
phase-1-analysis-checklist.md
sdk-ai-tracker-patterns.md

詳細

AgentControl への移行

あなたは、アプリケーションをハードコードされた LLM プロンプトから完全な LaunchDarkly AgentControl 実装へ移行する作業をガイドするスキルを使用しています。あなたの仕事は、移行を 5 つのステージ で実行し、各ステージで停止してユーザーの確認を待つことです。

  1. コードを監査する — 読み取り専用のスキャンを実行し、ハードコードされているすべてのもの(プロンプト、モデル、パラメーター、ツール、アプリスコープの設定値)の構造化されたリストを作成します。
  2. 呼び出しをラップする — SDK をインストールし、ハードコードされた値を反映したフォールバック付きの設定を LaunchDarkly に作成し、呼び出し箇所を書き換えて、リクエストごとに設定を新たに取得するようにします。
  3. ツールを移行する — 各ツールの JSON スキーマを抽出し、それを設定に紐付け、古いツールリストを参照しているすべての呼び出し箇所を置き換えます。
  4. トラッキングを追加する — プロバイダー呼び出しの周囲に、リクエストごとのトラッカー(所要時間、トークン、成功/エラー)を組み込みます。
  5. エバリュエーターを接続する — Playground + Datasets によるオフライン評価、またはサンプリングされたトラフィックを自動でスコアリングするオンラインジャッジのいずれかを導入します。

⚠️ 初回実行時に避けるべき 3 つの失敗モード。

  1. トラッカーが誤ったスコープにある。 ループを持つエージェントの場合、create_tracker() は setup_run エントリノード内でユーザーターンごとに 1 回発行してください。call_model の内部ではありません。イテレーションごとにファクトリーを呼び出すと N 個の runId が生成され、at-most-once ガードに引っかかります。詳細は agent-mode-frameworks.md § カスタム StateGraph を参照してください。
  2. load_chat_model ラッパーの再利用。 langchain-ai/react-agent のようなテンプレートには load_chat_model(f"{provider}/{name}") ヘルパーが同梱されており、これは init_chat_model(...) をラップし、すべてのバリエーションパラメーターを黙って破棄します。これを削除し(使わないようにするだけでは不十分です)、呼び出し箇所を create_langchain_model(ai_config) に置き換えてください。
  3. /configs-create 後にフォールスルーが切り替わっていない。 作成直後の設定のフォールスルーは自動生成された無効なバリエーションを指しているため、/configs-targeting が実行されるまで SDK は enabled=False を返します。ステージ 2 の検証の前に切り替えてください。

カバレッジ — どの形状がすでに踏み固められているか、どの形状が外挿を必要とするか

このスキルは Python と Node.js / TypeScript に最適化されています。その他の言語はインストールのみです。Python と Node におけるカバレッジの階層は次のとおりです:

形状PythonNode.jsリファレンス
ワンショット補完 (OpenAI / Anthropic / Bedrock / Gemini の直接呼び出し)✅ 実例あり✅ 実例ありbefore-after-examples.md、built-in-metrics/references/ 内のプロバイダー別ドキュメント
マネージドランナー (ManagedModel) 経由のチャットループ✅ ティア 1 パターン✅ ティア 1 パターンbuilt-in-metrics SKILL.md
LangChain の単一呼び出し✅ 実例あり✅ 実例ありlangchain-tracking.md
LangGraph のプリビルドエージェント (Python langchain.agents.create_agent、Node createReactAgent)✅ 実例あり✅ 実例ありagent-mode-frameworks.md § LangGraph
実行スコープのトラッカーを伴う LangGraph カスタム StateGraph (setup_run + call_model + finalize)✅ 詳細な実例あり⚠️ 言及のみ — Python から翻訳agent-mode-frameworks.md § カスタム StateGraph
CrewAI Agent✅ 実例あり— (Node フレームワークではありません)agent-mode-frameworks.md § CrewAI
Strands Agent✅ 実例あり⚠️ BedrockModel + OpenAIModel のみ (Anthropic なし)agent-mode-frameworks.md § Strands
カスタム ReAct ループ (手書き、任意のフレームワークまたはフレームワークなし)✅ 実例あり⚠️ フレームワーク非依存の不変条件を適用し、Python から翻訳agent-mode-frameworks.md § カスタム ReAct ループ
Vercel AI SDK (generateText / streamText)— (Python フレームワークではありません)⚠️ プロバイダーパッケージは存在しますが、スキルに実例はありませんbuilt-in-metrics のプロバイダーパッケージマトリクス
ストリーミング (SSE / WebSocket)⚠️ built-in-metrics のストリーミングドキュメントに委譲⚠️ 同様 — trackStreamMetricsOf + 手動 TTFT を使用streaming-tracking.md
マルチエージェントグラフ (スーパーバイザー + ワーカー)⚠️ 主なスコープ外、リファレンスを参照⚠️ 主なスコープ外、リファレンスを参照agent-graph-reference.md
LangGraph 以外のエージェントフレームワーク (Pydantic AI、DSPy、AutoGen、Haystack、LlamaIndex エージェント、Semantic Kernel)⚠️ 3 つの不変条件を適用、フレームワーク固有の例はなし⚠️ 同様agent-mode-frameworks.md § フレームワーク非依存の不変条件
Go、Ruby、.NETℹ️ インストールコマンドのみℹ️ インストールコマンドのみphase-1-analysis-checklist.md § SDK ルーティングテーブル

キーの読み方: ✅ = スキルにそのまま従います; ⚠️ = アーキテクチャは適用できますが、イディオムを翻訳するか、別のスキルを相互参照する必要があります; ℹ️ = スキルはインストール手順を超えません。

対象アプリが ⚠️ の列にある場合は、まず agent-mode-frameworks.md § フレームワーク非依存の不変条件 を読んでください — これらの 3 つのルール (1 ターンにつき 1 つの agent_config、1 ターンにつき 1 つのトラッカー、最大 1 回のメソッドはターン終了時に 1 回だけ発火する) はフレームワークに関係なく適用され、このスキルのすべてのコードスニペットはこれらの具体化です。Python の例の形状を、対象フレームワークのプリミティブに翻訳してください。

前提条件

このスキルを使用するには、リモートでホストされている LaunchDarkly MCP サーバーが環境に構成されていること、およびモデル、プロンプト、パラメーターの値をハードコードして LLM プロバイダーをすでに呼び出しているアプリケーションが必要です。

必要な環境:

  • LD_SDK_KEY — 対象の LaunchDarkly プロジェクトのサーバー側 SDK キー (sdk- で始まる)

このスキルが直接使用する MCP ツール: なし — LaunchDarkly への書き込みはすべて、目的別の兄弟スキルで行われます。

パターンを適用する前に SDK の CHANGELOG を確認してください。 このスキル全体で説明されている API サーフェスは、スキルが最後に更新された時点の SDK の動作を対象としています。それ以降の SDK リリースでは、メソッドの名前変更、削除、分割が行われている可能性があります。開始する前に、対象とする SDK の最新の CHANGELOG を取得し、これから適用しようとしているパターンと矛盾する記述がないか目を通してください:

CHANGELOG のエントリがこのスキルより新しく、これから使用しようとしている API を変更している場合は、CHANGELOG が優先されます — そしてスキルを更新する必要があります。

ハンドオフモデル。 このスキルは他のスキルを自動的に呼び出しません。LaunchDarkly への書き込みが必要な各段階で、このスキルは入力 (設定キー、モード、モデル、プロンプト、ツールスキーマ、judge キー) を準備し、その後次のスラッシュコマンドをユーザー自身が実行するよう伝えます。ユーザーがその兄弟スキルを完了したら、ここでの次のステップに戻ります。以下の「委譲」の行は、自動ハンドオフではなく次のステップの指示として扱ってください。

各段階でユーザーが実行する兄弟スキル:

  • projects — ステージ 2 の前、まだプロジェクトが存在しない場合のみ
  • configs-create — ステージ 2 (設定と最初のバリエーションを作成します)
  • tools — ステージ 3 (ツール定義を作成してアタッチします)
  • configs-targeting — ステージ 2 とステージ 4 の間 (新しいバリエーションをフォールスルーに昇格させ、SDK が実際にそれを配信するようにします)
  • online-evals — ステージ 5 (judge をアタッチし、カスタム judge を作成します)

コア原則

  1. 変更する前に検査する。 すべての段階は読み取り専用の監査から始まります。ステップ 1 がユーザーに確認されるまでコードに触れないでください。
  2. ビジネスロジックではなく設定を置き換える。 SDK 呼び出しは、モデル、パラメーター、プロンプトが定義されている箇所に対するドロップインであり、プロバイダーの呼び出し自体に対するものではありません。OpenAI/Anthropic/Bedrock の呼び出しはそのままの場所に残します。
  3. フォールバックは現在の動作を反映する。 completion_config / agent_config に渡すフォールバックは、削除したハードコードされた値を保持していなければなりません。そうすることで、LaunchDarkly に到達できない場合でもアプリは変わりません。
  4. 段階には順序がある。 ツールを追加する前にラップします。トラッキングの前にツールを追加します。eval を追加する前にトラッキングします。先に進みすぎると、トラフィックのない設定、コンテキストのないメトリクス、スコアリングする対象のない judge が生まれます。
  5. 目的別のスキルに手動でハンドオフする。 LaunchDarkly への書き込みが必要な各段階で、ユーザーに兄弟スラッシュコマンド (/configs-create、/tools、/configs-targeting、/online-evals) を実行するよう伝え、ユーザーが戻ってくるのを待ちます。このスキルは他のスキルを自動的に呼び出しません。

ワークフロー

最小限の実行可能な移行

ステージ 1~4(監査、ラップ、ツール、トラッカー)はそれぞれ独立してリリースできます。ステージ 4 で止まる移行は完了しており、本番環境に対応し、中核となる価値を提供します — 外部化されたプロンプトとモデル設定、ターゲティング、バリエーションの A/B テスト、Monitoring タブのメトリクスです。ステージ 5(評価器)は品質向上のための追加であり、ゲートではありません。評価器のせいでステージ 4 のロールアウトを妨げないでください。実行スコープのトラッカーパスをリリースし、メトリクスが流れることを確認してから、チームにデータセットをキュレーションする時間ができたときにステージ 5 に戻ってきてください。

とはいえ、ステージ 4 をスキップしないでください。トラッカーなしの移行では、外部化されたプロンプトは得られますが可視性がありません。これは残される利点の大部分を無駄にすることになります。

ステップ 1: コードベースを監査する (ステージ 1)

これは最初のステージです。読み取り専用 です — コードの書き込みも、LaunchDarkly リソースの作成も行いません。目的はリポジトリをスキャンし、移行が必要なすべてのハードコードされた値の構造化マニフェストを生成し、ステージ 2 でコードに手を付ける前に、そのマニフェストをユーザーに返して確認を求めることです。

phase-1-analysis-checklist.md を使用してスキャンします:

  1. 言語とパッケージマネージャー — Python (pip/poetry/uv)、TypeScript/JavaScript (npm/pnpm/yarn)、Go、Ruby、.NET
  2. LLM プロバイダー — OpenAI、Anthropic、Bedrock、Gemini、LangChain、LangGraph、CrewAI、Strands
  3. 既存の LaunchDarkly の使用状況 — 再利用できる既存の LDClient または ldclient の初期化
  4. ハードコードされたモデル設定 — モデル名の文字列リテラル、temperature / max_tokens / top_p、システムプロンプト、指示文字列
  5. プロンプト内のテンプレートプレースホルダー — .format() 呼び出し、プロンプト定数内の f-string、JS/TS テンプレートリテラル、%(var)s、手書きの str.replace("__VAR__", ...)。各プレースホルダー名とその実行時値のソースを記録します。すべてステージ 2 で Mustache {{ variable }} に書き換えられます。
  6. 外部化されたプロンプトファイル — YAML / JSON / TOML / Markdown / .prompt / .j2 ファイル および 実行時に読み込まれるプロンプトのプロンプトテンプレートレジストリ (langchain.hub.pull(...)、LangSmith client.pull_prompt(...)) をスキャンします。一般的な形式: CrewAI agents.yaml / tasks.yaml、LangChain Promptfiles、k8s ConfigMap オーバーレイ、prompt_* フィールドを持つ Pydantic Settings クラス。プレースホルダーの構文が異なる場合は、同じ Mustache への書き換え (ステージ 2 のサブステップ 5) が適用されます。phase-1-analysis-checklist.md § 4 を参照してください。
  7. ハードコードされたアプリスコープの調整項目 — 検索結果の上限、リトライバジェット、ツールタイムアウトのオーバーライド、機能トグル、プロンプトやモデルパラメータではないもののエージェントの動作を制御する設定データクラスのフィールド。これらはバリエーションの model.custom に属します (model.parameters ではありません。これはプロバイダー SDK に転送され、未知の kwargs でクラッシュします)。
  8. モードの決定 — 補完モード (チャットメッセージ配列) またはエージェントモード (単一の instructions 文字列)。補完モードがデフォルトであり、UI でアタッチされたジャッジをサポートする唯一のモードです。

監査で検出された各ハードコード対象について、以下を記録します:

  • ファイルパスと行範囲
  • 現在の値 (モデル名、プロンプト全文、パラメータ辞書)
  • 対象の設定フィールド (model.name、model.parameters.temperature、messages[].content、instructions)
  • 周囲の呼び出しが関数呼び出し / ツールを使用しているかどうか (ステージ 3 を左右します)
  • 周囲の呼び出しにリトライロジックがあるかどうか (ステージ 4 のトラッカー呼び出しの配置に影響します)

このマニフェストが、次の 4 ステージの契約となります。

ステージ 1 の出力 (構造化サマリーとしてユーザーに返します):

Language: Python 3.12
Package manager: uv
LLM provider: OpenAI
Existing LD SDK: none
Target mode: completion
Hardcoded targets:
  - src/chat.py:42   model="gpt-4o"
  - src/chat.py:43   temperature=0.7, max_tokens=2000
  - src/chat.py:45   system="You are a helpful assistant..."
Externalized prompt files: none (or e.g. "prompts/agents.yaml — CrewAI role/goal/backstory")
Prompt-template registries: none (or e.g. langchain.hub.pull("rlm/rag-prompt") at app.py:14)
Coverage totals: 3 hardcoded code targets · 0 externalized prompt files · 0 registry pulls
Proposed plan: single config key `chat-assistant`, mirror fallback, Stage 3 (tools) skipped (no function calling), Stage 4 (tracking) inline, Stage 5 (evals) attach built-in accuracy judge.

STOP。 このサマリーを提示し、カバレッジの合計を口に出して伝えてください (例: 「ハードコードされたコード対象が N 件、外部化されたプロンプトファイルが M 件見つかりました — これは想定と一致しますか?」)。そして、ユーザーが次の 4 つの明示的な形式のいずれかで返信するのを待ちます:

  • confirm — ステージ 2 に進みます。
  • add: <files or paths> — 新しい場所を加えて監査を再実行し、更新されたサマリーを提示します。
  • fix: <correction> — リスト内の対象 (プロバイダー、モード、プロンプト内容など) を更新し、再度確認します。
  • stop — ここで移行を一時停止します。

skip、next、go、ok、proceed を含め、他のいかなる言葉も確認として解釈しないでください。ユーザーに 4 つの形式のいずれかを選ぶよう求めてください。これはワークフローで最も重要なチェックポイントです — 監査が間違っていれば、それ以降のすべてのステージが間違ったものになります。ユーザーは、承認する前に、ハードコード対象のリストを、コード内にあると把握している内容と照合確認する必要があります。

ステップ 2: AI SDK で呼び出しをラップする (ステージ 2)

これはコードを書き込む最初のステージです。9 つのサブステップがあります。

  1. 監査で指摘された手書きのモデル / ツールラッパーを削除します。 これは新しい SDK をインストールする 前に 行ってください。そうすることで、置き換え後のコードが紛らわしいフォールバックインポートのないリポジトリに配置されます。Stage 1 の監査で洗い出されるはずだった 2 つの形は次のとおりです。

    • load_chat_model(f"{provider}/{name}") または任意の init_chat_model(...) ラッパー。 これは langchain-ai/react-agent および多くの派生リポジトリに含まれています。関数とそのモジュールを削除してください。置き換え後のコードは create_langchain_model(ai_config) です(次のサブステップでインストールします)。ラッパーをそのままにしておくと、このリポジトリでの次の編集でおなじみのヘルパーがインポートされ、バリエーションパラメータが気づかないうちに失われます。
    • 静的なツールリストをハードコードしている手書きの resolve_tools / TOOL_REGISTRY / ALL_TOOLS ヘルパー。 これらを削除してください。ldai_langchain.langchain_helper.build_structured_tools(ai_config, TOOL_REGISTRY_DICT) が正規の置き換え後のコードであり、Stage 3 で接続されます。手書きのバージョンを残しておくと、両方の形が併存し、次の担当者はおなじみのほうを選んでしまいます。

    リポジトリのレビュープロセスにとって有益であれば、削除は SDK のインストールとは別にコミットしてください。そうでなければサブステップ 2 にまとめてください。

  2. AI SDK をインストールします。 ステップ 1 でパッケージマネージャーを検出し、次をインストールします。

    • Python: launchdarkly-server-sdk + launchdarkly-server-sdk-ai>=0.20.0
    • Node.js/TypeScript: @launchdarkly/node-server-sdk + @launchdarkly/server-sdk-ai@^0.20.0
    • Go: github.com/launchdarkly/go-server-sdk/v7 + github.com/launchdarkly/go-server-sdk-ai

    Tier-2 プロバイダーのパッケージ(該当するプロバイダーを使用している場合のみ、Stage 4 でインストールします)。

    • OpenAI: launchdarkly-server-sdk-ai-openai>=0.4.0(Python)/ @launchdarkly/server-sdk-ai-openai@^0.5.5(Node)
    • LangChain / LangGraph: launchdarkly-server-sdk-ai-langchain>=0.5.0(Python)/ @launchdarkly/server-sdk-ai-langchain@^0.5.5(Node)
    • Vercel AI SDK(Node のみ): @launchdarkly/server-sdk-ai-vercel@^0.5.5
    • Anthropic、Gemini、Bedrock — プロバイダーパッケージは公開されていません。Tier-3 のカスタムエクストラクターを使用してください(built-in-metrics を参照)。
  3. 起動時に LDAIClient を一度だけ初期化します。 既存の LDClient があれば再利用してください。2 つ目のベースクライアントを作成しないでください。初期化は、既存のアプリ設定を管理しているのと同じモジュールに配置してください。

    Python:

    import os
    import ldclient
    from ldclient.config import Config
    from ldai.client import LDAIClient
    
    # Order matters: ldclient.get() raises if called before ldclient.set_config().
    # The set_config call is what initializes the singleton; .get() just returns it.
    sdk_key = os.environ.get("LD_SDK_KEY")
    if sdk_key:
        ldclient.set_config(Config(sdk_key))
    else:
        # Missing key: init in offline mode so the app still starts and the fallback
        # path runs on every call. Never raise at import time for a missing env var —
        # that turns a config gap into a boot failure.
        import logging
        logging.getLogger(__name__).warning(
            "LD_SDK_KEY not set; configs will use fallback values only."
        )
        ldclient.set_config(Config("", offline=True))
    
    ai_client = LDAIClient(ldclient.get())
    

    Node.js/TypeScript:

    import { init } from '@launchdarkly/node-server-sdk';
    import { initAi } from '@launchdarkly/server-sdk-ai';
    
    // The Node SDK does not have an explicit offline mode — a missing or invalid
    // key fails fast during waitForInitialization, and every agent_config /
    // completion_config call returns the fallback. Log a warning; do not throw.
    if (!process.env.LD_SDK_KEY) {
      console.warn('LD_SDK_KEY not set; configs will use fallback values only.');
    }
    const ldClient = init(process.env.LD_SDK_KEY ?? 'sdk-offline');
    await ldClient.waitForInitialization({ timeout: 10 }).catch(() => {
      // Swallow init failures in offline mode; fallback path runs.
    });
    const aiClient = initAi(ldClient);
    
  4. configs-create に引き継ぎます。 Stage 1 のマニフェストから抽出したモデル、プロンプト / 指示、パラメータ、モードを出力し、ユーザーに次のように伝えます。「これらの入力を使用して /configs-create を実行し、その後ここに戻ってください。」 コードから呼び出したいコンフィグキー(例: chat-assistant)を指定してください。兄弟スキルを自動で呼び出そうとしないでください。ユーザーがそれを完了するまで待ってから続行してください。

    configs-create が完了した後、ユーザーは新しいバリエーションをフォールスルーに昇格させるために /configs-targeting も実行する必要があります。 作成したばかりのバリエーションは、ターゲティングが更新されるまで、すべてのコンシューマーに対して enabled=False を返します。これを省略すると、Stage 2 の検証(以下のサブステップ 9)は、すべてのリクエストで気づかないうちにフォールバックパスをたどることになります。

  5. テンプレートのプレースホルダーを Mustache 構文に書き換えます。 ハードコードされたプロンプトが実行時の値を Python の .format()、f-string、JS テンプレートリテラル、その他の非 Mustache 構文(例: {system_time}、${userName}、%(topic)s)で補間している場合は、すべてのプレースホルダーを {{ variable }} の Mustache 形式に書き換えてください。これは、/configs-create に送信しようとしているファイル と、サブステップ 6 で記述するフォールバック文字列の 両方 で行ってください。AI SDK は、LD から提供されるパス および フォールバックパスにおいて、completion_config(...) / completionConfig(...) の第 4 引数である variables ディクショナリを使用して、Mustache レンダラーを通じて変数を補間します。フォールバックに Python スタイルの {system_time} リテラルを残しておくと、LaunchDarkly に到達できないときに気づかないうちにリグレッションを出荷してしまいます。レンダラーは単一括弧の形式にマッチせず、リテラルの {system_time} がプロンプトの一部としてプロバイダーに送信されます。

    変更前:

    SYSTEM_PROMPT = "You are a helpful assistant. The time is {system_time}."
    prompt = SYSTEM_PROMPT.format(system_time=datetime.now().isoformat())
    

    変更後(ソース内):

    SYSTEM_PROMPT = "You are a helpful assistant. The time is {{ system_time }}."
    # .format() is removed at the call site — the SDK interpolates via `variables`
    config = ai_client.completion_config(
        CONFIG_KEY,
        context,
        fallback,
        variables={"system_time": datetime.now().isoformat()},
    )
    

    書き換えが必要な一般的な形式:

    • Python の "{var}" / "{var!s}" / "%(var)s" → "{{ var }}"
    • プロンプト文字列内の JS/TS の `${var}` テンプレートリテラル → "{{ var }}"
    • 手書きの str.replace("__VAR__", value) スキーム → "{{ var }}"

    フォールバック固有のバリアントについては、fallback-defaults-pattern.md § テンプレートプレースホルダー を参照してください。

  6. フォールバックを構築します。 抽出したハードコードされた値を反映させます。Python では AICompletionConfigDefault / AIAgentConfigDefault を、Node ではプレーンなオブジェクトリテラルを使用します。インライン、ファイルベース、ブートストラップ生成のパターンについては、fallback-defaults-pattern.md を参照してください。

    Python フォールバック(completion モード):

    from ldai.client import AICompletionConfigDefault, ModelConfig, ProviderConfig, LDMessage
    
    fallback = AICompletionConfigDefault(
        enabled=True,
        model=ModelConfig(name="gpt-4o", parameters={"temperature": 0.7, "max_tokens": 2000}),
        provider=ProviderConfig(name="openai"),
        messages=[LDMessage(role="system", content="You are a helpful assistant...")],
    )
    
  7. ハードコードされた呼び出し箇所を置き換えます。 ハードコードされた model/prompt/params を completion_config / completionConfig(または agent_config / agentConfig)の呼び出しに差し替え、返されたフィールドを既存のプロバイダー呼び出しに読み込みます。プロバイダー呼び出しはそのまま維持してください。

    Python — 変更前:

    response = openai_client.chat.completions.create(
        model="gpt-4o",
        temperature=0.7,
        max_tokens=2000,
        messages=[
            {"role": "system", "content": "You are a helpful assistant..."},
            {"role": "user", "content": user_input},
        ],
    )
    

    Python — 変更後:

    context = Context.builder(user_id).set("email", user.email).build()
    config = ai_client.completion_config("chat-assistant", context, fallback)
    
    if not config.enabled:
        return disabled_response()
    
    params = config.model.parameters or {}
    response = openai_client.chat.completions.create(
        model=config.model.name,
        temperature=params.get("temperature"),
        max_tokens=params.get("max_tokens"),
        messages=[m.to_dict() for m in (config.messages or [])] + [
            {"role": "user", "content": user_input},
        ],
    )
    

    Python — 変更後(agent モード) — LangGraph、CrewAI、またはゴール/指示文字列を受け取るあらゆるフレームワーク向け:

    context = Context.builder(user_id).kind("user").build()
    config = ai_client.agent_config("support-agent", context, FALLBACK)
    
    if not config.enabled:
        return disabled_response()
    
    # config is a single AIAgentConfig object — NOT a (config, tracker) tuple.
    # Obtain the tracker once per execution via the factory: tracker = config.create_tracker()
    model_name = f"{config.provider.name}/{config.model.name}"
    instructions = config.instructions
    params = config.model.parameters or {}
    
    # Pass model_name + instructions into your framework's agent constructor.
    # Example: LangGraph prebuilt agent (Python — `from langchain.agents import create_agent`;
    # this replaces `langgraph.prebuilt.create_react_agent`, deprecated in LangGraph 1.0
    # and removed in 2.0. Same return shape; `prompt=` was renamed to `system_prompt=`.)
    # agent = create_agent(
    #     create_langchain_model(config),  # forwards every variation parameter
    #     TOOLS,                            # Stage 3 will replace this with a config.tools loader
    #     system_prompt=instructions,
    # )
    

    Python OpenAI、Node Anthropic、LangGraph の agent モードの完全なペアスニペットについては、before-after-examples.md を参照してください。

  8. config.enabled を確認します。 False が返された場合は、クラッシュせず、かつプロバイダーを呼び出さずに無効化パスを処理します。このチェックは必須であり、任意ではありません。

  9. 検証します。 有効な LD_SDK_KEY を設定してアプリを実行し、呼び出しが成功し、レスポンスが移行前の出力と一致することを確認します。次に、一時的に LD_SDK_KEY=sdk-invalid を設定する(または未設定にする)ことで、フォールバックパスがエラーなく実行されることを確認します。ステージ 3 に進む前に、両方のパスが動作する必要があります。

委任先: configs-create(サブステップ 4)。

ステップ 3: ツールを設定に移動する (ステージ 3)

監査対象のアプリに関数呼び出し / ツールがない場合は、このステップをスキップしてください。それ以外の場合は次のとおりです:

  1. 現在登録されているツールを列挙します。 探すべき一般的な形は次のとおりです:

    • openai.chat.completions.create(tools=[...]) — OpenAI 直接
    • anthropic.messages.create(tools=[...]) — Anthropic 直接
    • create_agent(llm, tools=[...], system_prompt=...) — LangGraph プリビルド (Python、langchain.agents、非推奨の langgraph.prebuilt.create_react_agent を置き換えます)
    • createReactAgent({ llm, tools: [...] }) — LangGraph.js プリビルド (Node、@langchain/langgraph/prebuilt)
    • Agent(tools=[...]) — CrewAI
    • Agent(tools=[...]) — Strands (Python の @tool デコレートされた呼び出し可能オブジェクトをコンストラクター経由で渡します。TS SDK は Zod スキーマのツールを使用します)
    • カスタム StateGraph — モジュールレベルの TOOLS = [...] リストが 両方 の model.bind_tools(TOOLS) と ToolNode(TOOLS) から参照されます。これは langchain-ai/react-agent テンプレートの形であり、通常このリストは tools.py モジュールにあります。bind_tools( と ToolNode( を一緒に grep してください — 同じリストを指し示します。

    各ツールの名前、説明、JSON スキーマを記録してください。

    @tool で定義された LangChain/LangGraph ツールの場合、tool.args_schema.model_json_schema() (または同等の Pydantic model_json_schema() 呼び出し) を介してスキーマを抽出してください。ツールとして使用されるプレーンな非同期呼び出し可能オブジェクト (カスタム StateGraph の形でよく見られます) の場合、LangChain はバインド時に関数シグネチャからスキーマを推論します — StructuredTool.from_function(fn).args_schema.model_json_schema() を介して抽出してください。スキーマを手書きしないでください。

  2. tools にハンドオフします。 抽出したツール名、説明、スキーマを出力し、ユーザーに伝えてください: 「これらのツールとバリエーションキーを指定して /tools を実行し、その後ここに戻ってください。」 兄弟スキルはツール定義 (create-ai-tool) を作成し、それらをバリエーション (update-ai-config-variation) にアタッチします。サブステップ 3 に進む前に、ユーザーが完了するのを待ってください。自動呼び出しはしないでください。

  3. 呼び出しサイトのハードコードされたツール配列を、config.tools (または使用言語の SDK 相当) からの読み取りに置き換えます。 ツール名から実際の実装関数を動的にロードしてください — 動的ツールファクトリパターンについては、devrel エージェントチュートリアルの agent-mode-frameworks.md を参照してください。

    カスタム StateGraph の形の場合、両方 の呼び出しサイトを更新する必要があります: .bind_tools(TOOLS) と ToolNode(TOOLS) の両方が、同じ config.tools 由来のリストから読み取る必要があります。一方を忘れると、LLM は新しいツールを見ているのにエグゼキューターはまだ古いものを実行している、またはその逆の状態になります。

  4. 検証します。 アプリを実行し、ツールのフローがまだ正しく実行されることを確認してください。get-ai-config (デリゲート経由) は、ツールがサーバーサイドでアタッチされていることを確認します。

デリゲート: tools (サブステップ 2)。

ステップ 4: トラッカーをインストゥルメントする (ステージ 4)

デリゲート: built-in-metrics が、プロバイダー呼び出しの周囲にリクエストごとの tracker.track_* 呼び出し (duration、tokens、success/error、feedback) を配線します。アプリが組み込みのエージェントメトリクスを超えるビジネスメトリクスを必要とする場合は、custom-metrics を併用してください。注意: これを launchdarkly-metric-instrument と混同しないでください。これは ldClient.track() 機能メトリクス用であり、別の API です。デリゲートスキルが参照する完全なメソッドごとの Python + Node マトリクスについては、sdk-ai-tracker-patterns.md を参照してください。

ハンドオフ: 設定キー、バリエーションキー、プロバイダー、および呼び出しがストリーミングかどうかを出力し、ユーザーに伝えてください: 「これらの入力を指定して /built-in-metrics を実行し、その後ここに戻ってください。」 自動呼び出しはしないでください。ユーザーが完了したら、サブステップ 5 (検証) のためにここに戻ってください。

  1. トラッカーを作成します。 ステージ 2 で返された config のファクトリを使用して、実行ごとのトラッカーを取得します: tracker = config.create_tracker()(Python)または const tracker = aiConfig.createTracker();(Node)。ファクトリはユーザーのターンごとに 1 回呼び出し、そのターン内のすべてのトラッキング呼び出しで返された tracker を再利用してください。各呼び出しは新しい runId を発行し、そのターンから送出されるすべてのイベントにタグ付けするため、エクスポートされたイベントやダウンストリームのクエリを通じて関連付けることができます。(Monitoring タブは現時点では集約を行っていますが、実行レベルのグループ化はダウンストリームの関心事です。ただし、runId は SDK の at-most-once ガードのキーにもなっているため、ターンの途中で新しいものを発行すると、イベントがどこに届くかに関係なくガードのセマンティクスが壊れます。)

    ファクトリをどこで呼び出すかは呼び出しの形によって異なります:

    • Completion モード / ワンショットのプロバイダー呼び出し: completion_config(...) が戻った直後に、リクエストを処理する同じ関数内でトラッカーを発行します。
    • ReAct ループを伴うエージェントモード(LangGraph、LangChain、カスタム): ループの前に1 回だけ実行される専用の setup_run エントリノードでトラッカーを発行し、グラフの状態に格納して、call_model / ツールハンドラー / 終端の finalize ノードから状態を読み取ります。ループ本体の中で track_duration / track_tokens / track_success を送出すると、at-most-once ガードに引っかかります。setup_run + call_model + finalize の完全なパターンについては agent-mode-frameworks.md § Custom StateGraph (run-scoped architecture) を参照してください。
    • マネージドランナー(Tier 1): このステップを完全にスキップします。ManagedModel は run() / invoke() ごとに内部的にトラッカーを発行します。アプリがこれを使用している場合はサブステップ 4 に進んでください。
  2. 4 段階のラダーからティアを選択します。 完全な表(チャットループ → Tier 1、プロバイダーパッケージ呼び出し → Tier 2、カスタム抽出器 → Tier 3、ストリーミング / 手動 → Tier 4)については sdk-ai-tracker-patterns.md § Tier decision table を参照してください。

  3. 選択したティアを接続します。 デリゲートスキルには、各ティアの完全な Python + Node の例と、プロバイダーごとのファイルが含まれています。参考として、プロバイダーパッケージ経由の OpenAI 向けに Tier 2/3 の例を簡略化して示します:

    Python:

    from ldai_openai import get_ai_metrics_from_response
    import openai
    
    client = openai.OpenAI()
    
    tracker = config.create_tracker()
    
    def call_openai():
        return client.chat.completions.create(
            model=config.model.name,
            messages=[{"role": "system", "content": config.messages[0].content},
                      {"role": "user", "content": user_prompt}],
        )
    
    # Exceptions are tracked automatically — track_metrics_of catches
    # exceptions, records tracker.track_error(), and re-raises. Wrap your
    # own try/except only for local handling (logging, fallback).
    response = tracker.track_metrics_of(get_ai_metrics_from_response, call_openai)
    

    Node:

    import { getAIMetricsFromResponse } from '@launchdarkly/server-sdk-ai-openai';
    
    const tracker = aiConfig.createTracker();
    // Exceptions are tracked automatically — trackMetricsOf catches
    // exceptions, records tracker.trackError(), and re-throws.
    const response = await tracker.trackMetricsOf(
      getAIMetricsFromResponse,
      () => openaiClient.chat.completions.create({
        model: aiConfig.model!.name,
        messages: [...aiConfig.messages, { role: 'user', content: userPrompt }],
      }),
    );
    

    Anthropic 直接、Bedrock(プロバイダーパッケージなし)、Gemini、カスタム HTTP については、LDAIMetrics を返す小さな抽出器を作成してください。デリゲートスキルの anthropic-tracking.md、bedrock-tracking.md、gemini-tracking.md を参照してください。LangChain のシングルノードと LangGraph は、launchdarkly-server-sdk-ai-langchain / @launchdarkly/server-sdk-ai-langchain プロバイダーパッケージを経由します。モデルは create_langchain_model(config)(Python)/ createLangChainModel(config)(Node)で構築し(どちらもすべてのバリエーションパラメーターを転送します)、get_ai_metrics_from_response / getAIMetricsFromResponse でトラッキングします。詳細は langchain-tracking.md を参照してください。

  4. アプリに高評価 / 低評価の UI がある場合はフィードバックトラッキングを接続します。 両方の SDK が {kind} 引数を受け取る trackFeedback を公開しています。

    Python:

    from ldai.tracker import FeedbackKind
    tracker.track_feedback({"kind": FeedbackKind.Positive})
    

    Node:

    import { LDFeedbackKind } from '@launchdarkly/server-sdk-ai';
    tracker.trackFeedback({ kind: LDFeedbackKind.Positive });
    

    プロセスをまたぐ遅延フィードバック。 高評価 UI がレスポンスを生成したプロセスとは別のプロセスで発火する場合、コンシューマー側で create_tracker() を再度呼び出さないでください。新しい runId が発行されてしまいます。トラッカーの再開トークン(Python では tracker.resumption_token、Node では tracker.resumptionToken)をメッセージと一緒に永続化し、フィードバックハンドラー内で LDAIConfigTracker.from_resumption_token(...)(Python)または aiClient.createTracker(token, context)(Node)を使ってトラッカーを復元してください。

  5. 検証します。 ステージング環境でラップされたエンドポイントにアクセスし、その後 LaunchDarkly の設定を開いて → Monitoring タブを確認します。Duration、token、generation のカウントが 1〜2 分以内に表示されるはずです。何も表示されない場合は、sdk-ai-tracker-patterns.md の「Troubleshooting」にあるチェックリストを順に確認してください。

ステップ 5: 評価をアタッチする (Stage 5)
  1. 3 つの評価パスの中から選びます。 これは最もよく誤解されるステージです — パスは 2 つではなく 3 つあり、マイグレーションの文脈で適切なデフォルトは、しばしば人々が飛ばしてしまうものです。

    パス使用する場面エージェントモードをサポートするか?
    オフライン評価 (マイグレーションの推奨デフォルト)出荷前のリグレッション: 固定データセットを LD Playground で新しいバリエーションに対して実行し、ベースラインと比較してスコアを付けます。出荷前に新しい設定がハードコード版と少なくとも同等に動作することを証明したいので、マイグレーションに最適です。はい — すべてのモード
    UI でアタッチする自動ジャッジLD UI で 1 つ以上のジャッジをバリエーションにアタッチします。ジャッジはサンプリングされたライブリクエストに対して自動的に実行されます。コード変更はゼロです。コンプリーションモードのみ (UI ウィジェットは現在コンプリーション専用です)
    プログラムによる直接ジャッジリクエストハンドラー内で ai_client.create_judge(...) を呼び出し、各呼び出しで judge.evaluate(input, output) を実行します。リクエストごとのコストとコードの複雑さが増します。サンプリングされた自動ジャッジでは不十分なワークフローを継続的にライブスコアリングするのに最適です。はい — すべてのモード (SDK は両方を同じように扱います)

    ほとんどのマイグレーションユーザーはオフライン評価から始めるべきです。その後、ロールアウトが安定した後に継続的なライブスコアリングが必要な場合にのみ、プログラムによる直接ジャッジを追加してください。

  2. エージェントモードのマイグレーションでは、オフライン評価をデフォルトにします。 UI でアタッチする自動ジャッジは現在コンプリーションモード専用です。エージェントモードで文書化されているパスは、(a) LD Playground + Datasets による オフラインリグレッション (すべてのモードで動作します)、または (b) 呼び出し箇所に組み込む プログラムによる直接ジャッジ のいずれかです。監査マニフェストからスターターデータセット CSV を生成し (1 行につき 1 つの代表的な入力)、Playground のウォークスルーについては Offline Evals guide をユーザーに案内してください。ユーザーが継続的なライブスコアリングを明示的に求めない限り、プログラムによる直接ジャッジを本番コードに組み込まないでください。

    マイグレーションにおける推奨オフライン評価の形:

    • まず default バリエーション (またはマイグレーション前のハードコードされた動作を反映する任意のバリエーション) をデータセットに対して実行します — これがベースラインです。
    • それを 異なるモデルファミリー を指す 2 番目のバリエーションにクローンします (たとえば、ベースラインが anthropic/claude-sonnet-4-5 なら、openai/gpt-4o または openai/gpt-4o-mini にクローンします)。比較は同系統間よりも、ファミリー間でのほうが最も有益です。
    • 組み込みの Accuracy ジャッジを合格しきい値 0.85 でアタッチし、両方のバリエーションを同じデータセットに対して実行します。
    • 勝者が Accuracy でベースラインを上回り、Relevance や Toxicity でリグレッションがない場合にのみ、/configs-targeting 経由で勝者をフォールスルーに昇格させます。

    この形をプロジェクトの datasets/README.md (または同等のもの) に書き込み、マイグレーションの出荷後も比較パターンが再現可能になるようにしてください。

  3. online-evals にハンドオフします — UI でアタッチするジャッジ (コンプリーションモード) の場合、またはプログラムによるパスから参照されるカスタムジャッジ設定を作成する場合に限ります。ユーザーに伝えてください: 「これらの入力を使用して /online-evals を実行し、その後ここに戻ってきてください。」 自動的に呼び出さないでください。渡すもの:

    • 親設定キーとバリエーションキー
    • 作成/アタッチする組み込みジャッジ (Accuracy、Relevance、Toxicity) またはカスタムジャッジキーのリスト
    • 対象環境

    デリゲートは、カスタムジャッジ設定の作成、バリエーション PATCH エンドポイント経由でのアタッチ、および各ジャッジ設定のフォールスルー設定を処理します。オフライン評価はこのデリゲートを経由しません — これは Playground のワークフローであり、API 書き込みではありません。

  4. プログラムによる直接判定の場合: create_judge + evaluate + track_judge_result を組み込みます。 これはステージ 5 でコードを書く唯一の経路です。Python での形は次のとおりです。

    from ldai.client import AIJudgeConfigDefault
    
    judge = ai_client.create_judge(
        judge_key,                               # judge config key in LD
        ld_context,
        AIJudgeConfigDefault(enabled=False),     # fallback: skip eval on SDK miss
    )
    
    if judge and judge.enabled:
        result = await judge.evaluate(
            input_text,
            output_text,
            sampling_rate=0.25,                  # optional; default 1.0 (always eval)
        )
        if result.sampled:
            tracker.track_judge_result(result)
    

    4 つのルール:

    • create_judge は Optional[Judge] を返します。 常に if judge and judge.enabled: でガードしてください。コンテキストに対してジャッジ設定が無効になっている場合や、プロバイダーが存在しない場合は None を返します。None の戻り値に対して直接 .evaluate() を呼び出すと AttributeError が発生します。
    • AICompletionConfigDefault ではなく AIJudgeConfigDefault を渡してください。 create_judge の default パラメーターは Optional[AIJudgeConfigDefault] と型付けされています。completion 型を渡すと型チェックが通らず、一部の古いサンプルにあるドキュメントレベルのバグです。
    • sampling_rate は create_judge ではなく evaluate() のパラメーターです。 デフォルトは 1.0(すべての呼び出しを評価)です。ライブ経路では、コストを抑えるためにより低い値(0.1〜0.25)を渡してください。
    • evaluate() は JudgeResult を返します(None になることはありません)。評価が実際に実行されたかどうかを知るには result.sampled を確認し、track_judge_result(result) を呼び出してください。Node では trackJudgeResult(result) と、同じ sampled フィールドを持つ LDJudgeResult を使用します。

    どのジャッジ設定キーを使用するかをユーザーに確認してください。 LaunchDarkly には Accuracy、Relevance、Toxicity という 3 つの組み込みジャッジが同梱されていますが、組み込みジャッジの実際の設定キーは SDK の正規の定数ではなく、ドキュメントにも記載されていません。ユーザーに LD UI で AgentControl > Library を開いてもらい、参照したいジャッジのキーをコピーしてもらうか、まず configs-create でカスタムジャッジ設定を作成してください。

  5. 検証します。

    • UI にアタッチされた自動ジャッジ: ステージングでリクエストをトリガーし、Monitoring タブ → [Evaluator metrics] ドロップダウンを開きます。設定されたサンプリングレートで、1〜2 分以内にスコアが表示されます。
    • プログラムによる直接判定: ラップされたエンドポイントを呼び出し、track_judge_result が親設定の Monitoring タブに記録されることを確認します。
    • オフライン評価: LD Playground でデータセットを実行し、ベースラインと新しいバリエーションのスコアを並べて比較します。ランタイムの組み込みは不要です。

委任: online-evals(サブステップ 3、任意 — UI にアタッチされたジャッジまたはカスタムジャッジの作成の場合のみ。オフライン評価は委任しません)。

エッジケース

状況対応
アプリがすでにフィーチャーフラグ用に LDClient を初期化しているそれを再利用してください — 既存のクライアントを LDAIClient() / initAi() に渡し、2 つ目のクライアントを作成しないでください
アプリが LangChain の ChatOpenAI(model=...) を使用している手書きのモデル構築を create_langchain_model(config)(Python)または createLangChainModel(config)(Node)に置き換えてください。config.model.name を読み取って手動で ChatOpenAI(model=...) に渡さないでください — このパターンでは、明示的に指定したパラメータ以外のすべてのバリエーションパラメータが失われます
プロバイダー呼び出しをラップするリトライ処理トラッカーはユーザーターンの先頭で 1 回だけ生成されます。リトライループはそのスコープの内側にあります。すべてのリトライ試行は同じ runId を共有します。トラッカーの呼び出し(track_duration / track_tokens / track_success / track_error)はリトライ本体の外側に置きます — ターンの最後に、成功パスまたは最終失敗パスで 1 回だけ呼び出します
アプリにツールがない — ステージ 3 をスキップステージ 2 の検証から直接ステージ 4(トラッキング)に進んでください
モードの不一致: ユーザーはエージェントと言ったが、監査ではワンショットチャットだったアプリが LangGraph のプリビルトエージェント(Python では langchain.agents.create_agent、Node では createReactAgent)、CrewAI の Agent、Strands の Agent、または同様の目標駆動型フレームワークを使用していない限り、completion モードを選択してください
アプリが Strands Agents(Python)を使用しているエージェントモードです。agent_config.provider.name をキーとする create_strands_model ディスパッチャーを構築し、AnthropicModel(model_id=..., max_tokens=...) または OpenAIModel(model_id=..., params=...) を返します。モデルクラスに params を渡す前に parameters.tools を削除してください — Strands は Agent(tools=[...]) を介してツールを受け取ります。トラッキングは Tier 3 です。invoke_async を tracker.track_duration_of(...) でラップし、result.metrics.accumulated_usage からトークンを記録します。agent-mode-frameworks.md § Strands Agent および strands-tracking.md を参照してください
TypeScript 上の Strands アプリTS SDK には BedrockModel と OpenAIModel しか含まれていません — Anthropic をバックエンドとするバリエーションには対応できません。マルチプロバイダーのバリエーションが必要な場合は Python SDK を使用してください
Anthropic SDK を使用する TypeScript アプリtrackAnthropicMetrics ヘルパーは存在しません。Tier 3 を使用してください。response.usage.input_tokens / response.usage.output_tokens を読み取って LDAIMetrics を返す小さなカスタムエクストラクターを備えた trackMetricsOf を使用します。正確なエクストラクターについては、built-in-metrics スキルの anthropic-tracking.md を参照してください
LD_SDK_KEY がないためにフォールバックがサイレントにクラッシュする起動時に警告をログに記録し、フォールバックで続行してください。インポート時に例外を発生させないでください
マルチエージェントグラフ(スーパーバイザー + ワーカー)単一のエージェントを移行した時点で停止してください。Agent Graph Definitions は両方の SDK で利用可能です — Python では launchdarkly-server-sdk-ai.agent_graph、Node では @launchdarkly/server-sdk-ai のグラフ API を介して利用できます。グラフレベルの移行パスについては agent-graph-reference.md を参照してください — これは意図的にこのスキルの主要スコープ外とされています
単一エージェント(ReAct、ツールループ)+ エージェントモードステージ 5 では、LD Playground + Datasets によるオフライン評価をデフォルトとしてください。UI にアタッチするジャッジは現在 completion 専用であり、プログラムによる直接ジャッジは呼び出しごとのコストを追加するため、移行が稼働して安定するまでは通常それに見合いません。Offline Evals guide を参照してください
Pydantic の args_schema を持つツール(LangChain の @tool)tool.args_schema.model_json_schema() を介してスキーマを抽出してください。デリゲート用の JSON スキーマを手書きしないでください
モジュールレベルの TOOLS リストを .bind_tools(TOOLS) でバインドし、ToolNode(TOOLS) を通じて実行するカスタム StateGraph(例: langchain-ai/react-agent テンプレート)TOOLS リストを見つけてください(通常は別の tools.py モジュールにあります)。同じ方法でスキーマを抽出してください。両方の呼び出し箇所 — .bind_tools(...) と ToolNode(...) — を、同じ config.tools 由来のリストを読み取るように置き換えてください
アプリがすでに設定を Context データクラスに外部化し、環境変数フォールバックを備えている(例: react-agent テンプレートの context.py)runtime.context.model / runtime.context.system_prompt の利用側を ai_client.agent_config(...) に置き換え、返された AIAgentConfig から読み取ってください。データクラスをフォールバックの形として維持するのではなく、空にしてください — 正規のフォールバックは Python の FALLBACK = AIAgentConfigDefault(...)(agent_config 呼び出し付近のトップレベル定数)であり、並行する Python データクラスではありません。フォールバック値の信頼できる情報源が 2 つあると乖離します。空の Context は LangGraph の context_schema 要件を満たすためだけのプレースホルダーです。thread_id やその他のリクエストごとの配線は、代わりに config: RunnableConfig を介して渡されます(agent-mode-frameworks.md § Custom StateGraph を参照)

やってはいけないこと

これらは、初回実行時の失敗として表面化する可能性が高い順に並んでいます。最初の 3 つのルール — トラッカーと config のライフタイムに関するもの — が、「移行は完了したように見えるのに、Monitoring タブが断片的 / おかしい」という報告のほとんどを占めています。

トラッカーと config のライフタイム (最も一般的な失敗モード)
  • ユーザーターンごとに create_tracker() / createTracker() を複数回呼び出さないでください。 1 ターン = すべての ReAct イテレーション、ツール呼び出し、リトライを含む、リクエスト/レスポンスサイクル全体です。各アプリ形態 (completion / agent loop / managed runner) における標準的な配置場所については、Stage 4 Step 1 を参照してください。
  • ループ本体の中で track_duration / track_tokens / track_success / track_error / track_time_to_first_token を呼び出さないでください。 これらはトラッカーごとに最大 1 回であり、2 回目以降の呼び出しは破棄されます。ループ内で蓄積し、終端 / finalize ノードで 1 回だけ emit してください。イベント単位のメソッド (track_tool_call、track_tool_calls、track_feedback、track_judge_result) は繰り返し呼び出しても安全です。完全なマトリクス: sdk-ai-tracker-patterns.md § At-most-once guards。
  • ユーザーターンごとに agent_config() / completion_config() を複数回呼び出さないでください。 各呼び出しはフラグ評価であり、$ld:ai:agent:config イベントを emit します。ループのステップやツール本体の中で再取得すると、Monitoring タブの agent-config カウントが膨らみ、ターンの途中でターゲティングが変更されると、1 つのターン内の LLM 呼び出し間でバリエーションが切り替わってしまいます。先頭で 1 回解決し、state に保持して、以降のすべてのコンシューマーが state から読み取るようにしてください。バリエーションスコープの knob を必要とするツールは、ツールファクトリパターン (セットアップ時に knob をクロージャで捕捉する make_search(ai_config)) を使用すべきです — agent-mode-frameworks.md § Getting knobs into tools を参照してください。
  • リクエストをまたいで config オブジェクトをキャッシュしないでください — ターンごとに 1 回解決するのは確かにそうですし、それでもターンごとに 1 回解決する必要があります。モジュールスコープでキャッシュすると、ターゲティング変更の仕組みが完全に無効になります。
  • LaunchDarkly を接続した後でフォールバックを削除しないでください。これは enabled=False および SDK 到達不能のパスに必要です。
  • completion_config / agent_config / completionConfig / agentConfig の戻り値をタプル展開しないでください。これらは (config, tracker) ではなく、単一 の config オブジェクト (例: AIAgentConfig、AICompletionConfig) を返します。トラッカーを取得するには、config.create_tracker() / aiConfig.createTracker() を呼び出してください。LLM はタプルの形と config.tracker プロパティの両方をハルシネーションします — 実際の API はファクトリです。
LangChain / LangGraph のパターン(2 番目によくある失敗モード)
  • リポジトリにすでに load_chat_model(f"{provider}/{name}") ヘルパーが含まれている場合は、それを使わないようにするだけでなく、削除してください。 この正確な形は langchain-ai/react-agent に同梱されており、数十の派生リポジトリにコピーされています。utils.load_chat_model、utils.build_model、または "provider/model" 文字列を分割する任意の単一引数の init_chat_model ラッパーを探してください。これを再利用することが初回実行時の失敗モードです。init_chat_model は名前とプロバイダーしか受け取らないため、すべてのバリエーションパラメータ(temperature、max_tokens、top_p、stop sequences)が黙って捨てられてしまいます。create_langchain_model(ai_config) は、model.parameters ディクショナリ全体を転送する一対一の代替品です。すべての呼び出し箇所を置き換えてから、次の読み手が手を伸ばせないようにラッパーファイル側を削除してください。
  • 同じルールが手作りの resolve_tools / TOOL_REGISTRY / ALL_TOOLS ヘルパーにも当てはまります。 テンプレートにすでに resolve_tools(tool_keys) やモジュールレベルの ALL_TOOLS リストがある場合は、ldai_langchain.langchain_helper から build_structured_tools をインポートし、手作りのバージョンを削除してください。build_structured_tools(ai_config, TOOL_REGISTRY_DICT) は ai_config.model.parameters.tools を読み取り、一致する呼び出し可能オブジェクトを LD ツールキーを StructuredTool.name とする LangChain の StructuredTool としてラップします。そのため、ToolNode の検索は 2 つ目のマッピングなしで機能します。リポジトリに両方を残さないでください。
  • アプリスコープの調整項目を model.parameters に直接入れないでください。create_langchain_model は parameters 内のすべてのキーを init_chat_model 経由でプロバイダー SDK に転送するため、max_search_results / retry_budget / feature_toggle のエントリは予期しないキーワード引数エラーでプロバイダーをクラッシュさせます。正しい置き場所は model.custom で、プロバイダーのヘルパーはこれを無視し、アプリは ai_config.model.get_custom("key") 経由で読み取ります。MCP の update-ai-config-variation ツールは現在トップレベルの custom を公開していないため、2 つのパスのいずれかを選択してください。(a) REST API 経由でバリエーションを PATCH して model.custom を直接設定する、または (b) MCP 経由で parameters.custom 内に(ネストされたディクショナリとして)設定し、両方の場所を読み取る防御的なアクセサを使用する。コードサンプルを含む完全なウォークスルーは langchain-tracking.md § MCP caveat にあります。
  • フォールバック内でツールスキーマを再エンコードしないでください。LaunchDarkly に到達できない場合、フォールバックはツールなしで(またはアプリが動作を継続するために必要な最小限のプロバイダー向けパラメータで)実行されるべきです。設定のツールスキーマを複製する _FALLBACK_TOOLS 配列を構築すると、移行でコードから追い出すはずだったハードコードされた設定を再導入することになります。
  • LaunchDarklyCallbackHandler を ldai.langchain からインポートしないでください。そのクラスもドット付きモジュールパスも存在しません。Python の LangChain ヘルパーパッケージは ldai_langchain(トップレベルモジュール、アンダースコア)です。正規のパターンとして create_langchain_model(config) + track_metrics_of_async(get_ai_metrics_from_response, lambda: llm.ainvoke(messages)) を使用してください。
ステージ / ハンドオフの規律
  • ユーザーが「とりあえずラップして」と言った場合でも、ステップ 1 を省略しないでください。監査を行わないと、フォールバックはハードコードされた動作からずれてしまいます。
  • プロンプトとモデルを抽出する前に configs-create に委任しないでください。委任先はそれらを入力として必要とします。
  • 最初の setup-ai-config の際にツールをアタッチしようとしないでください。ツールのアタッチは tools が所有する別のステップです。
  • 「configs-create に委任した」など、他の兄弟スキルに委任したと主張しないでください。このスキルは自動呼び出しを行いません。各ハンドオフで、入力を表示し、ユーザーに兄弟スラッシュコマンドを実行するよう伝えてから、待機してください。それ以外のことは、何が起きたかについてユーザーを誤解させます。
  • ステージ 2 とステージ 4 の間の /configs-targeting ステップを省略しないでください。作成されたばかりのバリエーションは、ターゲティングによってフォールスルーに昇格されるまで enabled=False を返します。ステージ 2 の検証は、すべてのリクエストで黙ってフォールバックパスをたどることになります。
  • マルチエージェントグラフの移行を一度に試みないでください。まず単一のエージェントを移行してください。次のステップとして agent-graph-reference.md を読んでください。
ステージ 5 の評価
  • トラッカーが整う前に評価を接続しないでください。ジャッジはトラフィックをスコアリングします。ステージ 4 のトラフィックがなければ、ジャッジする対象がありません。
  • ステージ 5 を「UI かプログラム的かのどちらか」として位置づけないでください。3 つのパスがあります: オフライン評価(移行における推奨デフォルト)、UI にアタッチされた自動ジャッジ(completion モードのみ)、そしてプログラム的な直接ジャッジです。オフライン評価はほとんどの人が省略するものであり、通常は正しい出発点です。
  • create_judge に sampling_rate を渡さないでください。これは create_judge() のパラメータではなく、Judge.evaluate() のパラメータです。
  • ジャッジ設定キー("accuracy-judge"、"relevance-judge" など)をハードコードしないでください。組み込みキーは SDK の正規の定数ではありません。ユーザーに LD UI の AgentControl > Library で調べてもらってください。
  • create_judge の後に if judge and judge.enabled: ガードを忘れないでください。これは Optional[Judge] を返し、コンテキストに対してジャッジ設定が無効になっている場合は None を返します。
API サーフェスの注意点
  • ステージ 4(トラッキング)に launchdarkly-metric-instrument を使わないでください。このスキルは ldClient.track() のフィーチャーメトリクス用であり、エージェントの tracker.track_* 呼び出し用ではありません。これらは異なる API です。
  • Python で track_request() を使わないでください。これは launchdarkly-server-sdk-ai には存在しません。プロバイダーパッケージまたはカスタムエクストラクタを伴う track_metrics_of を使うか、ストリーミングパスにいる場合は明示的な track_duration + track_tokens + track_success / track_error に落とし込んでください。
  • Python の tracker.track_*() メソッドに graph_key=... を渡さないでください。これは受け入れられる引数ではありません。グラフトラバーサル内で取得されたトラッカーは、正しいグラフキーで自動的に構成されます。

関連スキル

  • configs-create — 設定を作成するためにステージ 2 から呼び出されます
  • tools — ツール定義を作成してアタッチするためにステージ 3 から呼び出されます
  • online-evals — ジャッジをアタッチするためにステージ 5 から呼び出されます
  • configs-variations — 移行完了後、A/B テスト用のバリエーションを追加します
  • configs-targeting — 移行完了後、新しいバリエーションをユーザーにロールアウトします
  • configs-update — アプリの進化に合わせて設定プロパティを変更します
  • launchdarkly-metric-instrument — ldClient.track() のフィーチャーメトリクス用(エージェントトラッカー呼び出し用ではありません)

参照

  • phase-1-analysis-checklist.md — ステップ 1 の監査チェックリスト、grep パターン、SDK ルーティングテーブル、モード決定ツリー
  • before-after-examples.md — Python OpenAI、Node Anthropic、Python LangGraph 向けの、ハードコードからラップ済みへの変更前後のペアになったスニペット
  • sdk-ai-tracker-patterns.md — Python と Node のすべての tracker.track_* メソッドを並べて比較、自動ヘルパーマトリクス、よくある落とし穴
  • agent-mode-frameworks.md — agent_config を LangGraph、CrewAI、カスタム react ループに組み込む方法、動的ツール読み込みパターン
  • fallback-defaults-pattern.md — 3 つのフォールバックパターン(インライン、ファイルベース、ブートストラップ生成)とそれぞれを使うべき場面
  • agent-graph-reference.md — マルチエージェント移行向けの対象外ポインタードキュメント

コメント