理论提供基本知识,但实际应用能加深理解。学习如何使用LangSmith评估LangChain代理。这包括设置一个简单代理,创建评估数据集,让代理针对该数据集运行,并实现自定义评估逻辑,以程序化方式检查其表现。本练习假设您已设置好LangSmith并在环境中配置了API密钥(LANGCHAIN_API_KEY)。您还应具备创建LangChain代理和使用工具的基本知识。1. 定义待测代理首先,我们来定义一个使用搜索工具的简单代理。在此示例中,我们将使用Tavily作为搜索工具,但您也可以替换为其他搜索工具或自定义工具。请确保您已安装必要的软件包(langchain、langchain_openai、tavily-python、langsmith)。此外,请将您的Tavily API密钥(TAVILY_API_KEY)和OpenAI API密钥(OPENAI_API_KEY)设置为环境变量。import os from langchain_openai import ChatOpenAI from langchain_community.tools.tavily_search import TavilySearchResults from langchain import hub from langchain.agents import create_openai_functions_agent, AgentExecutor from langsmith import Client # 确保API密钥已设置为环境变量 # os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY" # os.environ["TAVILY_API_KEY"] = "YOUR_TAVILY_API_KEY" # os.environ["LANGCHAIN_API_KEY"] = "YOUR_LANGSMITH_API_KEY" # os.environ["LANGCHAIN_TRACING_V2"] = "true" # 确保已启用追踪 # os.environ["LANGCHAIN_PROJECT"] = "Agent Evaluation Example" # 可选:定义一个LangSmith项目 # 初始化LLM和工具 llm = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0) search_tool = TavilySearchResults(max_results=2) tools = [search_tool] # 获取提示模板 # 使用标准OpenAI函数代理提示 prompt = hub.pull("hwchase17/openai-functions-agent") # 创建代理 # 此代理旨在与支持函数调用的模型配合使用 agent = create_openai_functions_agent(llm, tools, prompt) # 创建代理执行器 agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # 测试调用(可选) # print(agent_executor.invoke({"input": "What was the score of the last SF Giants game?"})) 现在我们有了agent_executor,它代表我们要评估的系统。2. 在LangSmith中创建评估数据集评估需要一组输入,理想情况下还需要预期的输出或衡量代理表现的标准。让我们使用客户端库直接在LangSmith中创建一个小型数据集。我们将包含输入(给代理的问题)和可选的参考输出。# 初始化LangSmith客户端 client = Client() dataset_name = "简单搜索代理问题 V1" dataset_description = "需要网页搜索的基本问题。" # 检查数据集是否存在,如果不存在则创建 try: dataset = client.read_dataset(dataset_name=dataset_name) print(f"数据集 '{dataset_name}' 已存在。") except Exception: # LangSmith客户端在找不到时会抛出一个通用Exception dataset = client.create_dataset( dataset_name=dataset_name, description=dataset_description, ) print(f"已创建数据集 '{dataset_name}'。") # 定义示例(输入问题和可选参考输出) examples = [ ("法国的首都是什么?", "巴黎"), ("谁赢得了2023年一级方程式锦标赛冠军?", "马克斯·维斯塔潘"), ("空气的主要成分是什么?", "氮气"), ("总结电影《盗梦空间》的剧情。", "一个通过进入他人梦境窃取信息的盗贼,接手了一项反向任务:将一个想法植入目标的潜意识中。"), # 示例参考输出 ] # 将示例添加到数据集 for input_query, reference_output in examples: client.create_example( inputs={"input": input_query}, outputs={"reference": reference_output}, # 使用“reference”键表示预期输出 dataset_id=dataset.id, ) print(f"已向数据集 '{dataset_name}' 添加了{len(examples)}个示例。") 运行此代码后,您应该会在LangSmith账户中看到一个名为“简单搜索代理问题 V1”的新数据集,其中填充了定义的示例。create_example中的outputs字典可以存储参考值、标签或任何其他对评估有用的信息。3. 使用LangSmith运行评估代理已定义,数据集已创建,现在我们可以使用LangSmith的评估工具让代理针对数据集中的每个示例运行。我们将从不使用自定义评估器开始,主要目的是收集追踪记录和观察行为。from langsmith.evaluation import evaluate # 定义一个封装代理调用的函数 # 这是evaluate函数所必需的 def agent_predictor(inputs: dict) -> dict: """为给定输入字典运行代理执行器。""" return agent_executor.invoke({"input": inputs["input"]}) # 假设数据集输入是“input” # 运行评估 # 这将针对数据集中的每个示例执行agent_predictor # 结果和追踪将自动记录到LangSmith evaluation_results = evaluate( agent_predictor, data=dataset_name, # 可以直接传递数据集名称 description="搜索代理的首次评估运行。", project_name="代理评估运行 - 简单搜索", # 可选:记录到特定的项目运行 # metadata={"agent_version": "1.0"}, # 可选:向运行添加元数据 ) print("评估运行已完成。请在LangSmith中查看结果。") 导航到您的LangSmith项目。您应该会找到一个与数据集关联的新评估运行。点击它以查看详情:追踪: 数据集中每个示例的代理执行详细日志。您可以检查LLM调用、工具使用、输入和输出。结果表: 显示输入、实际输出、参考输出(如果提供)、延迟和令牌计数的汇总视图。4. 实现自定义评估器简单地运行代理和追踪有助于调试,但定量评估需要定义具体指标。让我们创建一个自定义评估器函数,检查代理的输出是否包含参考答案(不区分大小写)。from langsmith.evaluation import EvaluationResult, run_evaluator @run_evaluator def check_contains_reference(run, example) -> EvaluationResult: """ 检查代理的输出是否包含参考答案(不区分大小写)。 参数: run: 代理执行的LangSmith运行对象。 example: 数据集中的LangSmith示例对象。 返回: 一个包含得分(如果包含为1,否则为0)的EvaluationResult 和描述。 """ agent_output = run.outputs.get("output") if run.outputs else None reference_output = example.outputs.get("reference") if example.outputs else None if agent_output is None or reference_output is None: # 处理输出或参考缺失的情况 score = 0 comment = "代理输出或参考输出缺失。" elif str(reference_output).lower() in str(agent_output).lower(): score = 1 # 成功:在代理输出中找到参考答案 comment = "找到参考答案。" else: score = 0 # 失败:未找到参考答案 comment = f"输出中未找到参考 '{reference_output}'。" return EvaluationResult( key="contains_reference", # 指标名称 score=score, # 数值分数(此处为0或1) comment=comment # 可选的定性反馈 ) 此函数使用@run_evaluator装饰器,表明它专为LangSmith评估而设计。它访问代理的实际输出(run.outputs)和存储在数据集中的参考输出(example.outputs)。它返回一个包含指标名称和分数的EvaluationResult对象。5. 使用自定义评估器运行评估现在,让我们重新运行评估,这次包含我们的自定义评估器。# 再次运行评估,现在包含自定义评估器 custom_eval_results = evaluate( agent_predictor, data=dataset_name, evaluators=[check_contains_reference], # 传递自定义评估器函数 description="使用自定义“包含参考”检查的评估运行。", project_name="代理评估运行 - 自定义检查", # 记录到不同的运行项目 # metadata={"agent_version": "1.0", "evaluator": "contains_reference_v1"}, ) print("使用自定义评估器的评估运行已完成。请检查LangSmith。")返回LangSmith并查看此新的评估运行。在结果表中,您现在应该会看到一个名为contains_reference的新列(与我们EvaluationResult中的引用匹配)。此列将根据我们的自定义逻辑显示每个示例的分数(0或1)。您可以按此指标排序和筛选,以快速找出失败项。鼠标悬停或点击反馈单元格通常会显示评估器提供的comment。如果我们要可视化此简单评估的结果(假设,基于contains_reference得分),它可能看起来像这样:{"data": [{"x": ["通过 (1)", "失败 (0)"], "y": [3, 1], "type": "bar", "marker": {"color": ["#37b24d", "#f03e3e"]}}], "layout": {"title": "评估结果:“包含参考”指标", "xaxis": {"title": "得分"}, "yaxis": {"title": "示例数量"}, "bargap": 0.2}}一个简单的条形图,显示通过(得分=1)和未通过(得分=0)contains_reference评估指标的示例数量。后续步骤与注意事项本实践练习展示了使用LangSmith评估代理的核心流程:定义代理、创建数据集、运行评估以及实现自定义检查。在此基础上,您可以构建更复杂的评估:更精密的评估器: 实现使用正则表达式、语义相似度检查(例如,比较实际输出和参考输出的嵌入)或检查输出特定结构属性的评估器。LLM作为评判: 使用另一个LLM根据帮助性、准确性(与参考相比)或无害性等标准来评估代理的输出。LangChain提供了创建这些评估器的辅助功能。多个评估器: 将不同的评估器函数列表传递给evaluate,以同时计算多个指标。数据集管理: 随着应用的演进,制定整理和版本控制评估数据集的策略。与CI/CD集成: 将这些评估运行自动化作为持续集成流程的一部分,以便在部署前发现退步。使用LangSmith等工具进行系统评估对于构建可靠的LLM应用不可或缺。它超越了零星测试,提供可量化的指标和详细的追踪记录,以便随着时间推移理解和提升代理表现。