メインコンテンツへスキップ
これはインタラクティブなノートブックです。ローカルで実行するか、以下のリンクを利用できます:

Service API を使用してトレースを記録およびクエリする

このガイドでは、Weave Service API を使用してトレースを記録する方法を説明します。具体的には、Service API を使用して次のことを行います。
  1. シンプルな LLM 呼び出しとレスポンスのモックを作成し、Weave に記録する。
  2. より複雑な LLM 呼び出しとレスポンスのモックを作成し、Weave に記録する。
  3. 記録されたトレースに対してサンプルのルックアップクエリを実行する。
記録されたトレースを表示する このガイドのコードを実行したときに作成されるすべての Weave トレースは、team_id\project_id で指定される Weave プロジェクトの Traces タブを開き、トレース名を選択することで表示できます。
始める前に、前提条件 を完了してください。

前提条件: 変数とエンドポイントの設定

次のコードは、Service API にアクセスするために使用する URL エンドポイントを設定します: さらに、次の変数を設定する必要があります:
  • project_id: トレースを記録する対象の W&B プロジェクト名。
  • team_id: 利用する W&B チーム名。
  • wandb_token: 利用する W&B APIキー
import datetime
import json

import requests

# ヘッダーとURL
headers = {"Content-Type": "application/json"}
url_start = "https://trace.wandb.ai/call/start"
url_end = "https://trace.wandb.ai/call/end"
url_stream_query = "https://trace.wandb.ai/calls/stream_query"

# W&B 変数
team_id = ""
project_id = ""
wandb_token = ""

シンプルなトレース

次のセクションでは、シンプルなトレースの作成方法を説明します。
  1. シンプルなトレースを開始する
  2. シンプルなトレースを終了する

シンプルなトレースを開始する

次のコードは、サンプルの LLM 呼び出し payload_start を作成し、url_start エンドポイントを通じて Weave にログを記録します。payload_start オブジェクトは、クエリ Why is the sky blue? を用いた OpenAI の gpt-4o への呼び出しを模倣したものです。 成功すると、このコードはトレースが開始されたことを示すメッセージを出力します。
Call started. ID: 01939cdc-38d2-7d61-940d-dcca0a56c575, Trace ID: 01939cdc-38d2-7d61-940d-dcd0e76c5f34
python
## ------------
## トレースの開始
## ------------
payload_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "simple_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            # 展開されたトレースでチャットUIを生成するには、この "messages" スタイルを使用してください。
            "messages": [{"role": "user", "content": "Why is the sky blue?"}],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"コール開始。ID: {call_id}, トレースID: {trace_id}")
else:
    print("開始リクエストが失敗しました。ステータス:", response.status_code)
    print(response.text)
    exit()

シンプルなトレースを終了する

シンプルなトレースを完了するには、次のコードでサンプルの LLM 呼び出し payload_end を作成し、url_end エンドポイントを使って Weave に記録します。payload_end オブジェクトは、クエリ Why is the sky blue? に対して OpenAI の gpt-4o から返されるレスポンスを模倣しています。オブジェクトは、料金サマリー情報とチャット補完結果が Weave ダッシュボードのトレースビューに表示されるような形式になっています。 成功すると、このコードはトレースが完了したことを示すメッセージを出力します。
Call ended.
python
## ------------
## End trace
## ------------
payload_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            # 展開トレースのチャットUIにこの補完結果を追加するには、この "choices" 形式を使用します。
            "choices": [
                {
                    "message": {
                        "content": "It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions."
                    }
                },
            ]
        },
        # トレーステーブルで料金サマリー情報を生成できるよう、サマリーはこのような形式にします。
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Call ended.")
else:
    print("End request failed with status:", response.status_code)
    print(response.text)

複雑なトレース

次のセクションでは、マルチステップの RAG ルックアップに類似した、子スパンを含むより複雑なトレースを作成する手順を説明します。
  1. 複雑なトレースを開始する
  2. RAG ドキュメント検索用の子スパンを追加する
  3. LLM 補完呼び出し用の子スパンを追加する
  4. 複雑なトレースを終了する

複雑なトレースを開始する

