migrate について
ハードコードされた LLM のプロンプトや設定を LaunchDarkly AgentControl に移すための段階的なスキルです。コード監査、設定、ツール移行、トラッキング、評価を案内し、各段階で確認を求めます。
主な機能
- 015段階の移行ワークフロー
- 02読み取り専用のコード監査
- 03LaunchDarkly 設定の案内
- 04ツールスキーマの移行
- 05リクエスト指標のトラッキング
- 06評価器の設定案内
活用シーン
- 01プロンプトとモデル設定の外部化
- 02ツール定義の設定への移行
- 03リクエスト単位の利用状況追跡
- 04オフラインまたはオンライン評価の設定
MCP 対応
環境にリモートの LaunchDarkly MCP サーバーが必要ですが、このスキル自体は MCP ツールを直接使用しません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ launchdarkly/ ai-tooling --skill migrateインストール後、Claude Code で/migrateを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdreferences/agent-graph-reference.mdagent-mode-frameworks.mdbefore-after-examples.mdfallback-defaults-pattern.mdphase-1-analysis-checklist.mdsdk-ai-tracker-patterns.md詳細
AgentControl への移行
あなたは、アプリケーションをハードコードされた LLM プロンプトから完全な LaunchDarkly AgentControl 実装へ移行する作業をガイドするスキルを使用しています。あなたの仕事は、移行を 5 つのステージ で実行し、各ステージで停止してユーザーの確認を待つことです。
- コードを監査する — 読み取り専用のスキャンを実行し、ハードコードされているすべてのもの(プロンプト、モデル、パラメーター、ツール、アプリスコープの設定値)の構造化されたリストを作成します。
- 呼び出しをラップする — SDK をインストールし、ハードコードされた値を反映したフォールバック付きの設定を LaunchDarkly に作成し、呼び出し箇所を書き換えて、リクエストごとに設定を新たに取得するようにします。
- ツールを移行する — 各ツールの JSON スキーマを抽出し、それを設定に紐付け、古いツールリストを参照しているすべての呼び出し箇所を置き換えます。
- トラッキングを追加する — プロバイダー呼び出しの周囲に、リクエストごとのトラッカー(所要時間、トークン、成功/エラー)を組み込みます。
- エバリュエーターを接続する — Playground + Datasets によるオフライン評価、またはサンプリングされたトラフィックを自動でスコアリングするオンラインジャッジのいずれかを導入します。
⚠️ 初回実行時に避けるべき 3 つの失敗モード。
- トラッカーが誤ったスコープにある。 ループを持つエージェントの場合、
create_tracker()はsetup_runエントリノード内でユーザーターンごとに 1 回発行してください。call_modelの内部ではありません。イテレーションごとにファクトリーを呼び出すと N 個のrunIdが生成され、at-most-once ガードに引っかかります。詳細は agent-mode-frameworks.md § カスタムStateGraphを参照してください。load_chat_modelラッパーの再利用。langchain-ai/react-agentのようなテンプレートにはload_chat_model(f"{provider}/{name}")ヘルパーが同梱されており、これはinit_chat_model(...)をラップし、すべてのバリエーションパラメーターを黙って破棄します。これを削除し(使わないようにするだけでは不十分です)、呼び出し箇所をcreate_langchain_model(ai_config)に置き換えてください。/configs-create後にフォールスルーが切り替わっていない。 作成直後の設定のフォールスルーは自動生成された無効なバリエーションを指しているため、/configs-targetingが実行されるまで SDK はenabled=Falseを返します。ステージ 2 の検証の前に切り替えてください。
カバレッジ — どの形状がすでに踏み固められているか、どの形状が外挿を必要とするか
このスキルは Python と Node.js / TypeScript に最適化されています。その他の言語はインストールのみです。Python と Node におけるカバレッジの階層は次のとおりです:
| 形状 | Python | Node.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 を取得し、これから適用しようとしているパターンと矛盾する記述がないか目を通してください:
- Python: https://github.com/launchdarkly/python-server-sdk-ai/blob/main/packages/sdk/server-ai/CHANGELOG.md (および
packages/ai-providers/server-ai-{openai,langchain}/CHANGELOG.mdにあるプロバイダーごとの CHANGELOG) - Node: https://github.com/launchdarkly/js-core/blob/main/packages/sdk/server-ai/CHANGELOG.md (および
packages/ai-providers/server-ai-{openai,langchain,vercel}/CHANGELOG.mdにあるプロバイダーごとの CHANGELOG)
CHANGELOG のエントリがこのスキルより新しく、これから使用しようとしている API を変更している場合は、CHANGELOG が優先されます — そしてスキルを更新する必要があります。
ハンドオフモデル。 このスキルは他のスキルを自動的に呼び出しません。LaunchDarkly への書き込みが必要な各段階で、このスキルは入力 (設定キー、モード、モデル、プロンプト、ツールスキーマ、judge キー) を準備し、その後次のスラッシュコマンドをユーザー自身が実行するよう伝えます。ユーザーがその兄弟スキルを完了したら、ここでの次のステップに戻ります。以下の「委譲」の行は、自動ハンドオフではなく次のステップの指示として扱ってください。
各段階でユーザーが実行する兄弟スキル:
projects— ステージ 2 の前、まだプロジェクトが存在しない場合のみconfigs-create— ステージ 2 (設定と最初のバリエーションを作成します)tools— ステージ 3 (ツール定義を作成してアタッチします)configs-targeting— ステージ 2 とステージ 4 の間 (新しいバリエーションをフォールスルーに昇格させ、SDK が実際にそれを配信するようにします)online-evals— ステージ 5 (judge をアタッチし、カスタム judge を作成します)
コア原則
- 変更する前に検査する。 すべての段階は読み取り専用の監査から始まります。ステップ 1 がユーザーに確認されるまでコードに触れないでください。
- ビジネスロジックではなく設定を置き換える。 SDK 呼び出しは、モデル、パラメーター、プロンプトが定義されている箇所に対するドロップインであり、プロバイダーの呼び出し自体に対するものではありません。OpenAI/Anthropic/Bedrock の呼び出しはそのままの場所に残します。
- フォールバックは現在の動作を反映する。
completion_config/agent_configに渡すフォールバックは、削除したハードコードされた値を保持していなければなりません。そうすることで、LaunchDarkly に到達できない場合でもアプリは変わりません。 - 段階には順序がある。 ツールを追加する前にラップします。トラッキングの前にツールを追加します。eval を追加する前にトラッキングします。先に進みすぎると、トラフィックのない設定、コンテキストのないメトリクス、スコアリングする対象のない judge が生まれます。
- 目的別のスキルに手動でハンドオフする。 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 を使用してスキャンします:
- 言語とパッケージマネージャー — Python (pip/poetry/uv)、TypeScript/JavaScript (npm/pnpm/yarn)、Go、Ruby、.NET
- LLM プロバイダー — OpenAI、Anthropic、Bedrock、Gemini、LangChain、LangGraph、CrewAI、Strands
- 既存の LaunchDarkly の使用状況 — 再利用できる既存の
LDClientまたはldclientの初期化 - ハードコードされたモデル設定 — モデル名の文字列リテラル、temperature / max_tokens / top_p、システムプロンプト、指示文字列
- プロンプト内のテンプレートプレースホルダー —
.format()呼び出し、プロンプト定数内の f-string、JS/TS テンプレートリテラル、%(var)s、手書きのstr.replace("__VAR__", ...)。各プレースホルダー名とその実行時値のソースを記録します。すべてステージ 2 で Mustache{{ variable }}に書き換えられます。 - 外部化されたプロンプトファイル — YAML / JSON / TOML / Markdown /
.prompt/.j2ファイル および 実行時に読み込まれるプロンプトのプロンプトテンプレートレジストリ (langchain.hub.pull(...)、LangSmithclient.pull_prompt(...)) をスキャンします。一般的な形式: CrewAIagents.yaml/tasks.yaml、LangChain Promptfiles、k8s ConfigMap オーバーレイ、prompt_*フィールドを持つ Pydantic Settings クラス。プレースホルダーの構文が異なる場合は、同じ Mustache への書き換え (ステージ 2 のサブステップ 5) が適用されます。phase-1-analysis-checklist.md § 4 を参照してください。 - ハードコードされたアプリスコープの調整項目 — 検索結果の上限、リトライバジェット、ツールタイムアウトのオーバーライド、機能トグル、プロンプトやモデルパラメータではないもののエージェントの動作を制御する設定データクラスのフィールド。これらはバリエーションの
model.customに属します (model.parametersではありません。これはプロバイダー SDK に転送され、未知の kwargs でクラッシュします)。 - モードの決定 — 補完モード (チャットメッセージ配列) またはエージェントモード (単一の 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 つのサブステップがあります。
-
監査で指摘された手書きのモデル / ツールラッパーを削除します。 これは新しい 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 にまとめてください。
-
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を参照)。
- Python:
-
起動時に
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); -
configs-createに引き継ぎます。 Stage 1 のマニフェストから抽出したモデル、プロンプト / 指示、パラメータ、モードを出力し、ユーザーに次のように伝えます。「これらの入力を使用して/configs-createを実行し、その後ここに戻ってください。」 コードから呼び出したいコンフィグキー(例:chat-assistant)を指定してください。兄弟スキルを自動で呼び出そうとしないでください。ユーザーがそれを完了するまで待ってから続行してください。configs-createが完了した後、ユーザーは新しいバリエーションをフォールスルーに昇格させるために/configs-targetingも実行する必要があります。 作成したばかりのバリエーションは、ターゲティングが更新されるまで、すべてのコンシューマーに対してenabled=Falseを返します。これを省略すると、Stage 2 の検証(以下のサブステップ 9)は、すべてのリクエストで気づかないうちにフォールバックパスをたどることになります。 -
テンプレートのプレースホルダーを 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 § テンプレートプレースホルダー を参照してください。
- Python の
-
フォールバックを構築します。 抽出したハードコードされた値を反映させます。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...")], ) -
ハードコードされた呼び出し箇所を置き換えます。 ハードコードされた 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 を参照してください。
-
config.enabledを確認します。Falseが返された場合は、クラッシュせず、かつプロバイダーを呼び出さずに無効化パスを処理します。このチェックは必須であり、任意ではありません。 -
検証します。 有効な
LD_SDK_KEYを設定してアプリを実行し、呼び出しが成功し、レスポンスが移行前の出力と一致することを確認します。次に、一時的にLD_SDK_KEY=sdk-invalidを設定する(または未設定にする)ことで、フォールバックパスがエラーなく実行されることを確認します。ステージ 3 に進む前に、両方のパスが動作する必要があります。
委任先: configs-create(サブステップ 4)。
ステップ 3: ツールを設定に移動する (ステージ 3)
監査対象のアプリに関数呼び出し / ツールがない場合は、このステップをスキップしてください。それ以外の場合は次のとおりです:
-
現在登録されているツールを列挙します。 探すべき一般的な形は次のとおりです:
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=[...])— CrewAIAgent(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()(または同等の Pydanticmodel_json_schema()呼び出し) を介してスキーマを抽出してください。ツールとして使用されるプレーンな非同期呼び出し可能オブジェクト (カスタム StateGraph の形でよく見られます) の場合、LangChain はバインド時に関数シグネチャからスキーマを推論します —StructuredTool.from_function(fn).args_schema.model_json_schema()を介して抽出してください。スキーマを手書きしないでください。 -
toolsにハンドオフします。 抽出したツール名、説明、スキーマを出力し、ユーザーに伝えてください: 「これらのツールとバリエーションキーを指定して/toolsを実行し、その後ここに戻ってください。」 兄弟スキルはツール定義 (create-ai-tool) を作成し、それらをバリエーション (update-ai-config-variation) にアタッチします。サブステップ 3 に進む前に、ユーザーが完了するのを待ってください。自動呼び出しはしないでください。 -
呼び出しサイトのハードコードされたツール配列を、
config.tools(または使用言語の SDK 相当) からの読み取りに置き換えます。 ツール名から実際の実装関数を動的にロードしてください — 動的ツールファクトリパターンについては、devrel エージェントチュートリアルの agent-mode-frameworks.md を参照してください。カスタム
StateGraphの形の場合、両方 の呼び出しサイトを更新する必要があります:.bind_tools(TOOLS)とToolNode(TOOLS)の両方が、同じconfig.tools由来のリストから読み取る必要があります。一方を忘れると、LLM は新しいツールを見ているのにエグゼキューターはまだ古いものを実行している、またはその逆の状態になります。 -
検証します。 アプリを実行し、ツールのフローがまだ正しく実行されることを確認してください。
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 (検証) のためにここに戻ってください。
-
トラッカーを作成します。 ステージ 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 § CustomStateGraph(run-scoped architecture) を参照してください。 - マネージドランナー(Tier 1): このステップを完全にスキップします。
ManagedModelはrun()/invoke()ごとに内部的にトラッカーを発行します。アプリがこれを使用している場合はサブステップ 4 に進んでください。
- Completion モード / ワンショットのプロバイダー呼び出し:
-
4 段階のラダーからティアを選択します。 完全な表(チャットループ → Tier 1、プロバイダーパッケージ呼び出し → Tier 2、カスタム抽出器 → Tier 3、ストリーミング / 手動 → Tier 4)については sdk-ai-tracker-patterns.md § Tier decision table を参照してください。
-
選択したティアを接続します。 デリゲートスキルには、各ティアの完全な 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 を参照してください。 -
アプリに高評価 / 低評価の 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)を使ってトラッカーを復元してください。 -
検証します。 ステージング環境でラップされたエンドポイントにアクセスし、その後 LaunchDarkly の設定を開いて → Monitoring タブを確認します。Duration、token、generation のカウントが 1〜2 分以内に表示されるはずです。何も表示されない場合は、sdk-ai-tracker-patterns.md の「Troubleshooting」にあるチェックリストを順に確認してください。
ステップ 5: 評価をアタッチする (Stage 5)
-
3 つの評価パスの中から選びます。 これは最もよく誤解されるステージです — パスは 2 つではなく 3 つあり、マイグレーションの文脈で適切なデフォルトは、しばしば人々が飛ばしてしまうものです。
パス 使用する場面 エージェントモードをサポートするか? オフライン評価 (マイグレーションの推奨デフォルト) 出荷前のリグレッション: 固定データセットを LD Playground で新しいバリエーションに対して実行し、ベースラインと比較してスコアを付けます。出荷前に新しい設定がハードコード版と少なくとも同等に動作することを証明したいので、マイグレーションに最適です。 はい — すべてのモード UI でアタッチする自動ジャッジ LD UI で 1 つ以上のジャッジをバリエーションにアタッチします。ジャッジはサンプリングされたライブリクエストに対して自動的に実行されます。コード変更はゼロです。 コンプリーションモードのみ (UI ウィジェットは現在コンプリーション専用です) プログラムによる直接ジャッジ リクエストハンドラー内で ai_client.create_judge(...)を呼び出し、各呼び出しでjudge.evaluate(input, output)を実行します。リクエストごとのコストとコードの複雑さが増します。サンプリングされた自動ジャッジでは不十分なワークフローを継続的にライブスコアリングするのに最適です。はい — すべてのモード (SDK は両方を同じように扱います) ほとんどのマイグレーションユーザーはオフライン評価から始めるべきです。その後、ロールアウトが安定した後に継続的なライブスコアリングが必要な場合にのみ、プログラムによる直接ジャッジを追加してください。
-
エージェントモードのマイグレーションでは、オフライン評価をデフォルトにします。 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(または同等のもの) に書き込み、マイグレーションの出荷後も比較パターンが再現可能になるようにしてください。 - まず
-
online-evalsにハンドオフします — UI でアタッチするジャッジ (コンプリーションモード) の場合、またはプログラムによるパスから参照されるカスタムジャッジ設定を作成する場合に限ります。ユーザーに伝えてください: 「これらの入力を使用して/online-evalsを実行し、その後ここに戻ってきてください。」 自動的に呼び出さないでください。渡すもの:- 親設定キーとバリエーションキー
- 作成/アタッチする組み込みジャッジ (Accuracy、Relevance、Toxicity) またはカスタムジャッジキーのリスト
- 対象環境
デリゲートは、カスタムジャッジ設定の作成、バリエーション PATCH エンドポイント経由でのアタッチ、および各ジャッジ設定のフォールスルー設定を処理します。オフライン評価はこのデリゲートを経由しません — これは Playground のワークフローであり、API 書き込みではありません。
-
プログラムによる直接判定の場合:
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でカスタムジャッジ設定を作成してください。 -
検証します。
- 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 — マルチエージェント移行向けの対象外ポインタードキュメント