add-lens について
add-lensは、redis-irisのLensトレーシングをエージェントアプリに組み込むためのスキルです。ターンの境界、IDとセッション、モデルの計装、テレメトリーの不足箇所への対応を案内します。
主な機能
- 01エージェントのターンと起動箇所の特定
- 02エージェントIDを指定したLens初期化
- 03セッションコンテキスト付きのターン処理
- 04検索とプロンプト構成の計装
- 05プロセス間でのトレース伝播
- 06テレメトリーと既存Providerの検証
活用シーン
- 01エージェントアプリへのLensトレーシング導入
- 02検索とプロンプト構成の記録
- 03ワーカープロセスへのトレース伝播
MCP 対応
このスキルは、利用可能なドキュメントMCPでフレームワークとRedis Lensの最新情報を確認するよう案内します。MCPツール自体は提供しません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ redis/ agent-skills --skill add-lensインストール後、Claude Code で/add-lensを入力して読み込まれたか確認します。
詳細
Lens を追加する
エージェントの各ターンにつき 1 つのトレースを記録します。Lens UI では、エージェントの agent_id の下に表示されます。Lens は redis-iris 内で動作するため、プロビジョニングするサービスも CLI もありません。起動時に 2 行を追加し、メッセージごとに 1 ターンを記録すれば、あとはエージェントが作成するギャップを埋めるだけです。Lens は他の Iris 製品と併用することも、単独で使うこともできます。
完全なリファレンス:Lens(redis-iris の docs/core/lens.md)。
1. 調査する
プロジェクトを確認します。
- ターン:1 つのユーザーメッセージが 1 つの回答になる箇所(
app.invoke、Runner.run、runner.run_async、agent.run、kickoff、または独自に記述したループを囲むハンドラー)。 - ID:エージェント自身の名前が定義されている場所と、各リクエストのセッション ID またはスレッド ID、およびユーザー ID が定義されている場所。
agent_idとsession_idの両方を必ず設定します。Lens UI のすべてのビューはagent_idでフィルタリングされるため、これがないトレースは表示されません。ターンはセッションごとにまとめて表示されるため、セッション ID がないターンも表示されません(セッションなしのターンを表示する機能は今後追加予定です)。 - 起動処理:最初のターンより前に実行される箇所(アプリファクトリー、
main、ワーカーの起動処理)。 - モデルクライアント:フレームワークの下層で最終的にモデルを呼び出すライブラリ。Lens は
openai、anthropic、botocore(Bedrock)、langchain_coreの 4 つを計測します。多くのフレームワークはその下でこれらのいずれかを呼び出すため、手順 2 で確認します。それ以外のクライアント(たとえばgoogle-genaiやlitellm)では、手順 6 でインストゥルメンターを追加しない限り、LLM スパンもトークンも記録されません。 - 既存のテレメトリー:
opentelemetry、TracerProvider、opentelemetry-instrument、OTEL_*変数、または別の LLM 計測機能。グローバルプロバイダーをいつ誰が設定するかを確認します。 - 手順 5 で扱うギャップ:
.client呼び出し、カスタム検索、スレッドプール、プロセス間の移動、短時間だけ動作するプロセス。
次に、該当する構成を選びます。これにより、誰がターンを開始するかが決まります。
| エージェント | ターンの開始元 | 追加するもの |
|---|---|---|
redis_iris.integrations.langgraph.attach(hooks, graph) | attach。各 invoke / stream および非同期の同等処理で開始し、セッションには configurable.thread_id、ユーザーには configurable.user_id を使用します | lens.init() のみ |
workflows.turn(...) / workflows.aturn(...) | workflows.turn。session= と owner= を使用します | lens.init() のみ |
attach なしの LangGraph | あなた | app.invoke / app.ainvoke を lens.turn() で囲み、スレッド ID をセッションとして使います |
Google ADK(redis_iris.integrations.adk.attach を含む) | あなた:ADK の attach はターンを開始しないため、before と after ではトレースが 2 つになります | runner.run_async を lens.turn() で囲みます |
| OpenAI Agents SDK | あなた | Runner.run を lens.turn() で囲みます |
| Pydantic AI、CrewAI、その他のフレームワーク | あなた | agent.run / kickoff を lens.turn() で囲みます |
通常のループ(openai、anthropic、その他のクライアント) | あなた | 1 回のモデル呼び出しではなく、1 件のメッセージを処理するハンドラーを lens.turn() で囲みます |
1 つのプロセスに 2 つのループがある場合は、それぞれが独自の箇所でターンを開始します。すでにターンが開始されている場合はそのまま維持され、その中で attach と workflows.turn が新たなターンを追加することはありません。
2. MCP で最新の情報を確認する
コードを書く前に実施します。フレームワークの API を記憶だけで推測してはいけません。
- フレームワークのドキュメント:利用可能なドキュメント MCP(Context7 またはフレームワーク独自のもの)に問い合わせ、インストール済みバージョンの実行エントリーポイント、下層で呼び出すモデルクライアント、独自の OpenTelemetry スパンを出力するかどうか、スレッドまたは別のプロセスで処理を実行するかどうかを確認します。
- Redis のドキュメント:Redis ドキュメント MCP が接続されている場合は、Lens の概念を確認するために使用します。
- MCP が利用できない場合:仮想環境内のインストール済みパッケージのソースを読みます。その旨を報告に記載します。
3. インストールと設定
必ず追加機能をインストールしてください。これにより、lens.init() が OpenAI、Anthropic、Bedrock、LangChain、mcp、threading 向けに開始する計装が導入されます。これがないと、LLM スパンもトークンの合計数も記録されません。
uv.lockまたは[tool.uv]がある場合:uv add 'redis-iris[llm-tracing]'。- Poetry の場合:
poetry add 'redis-iris[llm-tracing]'。 - それ以外の場合:プロジェクトの requirements ファイルに
redis-iris[llm-tracing]を追加します。
エンドポイントとエージェントキーは Lens UI で取得します。これらを発行する CLI コマンドはないため、担当者に引き継ぎます。Lens UI を開いて Lens エンドポイントをコピーし、エージェントキーを作成して、以下のように両方を .env に設定するよう伝えてください。チャットでキーを尋ねたり、コマンドラインで渡したり、環境ファイルを表示、cat、grep したりしないでください。
IRIS_LENS_ENDPOINT= # the Iris host, such as https://iris.example.com
IRIS_LENS_API_KEY= # the Lens agent key
同じ 2 つの名前を、値を空にして .env.example にも追加します。.env はコミットしないでください。クラスター内のオンプレミス環境では、IRIS_LENS_ALLOW_INSECURE=true の場合に限り、エンドポイントを平文の http(http://lens-dataplane:9000)にできます。
コンテンツのキャプチャ設定はデフォルトのままにしてください。これについて尋ねないでください。
4. 接続
起動時に 1 回、最初のターンより前に、アプリ独自の OpenTelemetry セットアップ(手順 6)の後で実行します。
import logging
from redis_iris import lens
lens.init(agent_id="support-bot") # always: every Lens UI view is filtered by agent_id
state = lens.instrumentation()
if state.get("lens") != "on":
logging.warning("Lens is not recording: %s", state)
シグネチャで必須とされていなくても、必ず agent_id を渡してください。指定しないトレースは Lens UI に表示されません。エージェント自身の名前を基に選び、担当者に確認してください。lens.init() は環境変数からエンドポイントとキーを読み取り、例外を送出しません。戻り値は、エンドポイントが設定されていて Lens が無効化されていないことだけを示します。エンドポイントへの接続が拒否された場合や追加機能がない場合でも True になるため、代わりに lens.instrumentation() を確認してください。
次に、手順 1 の「あなた」が示す箇所で、1 ターンをラップします。
with lens.turn(thread_id, user_id=user_id) as t:
answer = await Runner.run(agent, message) # the framework's run call, unchanged
t.set_outcome("completed")
async with は不要です。lens.turn() は通常のコンテキストマネージャーで、await の周囲でも使えます。最初の引数はセッション ID です。必ずリクエストの実際のスレッド ID またはセッション ID を渡してください。定数や None は渡さないでください。Lens UI ではセッションごとにターンが表示され、セッション ID のないターンはまだ表示されません。配線中は IRIS_LENS_STRICT=true を設定し、セッション ID がない場合にセンチネル値を付けるのではなく、例外が送出されるようにしてください。t.trace_id は Lens におけるターンの ID です。リクエスト ID と合わせてログに記録すると便利です。
5. 計測漏れを補う
手順 1 で見つかったものだけを対象にします。
.client 呼び出し。 memory.client、playbook.client などの .client プロパティは生成された SDK です。Lens はこれらにパッチを適用しないため、ターンに計測の抜けが生じます。可能であればゴールオブジェクトのメソッドを使ってください。それができない場合は、呼び出しをラップします。
with lens.span("agent_memory.get_long_term_memory", memory_id=memory_id):
raw = memory.client.get_long_term_memory(memory_id=memory_id)
カスタム検索。 プロンプトに渡すベクトルストア、検索 API、データベースの読み取りでは、取得した内容と、プロンプトに入れた内容の両方を記録してください。そうすると、トレースに「5 件取得、3 件使用」と表示されます。
with lens.retrieval(query=message, data_source="kb") as r:
docs = index.search(message, k=5)
r.results([(d.id, d.score, d.text) for d in docs])
with lens.prompt_assembly() as p:
p.fetched([(d.id, d.score, d.text) for d in docs])
p.used([(d.id, d.score, d.text) for d in docs[:3]]) # whatever survived the token limit
エージェントが自身のストアから読み取るメモリにも、同じ方法で lens.memory_recall(query=, store_id=) を使います。Iris の hooks() と disclosure() はそれぞれ独自の prompt_assembly を記録するため、そのブロックには追加しないでください。
スレッドプール。 ThreadPoolExecutor の処理でターンが引き継がれるのは、lens.init() による [llm-tracing] の threading 計装がある場合だけです。asyncio タスクと asyncio.to_thread では、いずれも引き継がれます。IRIS_LENS_INSTRUMENT_THREADS=false が設定されている場合は削除してください。
プロセス間の引き継ぎ。 キュー、Celery タスク、サブプロセス、ワーカーにターンを引き継ぐと、コンテキストも引き継がない限り、新しいトレースが開始されます。
payload["lens"] = lens.inject() # sender, inside the turn
with lens.continue_from(payload.get("lens")): # receiver, around the work
handle(payload)
キャリアは自分のサービスにのみ送信してください。サードパーティや MCP 呼び出しの meta には送らないでください。また、信頼できない呼び出し元のヘッダーから作成されたキャリアを continue_from に渡さないでください。受信側のプロセスでは、同じ agent_id を指定して lens.init() を呼び出します。OpenTelemetry ですでに計装されている HTTP 呼び出しは、traceparent を自動的に引き継ぎます。
短時間で終了するプロセス。 スクリプト、CLI、バッチジョブ、テストの実行は、エクスポーターがフラッシュする前に終了することがあります。最後に一度だけ lens.shutdown(timeout_millis=5_000) を呼び出してください。これを呼び出すと、プロセスが終了するまで Lens が無効になるため、ターンごと、リクエストごと、またはウォーム状態の Lambda 呼び出しごとに呼び出さないでください。
6. 既存のテレメトリを利用する
Lens はプロバイダーを置き換えません。アプリに OpenTelemetry SDK の TracerProvider がある場合、Lens は最初のターンでプロセッサーを追加します。ない場合は、Lens がインストールします。
| アプリにすでにあるもの | 対応 |
|---|---|
独自の OpenTelemetry SDK のセットアップ、または opentelemetry-instrument | 最初のターンより前に実行されるようにしてください。アプリの OpenTelemetry の設定が遅れる場合は、IRIS_LENS_OWN_PROVIDER=false を設定し、Lens が先にプロバイダーをインストールするのではなく、アプリの設定を待つようにしてください。アプリ独自のエクスポーターも、ターン内で記録されたスパン(コンテンツを含む)を受け取るようになります。また、ターンはリクエストスパンにリンクされた独自のトレースになります。 |
| Lens の 4 つのクライアントのいずれかをすでにラップしているインストルメンテーション | Lens はそのクライアントに手を加えません(other_instrumentation)。同じグローバルプロバイダーに記録する場合、ターン内で記録されたスパンは Lens に届きます。lens.init() と最初のターンより前にセットアップしてください。 |
| Lens がインストルメントしないモデルクライアント | そのクライアント用の OpenTelemetry インストルメンターを追加するか、フレームワーク独自の OpenTelemetry トレーシングを有効にしてください(手順 2 で、対応しているか確認できます)。グローバルプロバイダーに記録してください。ターン内のスパンは Lens に届き、gen_ai.usage.input_tokens / output_tokens(または prompt_tokens / completion_tokens という名前)を持つ場合、ターンのトークン合計にもカウントされます。依存関係を追加する前に、担当者に確認してください。 |
| OpenTelemetry SDK 以外のトレーサープロバイダー | Lens はプロセッサーを追加できず、iris.lens: could not attach, telemetry disabled とログに出力します。この件を報告してください。アプリのトレーシングは変更しないでください。 |
| サンプリング率が 100% 未満のサンプラー | Lens はデフォルトでターンを強制的にサンプリングします。IRIS_LENS_SAMPLE_TURNS=inherit を設定すると、アプリのサンプラーがターンを除外できるようになります。 |
Lens 用に OTEL_EXPORTER_OTLP_* を設定しないでください。Lens のエクスポーターは OTEL_EXPORTER_OTLP_* 変数を読み取りません。HTTPS_PROXY、NO_PROXY、SSL_CERT_FILE は尊重します。
7. 検証
-
エージェントを起動し、LLM クライアントのインポート後に
lens.instrumentation()を出力します。'lens': 'on'になっていることを確認します。また、エージェントが OpenAI、Anthropic、Bedrock、または LangChain を使用する場合は、そのクライアントがprovidersの下でinstrumentedまたはother_instrumentationとして表示されることを確認します。それ以外のクライアントはここに表示されません。手順 4 で、そのクライアント独自のインストゥルメンターのスパンを確認してください。 -
値が正しくありませんか?
lens.instrumentation()で原因を確認します。値 原因 対処方法 lens: offプロセスに IRIS_LENS_ENDPOINTがない、IRIS_LENS_ENABLED=falseが設定されている、またはopentelemetry-sdkがインストールされていない(--no-depsでインストールした)lens.init()の前に.envを読み込みます。スイッチを解除します。依存関係も含めて再インストールしますlens: endpoint_refusedエンドポイントが https でもループバックでもない https を使用するか、オンプレミスでは IRIS_LENS_ALLOW_INSECURE=trueを設定しますlens: shut_downプロセス内で先に lens.shutdown()が実行されたプロセスの最後に移動します providers.<client>: instrumentor_missingまたはneeds_wraptこの環境に [llm-tracing]がインストールされていないエージェントの実行環境に追加機能をインストールします providers.<client>: needs_init環境変数で Lens は有効になっていますが、 lens.init()が実行されていない起動時に呼び出します providers.<client>: disabledIRIS_LENS_AUTO_INSTRUMENT=falseが設定されている解除します providers.<client>: failedパッチの適用に失敗した iris.lens: could not auto-instrument警告を確認します。この警告はlens.init()時、またはその後にアプリが初めてクライアントをインポートしたときに記録されます -
実際のセッション ID を使って実際のターンを 1 回実行し、
t.trace_id(または実行中にlens.current_trace_id())をログに記録します。 -
Lens UI を開き、
agent_idで絞り込んでセッションとそのターンを見つけます。LLM 呼び出し、そのトークン数、およびそのターンで発生した Iris の各製品、ツール、検索取得のスパンが表示されるはずです。 -
lens: onなのに UI が空の場合は、iris.lensの警告(エクスポート時の 401 または 403 はキーの誤り、または失効を意味します)、プロセス終了前にターンが終了したこと(手順 5、短命プロセスの場合)、およびlens.stats()を確認します。iris.lens.spans_exportedが増加し、iris.lens.export_failuresが 0 のままで、iris.lens.identity_unassignedも 0 のままである必要があります(0 以外の場合は、セッション ID なしでターンが開始されているため、UI に表示されません)。
8. 報告
エージェントの構成と、誰がターンを開始するか、agent_id、セッション ID とユーザー ID の取得元、モデルクライアントと Lens によるインストゥルメンテーションの有無、解消したギャップ、既存のテレメトリーとの Lens の共存方法、lens.instrumentation() の出力、Lens UI で見つけたトレース ID、および MCP 経由で確認できなかったことを列挙します。
ルール
- ユーザーのフレームワーク、グラフ、プロンプトを維持します。差分は最小限にします。
redis_iris.lensの API のみを使用します。Lens のためにtrace.set_tracer_provider()やtrace.get_tracer()を呼び出さないでください。- Lens がエージェント内で例外を発生させることはありません(
IRIS_LENS_STRICTの場合を除く)。そのため、try/except は不要です。 - チャットでシークレットを尋ねないでください。
.envをコミットしないでください。 - その他の Iris 製品:
add-redis-iris。