Skip to content

LangSmith 实用指南 #142

@Pines-Cheng

Description

@Pines-Cheng

评估智能体的中间步骤

在许多场景中,评估智能体不仅仅是关于最终结果,而是要理解它达到该决策所采取的步骤。本笔记本提供了一个入门演练,介绍如何配置评估器来基于智能体的"决策过程"进行评估,根据所选工具的序列进行评分。

智能体轨迹示例

我们将创建一个自定义运行评估器,捕获智能体的中间步骤并与预定义序列进行比较。这确保智能体不仅提供正确答案,而且在使用外部资源方面也是高效的。

基本步骤包括:

  1. 准备包含输入查询和预期智能体动作的数据集
  2. 定义具有特定工具和行为的智能体
  3. 构建检查所采取动作的自定义评估器
  4. 运行评估

评估完成后,您可以在 LangSmith 中查看结果。通过本指南,您将更好地了解如何将评估器应用于更复杂的输入,如智能体的轨迹。

%pip install -U langchain openai
import os

os.environ["LANGCHAIN_API_KEY"] = "您的API密钥"
os.environ["OPENAI_API_KEY"] = "您的OPENAI API密钥"
# 如果使用托管的Langsmith实例,请更新您的API URL
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"

1. 准备数据集

定义一个新的数据集。数据集至少应包含智能体需要解决的输入查询。我们还将在数据集中存储预期步骤,以演示智能体为解决查询而预期采取的动作序列。

可选地,您可以存储参考标签,以端到端的方式评估智能体的"正确性"。

import uuid
from langsmith import Client

client = Client()

questions = [
    (
        "为什么一个10美元的计算器应用成为了任天堂Switch上评分最高的游戏之一?",
        {
            "reference": "由于其高价位,它成为了网络梗。",
            "expected_steps": ["duck_duck_go"],
        },
    ),
    (
        "你好",
        {
            "reference": "您好,我能为您做些什么?",
            "expected_steps": [],  # 期望直接回应
        },
    ),
    (
        "Dejan Trajkov是谁?",
        {
            "reference": "马其顿教授、免疫学家和医生",
            "expected_steps": ["duck_duck_go"],
        },
    ),
    (
        "谁赢得了2023年U23世界摔跤锦标赛(男子自由式92公斤级)?",
        {
            "reference": "来自土耳其的Muhammed Gimri",
            "expected_steps": ["duck_duck_go"],
        },
    ),
    (
        "我周五的第一个会议是什么?",
        {
            "reference": '您的第一个会议是上午8:30的"团队站会"',
            "expected_steps": ["check_calendar"],  # 只期望日历工具
        },
    ),
]

uid = uuid.uuid4()
dataset_name = f"智能体评估示例 {uid}"
ds = client.create_dataset(
    dataset_name=dataset_name,
    description="使用搜索和日历检查的智能体评估数据集示例。",
)
client.create_examples(
    inputs=[{"question": q[0]} for q in questions],
    outputs=[q[1] for q in questions],
    dataset_id=ds.id,
)

2. 定义智能体

智能体程序的主要组件包括:

  • 智能体(或可运行对象):接受查询和中间状态,并响应下一步要采取的动作
  • 工具:智能体可以访问的工具
  • 执行器:控制选择后续动作时的循环行为

在此示例中,我们将创建一个智能体,它可以访问DuckDuckGo搜索客户端(用于信息搜索)和一个模拟工具来检查用户在给定日期的日历。

我们的智能体将使用OpenAI函数调用来确保它生成符合工具预期输入模式的参数。

from dateutil.parser import parse
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchResults
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool

@tool
def check_calendar(date: str) -> list:
    """检查用户在指定日期时间(ISO格式)的日历会议。"""
    date_time = parse(date)
    # 这是一个演示多个工具的占位符
    # 在测试时很容易模拟工具
    if date_time.weekday() == 4:
        return [
            "8:30 : 团队站会",
            "9:00 : 一对一会议",
            "9:45 设计评审",
        ]
    return ["专注时间"]  # 如果可以的话...

def agent(inputs: dict):
    llm = ChatOpenAI(
        model="gpt-3.5-turbo-16k",
        temperature=0,
    )
    tools = [
        DuckDuckGoSearchResults(
            name="duck_duck_go"
        ),  # 使用DuckDuckGo的通用互联网搜索
        check_calendar,
    ]
    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", "您是一个有用的助手。"),
            MessagesPlaceholder(variable_name="agent_scratchpad"),
            ("user", "{question}"),
        ]
    )
    runnable_agent = create_openai_tools_agent(llm, tools, prompt)

    executor = AgentExecutor(
        agent=runnable_agent,
        tools=tools,
        handle_parsing_errors=True,
        return_intermediate_steps=True,
    )
    return executor.invoke(inputs)

3. 定义评估器

我们将创建一个自定义运行评估器来检查智能体轨迹。它将运行的中间步骤与我们在上面数据集中保存的"基准真值"进行比较。

请查看下面的代码。注意此评估器期望智能体的响应包含"intermediate_steps"键,其中包含智能体动作列表。这通过在上面设置return_intermediate_steps=True来完成。

这也期望您的数据集在每个示例输出中都有"expected_steps"键,如上所述。

from typing import Optional
from langsmith.schemas import Example, Run

def intermediate_step_correctness(run: Run, example: Optional[Example] = None) -> dict:
    if run.outputs is None:
        raise ValueError("运行输出不能为None")
    # 这是每次运行的输出
    intermediate_steps = run.outputs.get("intermediate_steps") or []
    # 由于我们要与工具名称进行比较,现在需要获取它
    # 中间步骤是一个元组[AgentAction, Any]
    # 第一个元素是采取的动作
    # 第二个元素是采取该动作的观察结果
    trajectory = [action.tool for action, _ in intermediate_steps]
    # 这是我们上传到数据集的内容
    expected_trajectory = example.outputs["expected_steps"]
    # 仅根据是否正确来评分
    score = int(trajectory == expected_trajectory)
    return {"key": "中间步骤正确性", "score": score}

4. 评估

将您的自定义评估器添加到下面评估配置中的custom_evaluators列表中。

由于我们的数据集有多个输出键,我们必须通过设置reference_key="reference"来指示run_on_dataset函数使用哪个键作为QA评估器的基准真值。

from langsmith.evaluation import LangChainStringEvaluator, evaluate

# 现在需要指定这个,因为我们的数据集中有多个输出
def prepare_data(run: Run, example: Example) -> dict:
    return {
        "input": example.inputs["question"],
        "prediction": run.outputs["output"],
        "reference": example.outputs["reference"],
    }

# 基于参考答案测量QA响应是否"正确"
qa_evaluator = LangChainStringEvaluator("qa", prepare_data=prepare_data)
chain_results = evaluate(
    agent,
    data=dataset_name,
    evaluators=[intermediate_step_correctness, qa_evaluator],
    experiment_prefix="智能体评估示例",
    max_concurrency=1,
)

错误运行目标函数:_get_url() https://links.duckduckgo.com/d.js DuckDuckGoSearchException: 速率限制

结论

恭喜!您已成功通过将智能体的轨迹与预期的动作序列进行比较来执行简单的智能体轨迹评估。当您知道要采取的预期步骤时,这很有用。

一旦您为这种类型的评估配置了自定义评估器,就很容易使用现成的评估器(如LangChain的TrajectoryEvalChain)应用其他技术,该评估器可以指示LLM对智能体动作的有效性进行评分。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions