Agents 课程文档

奖励单元 2:Agent 的可观测性和评估

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Ask a Question Open In Colab

奖励单元 2:Agent 的可观测性和评估

您可以按照此 notebook 中的代码进行操作,您可以使用 Google Colab 运行它。

在本 notebook 中,我们将学习如何使用开源可观测性工具来监控 AI agent 的内部步骤(追踪)评估其性能

观察和评估 agent 行为的能力对于以下方面至关重要:

  • 调试任务失败或产生次优结果的问题
  • 实时监控成本和性能
  • 通过持续反馈提高可靠性和安全性

练习前提条件 🏗️

在运行此 notebook 之前,请确保您已完成以下操作:

🔲 📚 学习了 Agent 简介

🔲 📚 学习了 smolagents 框架

步骤 0:安装所需的库

我们将需要一些库来运行、监控和评估我们的 agent

%pip install 'smolagents[telemetry]'
%pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents
%pip install langfuse datasets 'smolagents[gradio]'

步骤 1:检测您的 Agent

在本 notebook 中,我们将使用 Langfuse 作为我们的可观测性工具,但您可以使用任何其他与 OpenTelemetry 兼容的服务。以下代码展示了如何为 Langfuse(或任何 OTel 端点)设置环境变量,以及如何检测您的 smolagent。

注意:如果您正在使用 LlamaIndex 或 LangGraph,您可以在此处此处找到有关检测它们的文档。

首先,让我们配置正确的环境变量,以设置与 Langfuse OpenTelemetry 端点的连接。

import os
import base64

# Get your own keys from https://cloud.langfuse.com
LANGFUSE_PUBLIC_KEY = "pk-lf-..." 
LANGFUSE_SECRET_KEY = "sk-lf-..." 
os.environ["LANGFUSE_PUBLIC_KEY"] = LANGFUSE_PUBLIC_KEY
os.environ["LANGFUSE_SECRET_KEY"] = LANGFUSE_SECRET_KEY
os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com"  # 🇪🇺 EU region example
# os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com"  # 🇺🇸 US region example

LANGFUSE_AUTH = base64.b64encode(
    f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode()
).decode()

os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = os.environ.get("LANGFUSE_HOST") + "/api/public/otel"
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}"

我们还需要配置我们的 Hugging Face 令牌以进行推理调用。

# Set your Hugging Face and other tokens/secrets as environment variable
os.environ["HF_TOKEN"] = "hf_..." 

接下来,我们可以为我们配置的 OpenTelemetry 设置一个 tracer-provider。

from opentelemetry.sdk.trace import TracerProvider
from openinference.instrumentation.smolagents import SmolagentsInstrumentor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
 
# Create a TracerProvider for OpenTelemetry
trace_provider = TracerProvider()

# Add a SimpleSpanProcessor with the OTLPSpanExporter to send traces
trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter()))

# Set the global default tracer provider
from opentelemetry import trace
trace.set_tracer_provider(trace_provider)
tracer = trace.get_tracer(__name__)

# Instrument smolagents with the configured provider
SmolagentsInstrumentor().instrument(tracer_provider=trace_provider)

步骤 2:测试您的检测

这是一个来自 smolagents 的简单 CodeAgent,用于计算 1+1。我们运行它以确认检测工作正常。如果一切设置正确,您将在您的可观测性仪表板中看到日志/span。

from smolagents import HfApiModel, CodeAgent

# Create a simple agent to test instrumentation
agent = CodeAgent(
    tools=[],
    model=HfApiModel()
)

agent.run("1+1=")

检查您的 Langfuse Traces Dashboard(或您选择的可观测性工具)以确认 span 和日志已被记录。

来自 Langfuse 的示例屏幕截图

Example trace in Langfuse

追踪链接

步骤 3:观察和评估更复杂的 Agent

现在您已经确认您的检测工作正常,让我们尝试一个更复杂的查询,以便我们可以看到高级指标(令牌使用量、延迟、成本等)是如何被跟踪的。

from smolagents import (CodeAgent, DuckDuckGoSearchTool, HfApiModel)

search_tool = DuckDuckGoSearchTool()
agent = CodeAgent(tools=[search_tool], model=HfApiModel())

agent.run("How many Rubik's Cubes could you fit inside the Notre Dame Cathedral?")

追踪结构

大多数可观测性工具记录追踪,其中包含span,span 代表您 agent 逻辑的每个步骤。在这里,追踪包含 agent 的整体运行以及以下子 span:

  • 工具调用 (DuckDuckGoSearchTool)
  • LLM 调用 (HfApiModel)

您可以检查这些内容,以精确地了解时间花费在哪里、使用了多少令牌等等

Trace tree in Langfuse

追踪链接

在线评估

在上一节中,我们了解了在线评估和离线评估之间的区别。现在,我们将了解如何在生产环境中监控您的 agent 并对其进行实时评估。

