メインコンテンツへスキップ
このガイドでは、アプリケーションを計装して、その実行を W&B Weave に詳細なトレースとして表示する方法を説明します。トレースでは、入力、出力、各操作の構造を Call として取り込むことで、LLM を活用したコードのデバッグ、評価、監視を行えます。 実行中のコードを Weave で詳細なトレースとして表示するには、Call を作成します。以下のセクションでは、そのための主な 3 つの方法を、手動での作業が少ないものから多いものの順に説明します。
  • LLM ライブラリ呼び出しの自動トラッキング
  • weave.op を使用したカスタム関数のトラッキング
  • API を直接使用する手動の Call トラッキング
トレース対象をどの程度細かく制御したいかに応じて、適切な方法を選択してください。

LLM ライブラリの Call の自動トラッキング

Weave は、openaianthropiccoheremistralLangChain など、多くの一般的なライブラリやフレームワークと自動的に統合します。LLM またはフレームワークのライブラリをインポートし、Weave プロジェクトを初期化してください。すると Weave は、追加のコード変更なしで、LLM またはプラットフォームに対するすべての Call を自動的に Weave プロジェクトにトレースします。サポートされるライブラリ インテグレーションの完全な一覧については、インテグレーション概要 を参照してください。
import weave

from openai import OpenAI
client = OpenAI()

# Weave トレースを初期化
weave.init('intro-example')

response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {
            "role": "user",
            "content": "How are you?"
        }
    ],
    temperature=0.8,
    max_tokens=64,
    top_p=1,
)
自動的な動作をより細かく制御したい場合は、LLM Call の自動トラッキングを設定する を参照してください。

カスタム関数のトラッキング

LLM アプリケーションには、トラッキングしたい追加のロジック (前処理や後処理、プロンプトなど) が含まれていることがよくあります。Weave が自動的にトレースする LLM Call とあわせて独自の関数も取得したい場合は、この方法を使用します。
Weave では、@weave.op デコレータを使って、これらの Call を手動でトラッキングできます。例:
import weave

# Weave トレースを初期化
weave.init('intro-example')

# 関数をデコレート
@weave.op
def my_function(name: str):
    return f"Hello, {name}!"

# 関数を呼び出す -- Weave が入力と出力を自動的にトラッキングします
print(my_function("World"))
クラスの method もトラッキングできます。

クラスとオブジェクトの method をトラッキングする

スタンドアロン関数に加えて、クラスやオブジェクトの method もトラッキングできます。weave.op で method をデコレートすると、クラス内の任意の method をトラッキングできます。
import weave

# Weave トレースを初期化する
weave.init("intro-example")

class MyClass:
    # method をデコレートする
    @weave.op
    def my_method(self, name: str):
        return f"Hello, {name}!"

instance = MyClass()

# method を呼び出す -- Weave が 入力 と 出力 を自動的にトラッキングします
print(instance.my_method("World"))

並列 (マルチスレッド) の関数Callをトレースする

デフォルトでは、並列に実行された Call はすべて、Weave で個別のルート Call として表示されるため、トレース階層を追いにくくなります。同じ親 Op の下に正しくネストするには、ThreadPoolExecutor を使用します。
次のコード例は、ThreadPoolExecutor の使用方法を示しています。 1 つ目の関数 func は、x を受け取って x+1 を返すシンプルな Op です。2 つ目の関数 outer は、入力のリストを受け取る別の Op です。 outer の内部で ThreadPoolExecutorexc.map(func, inputs) を使用すると、func の各 Call に同じ親トレースコンテキストが引き継がれます。
import weave

@weave.op
def func(x):
    return x+1

@weave.op
def outer(inputs):
    with weave.ThreadPoolExecutor() as exc:
        exc.map(func, inputs)

# Weave プロジェクト名を更新します
client = weave.init('my-weave-project')
outer([1,2,3,4,5])
Weave UI では、これにより 1 つの親 Call の下に 5 つの子 Call がネストされた形で表示されます。インクリメント処理が並列に実行されていても、完全な階層型トレースを取得できます。 outer の 1 つの親 Call の下に、5 つの子 Call がネストされている Trace UI。

Call の手動トラッキング

自動インテグレーションや weave.op デコレータのいずれもワークフローに合わない場合は、API を直接使用して手動で Call を作成できます。この方法では、Call の開始と終了のタイミングを完全に制御できますが、その分ボイラープレートが増えます。
import weave

# Weave トレースを初期化
client = weave.init('intro-example')

def my_function(name: str):
    # Call を開始
    call = client.create_call(op="my_function", inputs={"name": name})

    # ... 関数のコード ...

    # Call を終了
    client.finish_call(call, output="Hello, World!")

    # 関数を呼び出す
    print(my_function("World"))