作者:来自 Elastic Carly Richmond

学习如何使用 OpenTelemetry、 OpenLit 和 Elastic 监控 AI web agents,以识别性能瓶颈、 token 浪费和幻觉。
AI agents 的失败方式不像传统应用。它们会产生幻觉、陷入循环、消耗 token,并进行不可预测的工具调用,而这些都是标准监控从未设计去捕捉的。传统的 APM 工具显示 HTTP 状态码和延迟,但它们错过了真正重要的 AI 特有失败:提示注入攻击、评估分数下降以及工具调用循环。
本指南解释了对 AI web agents 进行全栈监控的关键考虑因素,并通过使用 OpenLit、 OpenTelemetry 和 Elastic 的最佳实践和实际示例进行说明。具体来说,我们将涵盖监控一个位于该示例 repo 中的 web 旅行规划器示例。
为什么 AI agent 可观测性是不同的?
传统监控的目标是检测并告警失败、性能问题、低效率和资源瓶颈。监控 AI agents 仍然遵循这一共同目标,但有几个差异必须被考虑:
- AI 模型是概率性的,这意味着相同的输入可能会产生不同的输出。这使得基于单一正确答案来定义和监控成功变得困难。
- AI 系统在表面上可能看起来运行正常,但其输出可能是可疑、不正确或有偏见的,而无法立即检测。因此,遥测必须能够捕捉隐藏能力,例如工具调用执行,以便 SRE 进行审查。
- LLM 的动态和不断演进的特性意味着由于数据、 embeddings 或 prompts 的变化,其行为在不同更新和版本之间可能发生巨大变化。这意味着在升级时进行监控和生产前评估对于性能连续性至关重要。
- 模型是黑盒。因此,通常很难理解 AI 为什么会做出特定决策。这使得与具有清晰、显式逻辑的系统相比,故障排查更加困难。
- 除了传统指标之外,还必须监控 AI 输出中的问题,例如幻觉(生成错误信息)、有害内容和偏见,这些问题可能损害用户信任并导致声誉风险。
- AI 系统的上下文性能可能会因上下文(包括用户交互)而有很大差异。捕捉用户 prompts 和遥测数据有助于建立系统性能的完整图景。
- 从安全角度来看,AI agents 可能容易受到对抗性攻击,包括数据投毒和混淆攻击。监控异常行为模式和 prompts 对于检测和缓解这些威胁至关重要。
基于这些原因,SRE 需要捕捉和分析的指标和追踪数据将有所不同。
AI agent 监控实践
让我们通过对一个实际的 AI agent 进行埋点并采集遥测数据来应用这些概念。在这里我们将使用 OpenLit 的 TypeScript SDK,这是一个开源库,用于在 JavaScript 应用中从 LLM 交互生成 OpenTelemetry 信号。具体来说,我们将对一个简单的 web 旅行规划 agent 进行埋点,该 agent 在这里提供,使用 LLM 根据用户 prompts 和来自各种工具的信息生成旅行推荐。由于其 TypeScript SDK 以及内置的捕捉 LLM 交互、工具调用以及生成评估和护栏指标的能力, OpenLit 非常适合这种 类 型的项目。

该架构图展示了关键组件:

本文中讨论的概念和最佳实践可以应用于任何 AI agent,而不受具体监控工具的限制。许多厂商都提供 AI 监控能力。也有其他开源技术可用于 agentic 监控,包括 LangSmith、 OpenLLMetry,或者使用 OpenTelemetry SDK 和 AI 语义约定进行手动埋点。
前提条件
该项目需要满足以下前提条件:
- 活跃的 Elastic 集群( Cloud、 Serverless 或 self-managed)
- OpenAI、 Azure OpenAI 或兼容的 LLM 提供商 API key
- Node.js 18+,以及 npm 或 yarn
- 兼容 OTLP 的端点( Elastic 托管的 OTLP 端点或 OTel collector)
应设置以下环境变量:
- OTEL_ENDPOINT:你的 Elastic OTLP 端点或 OTel collector URL
- OPENAI_API_KEY:用于评估 / 护栏 LLM 的 API key
- OPENAI_ENDPOINT:用于 OpenAI 兼容提供商的可选自定义 base URL
基础埋点
DevOps 工程师和 SRE 通常从自动埋点开始以获取基础遥测数据。这可以通过 OpenLit Python SDK 实现。然而在 TypeScript 中,我们需要手动将配置添加到 AI 入口点(这里是 api/chat/route.ts)。
首先使用你喜欢的包管理器安装依赖:
go
`npm install openlit`AI写代码
然后将 OpenLit 配置添加到入口点:
arduino
`
1. import openlit from "openlit";
3. // Other imports omitted for brevity
5. // Allow streaming responses up to 30 seconds to address typically longer responses from LLMs
6. export const maxDuration = 30;
8. openlit.init({
9. applicationName: "ai-travel-agent", // akin to OTEL resource name
10. environment: "development",
11. otlpEndpoint: process.env.OTEL_ENDPOINT, // OTLP compatible endpoint (Elastic ingest or OTel collector)
12. disableBatch: true, // batching disabled for demo purposes - not recommended for production use
13. });
15. // Post request handler
16. export async function POST(req: Request) {
17. // AI logic omitted for brevity - see full code in repo
18. }
`AI写代码
该埋点将自动为所有 LLM 交互(包括工具调用)生成 OpenTelemetry traces,并将其发送到指定的 OTLP 端点。请注意,在生产环境中而不是演示用途,应将 environment 设置为 production,并且不要禁用批处理,以确保最佳网络使用并保护 OTel 后端。
接下来我们将在后续章节中讨论生成的关键遥测信号。
输入
调试 AI agents 的第一条规则很简单:如果你没有捕捉 prompt,你就无法复现问题。与输入是可预测请求参数的传统应用不同,AI agents 消费的是自由形式的用户 prompts,这些 prompts 会因为细微措辞变化而触发截然不同的行为。 OpenLit 会自动将系统 prompts 和所有用户消息作为结构化属性捕捉到你的 traces 中,使你能够获得导致 agent 产生幻觉、陷入循环或失败的精确输入。

