第12课:LangSmith|大模型评测体系【基于LangSmith做问答、RAG、Agent效果自动评估】

文章目录
一、开篇导读
欢迎来到《LangSmith从入门到精通》专栏的第12节课。在上一节课中,你学会了如何创建和管理数据集,这是评测体系的“燃料”。本节课,我们将在此基础上建立一套完整的自动化评测体系——这是LLM应用从“可用”走向“可靠”的关键一跃。
评测在大模型应用开发中被严重低估。你换了一个Prompt模板,感觉回答“更流畅了”,但真的变好了吗?你的RAG应用在测试集上准确率不错,可上线后用户反馈却截然不同。你的Agent在简单任务上表现稳定,但遇到复杂的多步推理时就开始“兜圈子”。
这些问题不是“感觉”能解决的。LangSmith提供了一套完整的评测框架,涵盖离线评估与在线评估两大场景,内置30多种可复用的评估器模板,支持LLM-as-Judge和确定性代码评估器,并原生集成了RAG检索质量评估、Agent轨迹评估等关键能力。更重要的是,LangSmith倡导“Evaluation as a gate”(将评测作为质量闸门)的理念,让每一次Prompt更改或模型升级都必须经过评估套件的严格检验,才能进入生产环境。
本节课你将收获:
- 评测体系全景:理解LangSmith中离线评估与在线评估的分工与协作
- 内置评估器系统:掌握30+内置评估模板的分类选择与配置方法
- LLM-as-Judge原理:深入理解用大模型评估大模型的机制、优势与边界条件
- 自定义评估器开发:掌握Python确定性评估器的签名规范与实战应用
- RAG专项评估:针对检索质量与生成质量构建双维度评估体系,整合RAGAS框架
- Agent轨迹评估:突破“最终答案”局限,评估工具调用路径与单步决策质量
- 实验对比与CI集成:掌握LangSmith实验对比功能,将评估集成至CI流水线
二、知识前置铺垫
2.1 大模型评测的“不可能三角”
任何评估体系在设计之初都需要理解大模型评测面临的根本性挑战——我称之为“不可能三角”:
- 准确性(Accuracy) :评估结果是否与人类判断高度一致?
- 自动化程度(Automation) :能否无需人工干预地规模化运行?
- 成本(Cost) :评估本身的Token消耗和计算成本是否可控?
这三个目标不可同时最大化。例如,用GPT-4作为评估器(LLM-as-Judge)可以获得较高的准确性,但成本高昂;用基于规则的确定性评估器成本极低,但只能覆盖格式检查等简单场景;纯人工评估准确性最高,但自动化程度为零。
LangSmith的评估体系为这个“不可能三角”提供了务实的解决方案:通过支持多种评估器类型,让你在不同场景下合理权衡。离线评估阶段可以投入更多计算资源换取准确性,线上监控则依赖低成本定投规则。
2.2 为什么需要自动化评估
传统的单元测试之所以能“跑起来”,是因为代码逻辑是确定性的。你写assert a + b == c,结果只有True或False。LLM应用与此不同——同一个Prompt、同一个模型,每次回答可能有略微措辞上的变化,但可能全都正确。这导致传统assert无法直接复用。
评测的目标是用可量化的指标代替“我感觉”的主观判断。当Prompt从v2.1升级到v2.2时,评测套件能够告诉你:准确率从87%提升到了92%,但其中有3个测试用例的得分下降了,需要你重点关注。这种数据驱动的决策方式,是LLM应用超越“玩具阶段”的必备基础设施。
LangSmith评测体系的核心理念是“Evaluation as a gate”(将评测作为质量闸门)。每一次Prompt修改或模型升级,都必须通过评估套件,提供清晰的通过/失败结论——不仅仅是“准确率下降了多少”,而是“这次改动是否可上线”的确定性答案。
2.3 评估的三个核心组件
在LangSmith中运行一次评估需要三个关键组件:
- 数据集(Dataset) :一组测试输入(以及可选的期望输出)。这是你在第11节课已经掌握的内容。
- 目标函数(Target Function) :你想测试的应用模块——可以是单个LLM调用、一整个Chain,或是复杂的Agent工作流。
- 评估器(Evaluator) :对目标函数的输出进行打分的函数,可以是LLM-as-Judge、确定性代码、或自定义评分逻辑。
三、核心概念精讲
3.1 离线评估(Offline Evaluation)与在线评估(Online Evaluation)
LangSmith支持两种评估类型,分别对应不同的开发阶段和需求:
离线评估:上线前的质量检验
在开发或预发布环境中,基于固定数据集对目标函数进行批量评估。其目的是在Prompt调优、模型升级或链路重构后,量化验证效果变化,捕获回归问题。典型阈值设定可参考:Pass@3准确率≥85%(领域QA)、事实一致性≥90%(RAG)、精确匹配≥95%(工具输出)。
典型的离线评估工作流包括:创建数据集(手动构造或采自生产Trace)→ 配置评估器(可绑定至数据集实现自动化)→ 运行实验(遍历数据集、生成输出)→ 分析结果(对比不同实验版本的得分)。
在线评估:生产环境的实时监控
在真实用户流量上实时运行,对每条(或采样的)生产Trace应用评估器。其目的是在用户实际反馈之前主动发现问题,如检测到准确的RAG检索或幻觉等。在线评估通过自动化规则进行配置,支持LLM-as-Judge和自定义代码两种评估类型。
评估与监控的闭环的关键一步是:当在线评估发现异常时,可将失败的Trace一键添加到数据集中,作为新的测试用例纳入下次离线评估,形成闭环迭代。
3.2 三种评估器类型详解
LangSmith提供了三种核心评估器类型,覆盖了从确定性规则到AI评分的完整频谱。
| 评估器类型 | 原理 | 优势 | 局限 | 适用场景 |
|---|---|---|---|---|
| 预置LLM-as-Judge | 调用LLM,基于内置Prompt模板打分 | 开箱即用,覆盖安全、质量、轨迹等多维度 | 依赖LCM成本较高 | 需要快速建立质量基线 |
| 自定义LLM-as-Judge | 用户自定义评估Prompt,调用LLM打分 | 高度灵活 | 需要调优评测Prompt | 业务特定质量评估(风格、语气等) |
| 确定性代码评估器 | 纯Python/TS逻辑,无LLM调用 | 零成本、极快、确定性 | 只能评估客观规则 | 格式校验、精确匹配、数值范围检查 |
预置LLM-as-Judge是LangSmith最具特色和能力的内置评估体系。目前LangSmith提供了超过30种评估器模板,覆盖安全与安全、响应质量、轨迹分析、用户行为、多模态等五大类别。这些模板既可直接使用,也支持按需定制,且同时适用于在线监控和离线实验。
确定性代码评估器的设计哲学是将评估逻辑以函数形式直接写在UI界面中。它的运行环境支持numpy、pandas、sklearn等常用数据处理库,但无法访问互联网。评估器函数在线上监控场景接受run参数,在数据库场景接受run和example两个参数,用于与参考答案比对。
3.3 LLM-as-Judge的核心原理
LLM-as-Judge是LangSmith评估体系的核心技术,其基本思想是:用一个能力较强的大模型(如GPT-4o)来对另一个模型的输出进行评分。
LLM-as-Judge的背后逻辑是:经过大规模数据训练的大模型本身就具备了评判文本质量的能力——它能够判断一段回答是否回答了问题,是否包含幻觉信息,是否具有有害内容等。LangSmith将这种能力封装为标准化的Prompt模板,形成了开箱即用的评估器。
LLM-as-Judge的双重优势:
- 可扩展性:人工评估100个样本需要数小时,LLM-as-Judge可以在几分钟内完成,并且一致性远高于不同的标注员
- 灵活性:只需要修改Prompt模板,就可以调整评估标准、增加评估维度,无需重写代码
LLM-as-Judge的局限性:
- 评估模型本身的偏见会影响评估结果(如位置偏差、长度偏见等)
- 评估成本与评估所用模型的Token消耗直接相关
- 对于需要专业知识判断的场景,评估模型表现可能不如领域专家
不过,LangSmith也在持续改进这些不足,近年陆续推出了Few-shot示例校准、成对比较等工具,帮助提高评估一致性。
3.4 RAG评估的双维体系
RAG应用的评估天然包含两个相互关联的维度:
检索质量:评估系统能否为用户问题检索到正确的文档片段。即使生成模型再强,如果检索阶段返回了错误文档,最终的答案也不可能正确。常用的RAGAS检索指标包括体现搜索准确性的Context Precision(检索文档中相关文档的比例)、以及体现召回充分性的Context Recall(相关文档被成功检索的比例)。
生成质量:评估LLM基于检索到的文档生成的答案质量。这包括是否忠实于文档内容(Faithfulness)、是否能完整回答用户问题(Answer Relevancy)等。
一个完善的RAG评估体系需要在两个维度分别设置指标,防止“跑偏”。LangSmith既可以开箱即用地配置关于幻觉、文档相关性、答案有用性等维度的内置评估器,也可以深度集成RAGAS等专业框架,将评估日志输出到LangSmith中进行可视化管理。
3.5 Agent轨迹评估
Agent的最大特点是它的非确定性路径。对于同一个用户问题,同一个Agent在不同的执行中可能会选择不同的工具、不同的调用顺序,甚至不同的工具参数。
传统的评估方法只能看到最终输出,无法判断Agent的决策过程是否合理。LangSmith的轨迹评估能力填补了这一空白。LangSmith提供三种层次的Agent评估:
- 最终响应评估:评估Agent的最终输出是否正确
- 轨迹评估:评估Agent是否选择了预期的工具调用路径
- 单步评估:评估Agent在某个特定步骤的决策质量(例如是否为某个查询选择了正确的检索工具)
轨迹评估的实现依赖于追踪树。自定义评估器通过解析Root Run下的所有子Run,识别出所有工具调用的序列,与预期路径进行比较。LangSmith在平台层面已将轨迹评估作为Agent评估的核心能力之一。
四、原理底层剖析
4.1 LangSmith评估流程的数据流
当调用client.evaluate()时,程序遍历数据集中的每个Example,将Example中的inputs传递给目标函数执行,并将函数的输出和中间Run记录为Experiment中的新Run。随后,每个评估器都获得Run对象(以及可选的Example参考输出),执行评分后,通过Feedback API将打分结果写回Run。
4.3 LLM-as-Judge的Token流转与成本模型
当使用LLM-as-Judge评估器时,LangSmith会在内部发起一次对评估模型的调用。评估器会提取Run的输入和输出,将其填充到评估Prompt模板的占位符中,然后将完整模板发给评估模型。评估模型根据指令返回一个分数,LangSmith将其转换为Feedback对象关联到Run上。
在成本方面,评估模型的Token消耗会单独计入你的LangSmith账单(如果评估模型是OpenAI的话)。每个评估用例的Token消耗主要来自评估Prompt的长度(包含被评估的长回答)。在涉及RAG的场景中使用内部评估时,成本会成倍增加。
4.4 确定性代码评估器的沙箱执行
LangSmith中的一个独特能力是直接在UI中嵌入Python/TypeScript代码并安全执行。该运行环境提供了常用数据处理库,但无法访问互联网。当触发评估时,LangSmith后端将函数编译进安全的Python解释器中,传入Run对象所在有效负载,执行后将返回的字典转成多个Feedback条目。通过这种设计,LangSmith在保证安全的前提下实现了灵活的可扩展性。
五、环境配置手把手实战
5.1 确认LangSmith追踪配置
继续使用前几节课配置的.env文件:
# .env
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=lsv2_pt_你的Key
LANGSMITH_PROJECT=lesson12-evaluation-demo
OPENAI_API_KEY=sk-你的Key
5.2 安装必要依赖
pip install -U langsmith langchain langchain-openai pandas
5.3 创建测试数据集
通过Python SDK创建一个用于评测的问答数据集:
# 文件名: create_eval_dataset.py
from langsmith import Client
client = Client()
dataset_name = "qa_eval_dataset"
try:
dataset = client.read_dataset(dataset_name=dataset_name)
print(f"📁 数据集已存在: {dataset_name}")
except:
dataset = client.create_dataset(
dataset_name=dataset_name,
description="问答评估基准数据集",
data_type="kv"
)
examples = [
{"inputs": {"question": "什么是LangSmith?"},
"outputs": {"answer": "LangSmith是LangChain官方推出的LLM应用可观测性与评估平台。"}},
{"inputs": {"question": "LCEL有什么优势?"},
"outputs": {"answer": "LCEL支持并行执行、流式输出,并能无缝集成LangSmith追踪。"}},
{"inputs": {"question": "如何评估RAG应用的质量?"},
"outputs": {"answer": "通过创建测试数据集、运行RAG应用、使用评估器来衡量检索和生成质量。"}}
]
client.create_examples(dataset_id=dataset.id, examples=examples)
print(f"✅ 创建数据集: {dataset_name},包含 {len(examples)} 个示例")
六、完整可运行代码案例
6.1 基础评估
通过内置评估器对问答链进行自动化评估,直观理解评估三要素。
# 文件名: basic_evaluation.py
from langsmith import Client
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
client = Client()
dataset_name = "qa_eval_dataset"
# 定义目标函数(待评估的应用)
def answer_question(inputs: dict) -> dict:
prompt = PromptTemplate.from_template("请简洁回答:{question}")
chain = prompt | ChatOpenAI(model="gpt-3.5-turbo", temperature=0) | StrOutputParser()
answer = chain.invoke({"question": inputs["question"]})
return {"output": answer}
# 运行评估
experiment_results = client.evaluate(
target=answer_question,
data=dataset_name,
evaluators=[
"exact_match",
"contains",
"qa",
"embedding_distance"
],
experiment_prefix="baseline_eval",
metadata={"version": "gpt-3.5-turbo", "description": "初始基线评估"}
)
print(f"✅ 评估完成!实验名称: {experiment_results['experiment_name']}")
print("📊 请在LangSmith的Tests & Experiments选项卡中查看详细结果")
6.2 RAG应用全链路评估
构建完整的RAG链路,从检索到生成进行双维度评估。
# 文件名: rag_evaluation.py
import os, bs4
from langsmith import Client
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableConfig
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
client = Client()
dataset_name = "rag_eval_dataset"
rag_dataset = client.create_dataset(
dataset_name=dataset_name, description="RAG评估数据集"
)
client.create_examples(dataset_id=rag_dataset.id, examples=[
{"inputs": {"question": "What is Task Decomposition in LLM agents?"},
"outputs": {"answer": "Task decomposition is the process of breaking down a complex task into smaller sub-tasks.",
"context_precision": "high"}},
])
# 初始化RAG索引
urls = ["https://lilianweng.github.io/posts/2023-06-23-agent/"]
docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=250, chunk_overlap=0)
doc_splits = text_splitter.split_documents(docs_list)
vectorstore = InMemoryVectorStore.from_documents(
documents=doc_splits, embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever(k=4)
# 定义目标函数
def rag_qa(inputs: dict) -> dict:
question = inputs["question"]
docs = retriever.invoke(question)
docs_content = "\n\n".join(doc.page_content for doc in docs)
prompt = ChatPromptTemplate.from_messages([
("system", "基于以下文档回答用户问题。如果文档不包含答案,请说\"未找到相关信息\"。\n\n文档:{context}"),
("human", "{question}")
])
chain = prompt | ChatOpenAI(model="gpt-4", temperature=0)
response = chain.invoke({"context": docs_content, "question": question})
return {"output": response.content}
# 创建RAG评估实验
eval_result = client.evaluate(
target=rag_qa,
data=dataset_name,
evaluators=[], # 后续捆绑
experiment_prefix="rag_eval",
max_concurrency=5
)
6.3 使用RAGAS评估RAG质量
LangSmith与RAGAS深度集成,将RAGAS的评估结果输出到LangSmith中进行可视化管理。
# 文件名: ragas_integration.py
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
from langsmith import Client
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
import pandas as pd
client = Client()
dataset_name = "ragas_eval_dataset"
try:
dataset = client.read_dataset(dataset_name=dataset_name)
except:
dataset = client.create_dataset(dataset_name=dataset_name, description="RAGAS评估数据集")
ragas_df = pd.DataFrame([
{
"question": "What is Task Decomposition?",
"answer": "Task decomposition is breaking down a complex task into smaller sub-tasks.",
"contexts": ["Agents can plan by breaking down a large task into smaller sub-tasks.", "This improves task execution efficiency."],
"ground_truth": "Task decomposition is the process of dividing a complex task into smaller, manageable sub-tasks."
}
])
result = evaluate(
dataset=ragas_df,
metrics=[faithfulness, answer_relevancy, context_precision],
llm=ChatOpenAI(model="gpt-4"),
embeddings=OpenAIEmbeddings()
)
for idx in range(len(ragas_df)):
client.create_example(
dataset_id=dataset.id,
inputs={"question": ragas_df.iloc[idx]["question"]},
outputs={
"answer": ragas_df.iloc[idx]["answer"],
"faithfulness": result.iloc[idx]["faithfulness"],
"answer_relevancy": result.iloc[idx]["answer_relevancy"]
}
)
print(f"✅ 已写入示例 {idx}: {ragas_df.iloc[idx]['question']}")
print("🎯 RAGAS评估结果已写入LangSmith数据集")
6.4 Agent轨迹评估
评估Agent的思考路径和工具调用序列。
# 文件名: agent_trajectory_evaluation.py
import operator
from langsmith import Client, traceable
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.graph import StateGraph, END, START, MessagesState
from langgraph.prebuilt import ToolNode
client = Client()
dataset_name = "agent_trajectory_dataset"
try:
dataset = client.read_dataset(dataset_name=dataset_name)
except:
dataset = client.create_dataset(dataset_name=dataset_name, description="Agent轨迹评估数据集")
client.create_examples(dataset_id=dataset.id, examples=[
{"inputs": {"question": "我想退款最近买的耳机", "expected_tools": ["refund_policy", "check_order"]},
"outputs": {"final_answer": "已为您查询订单状态和退款政策"}}
])
@tool
@traceable(name="check_order", run_type="tool")
def check_order(order_id: str) -> str:
"""查询订单状态"""
return f"订单{order_id}状态:已发货,购买7天内可申请退款"
@tool
@traceable(name="refund_policy", run_type="tool")
def refund_policy() -> str:
"""查询退款政策"""
return "30天内未拆封可退全款,已拆封只能换货"
tools = [check_order, refund_policy]
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0).bind_tools(tools)
def call_model(state: MessagesState):
response = llm.invoke(state["messages"])
return {"messages": [response]}
def should_continue(state: MessagesState):
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "tools"
return END
# 构建Agent
workflow = StateGraph(MessagesState)
workflow.add_node("agent", call_model)
workflow.add_node("tools", ToolNode(tools))
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")
graph = workflow.compile()
# 复杂Agent评估的三个维度
def final_response_eval(run, example):
"""评估最终回答是否有效"""
output = run.outputs.get("output", "")
if "退款" in output.lower() or "订单" in output.lower():
return {"final_response_valid": 1}
return {"final_response_valid": 0}
def trajectory_eval(run, example):
"""评估Agent是否调用了预期的工具"""
expected_tools = example.inputs.get("expected_tools", [])
tool_calls = []
for child in run.child_runs:
if child.run_type == "tool":
tool_calls.append(child.name)
if set(expected_tools).issubset(set(tool_calls)):
return {"trajectory_match": 1}
return {"trajectory_match": 0}
def single_step_eval(run, example):
"""评估Agent第一步是否选择了正确的工具"""
first_tool = None
for child in run.child_runs:
if child.run_type == "tool":
first_tool = child.name
break
if first_tool == "check_order":
return {"first_step_correct": 1}
return {"first_step_correct": 0}
eval_result = client.evaluate(
target=lambda inputs: {"output": graph.invoke({"messages": [("user", inputs["question"])]})["messages"][-1].content},
data=dataset_name,
evaluators=[final_response_eval, trajectory_eval, single_step_eval],
experiment_prefix="agent_trajectory_eval"
)
6.5 自定义代码评估器
通过Python SDK实现确定性规则评估器。
# 文件名: custom_evaluator.py
from langsmith import Client
def exact_match_evaluator(run, example):
"""精确匹配评估器"""
actual = run.outputs.get("answer", "").strip().lower()
expected = example.outputs.get("answer", "").strip().lower()
return {"exact_match": 1 if actual == expected else 0}
def contains_keywords_evaluator(run, example):
"""关键词包含评估器"""
keywords = example.inputs.get("required_keywords", [])
actual = run.outputs.get("answer", "").lower()
matched = all(kw in actual for kw in keywords)
return {"keywords_found": 1 if matched else 0}
def length_threshold_evaluator(run, example):
"""长度阈值评估器"""
min_len = example.inputs.get("min_length", 10)
actual = run.outputs.get("answer", "")
return {"min_length_ok": 1 if len(actual) >= min_len else 0}
def structure_evaluator(run, example):
"""JSON结构验证评估器"""
import json
output = run.outputs.get("output", "")
try:
data = json.loads(output)
if "result" in data and isinstance(data["result"], str):
return {"valid_json_structure": 1}
except:
pass
return {"valid_json_structure": 0}
client = Client()
dataset = client.read_dataset(dataset_name="qa_eval_dataset")
eval_result = client.evaluate(
target=answer_question,
data=dataset.id,
evaluators=[exact_match_evaluator, length_threshold_evaluator],
experiment_prefix="custom_eval"
)
6.6 实验对比与版本迭代
将当前版本与基线版本进行对比,评估Prompt优化的实际效果。
# 文件名: experiment_comparison.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
baseline_prompt = PromptTemplate.from_template("请回答:{question}")
optimized_prompt = PromptTemplate.from_template(
"你是一个资深的AI专家,请用专业且易懂的语言回答:{question}"
)
def baseline_chain(question):
return (baseline_prompt | ChatOpenAI(model="gpt-4", temperature=0)).invoke({"question": question}).content
def optimized_chain(question):
return (optimized_prompt | ChatOpenAI(model="gpt-4", temperature=0)).invoke({"question": question}).content
experiment_results = client.evaluate(
target=optimized_chain,
data=dataset_name,
evaluators=["qa", "embedding_distance"],
experiment_prefix="v2_optimized_prompt"
)
print("\n🎯 请登录LangSmith进行对比分析:")
print(" 1. 点击 Experiments 选项卡")
print(" 2. 勾选 baseline_eval 和 v2_optimized_prompt 实验")
print(" 3. 点击 Compare 按钮")
print(" 4. 观察各评估指标的对比变化")
6.7 大规模评估优化
高并发与批量处理的最佳实践。
# 文件名: large_scale_evaluation.py
import asyncio
from langsmith import aevaluate
dataset = client.read_dataset(dataset_name=dataset_name)
async def atarget(inputs):
await asyncio.sleep(0.1)
return {"answer": f"这是关于'{inputs['question']}'的模拟回答"}
results = await aevaluate(
target=atarget,
data=dataset.id,
evaluators=[],
max_concurrency=20,
num_repetitions=3
)
6.8 在线评估配置与生产监控
通过Python API配置在线评估规则。
# 文件名: online_evaluation_setup.py
from langsmith import Client
client = Client()
# 获取项目信息
project = client.read_project(project_name="production-rag-app")
print(f"Project ID: {project.id}")
# 创建自动化规则(示例代码)
# 在线评估器在UI中配置,此示例展示如何通过API读取规则
rules = client.list_rules()
for rule in rules:
print(f"规则: {rule.name} - 评估器: {rule.evaluators}")
七、代码逐行详解
7.1 client.evaluate()核心参数
根据LangSmith SDK源码,evaluate函数的关键参数包括:
experiment_results = client.evaluate(
target=target_function, # 待评估的目标,可以是普通函数或Runnable
data=dataset_name, # 数据集名称或ID
evaluators=[...], # 评估器列表
summary_evaluators=[...], # 对整个数据集进行的聚合评估
experiment_prefix="baseline", # 实验名称前缀
metadata={"version": "1.0"}, # 附加元数据
max_concurrency=5, # 最大并发执行数
num_repetitions=1, # 每个数据项重复执行的次数
)
7.2 自定义评估器的签名规范
确定性代码评估器接受run和example两个参数,返回一个分数字典:
def perform_eval(run, example):
inputs = run['inputs'] # 目标函数的输入
outputs = run['outputs'] # 目标函数的输出
reference = example['outputs'] # 参考答案(可选)
score = ... # 你的评分逻辑
return {"metric_name": score} # 返回字典,支持多指标
如果是线上监控场景的单参数版本,则只接受run参数。
八、常见坑点与避坑指南
8.1 评估器绑定时机问题
典型症状:在数据集上配置了评估器,但运行实验时没有自动触发评估。
根本原因:LangSmith规定评估器绑定只影响配置之后创建的实验。绑定评估器之前已运行的实验不会被追溯评估。
解决方案:先绑定评估器,再运行实验。绑定后新创建的实验会自动触发。
8.2 LLM-as-Judge成本失控
典型症状:原本预算内的评估任务,账单大幅超出预期。
解决方案:
- 使用降级模型:用GPT-3.5-turbo代替GPT-4进行评估
- 合理设置在线评估采样率
- 避免在评估Prompt中包含过长的Context
- 仔细检查高版本SDK中“steps”特性的额外Token开销
8.3 确定性评估器环境限制
LangSmith中自定义代码评估器的运行环境无法访问互联网,并且不允许安装额外pip包。
解决方案:在本地充分测试评估逻辑,确保仅依赖允许的库。评估器函数代码需内联编写在UI中。因此复杂性较高的评估建议转为LLM-as-Judge方式。
8.4 Agent轨迹评估中的Run嵌套解析
Agent的多轮工具调用在LangSmith中形成多层嵌套的子Run结构。需要递归解析child_runs才能完整还原整个调用序列。
解决方案:
def collect_tool_calls(run):
tool_calls = []
if run.run_type == "tool":
tool_calls.append(run.name)
for child in run.child_runs or []:
tool_calls.extend(collect_tool_calls(child))
return tool_calls
8.5 数据集与被评估函数输入输出不匹配
评估器运行时会自动将Example的inputs字段完整传递给目标函数。如果数据集中定义了inputs和expected_outputs字段,需确保目标函数的输入类型兼容。常见错误是在数据集中添加了额外字段但函数未做兼容处理。
九、企业级落地最佳实践
9.1 构建三层评估金字塔
| 层级 | 评估类型 | 覆盖范围 | 频率 |
|---|---|---|---|
| L1 烟雾测试 | 确定性代码评估器 | 5-10个核心用例 | 每次PR |
| L2 回归测试 | LLM-as-Judge + 内置评估器 | 50-200个代表性用例 | 每次发布 |
| L3 全量基准测试 | 多维度复合评估 | 500+全量用例 | 每周/模型升级 |
9.2 Agent评估Checklist
LangSmith官方建议在构建Agent评估体系时遵循以下步骤:先人工审阅20-50条真实Agent执行轨迹,再基于观察结果定义明确的单个任务成功标准,启动最简可行的评估器,逐步扩展覆盖范围。Agent评估至少应覆盖最终响应正确性、轨迹工具调用路径合理性、单步决策质量三个层面。
9.3 CI/CD集成
# .github/workflows/eval.yml
- name: Run Evaluation Suite
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
python run_evaluation.py
- name: Check Evaluation Threshold
run: |
pass_rate=$(python get_eval_score.py)
if (( $(echo "$pass_rate < 0.85" | bc -l) )); then
echo "评估未通过: 通过率低于85%"
exit 1
fi
9.4 从生产问题到离线评估的闭环
- 在线评估发现异常Trace
- 在线评估发现的问题Trace通过UI一键加入数据集
- 标注员修正期望输出
- 运行离线评估验证修复效果
- 确认修复后部署上线
十、本节知识点总结
| 维度 | 核心内容 | 关键工具/方法 |
|---|---|---|
| 评估类型 | 离线评估 vs 在线评估 | evaluate()函数 / 自动化规则 |
| 内置评估器 | 30+预置模板 | exact_match, qa, embedding_distance, trajectory |
| LLM-as-Judge | 用大模型评估大模型输出 | 预置模板/自定义Prompt模板 |
| 确定性评估器 | 纯逻辑判断,零成本 | Python/TypeScript代码评估器 |
| RAG评估 | 检索质量 + 生成质量 | RAGAS集成、文档相关性、幻觉检测 |
| Agent轨迹评估 | 评估工具调用路径 | trajectory_eval / single_step_eval |
| 实验对比 | 版本差异量化分析 | Compare视图、图表对比 |
| 生产闭环 | 在线发现问题 → 加入数据集 → 离线验证 | Annotation Queue + Dataset |
十一、课后思考练习题
练习题1:理论理解
1.1 解释LLM-as-Judge的局限性,以及在什么场景下确定性代码评估器是更好的选择。
1.2 Agent轨迹评估与最终响应评估的核心差异是什么?为什么两者缺一不可?
1.3 假设你想评估RAG应用的检索质量,但数据集中没有标注“应该检索到哪些文档”,你如何设计评估方案?
练习题2:动手实践
2.1 基于basic_evaluation.py扩展,实现对5个以上自定义数据集示例的评估,同时支持精确匹配和语义相似度评估(嵌入距离)。
2.2 使用RAGAS完整评估你自己的RAG应用,输出faithfulness、answer_relevancy、context_precision三指标,并分析得分最低的维度。
2.3 构建一个包含至少3个工具的Agent,编写轨迹评估器验证预期工具调用顺序,并在评估报告中截图展示评估结果。
练习题3:场景设计
3.1 为智能客服系统设计一套评估体系(包含离线评估和在线评估两套方案),列出至少5个评估指标及其触发条件。
3.2 你现在需要验证从GPT-3.5-turbo升级到GPT-4o的效果,请详细描述你在LangSmith中如何操作实验对比。
下节课预告:
第13节课我们将深入探讨LangSmith在离线/内网环境中的部署方案,包括私有化配置适配方案、混合部署架构、数据合规与安全策略,以及企业版自托管的最佳实践。
下一节课见!
🔗《20节课 LangSmith 从入门到精通》系列课程导航
🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)