Open In Colab Weaveは LangChain Python library を通じて行われるすべての呼び出しの追跡とログ記録を簡単にするように設計されています。 LLMを扱う際、デバッグは避けられません。モデル呼び出しが失敗したり、出力の形式が正しくなかったり、ネストされたモデル呼び出しが混乱を招いたりする場合、問題を特定することは難しい場合があります。LangChainアプリケーションは多くの場合、複数のステップとLLM呼び出しで構成されているため、チェーンやエージェントの内部動作を理解することが重要です。 Weaveは LangChain アプリケーションのトレースを自動的にキャプチャすることでこのプロセスを簡素化します。これにより、アプリケーションのパフォーマンスを監視および分析でき、LLMワークフローのデバッグと最適化が容易になります。

はじめに

開始するには、スクリプトの先頭で単に weave.init() を呼び出します。weave.init()の引数は、トレースを整理するのに役立つプロジェクト名です。
import weave
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# Initialize Weave with your project name
# highlight-next-line
weave.init("langchain_demo")

llm = ChatOpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")

llm_chain = prompt | llm

output = llm_chain.invoke({"number": 2})

print(output)

呼び出しメタデータの追跡

LangChain呼び出しからメタデータを追跡するには、weave.attributes コンテキストマネージャーを使用できます。このコンテキストマネージャーを使用すると、チェーンや単一のリクエストなど、特定のコードブロックにカスタムメタデータを設定できます。
import weave
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# Initialize Weave with your project name
# highlight-next-line
weave.init("langchain_demo")

llm = ChatOpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")

llm_chain = prompt | llm

# highlight-next-line
with weave.attributes({"my_awesome_attribute": "value"}):
    output = llm_chain.invoke()

print(output)
WeaveはLangChain呼び出しのトレースに対してメタデータを自動的に追跡します。以下に示すように、Weaveウェブインターフェイスでメタデータを表示できます: langchain_attributes.png

トレース

開発中および本番環境の両方で、LLMアプリケーションのトレースを中央データベースに保存することは重要です。これらのトレースは、貴重なデータセットを提供することで、アプリケーションのデバッグと改善に不可欠です。 WeaveはLangChainアプリケーションのトレースを自動的にキャプチャします。プロンプトテンプレート、チェーン、LLM呼び出し、ツール、エージェントステップなど、LangChainライブラリを通じて行われるすべての呼び出しを追跡およびログに記録します。Weaveウェブインターフェイスでトレースを表示できます。 langchain_trace.png

手動での呼び出しのトレース

自動トレースに加えて、WeaveTracer コールバックまたは weave_tracing_enabled コンテキストマネージャーを使用して手動で呼び出しをトレースできます。これらの方法は、LangChainアプリケーションの個々の部分でリクエストコールバックを使用するのに似ています。 Note: Weaveはデフォルトでランチェーン・ランナブルをトレースし、これは weave.init() を呼び出すときに有効になります。環境変数 WEAVE_TRACE_LANGCHAIN"false" に設定することで、weave.init() を呼び出す前にこの動作を無効にできます。これにより、アプリケーション内の特定のチェーンや個々のリクエストのトレース動作を制御できます。

Using WeaveTracer

特定のリクエストをトレースするために、WeaveTracer コールバックを個々のLangChainコンポーネントに渡すことができます。
import os

os.environ["WEAVE_TRACE_LANGCHAIN"] = "false" # <- explicitly disable global tracing.

from weave.integrations.langchain import WeaveTracer
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
import weave

# Initialize Weave with your project name
# highlight-next-line
weave.init("langchain_demo")  # <-- we don't enable tracing here because the env var is explicitly set to `false`

# highlight-next-line
weave_tracer = WeaveTracer()

# highlight-next-line
config = {"callbacks": [weave_tracer]}

llm = ChatOpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")

llm_chain = prompt | llm

# highlight-next-line
output = llm_chain.invoke({"number": 2}, config=config) # <-- this enables tracing only for this chain invoke.

llm_chain.invoke({"number": 4})  # <-- this will not have tracing enabled for langchain calls but openai calls will still be traced

Using weave_tracing_enabled コンテキストマネージャー

あるいは、weave_tracing_enabled コンテキストマネージャーを使用して、特定のコードブロックのトレースを有効にすることもできます。
import os

os.environ["WEAVE_TRACE_LANGCHAIN"] = "false" # <- explicitly disable global tracing.

from weave.integrations.langchain import weave_tracing_enabled
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
import weave

# Initialize Weave with your project name
# highlight-next-line
weave.init("langchain_demo")  # <-- we don't enable tracing here because the env var is explicitly set to `false`

llm = ChatOpenAI()
prompt = PromptTemplate.from_template("1 + {number} = ")

llm_chain = prompt | llm

# highlight-next-line
with weave_tracing_enabled():  # <-- this enables tracing only for this chain invoke.
    output = llm_chain.invoke({"number": 2})


llm_chain.invoke({"number": 4})  # <-- this will not have tracing enabled for langchain calls but openai calls will still be traced

設定

呼び出し時に weave.init、環境変数 WEAVE_TRACE_LANGCHAIN"true" に設定することでトレースが有効になります。これにより、WeaveはLangChainアプリケーションのトレースを自動的にキャプチャできます。この動作を無効にしたい場合は、環境変数を "false".