完整对话需要对 SRE 可用,以便理解故障和性能问题的上下文,并识别可能导致问题的输入模式。然而,这些输入同样有助于改进 agent 行为,并且在对诸如 PII 等可识别属性进行清理后,可以用作测试消息来评估模型性能和验证改进效果。
除了 prompts 之外,我们仍然需要全面的日志记录,特别是捕捉应用程序产生的完整堆栈 traces。这对于诊断来自底层基础设施或代码库的问题至关重要,而不仅仅是 AI 模型本身的问题。例如,下面发送到 Elastic 的错误显示了一个简单的 fetch 错误。我们不能忘记,传统错误在 AI 应用中仍然会发生,捕捉这些错误是至关重要的。

跟踪 - Tracing
Traces 对理解请求在 AI agent 中的流转至关重要,尤其是在涉及工具调用时。通常,traces 是 span 的层级结构,每个 span 本身是一个独立的计时单元,表示特定操作,例如数据库查询或 HTTP handler。在 AI 系统中,它们还表示 LLM 发起的工具调用,以及工具执行过程中进行的 API 调用和数据检索步骤。
可视化工具调用模式在验证生产前系统以及监控生产系统时非常重要,原因有以下几点:
- 它帮助我们评估不同模型的工具调用能力。LLMs 会根据用户 prompt、系统指令和工具元数据(如名称和描述)选择使用哪些工具。通过可视化工具调用模式,我们可以了解模型是否正确理解工具元数据,并根据 prompt 做出适当调用。
- 它允许我们识别低效或错误的工具调用模式。例如,如果我们看到对同一工具的重复调用且输入相似,可能表明模型陷入循环或未有效利用工具。或者,如果我们期望调用多个工具但只调用了一个工具,可能表明模型未正确连接 prompt 或系统指令要求调用的工具未被使用。
- 还可以识别常见的工具调用模式,以优化可用工具。例如,如果 location 和 weather 工具经常一起被调用,可能有必要将它们合并为一个工具,在一次调用中提供两条信息。
通过上述配置,我们可以查看每个工具调用的 traces,如下示例所示:

指标 - Metrics
虽然 tracing 对理解请求和工具调用的流转至关重要,但 metrics 对监控系统整体健康和性能,无论是否为 agentic 系统,都同样关键。在考虑 metrics 时,许多人只想到成本和总 token 使用量。虽然这两者都很重要,但它们并不是唯一关键的指标。
通过上面的示例, OpenLit 会自动生成可用于评估 agent 性能的关键 metrics,例如请求延迟、错误率、成本和 token 使用量,这些指标可以在 Elastic 中可视化,以识别趋势和异常。token 使用量可以按输入、输出和推理 token 数量进行拆分,帮助我们识别生成周期关键阶段的优化机会。例如,输入 token 数量的增加可能表明上下文长度显著增加,可以通过 prompt 和上下文工程 技术进行优化。

同样重要的是,确保 metrics 捕捉传统性能指标,例如 CPU、内存以及对缓存、传统数据库和向量数据库的请求计数。这有助于我们识别性能问题是由 AI 模型本身引起,还是由底层基础设施问题导致的。对关键指标的激增进行告警,例如 token 使用量大幅增加或请求量激增,也被视为最佳实践。
评估 - Evaluation
AI evaluation 指评估 AI 模型性能及其生成响应质量的过程。这涉及监控各种 metrics 和信号,以确保 AI 系统按预期运行,提供准确输出,并且不表现出不良行为,例如幻觉、有害行为或偏见。虽然 evaluation 通常被视为生产前活动,用于测试和验证 agentic 系统,但在生产环境中持续监控这些信号以随时间识别问题也很重要。
我们可以使用几种不同的 evaluation 方法。 OpenLit 利用 AI 作为 Judge。这涉及使用一个 LLM 根据一组标准评估另一个 LLM 生成输出的质量。下面展示了一个传统 evaluation 的示例:

从监控角度考虑 evaluation 时,重要的是在生产环境中识别幻觉、偏见、有害内容以及潜在的注入问题。幻觉、偏见和有害响应会使我们面临声誉风险和用户信任丧失。开箱即用, OpenLit 会识别以下问题,计算评分并提供问题说明:
| Issue | Description |
|---|---|
| Hallucinations | LLM 根据提供的上下文和自身知识生成虚假或误导性信息 |
| Bias | 生成的响应包含偏见或对受保护群体和特征产生负面影响的陈述,包括但不限于性别、种族、社会经济地位或宗教 |
| Toxicity | LLM 返回有害或冒犯性内容,这些内容可能具有威胁性、骚扰性或轻视性 |
可以使用以下代码识别这些问题:
javascript
``
1. import openlit from "openlit";
3. // Other imports omitted for brevity
5. // Allow streaming responses up to 30 seconds to address typically longer responses from LLMs
6. export const maxDuration = 30;
8. // Tools and Azure configuration omitted for brevity
10. openlit.init({
11. applicationName: "ai-travel-agent",
12. environment: "development",
13. otlpEndpoint: process.env.OTEL_ENDPOINT,
14. disableBatch: true,
15. });
17. // Choose one of the following approaches:
18. // Option 1: enable all available evaluations
19. const evalsAll = openlit.evals.All({
20. provider: "openai",
21. collectMetrics: true, // Ensures evaluations are exported to Elastic
22. apiKey: process.env.OPENAI_API_KEY,
23. baseUrl: process.env.OPENAI_ENDPOINT
24. });
26. // Option 2: enable specific evaluations with custom configuration
27. const evalsHallucination = openlit.evals.Hallucination({
28. provider: "openai",
29. collectMetrics: true,
30. apiKey: process.env.OPENAI_API_KEY,
31. baseUrl: process.env.OPENAI_ENDPOINT
32. });
34. // Post request handler
35. export async function POST(req: Request) {
36. const { messages, id } = await req.json();
38. try {
39. const convertedMessages = await convertToModelMessages(messages);
40. const prompt = `You are a helpful assistant that returns travel itineraries...`;
42. const result = streamText({
43. model: azure("gpt-4o"),
44. system: prompt,
45. messages: convertedMessages,
46. stopWhen: stepCountIs(2),
47. tools,
48. experimental_telemetry: { isEnabled: true },
49. onFinish: async ({ text, steps }) => {
50. // Concatenate tool results and content as full evaluation context
51. const toolResults = steps.flatMap((step) => {
52. return step.content
53. .filter((content) => content.type == "tool-result")
54. .map((c) => {
55. return JSON.stringify(c.output);
56. });
57. });
59. // Measure evaluation
60. const evalResults = await evalsAll.measure({
61. prompt: prompt,
62. contexts: convertedMessages
63. .map((m) => {
64. return m.content.toString();
65. })
66. .concat(toolResults),
67. text: text,
68. });
69. console.log(`Evals results: ${evalResults}`);
70. },
71. });
73. // Return data stream to allow the useChat hook to handle the results as they are streamed through for a better user experience
74. return result.toUIMessageStreamResponse();
75. } catch (e) {
76. console.error(e);
77. return new NextResponse(
78. "Unable to generate a plan. Please try again later!"
79. );
80. }
81. }
``AI写代码收起代码块
通过使用 collectMetrics 选项,evaluation 结果会自动作为 metrics 导出到 Elastic,使我们能够随时间监控 AI agent 输出的质量,并识别生产中可能出现的趋势或问题。evaluation 结果还可以用于触发告警或自动响应,例如当某些阈值或 SLOs 被触发时,如高评分持续数分钟、随着时间增加检测到的幻觉数量增加,或触发有害结果。