次のコードは、複数のスパンを含む、より複雑なトレースの作成方法を示します。例としては、Retrieval-Augmented Generation (RAG) による検索のあとに LLM 呼び出しを行うケースが挙げられます。前半では、全体の処理を表す親トレース (payload_parent_start) を初期化します。この例では、「このドキュメントの要点を要約してもらえますか?」というユーザーのクエリ Can you summarize the key points of this document? を処理する操作が対象です。 payload_parent_start オブジェクトは、マルチステップワークフローの最初のステップを模倣し、url_start エンドポイントを使って Weave にこの操作を記録します。 成功すると、このコードは親呼び出しが記録されたことを示すメッセージを出力します。
Parent call started. ID: 01939d26-0844-7c43-94bb-cdc471b6d65f, Trace ID: 01939d26-0844-7c43-94bb-cdd97dc296c8
python
## ------------
## トレースを開始(親)
## ------------

# 親コール: 開始
payload_parent_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "complex_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {"question": "Can you summarize the key points of this document?"},
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_parent_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    parent_call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"親コールを開始しました。ID: {parent_call_id}, Trace ID: {trace_id}")
else:
    print("親の開始リクエストが失敗しました。ステータス:", response.status_code)
    print(response.text)
    exit()

RAG ドキュメント検索用の子スパンを追加する

次のコードは、前のステップで開始した複雑な親トレースに子スパンを追加する方法を示します。このステップでは、全体的なワークフローの中で RAG ドキュメント検索のサブ処理を表現します。 子トレースは payload_child_start オブジェクトで開始されます。このオブジェクトには次のフィールドが含まれます:
  • trace_id: この子スパンを親トレースにリンクします。
  • parent_id: この子スパンを親の処理に関連付けます。
  • inputs: 検索クエリをログに記録します。例: "This is a search query of the documents I'm looking for."
url_start エンドポイントの呼び出しが成功すると、子スパンの呼び出しが開始され完了したことを示すメッセージが出力されます。
Child call started. ID: 01939d32-23d6-75f2-9128-36a4a806f179
Child call ended.
python
## ------------
## 子スパン:
## 例: RAGドキュメント検索
## ------------

# 子コール: 開始
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "rag_document_lookup",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "document_search": "This is a search query of the documents I'm looking for."
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"Child call started. ID: {child_call_id}")
else:
    print("Child start request failed with status:", response.status_code)
    print(response.text)
    exit()

# 子コール: 終了
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "document_results": "This will be the RAG'd document text which will be returned from the search query."
        },
        "summary": {},
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Child call ended.")
else:
    print("Child end request failed with status:", response.status_code)
    print(response.text)

LLM completion 呼び出し用の子スパンを追加する

次のコードは、複雑な親トレースに別の子スパンを追加し、LLM completion 呼び出しを表現する方法を示します。このステップでは、直前の RAG 処理で取得したドキュメントコンテキストに基づいて、AI の応答生成をモデリングします。 LLM completion のトレースは payload_child_start オブジェクトで開始されます。このオブジェクトには次の情報が含まれます:
  • trace_id: この子スパンを親トレースにリンクします。
  • parent_id: 子スパンを全体的なワークフローに関連付けます。
  • inputs: ユーザーのクエリと、それに付加されたドキュメントコンテキストを含む、LLM への入力メッセージを記録します。
  • model: この処理で使用するモデルを指定します(gpt-4o)。
成功すると、コードは LLM の子スパントレースが開始および終了したことを示すメッセージを出力します。
Child call started. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
操作が完了すると、payload_child_end オブジェクトは output フィールドに LLM が生成したレスポンスをログし、トレースを終了します。利用状況の概要情報もあわせてログされます。 成功すると、LLM の子スパンのトレースが開始され終了したことを示すメッセージが出力されます。
Child call started. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
Child call ended.
python
## ------------
## 子スパン:
## LLM補完呼び出しを作成する
## ------------

# 子呼び出し: 開始
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "llm_completion",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "messages": [
                {
                    "role": "user",
                    "content": "With the following document context, could you help me answer:\n Can you summarize the key points of this document?\n [+ appended document context]",
                }
            ],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"Child call started. ID: {child_call_id}")
else:
    print("Child start request failed with status:", response.status_code)
    print(response.text)
    exit()

