在这里插入图片描述

文章目录


一、开篇导读

欢迎来到《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中运行一次评估需要三个关键组件:

  1. 数据集(Dataset) :一组测试输入(以及可选的期望输出)。这是你在第11节课已经掌握的内容。
  2. 目标函数(Target Function) :你想测试的应用模块——可以是单个LLM调用、一整个Chain,或是复杂的Agent工作流。
  3. 评估器(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评估流程的数据流

渲染错误: Mermaid 渲染失败: No diagram type detected matching given configuration for text: 用户/CI触发评估 → Client.evaluate() → 从数据集加载Examples → 遍历每个Example → 调用目标函数 → 记录输出和Run → 调用评估器列表 → 为每个评估指标生成Feedback → 聚合为Experiment

当调用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 自定义评估器的签名规范

确定性代码评估器接受runexample两个参数,返回一个分数字典:

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字段完整传递给目标函数。如果数据集中定义了inputsexpected_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 从生产问题到离线评估的闭环

  1. 在线评估发现异常Trace
  2. 在线评估发现的问题Trace通过UI一键加入数据集
  3. 标注员修正期望输出
  4. 运行离线评估验证修复效果
  5. 确认修复后部署上线

十、本节知识点总结

维度 核心内容 关键工具/方法
评估类型 离线评估 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 从入门到精通》系列课程导航

去订阅

🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