mcpField
L
langsmith-evaluator

langsmith-evaluator

github.com/jackjin1997テスト・品質1337 回インストール19 週間前に更新
リポジトリ

langsmith-evaluator について

langsmith-evaluatorは、データセット上のエージェントの性能を測る評価器を作成・管理するスキルです。LLMによる判定と決定的なコード評価に対応し、LangSmithへの評価器アップロードも行えます。

主な機能

  1. 01LLMによる判定
  2. 02決定的な評価器の作成
  3. 03回答と実行軌跡の検査
  4. 04LangSmithへの評価器登録

活用シーン

  1. 01データセットで回答品質を評価
  2. 02出力と正解例を照合
  3. 03エージェントのツール呼び出し順を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jackjin1997/clawforge --skill langsmith-evaluator

インストール後、Claude Code で/langsmith-evaluatorを入力して読み込まれたか確認します。

同梱ファイルscripts/upload_evaluators.py

詳細

LangSmith 評価者

データセットでエージェントのパフォーマンスを測定する評価者を作成します。LangSmith では、LLM による判定(LLM を使用して出力を評価)とカスタムコード(決定論的なロジック)の 2 種類がサポートされています。

セットアップ

環境変数
LANGSMITH_API_KEY=lsv2_pt_your_api_key_here          # Required
LANGSMITH_WORKSPACE_ID=your-workspace-id              # Optional: for org-scoped keys
OPENAI_API_KEY=your_openai_key                        # For LLM as Judge
依存関係
pip install langsmith langchain-openai python-dotenv

評価者の形式

評価者では、次の 2 種類の関数シグネチャがサポートされています。

方法 1:Dict パラメーター(ローカルで評価を実行する場合):

def evaluator_name(inputs: dict, outputs: dict, reference_outputs: dict = None) -> dict:
    """Evaluate a single prediction."""
    user_query = inputs.get("query", "")
    agent_response = outputs.get("expected_response", "")
    expected = reference_outputs.get("expected_response", "") if reference_outputs else None

    return {
        "key": "metric_name",    # Metric identifier
        "score": 0.85,           # Number or boolean
        "comment": "Reason..."   # Optional explanation
    }

方法 2:Run/Example パラメーター(LangSmith にアップロードする場合):

def evaluator_name(run, example):
    """Evaluate using run/example dicts.

    Args:
        run: Dict with run["outputs"] containing agent outputs
        example: Dict with example["outputs"] containing expected outputs
    """
    agent_response = run["outputs"].get("expected_response", "")
    expected = example["outputs"].get("expected_response", "")

    return {
        "metric_name": 0.85,      # Metric name as key directly
        "comment": "Reason..."    # Optional explanation
    }

LLM による判定の評価者

確実に評価するには、構造化出力を使用します。

from typing import TypedDict, Annotated
from langchain_openai import ChatOpenAI

class AccuracyGrade(TypedDict):
    """Structured evaluation output."""
    reasoning: Annotated[str, ..., "Explain your reasoning"]
    is_accurate: Annotated[bool, ..., "True if response is accurate"]
    confidence: Annotated[float, ..., "Confidence 0.0-1.0"]

# Configure model with structured output
judge = ChatOpenAI(model="gpt-4o-mini", temperature=0).with_structured_output(
    AccuracyGrade, method="json_schema", strict=True
)

async def accuracy_evaluator(run, example):
    """Evaluate factual accuracy for LangSmith upload."""
    expected = example["outputs"].get('expected_response', '')
    agent_output = run["outputs"].get('expected_response', '')

    prompt = f"""Expected: {expected}
Agent Output: {agent_output}
Evaluate accuracy:"""

    grade = await judge.ainvoke([{"role": "user", "content": prompt}])

    return {
        "accuracy": 1 if grade["is_accurate"] else 0,
        "comment": f"{grade['reasoning']} (confidence: {grade['confidence']})"
    }

一般的な指標: 完全性、正確性、有用性、プロフェッショナリズム

カスタムコード評価者

完全一致
def exact_match_evaluator(run, example):
    """Check if output exactly matches expected."""
    output = run["outputs"].get("expected_response", "").strip().lower()
    expected = example["outputs"].get("expected_response", "").strip().lower()

    match = output == expected
    return {
        "exact_match": 1 if match else 0,
        "comment": f"Match: {match}"
    }
軌跡の検証
def trajectory_evaluator(run, example):
    """Evaluate tool call sequence."""
    trajectory = run["outputs"].get("expected_trajectory", [])
    expected = example["outputs"].get("expected_trajectory", [])

    # Exact sequence match
    exact = trajectory == expected

    # All required tools used (order-agnostic)
    all_tools = set(expected).issubset(set(trajectory))

    # Efficiency: count extra steps
    extra_steps = len(trajectory) - len(expected)

    return {
        "trajectory_match": 1 if exact else 0,
        "comment": f"Exact: {exact}, All tools: {all_tools}, Extra: {extra_steps}"
    }