# 子呼び出し: 終了
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "This is the response generated by the LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Child call ended.")
else:
    print("Child end request failed with status:", response.status_code)
    print(response.text)

複雑なトレースを終了する

次のコードは、親トレースを確定してワークフロー全体の完了を示す方法を示します。このステップでは、すべての子スパン(例: RAG ルックアップや LLM 生成)の結果を集約し、最終的な出力とメタデータをログに記録します。 トレースは payload_parent_end オブジェクトを使って確定します。このオブジェクトには次が含まれます:
  • id: 最初に親トレースを開始したときの parent_call_id
  • output: ワークフロー全体の最終出力を表します。
  • summary: ワークフロー全体の使用状況データを集約します。
  • prompt_tokens: すべてのプロンプトで使用されたトークンの合計。
  • completion_tokens: すべてのレスポンスで生成されたトークンの合計。
  • total_tokens: ワークフローにおけるトークン数の合計。
  • requests: 発行されたリクエストの総数(この例では 1)。
成功すると、次のような出力が得られます:
Parent call ended.
python
## ------------
## End trace
## ------------

# 親呼び出しの終了
payload_parent_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": parent_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "This is the response generated by the LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_parent_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Parent call ended.")
else:
    print("Parent end request failed with status:", response.status_code)
    print(response.text)

ルックアップクエリを実行する

次のコードは、前の例で作成したトレースをクエリし、inputs.model フィールドが gpt-4o に等しいトレースだけをフィルタリングして抽出する方法を示します。 query_payload オブジェクトには次の項目が含まれます:
  • project_id: クエリ対象のチームとプロジェクトを識別します。
  • filter: クエリが trace roots(最上位のトレース)のみを返すようにします。
  • query: $expr 演算子を使ってフィルタリングロジックを定義します:
    • $getField: inputs.model フィールドを取得します。
    • $literal: inputs.model"gpt-4o" に等しいトレースにマッチさせます。
  • limit: クエリ結果を 10,000 件に制限します。
  • offset: クエリの開始位置を最初の結果に設定します。
  • sort_by: 結果を started_at タイムスタンプで降順に並べ替えます。
  • include_feedback: 結果からフィードバックデータを除外します。
クエリが成功すると、レスポンスにはクエリパラメータに一致するトレースデータが含まれます:
{'id': '01939cf3-541f-76d3-ade3-50cfae068b39', 'project_id': 'cool-new-team/uncategorized', 'op_name': 'simple_trace', 'display_name': None, 'trace_id': '01939cf3-541f-76d3-ade3-50d5cfabe2db', 'parent_id': None, 'started_at': '2024-12-06T17:10:12.590000Z', 'attributes': {}, 'inputs': {'messages': [{'role': 'user', 'content': 'Why is the sky blue?'}], 'model': 'gpt-4o'}, 'ended_at': '2024-12-06T17:47:08.553000Z', 'exception': None, 'output': {'choices': [{'message': {'content': 'It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions.'}}]}, 'summary': {'usage': {'gpt-4o': {'prompt_tokens': 10, 'completion_tokens': 20, 'requests': 1, 'total_tokens': 30}}, 'weave': {'status': 'success', 'trace_name': 'simple_trace', 'latency_ms': 2215963}}, 'wb_user_id': 'VXNlcjoyMDk5Njc0', 'wb_run_id': None, 'deleted_at': None}
python
query_payload = {
    "project_id": f"{team_id}/{project_id}",
    "filter": {"trace_roots_only": True},
    "query": {
        "$expr": {"$eq": [{"$getField": "inputs.model"}, {"$literal": "gpt-4o"}]}
    },
    "limit": 10000,
    "offset": 0,
    "sort_by": [{"field": "started_at", "direction": "desc"}],
    "include_feedback": False,
}
response = requests.post(
    url_stream_query, headers=headers, json=query_payload, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Query successful!")
    try:
        data = response.json()
        print(data)
    except json.JSONDecodeError as e:
        # 代替デコード
        json_objects = response.text.strip().split("\n")
        parsed_data = [json.loads(obj) for obj in json_objects]
        print(parsed_data)
else:
    print(f"Query failed with status code: {response.status_code}")
    print(response.text)