原文出处:Hugging Face Agents Course · units/zh-CN/bonus_unit2/monitoring-and-evaluating-agents-notebook.mdx 原作者:Hugging Face · 许可证:Apache-2.0 License 本篇为课程官方中文译文(Hugging Face 社区翻译),诸葛AI学院仅做格式整理(去除图片与交互组件),版权归原作者所有。
附加单元 2:AI 智能体(AI Agent)的可观测性与评估
你可以跟随这个 notebook 中的代码进行操作,你可以在 Google Colab 上运行它。
在这个 notebook 中,我们将学习如何使用开源可观测性工具来监督我们 AI 智能体的内部步骤(追踪)并评估其性能。
观测和评估智能体行为的能力对于以下方面至关重要: - 当任务失败或产生次优结果时调试问题 - 实时跟踪成本和性能 - 通过持续反馈提高可靠性和安全性
练习先决条件 🏗️
在运行此 notebook 之前,请确保你已经:
🔲 📚 学习了 智能体简介
🔲 📚 学习了 smolagents 框架
步骤 0:安装所需的库
我们将需要一些库,以便我们能够运行、监控和评估我们的智能体:
python
%pip install 'smolagents[telemetry]'
%pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents
%pip install langfuse datasets 'smolagents[gradio]'
步骤 1:检测你的智能体
在这个 notebook 中,我们将使用 Langfuse 作为我们的可观测性工具,但你可以使用任何其他兼容 OpenTelemetry 的服务。下面的代码展示了如何为 Langfuse(或任何 OTel 端点)设置环境变量,以及如何检测你的 smolagent。
请注意: 如果你正在使用 LlamaIndex 或 LangGraph,你可以在这里和这里找到检测它们的文档。
首先,让我们配置正确的环境变量,以设置到 Langfuse OpenTelemetry 端点的连接。
```python import os import base64
从 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" # 🇪🇺 欧盟区域示例
os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 美国区域示例
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 token 用于推理调用。
```python
将你的 Hugging Face 和其他 token或者密钥设置为环境变量
os.environ["HF_TOKEN"] = "hf_..." ``` 接下来,我们可以为我们配置的 OpenTelemetry 设置一个 tracer-provider。
```python 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
为 OpenTelemetry 创建一个 TracerProvider
trace_provider = TracerProvider()
添加一个带有 OTLPSpanExporter 的 SimpleSpanProcessor 来发送追踪
trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter()))
设置全局默认 tracer provider
from opentelemetry import trace trace.set_tracer_provider(trace_provider) tracer = trace.get_tracer(name)
使用配置的 provider 检测 smolagents
SmolagentsInstrumentor().instrument(tracer_provider=trace_provider)
```
步骤 2:测试你的检测
这里有一个来自 smolagents 的简单 CodeAgent,用于计算 1+1。我们运行它来确认检测是否正常工作。如果一切设置正确,你将在你的可观测性仪表板中看到日志/跨度(spans)。
```python from smolagents import InferenceClientModel, CodeAgent
创建一个简单的智能体来测试检测
agent = CodeAgent( tools=[], model=InferenceClientModel() )
agent.run("1+1=") ```
检查你的 Langfuse Traces Dashboard(或你选择的可观测性工具)以确认跨度(spans)和日志已被记录。
Langfuse 中的示例截图:
步骤 3:观测和评估更复杂的AI智能体
既然你已经确认你的检测工作正常,让我们尝试一个更复杂的查询,这样我们就可以看到高级指标(token 使用量、延迟、成本等)是如何被追踪的。
```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel)
search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel())
agent.run("How many Rubik's Cubes could you fit inside the Notre Dame Cathedral?") ```
追踪结构
大多数可观测性工具会记录一个追踪(trace),其中包含跨度(spans),每个跨度代表你的智能体逻辑的一个步骤。在这里,追踪包含了整体的智能体运行以及用于以下内容的子跨度: - 工具调用 (DuckDuckGoSearchTool) - LLM 调用 (InferenceClientModel)
你可以检查这些跨度,以精确地了解时间花在哪里、使用了多少 token 等等:
Langfuse 中的追踪树:
在线评估
在上一节中,我们了解了在线评估和离线评估的区别。现在,我们将了解如何在生产环境中监控你的智能体并实时评估它。
生产环境中要追踪的常见指标
- 成本 — smolagents 检测会捕获 token 使用量,你可以通过为每个 token 分配价格将其转换为近似成本。
- 延迟 — 观察完成每个步骤或整个运行所需的时间。
- 用户反馈 — 用户可以提供直接反馈(点赞/点踩)来帮助优化或纠正智能体。
- LLM 作为评判者 — 使用一个单独的 LLM 来近乎实时地评估你的智能体的输出(例如,检查毒性或正确性)。
下面,我们展示这些指标的示例。
1. 成本
下面是一个显示 Qwen2.5-Coder-32B-Instruct 调用使用情况的截图。这对于查看成本高昂的步骤并优化你的智能体很有用。
2. 延迟
我们还可以看到完成每个步骤所需的时间。在下面的示例中,整个对话花费了 32 秒,你可以按步骤分解。这有助于你识别瓶颈并优化你的智能体。
3. 附加属性
你还可以通过在跨度(spans)上设置附加属性——例如用户 ID、会话 ID 或标签。例如,smolagents 检测使用 OpenTelemetry 来附加诸如 langfuse.user.id 或自定义标签之类的属性。
```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) from opentelemetry import trace
search_tool = DuckDuckGoSearchTool() agent = CodeAgent( tools=[search_tool], model=InferenceClientModel() )
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?")
```
4. 用户反馈
如果你的智能体嵌入到用户界面中,你可以记录直接的用户反馈(例如聊天界面中的点赞/点踩)。下面是使用 Gradio 嵌入带有简单反馈机制的聊天示例。
在下面的代码片段中,当用户发送聊天消息时,我们捕获 OpenTelemetry 追踪 ID。如果用户喜欢/不喜欢上一个答案,我们将评分附加到该追踪上。
```python import gradio as gr from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel) from langfuse import Langfuse
langfuse = Langfuse() model = InferenceClientModel() agent = CodeAgent(tools=[], model=model, add_base_tools=True)
formatted_trace_id = None # 为演示目的,我们将在全局存储当前的 trace_id
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): # 作为演示,我们将用户反馈映射为 1 (喜欢) 或 0 (不喜欢) 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")
# 当用户在提示框上按 'Enter' 时,我们运行 'respond'
prompt_box.submit(
fn=respond,
inputs=[prompt_box, chatbot],
outputs=chatbot
)
# 当用户点击消息上的 '喜欢' 按钮时,我们运行 'handle_like'
chatbot.like(handle_like, None, None)
demo.launch()
```
然后,用户反馈会被捕获到你的可观测性工具中:
5. LLM 作为评判者
LLM 作为评判者(LLM-as-a-Judge)是另一种自动评估你的智能体输出的方法。你可以设置一个单独的 LLM 调用来衡量输出的正确性、毒性、风格或你关心的任何其他标准。
工作流程: 1. 你定义一个评估模板,例如,“检查文本是否有毒。” 2. 每次你的智能体生成输出时,你将该输出连同模板一起传递给你的“评判者” LLM。 3. 评判者 LLM 会返回一个评分或标签,你将其记录到你的可观测性工具中。
来自 Langfuse 的示例:
```python
示例:检查智能体的输出是否有毒。
from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel)
search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel())
agent.run("Can eating carrots improve your vision?")
```
你可以看到这个例子的答案被判定为“无毒”。
6. 可观测性指标概览
所有这些指标都可以在仪表板中一起可视化。这使你能够快速查看你的智能体在多个会话中的表现,并帮助你随时间追踪质量指标。
离线评估
在线评估对于实时反馈至关重要,但你还需要离线评估——在开发之前或期间进行系统性检查。这有助于在将更改推送到生产环境之前维护质量和可靠性。
数据集评估
在离线评估中,你通常: 1. 拥有一个基准数据集(包含提示和预期输出对) 2. 在该数据集上运行你的智能体 3. 将输出与预期结果进行比较,或使用额外的评分机制
下面,我们使用 GSM8K 数据集 来演示这种方法,该数据集包含数学问题和解决方案。
```python import pandas as pd from datasets import load_dataset
从 Hugging Face 获取 GSM8K
dataset = load_dataset("openai/gsm8k", 'main', split='train') df = pd.DataFrame(dataset) print("GSM8K 数据集的前几行:") print(df.head())
```
接下来,我们在 Langfuse 中创建一个数据集实体来追踪运行。然后,我们将数据集中的每个项目添加到系统中。(如果你不使用 Langfuse,你可以简单地将这些存储在你自己的数据库或本地文件中进行分析。)
```python from langfuse import Langfuse langfuse = Langfuse()
langfuse_dataset_name = "gsm8k_dataset_huggingface"
在 Langfuse 中创建数据集
langfuse.create_dataset( name=langfuse_dataset_name, description="从 Huggingface 上传的 GSM8K 基准数据集", metadata={ "date": "2025-03-10", "type": "benchmark" } )
```
```python 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: # 仅上传前 10 个项目用于演示 break
```
在数据集上运行智能体
我们定义一个辅助函数 run_smolagent(),它:
1. 启动一个 OpenTelemetry 跨度(span)
2. 在提示上运行我们的智能体
3. 在 Langfuse 中记录追踪 ID
然后,我们遍历每个数据集项目,运行智能体,并将追踪链接到数据集项目。如果需要,我们还可以附加一个快速评估分数。
```python from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel, LiteLLMModel)
示例:使用 InferenceClientModel 或 LiteLLMModel 访问 openai、anthropic、gemini 等模型:
model = InferenceClientModel()
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
```
```python dataset = langfuse.get_dataset(langfuse_dataset_name)
针对每个数据集项目运行我们的智能体(上面限制为前 10 个)
for item in dataset.items: langfuse_trace, output = run_smolagent(item.input["text"])
# 将追踪链接到数据集项目以供分析
item.link(
langfuse_trace,
run_name="smolagent-notebook-run-01",
run_metadata={ "model": model.model_id }
)
# 可选地,存储一个快速评估分数用于演示
langfuse_trace.score(
name="<example_eval>",
value=1,
comment="这是一条评论"
)
刷新数据以确保所有遥测数据都已发送
langfuse.flush()
```
你可以用不同的配置重复这个过程: - 模型 (OpenAI GPT, 本地 LLM 等) - 工具 (使用搜索 vs. 不使用搜索) - 提示 (不同的系统消息)
然后在你的可观测性工具中并排比较它们:
结语
在这个 notebook 中,我们介绍了如何: 1. 设置可观测性 使用 smolagents + OpenTelemetry 导出器 2. 检查检测 通过运行一个简单的智能体 3. 捕获详细指标 (成本、延迟等) 通过可观测性工具 4. 收集用户反馈 通过 Gradio 界面 5. 使用 LLM 作为评判者 自动评估输出 6. 执行离线评估 使用基准数据集
🤗 编代码愉快!