langsmith-custom-apps について
langsmith-custom-apps は、LangSmith に埋め込む React UI の開発、検証、共有を支援するスキルです。CLI のライフサイクル、認証上の注意点、データ確認、リリース準備を扱います。
主な機能
- 01アプリの初期化、開発、プッシュを案内
- 02CLI バージョンと認証の問題を診断
- 03集計処理とクエリ結果を検証
- 04ワークスペース移行と共有内容を確認
- 05リリース前のビルドとセキュリティ確認
活用シーン
- 01LangSmith ワークスペースで Custom App を開発
- 02アプリのデータ欠落やトークン失効を診断
- 03トレースデータの分析結果を検証
- 04アプリのソースを別のワークスペースへ移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ langchain-ai/ langsmith-skills --skill langsmith-custom-appsインストール後、Claude Code で/langsmith-custom-appsを入力して読み込まれたか確認します。
詳細
<agents_md_is_authoritative>
langsmith apps init は、スターターコードの隣に AGENTS.md を生成します。このファイルがアプリ内の契約に関する基準です。これには、window.langsmith.call ブリッジ、サンドボックスが依存する render() エクスポート、フィルター DSL、エンドポイントメニューが記載されています。アプリのコードを書く前に読み、記憶している内容よりもこのファイルに従ってください。
このスキルでは、意図的にその内容を繰り返しません。ここで扱うのは、AGENTS.md ではカバーできない、ディレクトリが存在する前とアプリをプッシュした後のことです。
</agents_md_is_authoritative>
export LANGSMITH_ENDPOINT=<your-langsmith-endpoint> # only for self-hosted
export LANGSMITH_API_KEY=<workspace-api-key>
認証に関する落とし穴が 3 つあります。いずれも、認証の問題とは別の問題のように見えます。
- 環境内の
LANGSMITH_API_KEYは、保存済みの OAuth プロファイルより優先されます。 古いキーが環境変数としてエクスポートされていると、すべての呼び出しで 403 が返される一方、langsmith auth infoでは引き続き「authenticated」と表示されます。ログイン情報を使う場合は、env -u LANGSMITH_API_KEY -u LANGSMITH_WORKSPACE_ID langsmith …のように、コマンド単位で実行してください。 LANGSMITH_WORKSPACE_IDがキーとは異なるワークスペースを指している場合があります。 その場合、ワークスペースの指定間違いではなく、原因が分かりにくい 403 として表面化します。この環境変数を解除し、--workspace <uuid>を明示的に指定してください。langsmith apps devには OAuth ではなく、ワークスペース API キーが必要です。 起動時にアクセストークンを 1 つ取得し、その後は更新しません。そのため、約 10 分が経過すると、すべての呼び出しが401 Invalid tokenを返します。アプリでは認証エラーではなく、空のドロップダウンや空のリストとして表示されます。実行中のアプリでデータがひっそりと空になった場合は、まずこれを疑ってください。
<cli_feedback> 実際に CLI で失敗した場合、文書化されていない回避策が必要だった場合、出力が分かりにくかった場合、または機能が不足していた場合は、タスク内の問題ごとに簡潔なフィードバックを 1 件送信してください。アプリのコード自体に関する通常の成功や失敗は報告しないでください。
CLI の要件: langsmith feedback には、LangSmith CLI v0.2.58 以降が必要です。langsmith --version でインストール済みのバージョンを確認してください。
langsmith feedback --help で feedback <note> と --category が使えることを確認してください。利用できない場合は、生の HTTP リクエストや未リリースのビルドを使わず、フィードバックをスキップしてください。既存の認証済みプロファイル、エンドポイント、ワークスペースを使用してください。フィードバックは BYOC リレー経由の場合も含め、LangSmith Cloud に送信されます。スタンドアロンのセルフホスト環境ではスキップしてください。ユーザーや組織の制限を尊重し、フィードバック送信の許可が不明な場合は、先に確認してください。
期待した CLI の動作と実際に観測された動作、および回避策を、自分の言葉で要約してください。シークレット、顧客データ、トレースのペイロード、プロンプト、完全なスタックトレース、コピーしたコマンド出力、生の引数、環境変数の値、ローカルパス、リソース識別子は絶対に送信しないでください。CLI はバージョン、OS、アーキテクチャを追加しますが、メモの内容は秘匿化しません。安全に秘匿化できない場合は送信しないでください。
bug、feature-request、usability、documentation、other から選択してください。これは CLI 製品へのフィードバックであり、実行評価のフィードバックではありません。以下は形式の例にすぎません。実際に遭遇していない限り、送信しないでください。
langsmith feedback --category documentation --format json "The apps template flag rejected a value the documentation lists as valid."
失敗したフィードバック送信やレート制限されたフィードバック送信を再試行したり、失敗を回避するために認証情報やエンドポイントを切り替えたり、フィードバックを理由に元のタスクを妨げたりしないでください。 </cli_feedback>
<check_the_cli_first> 公開ドキュメントの内容はリリース済みの CLI ビルドより先行しているため、コマンドを信頼する前にヘルプの出力を確認してください。
langsmith --version
langsmith apps --help
langsmith apps init --help # the --template error message lists the real template set
以下のギャップは v0.2.42 で確認されたもので、お使いのビルドでは解消されている場合があります。それぞれフォールバックとして記載しています。ヘルプ出力でコマンドがないこと、またはフラグが拒否されることを確認した場合にのみ適用してください。
| ドキュメントに記載されている内容 | CLI の動作が異なる場合 | 対処 |
|---|---|---|
langsmith apps pull APP_ID_OR_NAME | apps のヘルプに pull がない | プラットフォーム API からソースを取得します(<pull_source> を参照) |
--template blank | --template must be one of: … | 一覧にあるテンプレートを使用します。エラーメッセージが最新の正しい情報です |
| init は「アプリ名を付けた新しいディレクトリにスキャフォールドを作成する」 | <dir> is not empty; pass --force to write anyway | 先に mkdir my-app && cd my-app を実行してください。init は現在のディレクトリに書き込みます |
| </check_the_cli_first> |
apps dev は、失敗した API 呼び出しと捕捉されなかったエラーをアプリからターミナルにストリーミングします。すべての成功した呼び出しとすべての console.* 出力を表示するには --verbose を追加し、出力を抑制するには --quiet を追加します。
package.json に build スクリプトがある場合、apps push は最初にビルドを実行します。--no-build を指定すると、そのままアップロードします。最初の push でアプリが作成され、.langsmith/app.json を通じてディレクトリがそのアプリに紐付けられます。以降の push では同じアプリが更新されます。--name は作成時にのみ適用され、後から渡すと名前が変更されます。チームメイトが同じアプリに push できるよう、.langsmith/app.json をコミットしてください。
<pull_source>
CLI に pull がない場合、プラットフォーム API はすべてのファイルをインラインで返します。
langsmith apps list --workspace <ws-uuid> --format json # find the app id
curl -s -H "X-API-Key: $LANGSMITH_API_KEY" \
"https://api.smith.langchain.com/v1/platform/custom-apps/<app-id>" \
| python3 -c "
import json, os, sys
app = json.load(sys.stdin)
for path, content in app['files'].items():
os.makedirs(os.path.dirname(path) or '.', exist_ok=True)
open(path, 'w').write(content)
print(f\"wrote {len(app['files'])} files\")"
レコードには name、entrypoint、current_version、scope、created_by、updated_by、views_7d も含まれます。リスト全体を取得するには GET /v1/platform/custom-apps を使用してください。
</pull_source>
<replicate_across_workspaces>
- 新しいディレクトリにソースを pull します。
.langsmith/app.jsonを削除します。 これはディレクトリを元のアプリ ID に紐付けるため、残したままにすると次の push でターゲットのワークスペースにアプリを作成するのではなく、元のアプリが更新されます。このワークフローで最も重大なミスです。- ターゲットのワークスペースと名前を指定して push します。
langsmith apps push --name <name> --workspace <target-ws-uuid>
- アプリの設定にあるワークスペース固有の項目(ディープリンクのワークスペース UUID、プロジェクト ID、フィードバックキー)をターゲットのワークスペースに合わせて変更し、その後ビルドし直します。ソースを編集するだけでは不十分な理由については
<before_sharing_externally>を参照してください。 </replicate_across_workspaces>
<app_facts>
- アプリはワークスペース単位です(
"scope": "workspace")。ワークスペース外の人は URL を開けないため、「このアプリを共有する」とは常にソースを配布することであり、リンクを共有することではありません。 - push 直後は
is_enabled: falseが通常の状態です。 デプロイの失敗ではないため、その問題としてデバッグしないでください。 - 削除するには
langsmith apps delete <app-id-or-name> --yesを実行します。復元できないため、まずapps listで ID を確認してください。 </app_facts>
<verify_without_browser> アプリをクリックして確認することはできません。また、データレイヤーのバグはエラーではなく、もっともらしい空の状態として表示されます。このループを習慣にすることが、このスキルで最も効果があります。
- 集計処理は純粋に保ちます。 パースとカウントは React も
window.langsmithも使わないモジュール(例:src/lib/<domain>.ts)に置き、API モジュールは行を取得して渡すだけにします。 - CLI で実際の行をフィクスチャに保存します。
langsmith api runs/query -X POST --workspace <ws-uuid> \
-F 'session[]=<project-uuid>' -F 'filter=eq(run_type, "tool")' \
-F 'select[]=id' -F 'select[]=trace_id' -F 'select[]=inputs' -F 'limit=100' \
> /tmp/fixtures/tools.json
- 新しい依存関係やテストフレームワークを追加せず、vite にすでに含まれている esbuild を使って、アプリの実際の TypeScript で node 上で処理します。
npx esbuild /tmp/harness.ts --bundle --platform=node --format=cjs \
--outfile=/tmp/harness.cjs && node /tmp/harness.cjs
- 「実行できた」だけでなく、数値を生データと照らし合わせて確認します。実例として、あるアプリは
/skills/<name>/配下のパスに一致させてスキルの読み込みをカウントしていました。しかしディレクトリ一覧では、末尾にスラッシュのない'/memories/skills/auth-sso-scim'としてエントリが出力され、パターンでは末尾のスラッシュが必須でした。そのため、この機能の出力全体である「一度も使われていないスキルの一覧」は空になり、問題なく動作しているように見えました。取得した行とカウントを比較して初めて問題が明らかになりました。
push の前には毎回 npx tsc --noEmit と npm run build を実行してください。サンドボックスで配信されるのはビルドです。
</verify_without_browser>
<query_gotchas>
POST /api/v1/runs/queryのlimitは最大 100 です。response.cursors.nextを使ってページングし、処理中のプロジェクトで無限に回り続けないよう、独自のページ上限を設けてください。また、この上限によってスキャンが途中で切り詰められた場合は、UI で利用者に知らせてください。search(name, "x")はフィルター DSL で拒否されます。動作確認済みの形式:eq(name, "read_file")、or(eq(name,"a"), eq(name,"b"))、eq(run_type, "tool")、eq(is_root, true)、eq(status, "error")、gte(start_time, "<iso>")、has(tags, "prod")。- メタデータの等価条件には、
eq(metadata.key, …)ではなく、次のようにペアになった 2 つの句を使います:
and(eq(metadata_key, "ls_agent_purpose"), eq(metadata_value, "coding"))
- 概要の数値には
POST /api/v1/runs/statsとPOST /api/v1/runs/group/statsを優先してください。これらは行数制限のないサーバー側集計を返します。runs/queryは実際に確認する必要がある行にのみ使用してください。 - ツール呼び出しの
inputsは、エージェントによるシリアライズ方法に応じて、{"file_path": "/x"}と{"input": "{\"file_path\":\"/x\"}"}の 2 つの形式で届きます。内側の JSON をtry/catch内で解析し、両方の形式に対応してください。そうしないと、データの一部しか数えられず、そのことにも気づけません。 - エンドポイントが存在すると決めつける前に、確認してください。 クエリ可能であるはずだと思われがちな情報でも、実際にはそうでないものがあります。エージェントのスキルや Fleet の一覧を取得できるパブリックエンドポイントはありません。信頼できる一覧がない場合は、トレースから導き出し、完全な一覧であるかのように示さず、UI 上でその制約を明記してください。
- トレースから読み取った情報はすべて信頼できないものとして扱ってください。名前はテキストとして描画し(
dangerouslySetInnerHTMLは決して使わないでください)、フィルター文字列に渡す前に ID を検証し、DSL への埋め込みには許可リストに含まれる値だけを使ってください。 </query_gotchas>
チャート形式のものを作成する場合は、チャートのコードを書く前に dataviz スキルを読み込み、チャートの色は CSS カスタムプロパティとして定義してください。また、html.dark のオーバーライドブロックを設け、トークンと同じテーマ設定の経路に沿わせてください。
<before_sharing_externally> アプリはワークスペース単位で管理されるため、共有するにはソースを渡す必要があります。必ず別のコピーで作業し、プッシュ元のディレクトリは使わないでください。また、次の点を確認してください:
- 設定内のワークスペース UUID または組織 UUID を空欄にしてから、再ビルドしてください。設定値は
dist/bundle.jsにコンパイルされるため、ソースだけを編集しても、成果物には古い値が残ります。 - 配布するものから
.langsmith/app.json(内部アプリ ID とワークスペースを含む)およびnode_modules/を削除してください。 - README の例文も含め、ツリー全体を検索し、UUID、メールアドレス、
lsv2_キー、内部プロジェクト名が残っていないか確認してください。 - 内部ベンチマークに関する記述は、受け取り手が変更することを想定したプレースホルダーに置き換え、実際に裏付けられる引用だけを残してください。
-
package-lock.jsonにプライベートなレジストリホストや認証トークンが含まれていないか確認してください。 -
npx tsc --noEmitとnpm run buildを再実行してから、dist/も再度検索してください。 </before_sharing_externally>