关于 langsmith-evaluator
langsmith-evaluator 介绍在 LangSmith 中定义、运行和上传评估器的方法,面向需要检查 Agent 输出或执行轨迹的开发者。内容涵盖基于 LLM 的评审与自定义代码评估,并区分本地和在线评估流程。
主要功能
- 01定义 LLM 评审评估器
- 02编写确定性代码评估器
- 03捕获运行输出与执行轨迹
- 04运行本地及在线评估
- 05将代码评估器上传至 LangSmith
适用场景
- 01按参考答案评估 Agent 输出
- 02验证工具调用轨迹顺序
- 03对生产运行执行实时质量检查
- 04在 LangSmith 数据集上运行实验
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ langchain-ai/ skills-benchmarks --skill langsmith-evaluator安装后在 Claude Code 中输入/langsmith-evaluator确认已加载。
详细介绍
LANGSMITH_API_KEY=lsv2_pt_your_api_key_here # REQUIRED
LANGSMITH_PROJECT=your-project-name # Check this to know which project has traces
LANGSMITH_WORKSPACE_ID=your-workspace-id # Optional: for org-scoped keys
OPENAI_API_KEY=your_openai_key # For LLM as Judge
必须进行身份验证:设置 LANGSMITH_API_KEY 环境变量,或在 CLI 命令中传入 --api-key 标志(首选):
langsmith evaluator list --api-key $LANGSMITH_API_KEY
重要: 在查询或与 LangSmith 交互之前,务必检查环境变量或 .env 文件中的 LANGSMITH_PROJECT。这会告知你相关跟踪记录和数据所在的项目。如果 LangSmith 项目不可用,请自行判断并确定合适的项目。
Python 依赖项
pip install langsmith langchain-openai python-dotenv
CLI 工具(用于上传评估器)
curl -sSL https://raw.githubusercontent.com/langchain-ai/langsmith-cli/main/scripts/install.sh | sh
JavaScript 依赖项
npm install langsmith openai
<crucial_requirement>
黄金法则:先检查,再实现
关键: 在编写任何评估器或提取逻辑之前,你必须:
- 运行你的 Agent,使用示例输入并捕获实际输出
- 检查输出——打印输出、查询 LangSmith 跟踪记录,并了解确切结构
- 只有在此之后,才能编写处理该输出的代码
输出结构会因框架、Agent 类型和配置而有很大差异。切勿假设其结构——务必先验证。当输出中不包含所需数据时,查询 LangSmith 跟踪记录,了解如何从执行过程中提取数据。 </crucial_requirement>
<evaluator_format>
离线评估器与在线评估器
离线评估器(附加到数据集):
- 函数签名:
(run, example)——同时接收运行输出和数据集示例 - 用途:将 Agent 输出与数据集中的预期值进行比较
- 上传时使用:
--dataset "Dataset Name"
在线评估器(附加到项目):
- 函数签名:
(run)——仅接收运行输出,不接收example参数 - 用途:对生产环境中的运行进行实时质量检查(没有参考数据)
- 上传时使用:
--project "Project Name"
关键——返回格式:
- 每个评估器只返回一个指标。需要多个指标时,请创建多个评估器函数。
- 不要返回
{"metric_name": value}或指标列表,否则会报错。
关键——本地评估器与已上传评估器的差异:
本地 evaluate() | 上传到 LangSmith | |
|---|---|---|
| 列名 | Python:根据函数名自动生成。TypeScript:必须包含 key 字段,否则列名为空 | 根据上传时设置的评估器名称生成。不要包含 key——否则会创建重复列 |
Python run 类型 | RunTree 对象 → run.outputs(属性访问) | dict → run["outputs"](下标访问)。兼容两种情况:run.outputs if hasattr(run, "outputs") else run.get("outputs", {}) |
TypeScript run 类型 | 始终使用属性访问:run.outputs?.field | 始终使用属性访问:run.outputs?.field |
| Python 返回值 | {"score": value, "comment": "..."} | {"score": value, "comment": "..."} |
| TypeScript 返回值 | { key: "name", score: value, comment: "..." } | { score: value, comment: "..." } |
| </evaluator_format> |
<evaluator_types>
- LLM-as-Judge - 使用大模型对输出评分。最适用于主观质量评估(准确性、实用性、相关性)。
- 自定义代码 - 确定性逻辑。最适用于客观检查(完全匹配、执行轨迹验证、格式合规性)。 </evaluator_types>
<llm_judge>
LLM-as-Judge 评估器
注意: CLI 目前不支持上传 LLM-as-Judge 评估器——仅支持代码评估器。对于针对数据集的评估,强烈建议定义本地评估器,并通过 evaluate(evaluators=[...]) 使用。
class Grade(TypedDict): reasoning: Annotated[str, ..., "Explain your reasoning"] is_accurate: Annotated[bool, ..., "True if response is accurate"]
judge = ChatOpenAI(model="gpt-4o-mini", temperature=0).with_structured_output(Grade, method="json_schema", strict=True)
async def accuracy_evaluator(run, example): run_outputs = run.outputs if hasattr(run, "outputs") else run.get("outputs", {}) or {} example_outputs = example.outputs if hasattr(example, "outputs") else example.get("outputs", {}) or {} grade = await judge.ainvoke([{"role": "user", "content": f"Expected: {example_outputs}\nActual: {run_outputs}\nIs this accurate?"}]) return {"score": 1 if grade["is_accurate"] else 0, "comment": grade["reasoning"]}
</python>
<typescript>
```javascript
import OpenAI from "openai";
const openai = new OpenAI();
async function accuracyEvaluator(run, example) {
const runOutputs = run.outputs ?? {};
const exampleOutputs = example.outputs ?? {};
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
temperature: 0,
response_format: { type: "json_object" },
messages: [
{ role: "system", content: 'Respond with JSON: {"is_accurate": boolean, "reasoning": string}' },
{ role: "user", content: `Expected: ${JSON.stringify(exampleOutputs)}\nActual: ${JSON.stringify(runOutputs)}\nIs this accurate?` }
]
});
const grade = JSON.parse(response.choices[0].message.content);
return { score: grade.is_accurate ? 1 : 0, comment: grade.reasoning };
}
<code_evaluators>
自定义代码评估器
编写评估器前:
- 检查数据集,了解预期的字段名称(参见上方的 Golden Rule)
- 测试运行函数,并确认其输出结构与数据集架构一致
- 查询 LangSmith 跟踪记录以调试任何不匹配
<run_functions>
定义运行函数
运行函数会执行你的 Agent,并返回用于评估的输出。
重要——先测试运行函数: 编写评估器前,你必须测试运行函数并检查实际输出结构。输出形式会因框架、Agent 类型和配置而异。
调试工作流:
- 使用示例输入运行一次 Agent
- 查询跟踪记录以查看执行结构
- 打印原始输出,并对照跟踪记录验证输出是否包含正确的数据
- 根据需要调整运行函数
- 确认输出与数据集架构一致
尽最大努力让运行函数的输出与数据集架构一致。 这样评估器就会简单且可复用。如果无法匹配,评估器必须知道如何提取并比较双方的正确字段。
```python def run_agent(inputs: dict) -> dict: result = your_agent.run(inputs) # ALWAYS inspect output shape first - run this, check the print, query traces print(f"DEBUG - type: {type(result)}, keys: {result.keys() if hasattr(result, 'keys') else 'N/A'}") print(f"DEBUG - value: {result}") return {"output": result} # Adjust to match your dataset schema ``` ```javascript async function runAgent(inputs) { const result = await yourAgent.invoke(inputs); // ALWAYS inspect output shape first console.log("DEBUG - type:", typeof result, "keys:", Object.keys(result)); console.log("DEBUG - value:", result); return { output: result }; // Adjust to match your dataset schema } ```捕获执行轨迹
对于执行轨迹评估,运行函数必须捕获执行期间的工具调用。
重要: 运行输出格式会因框架和 Agent 类型而有很大差异。实现前,你必须先检查:
LangGraph Agent(LangChain OSS): 使用 stream_mode="debug" 和 subgraphs=True 捕获嵌套子 Agent 的工具调用。
import uuid
def run_agent_with_trajectory(agent, inputs: dict) -> dict:
config = {"configurable": {"thread_id": f"eval-{uuid.uuid4()}"}}
trajectory = []
final_result = None
for chunk in agent.stream(inputs, config=config, stream_mode="debug", subgraphs=True):
# STEP 1: Print chunks to understand the structure
print(f"DEBUG chunk: {chunk}")
# STEP 2: Write extraction based on YOUR observed structure
# ... your extraction logic here ...
# IMPORTANT: After running, query the LangSmith trace to verify
# your trajectory data is complete. Default output may be missing
# tool calls that appear in the trace.
return {"output": final_result, "trajectory": trajectory}
自定义 / 非 LangChain Agent:
- 先检查输出——运行 Agent 并检查结果结构。执行轨迹数据可能已包含在输出中(例如
result.tool_calls、result.steps等) - 回调 / 钩子——如果框架支持执行回调,请注册一个钩子,在每次调用时记录工具名称
- 解析执行日志——作为最后手段,从结构化日志或跟踪数据中提取工具名称
关键是在工具执行时捕获工具名称,而不是在定义时捕获。 </run_functions>
## 将评估器上传到 LangSmith重要 — 自动运行行为:
上传到数据集的评估器会在你对该数据集运行实验时自动运行。你无需将它们传递给 evaluate()——只需针对数据集运行 Agent,上传的评估器就会自动执行。
重要 — 本地与已上传的评估器:
已上传的评估器在沙盒环境中运行,可访问的包非常有限。只能使用内置库或标准库导入,并将所有导入语句放在评估器函数体内部。对于数据集(离线)评估器,建议先使用 evaluate(evaluators=[...]) 在本地运行——这样你就可以访问所有包。
重要 — 代码评估器与结构化评估器:
- 代码评估器(CLI 上传的评估器):在无法使用外部包的受限环境中运行。适用于确定性逻辑(精确匹配、轨迹验证)。
- 结构化评估器(LLM 作为评审):通过 LangSmith UI 配置,使用特定的载荷格式,包含模型、提示词和架构。CLI 目前不支持此格式。
重要 — 选择正确的目标:
--dataset:签名为(run, example)的离线评估器——用于与预期值进行比较--project:签名为(run)的在线评估器——用于实时质量检查
必须指定其中一项。不支持全局评估器。
# List all evaluators
langsmith evaluator list --api-key $LANGSMITH_API_KEY
# Upload offline evaluator (attached to dataset)
langsmith evaluator upload my_evaluators.py \
--name "Trajectory Match" --function trajectory_evaluator \
--dataset "My Dataset" --replace --api-key $LANGSMITH_API_KEY
# Upload online evaluator (attached to project)
langsmith evaluator upload my_evaluators.py \
--name "Quality Check" --function quality_check \
--project "Production Agent" --replace --api-key $LANGSMITH_API_KEY
# Delete
langsmith evaluator delete "Trajectory Match" --api-key $LANGSMITH_API_KEY
重要 — 安全提示:
- CLI 会在执行破坏性操作前提示确认
- 除非用户明确要求,否则切勿使用
--yes标志
<best_practices>
- 对 LLM 评审使用结构化输出——比解析自由文本更可靠
- 让评估器与数据集类型匹配
- 最终回答 → 使用 LLM 作为评审来评估质量
- 轨迹 → 使用自定义代码来评估序列
- 对 LLM 评审使用异步方式——支持并行评估
- 独立测试评估器——先使用已知的好坏示例进行验证
- 选择合适的语言
- Python:用于 Python Agent 和 langchain 集成
- JavaScript:用于 TypeScript/Node.js Agent </best_practices>
<running_evaluations>
运行评估
已上传的评估器会在运行实验时自动运行——无需编写代码。本地评估器则需直接传入,用于开发或测试。
```python from langsmith import evaluateUploaded evaluators run automatically
results = evaluate(run_agent, data="My Dataset", experiment_prefix="eval-v1")
Or pass local evaluators for testing
results = evaluate(run_agent, data="My Dataset", evaluators=[my_evaluator], experiment_prefix="eval-v1")
</python>
<typescript>
```javascript
import { evaluate } from "langsmith/evaluation";
// Uploaded evaluators run automatically
const results = await evaluate(runAgent, {
data: "My Dataset",
experimentPrefix: "eval-v1",
});
// Or pass local evaluators for testing
const results = await evaluate(runAgent, {
data: "My Dataset",
evaluators: [myEvaluator],
experimentPrefix: "eval-v1",
});
丰富的实验元数据
将 metadata={...} 传递给 evaluate(),即可为实验添加结构化信息标签。保留键 models、prompts 和 tools 会自动填充 LangSmith 实验界面中的专用列,便于按模型、提供方、提示词版本或工具范围筛选和比较运行结果。其他键均以自由格式元数据的形式存储。
results = evaluate( run_agent, data="My Dataset", evaluators=[my_evaluator], experiment_prefix="eval-v1", metadata=EXPERIMENT_METADATA, )
</python>
<typescript>
```javascript
const EXPERIMENT_METADATA = {
models: ["openai:gpt-4o-mini"],
prompts: ["my-org/my-eval-prompt:abc12345"],
tools: [
{
name: "web_search",
description: "Search the web for information",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
],
};
const results = await evaluate(runAgent, {
data: "My Dataset",
evaluators: [myEvaluator],
experimentPrefix: "eval-v1",
metadata: EXPERIMENT_METADATA,
});
不要将机密信息放入元数据中——元数据会持久保存并显示在 LangSmith UI 中。 </running_evaluations>
## 常见问题**输出与预期不符:**查询 LangSmith 跟踪记录。它会显示每个步骤的精确输入和输出——将你找到的内容与要提取的内容进行比较。
**每个评估器只能有一个指标:**返回 {"score": value, "comment": "..."}。如需多个指标,请创建多个独立函数。
**字段名称不匹配:**运行函数的输出必须与数据集架构完全一致。先使用 client.read_example(example_id) 检查数据集。
**RunTree 与 dict(仅限 Python):**本地 evaluate() 会传入 RunTree,已上传的评估器则接收 dict。请同时处理这两种类型:
run_outputs = run.outputs if hasattr(run, "outputs") else run.get("outputs", {}) or {}
TypeScript 始终使用属性访问:run.outputs?.field