生产环境中要跟踪的常用指标

  1. 成本 — smolagents 检测捕获令牌使用情况,您可以通过为每个令牌分配价格将其转换为近似成本。
  2. 延迟 — 观察完成每个步骤或整个运行所需的时间。
  3. 用户反馈 — 用户可以提供直接反馈(赞/踩),以帮助改进或纠正 agent。
  4. LLM 即法官 — 使用单独的 LLM 几乎实时地评估您 agent 的输出(例如,检查毒性或正确性)。

下面,我们展示这些指标的示例。

1. 成本

下面是一个屏幕截图,显示了 Qwen2.5-Coder-32B-Instruct 调用的使用情况。这有助于查看成本高昂的步骤并优化您的 agent。

Costs

追踪链接

2. 延迟

我们还可以看到完成每个步骤需要多长时间。在下面的示例中,整个对话耗时 32 秒,您可以按步骤细分。这有助于您识别瓶颈并优化您的 agent。

Latency

追踪链接

3. 附加属性

您还可以通过在 span 上设置附加属性(例如用户 ID、会话 ID 或标签)。例如,smolagents 检测使用 OpenTelemetry 附加属性,如 langfuse.user.id 或自定义标签。

from smolagents import (CodeAgent, DuckDuckGoSearchTool, HfApiModel)
from opentelemetry import trace

search_tool = DuckDuckGoSearchTool()
agent = CodeAgent(
    tools=[search_tool],
    model=HfApiModel()
)

with tracer.start_as_current_span("Smolagent-Trace") as span:
    span.set_attribute("langfuse.user.id", "smolagent-user-123")
    span.set_attribute("langfuse.session.id", "smolagent-session-123456789")
    span.set_attribute("langfuse.tags", ["city-question", "testing-agents"])

    agent.run("What is the capital of Germany?")

Enhancing agent runs with additional metrics

4. 用户反馈

如果您的 agent 嵌入到用户界面中,您可以记录直接的用户反馈(例如聊天 UI 中的赞/踩)。下面是使用 Gradio 嵌入带有简单反馈机制的聊天的示例。

在下面的代码片段中,当用户发送聊天消息时,我们捕获 OpenTelemetry 追踪 ID。如果用户喜欢/不喜欢最后一个答案,我们会将分数附加到追踪。

import gradio as gr
from opentelemetry.trace import format_trace_id
from smolagents import (CodeAgent, HfApiModel)
from langfuse import Langfuse

langfuse = Langfuse()
model = HfApiModel()
agent = CodeAgent(tools=[], model=model, add_base_tools=True)

formatted_trace_id = None  # We'll store the current trace_id globally for demonstration

def respond(prompt, history):
    with trace.get_tracer(__name__).start_as_current_span("Smolagent-Trace") as span:
        output = agent.run(prompt)

        current_span = trace.get_current_span()
        span_context = current_span.get_span_context()
        trace_id = span_context.trace_id
        global formatted_trace_id
        formatted_trace_id = str(format_trace_id(trace_id))
        langfuse.trace(id=formatted_trace_id, input=prompt, output=output)

    history.append({"role": "assistant", "content": str(output)})
    return history

def handle_like(data: gr.LikeData):
    # For demonstration, we map user feedback to a 1 (like) or 0 (dislike)
    if data.liked:
        langfuse.score(
            value=1,
            name="user-feedback",
            trace_id=formatted_trace_id
        )
    else:
        langfuse.score(
            value=0,
            name="user-feedback",
            trace_id=formatted_trace_id
        )

with gr.Blocks() as demo:
    chatbot = gr.Chatbot(label="Chat", type="messages")
    prompt_box = gr.Textbox(placeholder="Type your message...", label="Your message")

    # When the user presses 'Enter' on the prompt, we run 'respond'
    prompt_box.submit(
        fn=respond,
        inputs=[prompt_box, chatbot],
        outputs=chatbot
    )

    # When the user clicks a 'like' button on a message, we run 'handle_like'
    chatbot.like(handle_like, None, None)

demo.launch()

然后,用户反馈将在您的可观测性工具中捕获

User feedback is being captured in Langfuse

5. LLM 即法官

LLM 即法官是另一种自动评估您 agent 输出的方法。您可以设置一个单独的 LLM 调用来衡量输出的正确性、毒性、风格或您关心的任何其他标准。

工作流程:

  1. 您定义一个评估模板,例如“检查文本是否具有毒性。”
  2. 每次您的 agent 生成输出时,您都将该输出与模板一起传递给您的“法官”LLM。
  3. 法官 LLM 会回复一个评分或标签,您将其记录到您的可观测性工具中。

来自 Langfuse 的示例

LLM-as-a-Judge Evaluation Template LLM-as-a-Judge Evaluator

# Example: Checking if the agent’s output is toxic or not.
from smolagents import (CodeAgent, DuckDuckGoSearchTool, HfApiModel)

