外观
评估("evals")通过评估智能体的执行轨迹——即它产生的消息与工具调用序列——来衡量其表现如何。与验证基本正确性的集成测试不同,评估会根据参考或评分标准(rubric)对智能体行为进行打分,因此在您更改提示词、工具或模型时,评估有助于捕捉回归问题。
评估器是一个接收智能体输出(以及可选的参考输出)并返回分数的函数:
python
def evaluator(*, outputs: dict, reference_outputs: dict):
output_messages = outputs["messages"]
reference_messages = reference_outputs["messages"]
score = compare_messages(output_messages, reference_messages)
return {"key": "evaluator_score", "score": score}typescript
function evaluator({ outputs, referenceOutputs }: {
outputs: Record<string, any>;
referenceOutputs: Record<string, any>;
}) {
const outputMessages = outputs.messages;
const referenceMessages = referenceOutputs.messages;
const score = compareMessages(outputMessages, referenceMessages);
return { key: "evaluator_score", score: score };
}agentevals 包为智能体轨迹提供了预构建的评估器。您可以通过轨迹匹配(确定性比较)或使用LLM 裁判(定性评估)进行评估:
| 方法 | 使用时机 |
|---|---|
| 轨迹匹配 | 您已知预期的工具调用,希望进行快速、确定性且零成本的检查 |
| LLM 裁判 | 您希望在无需严格预期的情况下评估整体质量和推理能力 |
安装 AgentEvals
bash
pip install agentevalsbash
npm install agentevals @langchain/core或者,直接克隆 AgentEvals 仓库。
轨迹匹配评估器
AgentEvals 提供 create_trajectory_match_evaluator 函数,用于将智能体的轨迹与参考轨迹进行匹配。共有四种模式: AgentEvals 提供 createTrajectoryMatchEvaluator 函数,用于将智能体的轨迹与参考轨迹进行匹配。共有四种模式:
| 模式 | 描述 | 使用场景 |
|---|---|---|
strict | 消息结构与工具调用按相同顺序精确匹配(消息内容可以不同) | 测试特定序列(例如先进行策略查询,再执行授权) |
unordered | 消息结构与工具调用与参考相同,但工具调用可以以任意顺序发生 | 在顺序无关紧要时验证信息检索 |
subset | 智能体仅调用参考中的工具(无额外调用) | 确保智能体不超过预期范围 |
superset | 智能体至少调用参考中的工具(允许额外调用) | 验证是否执行了最低限度的必需操作 |
以下示例共用同一套基础配置:一个带有 get_weather 工具的智能体:
python
from langchain.agents import create_agent
from langchain.tools import tool
from langchain.messages import HumanMessage, AIMessage, ToolMessage
from agentevals.trajectory.match import create_trajectory_match_evaluator
@tool
def get_weather(city: str):
"""Get weather information for a city."""
return f"It's 75 degrees and sunny in {city}."
agent = create_agent("claude-sonnet-4-6", tools=[get_weather])ts
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { HumanMessage, AIMessage, ToolMessage } from "@langchain/core/messages";
import { createTrajectoryMatchEvaluator } from "agentevals";
import * as z from "zod";
const getWeather = tool(
async ({ city }) => {
return `It's 75 degrees and sunny in ${city}.`;
},
{
name: "get_weather",
description: "Get weather information for a city.",
schema: z.object({ city: z.string() }),
}
);
const agent = createAgent({
model: "claude-sonnet-4-6",
tools: [getWeather],
});严格匹配
strict 模式确保轨迹中包含顺序相同、工具调用相同的消息,但允许消息内容存在差异。当您需要强制特定操作顺序时(例如要求先进行策略查询再授权操作),此模式非常有用。
python
evaluator = create_trajectory_match_evaluator(
trajectory_match_mode="strict",
)
def test_weather_tool_called_strict():
result = agent.invoke({
"messages": [HumanMessage(content="What's the weather in San Francisco?")]
})
reference_trajectory = [
HumanMessage(content="What's the weather in San Francisco?"),
AIMessage(content="", tool_calls=[
{"id": "call_1", "name": "get_weather", "args": {"city": "San Francisco"}}
]),
ToolMessage(content="It's 75 degrees and sunny in San Francisco.", tool_call_id="call_1"),
AIMessage(content="The weather in San Francisco is 75 degrees and sunny."),
]
evaluation = evaluator(
outputs=result["messages"],
reference_outputs=reference_trajectory
)
# {
# 'key': 'trajectory_strict_match',
# 'score': True,
# 'comment': None,
# }
assert evaluation["score"] is Truets
const evaluator = createTrajectoryMatchEvaluator({
trajectoryMatchMode: "strict",
});
async function testWeatherToolCalledStrict() {
const result = await agent.invoke({
messages: [new HumanMessage("What's the weather in San Francisco?")]
});
const referenceTrajectory = [
new HumanMessage("What's the weather in San Francisco?"),
new AIMessage({
content: "",
tool_calls: [
{ id: "call_1", name: "get_weather", args: { city: "San Francisco" } }
]
}),
new ToolMessage({
content: "It's 75 degrees and sunny in San Francisco.",
tool_call_id: "call_1"
}),
new AIMessage("The weather in San Francisco is 75 degrees and sunny."),
];
const evaluation = await evaluator({
outputs: result.messages,
referenceOutputs: referenceTrajectory
});
expect(evaluation.score).toBe(true);
}无序匹配
unordered 模式允许相同的工具调用以任意顺序发生。当您希望验证是否检索到了特定信息但不关心顺序时,此模式非常有用。例如,一个使用不同的工具调用同时查询某个城市天气和活动的智能体。
python
@tool
def get_events(city: str):
"""Get events happening in a city."""
return f"Concert at the park in {city} tonight."
agent = create_agent("claude-sonnet-4-6", tools=[get_weather, get_events])
evaluator = create_trajectory_match_evaluator(
trajectory_match_mode="unordered",
)
def test_multiple_tools_any_order():
result = agent.invoke({
"messages": [HumanMessage(content="What's happening in SF today?")]
})
reference_trajectory = [
HumanMessage(content="What's happening in SF today?"),
AIMessage(content="", tool_calls=[
{"id": "call_1", "name": "get_events", "args": {"city": "SF"}},
{"id": "call_2", "name": "get_weather", "args": {"city": "SF"}},
]),
ToolMessage(content="Concert at the park in SF tonight.", tool_call_id="call_1"),
ToolMessage(content="It's 75 degrees and sunny in SF.", tool_call_id="call_2"),
AIMessage(content="Today in SF: 75 degrees and sunny with a concert at the park tonight."),
]
evaluation = evaluator(
outputs=result["messages"],
reference_outputs=reference_trajectory,
)
assert evaluation["score"] is Truets
const getEvents = tool(
async ({ city }: { city: string }) => {
return `Concert at the park in ${city} tonight.`;
},
{
name: "get_events",
description: "Get events happening in a city.",
schema: z.object({ city: z.string() }),
}
);
const agent = createAgent({
model: "claude-sonnet-4-6",
tools: [getWeather, getEvents],
});
const evaluator = createTrajectoryMatchEvaluator({
trajectoryMatchMode: "unordered",
});
async function testMultipleToolsAnyOrder() {
const result = await agent.invoke({
messages: [new HumanMessage("What's happening in SF today?")]
});
const referenceTrajectory = [
new HumanMessage("What's happening in SF today?"),
new AIMessage({
content: "",
tool_calls: [
{ id: "call_1", name: "get_events", args: { city: "SF" } },
{ id: "call_2", name: "get_weather", args: { city: "SF" } },
]
}),
new ToolMessage({
content: "Concert at the park in SF tonight.",
tool_call_id: "call_1"
}),
new ToolMessage({
content: "It's 75 degrees and sunny in SF.",
tool_call_id: "call_2"
}),
new AIMessage("Today in SF: 75 degrees and sunny with a concert at the park tonight."),
];
const evaluation = await evaluator({
outputs: result.messages,
referenceOutputs: referenceTrajectory,
});
expect(evaluation.score).toBe(true);
}子集与超集匹配
superset 和 subset 模式匹配部分轨迹。superset 模式验证智能体至少调用了参考轨迹中的工具,并允许额外的工具调用。subset 模式确保智能体没有调用参考轨迹之外的其他工具。
python
@tool
def get_detailed_forecast(city: str):
"""Get detailed weather forecast for a city."""
return f"Detailed forecast for {city}: sunny all week."
agent = create_agent("claude-sonnet-4-6", tools=[get_weather, get_detailed_forecast])
evaluator = create_trajectory_match_evaluator(
trajectory_match_mode="superset",
)
def test_agent_calls_required_tools_plus_extra():
result = agent.invoke({
"messages": [HumanMessage(content="What's the weather in Boston?")]
})
# 参考轨迹只要求 get_weather,但智能体可能调用额外的工具
reference_trajectory = [
HumanMessage(content="What's the weather in Boston?"),
AIMessage(content="", tool_calls=[
{"id": "call_1", "name": "get_weather", "args": {"city": "Boston"}},
]),
ToolMessage(content="It's 75 degrees and sunny in Boston.", tool_call_id="call_1"),
AIMessage(content="The weather in Boston is 75 degrees and sunny."),
]
evaluation = evaluator(
outputs=result["messages"],
reference_outputs=reference_trajectory,
)
assert evaluation["score"] is Truets
const getDetailedForecast = tool(
async ({ city }: { city: string }) => {
return `Detailed forecast for ${city}: sunny all week.`;
},
{
name: "get_detailed_forecast",
description: "Get detailed weather forecast for a city.",
schema: z.object({ city: z.string() }),
}
);
const agent = createAgent({
model: "claude-sonnet-4-6",
tools: [getWeather, getDetailedForecast],
});
const evaluator = createTrajectoryMatchEvaluator({
trajectoryMatchMode: "superset",
});
async function testAgentCallsRequiredToolsPlusExtra() {
const result = await agent.invoke({
messages: [new HumanMessage("What's the weather in Boston?")]
});
const referenceTrajectory = [
new HumanMessage("What's the weather in Boston?"),
new AIMessage({
content: "",
tool_calls: [
{ id: "call_1", name: "get_weather", args: { city: "Boston" } },
]
}),
new ToolMessage({
content: "It's 75 degrees and sunny in Boston.",
tool_call_id: "call_1"
}),
new AIMessage("The weather in Boston is 75 degrees and sunny."),
];
const evaluation = await evaluator({
outputs: result.messages,
referenceOutputs: referenceTrajectory,
});
expect(evaluation.score).toBe(true);
}INFO
您还可以设置 tool_args_match_mode 属性和/或 tool_args_match_overrides,自定义评估器如何判断实际轨迹与参考轨迹中工具调用之间的相等性。默认情况下,仅当工具调用针对同一工具且参数相同时才被视为相等。更多详情请访问仓库。 您还可以设置 toolArgsMatchMode 属性和/或 toolArgsMatchOverrides,自定义评估器如何判断实际轨迹与参考轨迹中工具调用之间的相等性。默认情况下,仅当工具调用针对同一工具且参数相同时才被视为相等。更多详情请访问仓库。
LLM 裁判评估器
您可以使用 create_trajectory_llm_as_judge 函数让 LLM 评估智能体的执行路径。与轨迹匹配评估器不同,它不要求提供参考轨迹,但如果可用,也可以提供一份。 您可以使用 createTrajectoryLLMAsJudge 函数让 LLM 评估智能体的执行路径。与轨迹匹配评估器不同,它不要求提供参考轨迹,但如果可用,也可以提供一份。
无参考轨迹
python
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT
evaluator = create_trajectory_llm_as_judge(
model="openai:o3-mini",
prompt=TRAJECTORY_ACCURACY_PROMPT,
)
def test_trajectory_quality():
result = agent.invoke({
"messages": [HumanMessage(content="What's the weather in Seattle?")]
})
evaluation = evaluator(
outputs=result["messages"],
)
assert evaluation["score"] is Truets
import { createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT } from "agentevals";
const evaluator = createTrajectoryLLMAsJudge({
model: "openai:o3-mini",
prompt: TRAJECTORY_ACCURACY_PROMPT,
});
async function testTrajectoryQuality() {
const result = await agent.invoke({
messages: [new HumanMessage("What's the weather in Seattle?")]
});
const evaluation = await evaluator({
outputs: result.messages,
});
expect(evaluation.score).toBe(true);
}有参考轨迹
如果您有参考轨迹,请使用预构建的 TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE 提示词:
python
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE
evaluator = create_trajectory_llm_as_judge(
model="openai:o3-mini",
prompt=TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
)
evaluation = evaluator(
outputs=result["messages"],
reference_outputs=reference_trajectory,
)ts
import { createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE } from "agentevals";
const evaluator = createTrajectoryLLMAsJudge({
model: "openai:o3-mini",
prompt: TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
});
const evaluation = await evaluator({
outputs: result.messages,
referenceOutputs: referenceTrajectory,
});INFO
若要对 LLM 评估轨迹的方式进行更多配置,请访问仓库。
异步支持
所有 agentevals 评估器都支持 Python asyncio。在函数名的 create_ 后添加 async 即可获得异步版本。
异步裁判与评估器示例
python
from agentevals.trajectory.llm import create_async_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT
from agentevals.trajectory.match import create_async_trajectory_match_evaluator
async_judge = create_async_trajectory_llm_as_judge(
model="openai:o3-mini",
prompt=TRAJECTORY_ACCURACY_PROMPT,
)
async_evaluator = create_async_trajectory_match_evaluator(
trajectory_match_mode="strict",
)
async def test_async_evaluation():
result = await agent.ainvoke({
"messages": [HumanMessage(content="What's the weather?")]
})
evaluation = await async_judge(outputs=result["messages"])
assert evaluation["score"] is True在 LangSmith 中运行评估
为了随时间追踪实验结果,请将评估器结果记录到 LangSmith。首先,设置所需的环境变量:
bash
export LANGSMITH_API_KEY="your_langsmith_api_key"
export LANGSMITH_TRACING="true"LangSmith 提供两种主要方式来运行评估:pytest 集成和 evaluate 函数。
使用 pytest 集成
python
import pytest
from langsmith import testing as t
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT
trajectory_evaluator = create_trajectory_llm_as_judge(
model="openai:o3-mini",
prompt=TRAJECTORY_ACCURACY_PROMPT,
)
@pytest.mark.langsmith
def test_trajectory_accuracy():
result = agent.invoke({
"messages": [HumanMessage(content="What's the weather in SF?")]
})
reference_trajectory = [
HumanMessage(content="What's the weather in SF?"),
AIMessage(content="", tool_calls=[
{"id": "call_1", "name": "get_weather", "args": {"city": "SF"}},
]),
ToolMessage(content="It's 75 degrees and sunny in SF.", tool_call_id="call_1"),
AIMessage(content="The weather in SF is 75 degrees and sunny."),
]
t.log_inputs({})
t.log_outputs({"messages": result["messages"]})
t.log_reference_outputs({"messages": reference_trajectory})
trajectory_evaluator(
outputs=result["messages"],
reference_outputs=reference_trajectory
)使用 pytest 运行评估:
bash
pytest test_trajectory.py --langsmith-output使用 evaluate 函数
创建一个 LangSmith 数据集,然后使用 evaluate 函数。数据集必须具有以下模式:
- input:调用智能体时使用的输入消息
{"messages": [...]}。 - output:智能体输出中预期的消息历史
{"messages": [...]}。对于轨迹评估,您可以选择只保留助手消息。
python
from langsmith import Client
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT
client = Client()
trajectory_evaluator = create_trajectory_llm_as_judge(
model="openai:o3-mini",
prompt=TRAJECTORY_ACCURACY_PROMPT,
)
def run_agent(inputs):
return agent.invoke(inputs)["messages"]
experiment_results = client.evaluate(
run_agent,
data="your_dataset_name",
evaluators=[trajectory_evaluator]
)TIP
要了解更多关于评估智能体的信息,请参阅 LangSmith 文档。
LangSmith 提供两种主要方式来运行评估:Vitest/Jest 集成和 evaluate 函数。
使用 vitest/jest 集成
ts
import * as ls from "langsmith/vitest";
// import * as ls from "langsmith/jest";
import { createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT } from "agentevals";
const trajectoryEvaluator = createTrajectoryLLMAsJudge({
model: "openai:o3-mini",
prompt: TRAJECTORY_ACCURACY_PROMPT,
});
ls.describe("trajectory accuracy", () => {
ls.test("accurate trajectory", {
inputs: {
messages: [
{ role: "user", content: "What is the weather in SF?" }
]
},
referenceOutputs: {
messages: [
new HumanMessage("What is the weather in SF?"),
new AIMessage({
content: "",
tool_calls: [
{ id: "call_1", name: "get_weather", args: { city: "SF" } }
]
}),
new ToolMessage({
content: "It's 75 degrees and sunny in SF.",
tool_call_id: "call_1"
}),
new AIMessage("The weather in SF is 75 degrees and sunny."),
],
},
}, async ({ inputs, referenceOutputs }) => {
const result = await agent.invoke({
messages: [new HumanMessage("What is the weather in SF?")]
});
ls.logOutputs({ messages: result.messages });
await trajectoryEvaluator({
inputs,
outputs: result.messages,
referenceOutputs,
});
});
});使用您的测试运行器运行评估:
bash
vitest run test_trajectory.eval.ts
# or
jest test_trajectory.eval.ts使用 evaluate 函数
创建一个 LangSmith 数据集,然后使用 evaluate 函数。数据集必须具有以下模式:
- input:调用智能体时使用的输入消息
{"messages": [...]}。 - output:智能体输出中预期的消息历史
{"messages": [...]}。对于轨迹评估,您可以选择只保留助手消息。
ts
import { evaluate } from "langsmith/evaluation";
import { createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT } from "agentevals";
const trajectoryEvaluator = createTrajectoryLLMAsJudge({
model: "openai:o3-mini",
prompt: TRAJECTORY_ACCURACY_PROMPT,
});
async function runAgent(inputs: any) {
const result = await agent.invoke(inputs);
return result.messages;
}
await evaluate(
runAgent,
{
data: "your_dataset_name",
evaluators: [trajectoryEvaluator],
}
);TIP
要了解更多关于评估智能体的信息,请参阅 LangSmith 文档。