使用 LLM 评估结果的优势在于,与手动质量检查相比,它们能够快速识别问题和不准确之处。然而,这种方法也存在局限性,具体包括:
- 由于额外请求 LLM 来评估结果而导致成本和延迟增加。可以通过使用更小、更便宜的模型进行评估、仅评估部分响应样本,或使用缓存响应来减少针对类似问题的 LLM 调用次数,从而缓解这一问题。
- LLM 评估容易产生偏见。具体来说,Zheng 等人在 2023 年的论文中指出 LLM 评估可能受到以下影响:
- 位置偏差(Positional bias):LLM 更倾向于选择答案位于响应特定位置的回答,可能会遗漏位于其他位置的正确答案。
- 自我强化偏差(Self-enhancement bias):LLM 对其自身生成的响应相较于其他模型的响应表现出偏好。如果希望使用更便宜或自托管的模型进行评估,这一点需要考虑。
- 冗长偏差(Verbosity bias):LLM 更倾向于选择较为详尽的响应,而非简洁回答。
Guardrail 监控
除了评估响应质量外,我们还必须监控可能对用户有害或无关的响应。模型内置保护的质量存在不稳定性,并且依赖于具体模型。多篇研究论文,包括 Anthropic 在其 2025 年 agentic misalignment 论文中指出,在某些情况下,模型可能会采取恶意行为,绕过公司政策和道德预期。
监控工具中的 Guardrail 检测允许我们识别 AI agents 生成的高风险响应,例如生成有害内容、参与不当交互,或执行注入操作试图入侵系统或获取机密信息。以 OpenLit 为例,我们能够监控以下类型的 guardrail 违规:
| Guardrail Type | Description |
|---|---|
| Prompt Injection | 检测恶意注入尝试、冒充及其他越狱技术 |
| Sensitive Topics | 检测涉及政治、宗教、成人内容、药物滥用或暴力等争议性、敏感或非法话题的内容 |
| Restricted Topics | 检测违反公司政策、道德指南或工具应避免的内容,例如提供财务或法律建议的内容 |
可以使用 OpenLit 按照以下代码设置这些防护:
php
``
1. import openlit from "openlit";
3. // Other imports omitted for brevity
5. // Allow streaming responses up to 30 seconds to address typically longer responses from LLMs
6. export const maxDuration = 30;
8. // Tools and Azure configuration omitted for brevity
10. openlit.init({
11. applicationName: "ai-travel-agent",
12. environment: "development",
13. otlpEndpoint: process.env.OTEL_ENDPOINT,
14. disableBatch: true,
15. });
17. // Choose one of the following approaches:
18. // Option 1: enable all available guardrails
19. const guardsAll = openlit.guard.All({
20. provider: "openai",
21. collectMetrics: true,
22. apiKey: process.env.OPENAI_API_KEY,
23. baseUrl: process.env.OPENAI_ENDPOINT,
24. validTopics: ["travel", "culture"],
25. invalidTopics: ["finance", "software engineering"],
26. });
28. // Option 2: enables specific guardrail types (for example, prompt injection detection)
29. const guardsPromptInjection = openlit.guard.PromptInjection({
30. provider: "openai",
31. collectMetrics: true, // Ensures guardrail breaches are exported to Elastic
32. apiKey: process.env.OPENAI_API_KEY,
33. baseUrl: process.env.OPENAI_ENDPOINT
34. });
36. // Post request handler
37. export async function POST(req: Request) {
38. const { messages, id } = await req.json();
40. try {
41. const convertedMessages = await convertToModelMessages(messages);
42. const prompt = `You are a helpful assistant that returns travel itineraries...`;
44. const result = streamText({
45. model: azure("gpt-4o"),
46. system: prompt,
47. messages: convertedMessages,
48. stopWhen: stepCountIs(2),
49. tools,
50. experimental_telemetry: { isEnabled: true },
51. onFinish: async ({ text, steps }) => {
52. const guardrailResult = await guardsAll.detect(text);
53. console.log(`Guardrail results: ${guardrailResult}`);
54. },
55. });
57. // Return data stream to allow the useChat hook to handle the results as they are streamed through for a better user experience
58. return result.toUIMessageStreamResponse();
59. } catch (e) {
60. console.error(e);
61. return new NextResponse(
62. "Unable to generate a plan. Please try again later!"
63. );
64. }
65. }
``AI写代码收起代码块
在发生 guardrail 违规时,包含违规详情的 metrics 会发送到 Elastic,类似如下示例:

当然,我们可以利用 dashboards 可视化 guardrail 违规的趋势,包括按类别统计的指标,如下示例所示(对应的 NDJSON 可在此获取):

我们还可以对这些违规行为采取操作,通过可用的告警工具触发告警通知相关团队。这些告警应根据检测到问题的严重性及分类触发,例如涉及暴力、非法主题或注入攻击的情况可能会立即触发,而轻微不准确则可能延迟触发。Guardrail 违规还可用于触发自动响应,例如阻止响应发送给用户,或向用户提供警告信息,提示其请求已被标记以供审核,从而为相关团队触发 human-in-the-loop 响应。
结论
AI agents 正变得更加自主、强大且不可预测。因此,在开发过程中及组织文化中尽早引入监控遥测非常重要。本文帮助你理解监控 AI agents 的不同之处,以及如何使用 OpenLit 生成 OpenTelemetry 信号并发送到 Elastic。查看此处的代码,开始在生产环境中监控你的 AI agents。