search_tool = DuckDuckGoSearchTool()
agent = CodeAgent(tools=[search_tool], model=HfApiModel())

agent.run("Can eating carrots improve your vision?")

您可以看到此示例的答案被判断为“无毒”。

LLM-as-a-Judge Evaluation Score

6. 可观测性指标概述

所有这些指标都可以一起在仪表板中可视化。这使您能够快速查看您的 agent 在多个会话中的表现,并帮助您随时间跟踪质量指标。

Observability metrics overview

离线评估

在线评估对于实时反馈至关重要,但您还需要离线评估——在开发之前或期间进行系统检查。这有助于在将更改推广到生产环境之前保持质量和可靠性。

数据集评估

在离线评估中,您通常会:

  1. 拥有一个基准数据集(包含提示和预期输出对)
  2. 在该数据集上运行您的 agent
  3. 将输出与预期结果进行比较,或使用额外的评分机制

下面,我们使用 GSM8K 数据集 演示此方法,该数据集包含数学问题和解答。

import pandas as pd
from datasets import load_dataset

# Fetch GSM8K from Hugging Face
dataset = load_dataset("openai/gsm8k", 'main', split='train')
df = pd.DataFrame(dataset)
print("First few rows of GSM8K dataset:")
print(df.head())

接下来,我们在 Langfuse 中创建一个数据集实体来跟踪运行情况。然后,我们将数据集中的每个项目添加到系统中。(如果您不使用 Langfuse,您可以简单地将它们存储在您自己的数据库或本地文件中以进行分析。)

from langfuse import Langfuse
langfuse = Langfuse()

langfuse_dataset_name = "gsm8k_dataset_huggingface"

# Create a dataset in Langfuse
langfuse.create_dataset(
    name=langfuse_dataset_name,
    description="GSM8K benchmark dataset uploaded from Huggingface",
    metadata={
        "date": "2025-03-10", 
        "type": "benchmark"
    }
)
for idx, row in df.iterrows():
    langfuse.create_dataset_item(
        dataset_name=langfuse_dataset_name,
        input={"text": row["question"]},
        expected_output={"text": row["answer"]},
        metadata={"source_index": idx}
    )
    if idx >= 9: # Upload only the first 10 items for demonstration
        break

Dataset items in Langfuse

在数据集上运行 Agent

我们定义一个辅助函数 run_smolagent(),它:

  1. 启动一个 OpenTelemetry span
  2. 在提示上运行我们的 agent
  3. 在 Langfuse 中记录追踪 ID

然后,我们循环遍历每个数据集项目,运行 agent,并将追踪链接到数据集项目。如果需要,我们还可以附加一个快速评估分数。

from opentelemetry.trace import format_trace_id
from smolagents import (CodeAgent, HfApiModel, LiteLLMModel)

# Example: using HfApiModel or LiteLLMModel to access openai, anthropic, gemini, etc. models:
model = HfApiModel()

agent = CodeAgent(
    tools=[],
    model=model,
    add_base_tools=True
)

def run_smolagent(question):
    with tracer.start_as_current_span("Smolagent-Trace") as span:
        span.set_attribute("langfuse.tag", "dataset-run")
        output = agent.run(question)

        current_span = trace.get_current_span()
        span_context = current_span.get_span_context()
        trace_id = span_context.trace_id
        formatted_trace_id = format_trace_id(trace_id)

        langfuse_trace = langfuse.trace(
            id=formatted_trace_id, 
            input=question, 
            output=output
        )
    return langfuse_trace, output
dataset = langfuse.get_dataset(langfuse_dataset_name)

# Run our agent against each dataset item (limited to first 10 above)
for item in dataset.items:
    langfuse_trace, output = run_smolagent(item.input["text"])

    # Link the trace to the dataset item for analysis
    item.link(
        langfuse_trace,
        run_name="smolagent-notebook-run-01",
        run_metadata={ "model": model.model_id }
    )

    # Optionally, store a quick evaluation score for demonstration
    langfuse_trace.score(
        name="<example_eval>",
        value=1,
        comment="This is a comment"
    )

# Flush data to ensure all telemetry is sent
langfuse.flush()

您可以对不同的内容重复此过程:

  • 模型(OpenAI GPT、本地 LLM 等)
  • 工具(搜索与不搜索)
  • 提示(不同的系统消息)

然后在您的可观测性工具中并排比较它们

Dataset run overview Dataset run comparison

最终想法

在本 notebook 中,我们介绍了如何:

  1. 使用 smolagents + OpenTelemetry 导出器设置可观测性
  2. 通过运行一个简单的 agent 检查检测
  3. 通过可观测性工具捕获详细指标(成本、延迟等)
  4. 通过 Gradio 界面收集用户反馈
  5. 使用 LLM 即法官自动评估输出
  6. 使用基准数据集执行离线评估

🤗 祝您编码愉快!

< > 在 GitHub 上更新