agentevals

repository·main·Indexed 20 days ago

https://github.com/langchain-ai/agentevals

A collection of evaluators and utilities for agentic applications, specifically focusing on evaluating agent trajectories (intermediate steps). It provides LLM-as-judge evaluators and trajectory match evaluators with configurable match modes (strict, unordered, subset, superset) and customizable tool argument matching. Available for Python and TypeScript.

Tokens
13.6K
Snippets
38
Records
44
Agent score
66%

What's inside agentevals

  1. What is a Graph Trajectory and how is it structured?

    main

    For graph-based agents (like LangGraph), agentevals uses a graph trajectory format instead of simple message lists. This format represents trajectories in terms of nodes visited (steps) rather than just messages, making it easier to evaluate complex agent behaviors like tool calls and interrupts.

    A GraphTrajectory consists of:

    • inputs: A list of inputs representing the start of new invocations in a thread.
    • results: The final output from each turn in the thread.
    • steps: A list of lists representing the internal nodes/steps taken for each turn (e.g., ['__start__', 'agent', 'tools', '__interrupt__']).
    # Python structure
    class GraphTrajectory(TypedDict):
        inputs: Optional[list[dict]]
        results: list[dict]
        steps: list[list[str]]
    // TypeScript structure
    export type GraphTrajectory = {
      inputs?: (Record<string, unknown> | null)[];
      results: Record<string, unknown>[];
      steps: string[][];
    };
  2. Configure trajectory match modes

    main

    The trajectory_match_mode (Python) or trajectoryMatchMode (TypeScript) defines the strategy used to compare the actual trajectory against the reference.

    Available modes:

    • strict: Ensures trajectories contain the same messages in the same order with the same tool calls. It allows for differences in message content (text). Useful for enforcing specific tool call sequences.
    • unordered: Ensures trajectories contain the same tool calls, but the order does not matter. Useful when the specific sequence of information retrieval is flexible.
    • subset: Ensures the actual trajectory contains a subset of the tool calls found in the reference trajectory. Useful for ensuring an agent does not call tools beyond the expected set.
    • superset: Ensures the actual trajectory contains a superset of the tool calls found in the reference trajectory. Useful for ensuring key tools are called, even if the agent calls extra ones.
  3. Customize tool argument matching

    main

    By default, tool calls are only considered equal if they use the same tool and have identical arguments. You can customize this using tool_args_match_mode (Python) or toolArgsMatchMode (TypeScript) and tool_args_match_overrides (Python) or toolArgsMatchOverrides (TypeScript).

    Match Modes:

    • exact: (Default) Arguments must match exactly.
    • ignore: Any two tool calls for the same tool are considered equivalent regardless of arguments.
    • subset: A tool call is equivalent if its arguments are a subset/superset of the reference tool call's arguments.
    • superset: A tool call is equivalent if its arguments are a superset/subset of the reference tool call's arguments.

    Overrides: tool_args_match_overrides takes precedence over the global match mode. It accepts a dictionary where keys are tool names and values are:

    • A ToolArgsMatchMode ("exact", "ignore", "subset", or "superset").
    • A list of field names within the tool call that must match exactly.
    • A comparator function (arg1, arg2) -> bool that returns whether the arguments are equal.
  4. Use Trajectory LLM-as-judge for evaluation

    main

    The LLM-as-judge trajectory evaluator uses a language model to assess an agent's trajectory. Unlike trajectory match evaluators, it does not require a reference trajectory to function, making it useful for evaluating general reasoning or correctness.

    If you have a reference trajectory, you can provide it to the evaluator by using a prompt that supports a reference variable (such as TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE) and passing the reference_outputs argument during evaluation.

    # Python Example: Basic usage without reference
    import json
    from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT
    
    evaluator = create_trajectory_llm_as_judge(
      prompt=TRAJECTORY_ACCURACY_PROMPT,
      model="openai:o3-mini"
    )
    
    outputs = [
        {"role": "user", "content": "What is the weather in SF?"},
        {
            "role": "assistant",
            "content": "",
            "tool_calls": [
                {
                    "function": {
                        "name": "get_weather",
                        "arguments": json.dumps({"city": "SF"}),
                    }
                }
            ],
        },
        {"role": "tool", "content": "It's 80 degrees and sunny in SF."},
        {"role": "assistant", "content": "The weather in SF is 80 degrees and sunny."},
    ]
    
    eval_result = evaluator(outputs=outputs)
    print(eval_result)
  5. Use Agent trajectory match evaluators

    main

    Agent trajectory match evaluators judge an agent's execution trajectory against an expected reference trajectory or using an LLM.

    To use these evaluators, format your agent's trajectory as either:

    1. A list of OpenAI format dictionaries.
    2. A list of LangChain BaseMessage classes.

    AgentEvals handles the message formatting internally. You can create these evaluators using create_trajectory_match_evaluator/createTrajectoryMatchEvaluator or create_async_trajectory_match_evaluator.

    # Python example
    from agentevals.trajectory.match import create_trajectory_match_evaluator
    
    evaluator = create_trajectory_match_evaluator(trajectory_match_mode="strict")
    result = evaluator(outputs=outputs, reference_outputs=reference_outputs)
  6. Use Python Async Support in AgentEvals

    main

    All agentevals evaluators support Python asyncio.

    Naming Conventions:

    • Evaluators using a factory function: async is placed immediately after create_ (e.g., create_async_trajectory_llm_as_judge).
    • Evaluators used directly: end with async (e.g., trajectory_strict_match_async).

    When using the OpenAI client directly, pass AsyncOpenAI to the judge parameter.

    from agentevals.trajectory.llm import create_async_trajectory_llm_as_judge
    from openai import AsyncOpenAI
    
    evaluator = create_async_trajectory_llm_as_judge(
        prompt="What is the weather in {inputs}?",
        judge=AsyncOpenAI(),
        model="o3-mini",
    )
    
    result = await evaluator(inputs="San Francisco")
  7. Integrate AgentEvals with LangSmith using Pytest

    main

    You can track agent evaluation experiments in LangSmith by using the pytest integration.

    Setup:

    1. Set the following environment variables:
      • LANGSMITH_API_KEY: Your LangSmith API key.
      • LANGSMITH_TRACING: Set to "true".
    2. Use langsmith.testing to log inputs, outputs, and reference outputs.
    3. Use the @pytest.mark.langsmith decorator on your test functions.
    4. Run the tests using the --langsmith-output flag.

    Note: You can provide a feedback_key parameter when creating the evaluator to name the feedback in LangSmith.

    export LANGSMITH_API_KEY="your_langsmith_api_key"
    export LANGSMITH_TRACING="true"
    
    pytest test_trajectory.py --langsmith-output
  8. Install agentevals

    main

    Install the agentevals package via pip for Python or npm for TypeScript. If you are using LLM-as-judge evaluators, ensure you have an LLM client installed. By default, agentevals uses LangChain chat model integrations (like langchain_openai).

    # Python
    pip install agentevals
    
    # TypeScript
    npm install agentevals @langchain/core
  9. Integrate AgentEvals with LangSmith using Vitest/Jest

    main

    For TypeScript users, you can log evaluations to LangSmith using vitest or jest integrations.

    Setup:

    1. Set the following environment variables:
      • LANGSMITH_API_KEY: Your LangSmith API key.
      • LANGSMITH_TRACING: Set to "true".
    2. Use langsmith/vitest (or langsmith/jest) to define tests with ls.describe and ls.test.
    3. Use ls.logOutputs to record the agent's behavior.
    4. Run the tests using your preferred runner (e.g., vitest run).
    import * as ls from "langsmith/vitest";
    import { createTrajectoryLLMAsJudge } from "agentevals";
    
    const trajectoryEvaluator = createTrajectoryLLMAsJudge({
      model: "openai:o3-mini",
    });
    
    ls.describe("trajectory accuracy", () => {
      ls.test("accurate trajectory", {
        inputs: { messages: [{ role: "user", content: "What is the weather in SF?" }] },
        referenceOutputs: { messages: [...] },
      }, async ({ inputs, referenceOutputs }) => {
        const outputs = [...];
        ls.logOutputs({ messages: outputs });
    
        await trajectoryEvaluator({
          inputs,
          outputs,
          referenceOutputs,
        });
      });
    });
  10. Run bulk evaluations using LangSmith's evaluate function

    main

    Instead of per-test logging, you can run evaluations against a pre-existing LangSmith dataset using the evaluate function.

    Python Usage: Use langsmith.Client().evaluate() passing a target function (your agent), a dataset name, and a list of agentevals evaluators.

    TypeScript Usage: Import evaluate from langsmith/evaluation and pass a target function, a configuration object containing the data (dataset name) and evaluators array.

    from langsmith import Client
    from agentevals.trajectory.llm import create_trajectory_llm_as_judge
    
    client = Client()
    
    trajectory_evaluator = create_trajectory_llm_as_judge(
        model="openai:o3-mini",
    )
    
    experiment_results = client.evaluate(
        lambda inputs: "What color is the sky?", # Your agent function
        data="Sample dataset",
        evaluators=[trajectory_evaluator]
    )
  11. Strict trajectory matching logic

    main

    A strict trajectory match requires that:

    1. The number of steps in outputs and referenceOutputs are identical.
    2. At every step, the role of the message matches.
    3. The presence of tool calls matches (both must have them or both must not).
    4. If tool calls are present, they must appear in the same order and have the same number of calls.
    5. For each tool call, the function name must match, and if toolCallArgsExactMatch is enabled, the arguments must also match based on the configured toolArgsMatchMode.