LangChainコールバックとの関係

自動ログ記録

提供される自動ログ記録 weave.init() は、LangChainアプリケーションのすべてのコンポーネントにコンストラクタコールバックを渡すのと似ています。これは、プロンプトテンプレート、チェーン、LLM呼び出し、ツール、エージェントステップなど、すべての相互作用がアプリケーション全体でグローバルに追跡されることを意味します。

手動ログ記録

手動ログ記録メソッド(WeaveTracer および weave_tracing_enabled)は、LangChainアプリケーションの個々の部分でリクエストコールバックを使用するのに似ています。これらの方法は、アプリケーションのどの部分がトレースされるかをより細かく制御できます:
  • コンストラクタコールバック: チェーンまたはコンポーネント全体に適用され、すべての相互作用を一貫してログに記録します。
  • リクエストコールバック:特定のリクエストに適用され、特定の呼び出しの詳細なトレースを可能にします。
WeaveとLangChainを統合することで、LLMアプリケーションの包括的なロギングとモニタリングを確保し、デバッグとパフォーマンス最適化を容易にすることができます。 より詳細な情報については、LangChainドキュメントを参照してください。

モデルと評価

プロンプト、モデル構成、推論パラメータなど複数のコンポーネントを持つ様々なユースケースのアプリケーションでLLMを整理し評価することは難しいです。weave.Modelを使用することで、システムプロンプトや使用するモデルなどの実験の詳細を記録し整理することができ、異なるイテレーションを比較しやすくなります。 次の例はLangchainチェーンをWeaveModelでラップする方法を示しています:
import json
import asyncio

import weave

from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# Initialize Weave with your project name
# highlight-next-line
weave.init("langchain_demo")

# highlight-next-line
class ExtractFruitsModel(weave.Model):
    model_name: str
    prompt_template: str

# highlight-next-line
    @weave.op()
    async def predict(self, sentence: str) -> dict:
        llm = ChatOpenAI(model=self.model_name, temperature=0.0)
        prompt = PromptTemplate.from_template(self.prompt_template)

        llm_chain = prompt | llm
        response = llm_chain.invoke({"sentence": sentence})
        result = response.content

        if result is None:
            raise ValueError("No response from model")
        parsed = json.loads(result)
        return parsed

model = ExtractFruitsModel(
    model_name="gpt-3.5-turbo-1106",
    prompt_template='Extract fields ("fruit": <str>, "color": <str>, "flavor": <str>) from the following text, as json: {sentence}',
)
sentence = "There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy."

prediction = asyncio.run(model.predict(sentence))

# if you're in a Jupyter Notebook, run:
# prediction = await model.predict(sentence)

print(prediction)
このコードはWeave UIで視覚化できるモデルを作成します: langchain_model.png Weave Modelsはserve、およびEvaluationsと共に使用することもできます。

評価

評価はモデルのパフォーマンスを測定するのに役立ちます。weave.Evaluationクラスを使用することで、特定のタスクやデータセットに対するモデルのパフォーマンスを記録し、異なるモデルやアプリケーションのイテレーションを比較しやすくなります。次の例は、作成したモデルを評価する方法を示しています:

from weave.scorers import MultiTaskBinaryClassificationF1

sentences = [
    "There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy.",
    "Pounits are a bright green color and are more savory than sweet.",
    "Finally, there are fruits called glowls, which have a very sour and bitter taste which is acidic and caustic, and a pale orange tinge to them.",
]
labels = [
    {"fruit": "neoskizzles", "color": "purple", "flavor": "candy"},
    {"fruit": "pounits", "color": "bright green", "flavor": "savory"},
    {"fruit": "glowls", "color": "pale orange", "flavor": "sour and bitter"},
]
examples = [
    {"id": "0", "sentence": sentences[0], "target": labels[0]},
    {"id": "1", "sentence": sentences[1], "target": labels[1]},
    {"id": "2", "sentence": sentences[2], "target": labels[2]},
]

@weave.op()
def fruit_name_score(target: dict, output: dict) -> dict:
    return {"correct": target["fruit"] == output["fruit"]}


evaluation = weave.Evaluation(
    dataset=examples,
    scorers=[
        MultiTaskBinaryClassificationF1(class_names=["fruit", "color", "flavor"]),
        fruit_name_score,
    ],
)
scores = asyncio.run(evaluation.evaluate(model)))
# if you're in a Jupyter Notebook, run:
# scores = await evaluation.evaluate(model)

print(scores)
このコードはWeave UIで視覚化できる評価トレースを生成します: langchain_evaluation.png WeaveとLangchainを統合することで、LLMアプリケーションの包括的なロギングとモニタリングを確保し、デバッグとパフォーマンス最適化を容易にすることができます。

既知の問題

  • 非同期呼び出しのトレース - LangchainのAsyncCallbackManagerの実装におけるバグにより、非同期呼び出しが正しい順序でトレースされません。これを修正するためにPRを提出しました。そのため、ainvokeastreamおよびabatchメソッドをLangchain Runnablesで使用する場合、トレース内の呼び出し順序が正確でない可能性があります。