単一ステップの検証
def single_step_evaluator(run, example):
    """Evaluate single node output."""
    output = run["outputs"].get("output", {})
    expected = example["outputs"].get("expected_output", {})
    node_name = run["outputs"].get("node_name", "")

    # For classification nodes
    if "classification" in node_name:
        classification = output.get("classification", "")
        expected_class = expected.get("classification", "")
        match = classification.lower() == expected_class.lower()

        return {
            "classification_correct": 1 if match else 0,
            "comment": f"Output: {classification}, Expected: {expected_class}"
        }

    # For other nodes
    match = output == expected
    return {
        "output_match": 1 if match else 0,
        "comment": f"Match: {match}"
    }

評価の実行

from langsmith import Client

client = Client()

# Define your agent function
def run_agent(inputs: dict) -> dict:
    """Your agent invocation logic."""
    result = your_agent.invoke(inputs)
    return {"expected_response": result}

# Run evaluation
results = await client.aevaluate(
    run_agent,
    data="Skills: Final Response",              # Dataset name
    evaluators=[
        exact_match_evaluator,
        accuracy_evaluator,
        trajectory_evaluator
    ],
    experiment_prefix="skills-eval-v1",
    max_concurrency=4
)

評価者を LangSmith にアップロードする

アップロードスクリプトは、カスタム評価者を LangSmith にデプロイするためのユーティリティツールです。ユースケースに特化した評価者を作成してから、アップロードします。

評価者をアップロードするには、skills/langsmith-evaluator/scripts/ に移動します。

重要: LangSmith API では、評価者に (run, example) シグネチャを使用する必要があります。

  • run:エージェントの出力を含む run["outputs"] を持つ dict
  • example:期待される出力を含む example["outputs"] を持つ dict
評価者ファイルの作成
# my_project/evaluators/custom_evals.py

def my_custom_evaluator(run, example):
    """Your custom evaluation logic.

    Args:
        run: Dict with run["outputs"] - agent outputs
        example: Dict with example["outputs"] - expected outputs

    Returns:
        Dict with metric_name as key, score as value, optional comment
    """
    # Extract relevant data
    agent_output = run["outputs"].get("expected_trajectory", [])
    expected = example["outputs"].get("expected_trajectory", [])

    # Your custom logic here
    match = agent_output == expected

    return {
        "my_metric": 1 if match else 0,
        "comment": "Custom reasoning here"
    }
アップロード
# List existing evaluators
python upload_evaluators.py list

# Upload evaluator
python upload_evaluators.py upload my_evaluators.py \
  --name "Trajectory Match" \
  --function trajectory_match \
  --dataset "Skills: Trajectory" \
  --replace

# Delete evaluator (will prompt for confirmation)
python upload_evaluators.py delete "Trajectory Match"

# Skip confirmation prompts (use with caution)
python upload_evaluators.py delete "Trajectory Match" --yes
python upload_evaluators.py upload my_evaluators.py \
  --name "Trajectory Match" \
  --function trajectory_match \
  --replace --yes

オプション:

  • --name - LangSmith での表示名
  • --function - 抽出する関数名
  • --dataset - 対象のデータセット名
  • --project - 対象のプロジェクト名
  • --sample-rate - サンプリング率(0.0~1.0)
  • --replace - 存在する場合は置き換えます(確認を求めます)
  • --yes - 置き換え/削除の確認プロンプトをスキップします

重要 — 安全確認プロンプト:

  • 削除や置き換えなどの破壊的な操作の前に、スクリプトは確認を求めます
  • 必ずこれらのプロンプトに従ってください — 続行する前にユーザーの入力を待ちます
  • ユーザーが明示的に要求しない限り、--yes フラグは使用しないでください
  • --yes フラグはすべての安全確認プロンプトをスキップします。ユーザーが明示的に許可した自動化ワークフローでのみ使用してください

ベストプラクティス

  1. LLM による判定には構造化出力を使用する - 自由形式のテキストを解析するよりも信頼性が高くなります
  2. データセットの種類に合わせて評価者を選ぶ
    • 最終応答 → 品質の評価には LLM による判定、形式の評価にはカスタムコード
    • 単一ステップ → 完全一致にはカスタムコード
    • 軌跡 → 順序/効率の評価にはカスタムコード
  3. 複数の評価者を組み合わせる - 主観的な評価(LLM)と客観的な評価(コード)の両方を実行します
  4. LLM による判定には非同期処理を使用する - 並列評価が可能になり、大幅に高速化します
  5. 評価者を個別にテストする - まず、正解と不正解が分かっている例で検証します
  6. LangSmith にアップロードする - 新しい実行に対する評価を自動化します

ワークフローの例

# 1. Create evaluators file
cat > evaluators.py <<'EOF'
def exact_match(run, example):
    """Check if output exactly matches expected."""
    output = run["outputs"].get("expected_response", "").strip().lower()
    expected = example["outputs"].get("expected_response", "").strip().lower()
    match = output == expected
    return {
        "exact_match": 1 if match else 0,
        "comment": f"Match: {match}"
    }
EOF

# 2. Upload to LangSmith
python upload_evaluators.py upload evaluators.py \
  --name "Exact Match" \
  --function exact_match \
  --dataset "Skills: Final Response" \
  --replace

# 3. Evaluator runs automatically on new dataset runs

リソース

関連スキル

  • トレースのクエリとエクスポートには langsmith-trace スキルを使用します
  • トレースから評価データセットを生成するには langsmith-dataset スキルを使用します

コメント