使用 OpenLit、 OpenTelemetry 和 Elastic 的 AI Agent 可观测性

作者:来自 Elastic carly.richmond

传统上,我们依赖 Observability 诊断信息来了解我们的应用在做什么。尤其是在节日期间,如果抽到值班短签,我们会一直担心被呼叫。现在我们正在构建 AI agents,我们也需要一种方式来观测它们!

在这里,我们将介绍如何使用 OpenLitOpenTelemetry 来生成遥测数据,帮助你诊断问题并识别常见问题。具体来说,我们将为一个简单的旅行规划器进行埋点(为这个季节寻找更温暖目的地的人准备 🌞),该规划器使用此 repo 中提供的 AI SDK 构建。

什么是 OpenLit 和 OpenTelemetry?

OpenTelemetry 是一个 CNCF 孵化项目,提供 SDKs 和工具,用于生成有关软件组件行为的信息,帮助你诊断问题。

另一方面,OpenLit 是一个开源工具,用于生成 OTLP (或 OpenTelemetry Protocol )信号,以展示 AI agentsLLM 和向量数据库的交互。它目前为 PythonTypeScript 提供 SDK 支持(我们将使用后者),并提供一个 Kubernetes operator

基础 AI tracingmetrics

在为我们的 AI 代码做埋点之前,我们需要安装所需的依赖项:

go 复制代码
`npm install openlit`AI写代码

安装完成后,我们需要在调用 LLM 的应用代码片段中初始化 OpenLit 。在我们的应用中,这是 route.ts 文件:

javascript 复制代码
``

1.  import openlit from "openlit";

3.  import { ollama } from "ollama-ai-provider-v2";
4.  import { streamText, stepCountIs, convertToModelMessages, ModelMessage } from "ai";
5.  import { NextResponse } from "next/server";

7.  import { weatherTool } from "@/app/ai/weather.tool";
8.  import { fcdoTool } from "@/app/ai/fcdo.tool";
9.  import { flightTool } from "@/app/ai/flights.tool";
10.  import { getSimilarMessages, persistMessage } from "@/app/util/elasticsearch";

12.  // Allow streaming responses up to 30 seconds to address typically longer responses from LLMs
13.  export const maxDuration = 30;

15.  const tools = {
16.    flights: flightTool,
17.    weather: weatherTool,
18.    fcdo: fcdoTool,
19.  };

21.  openlit.init({
22.    applicationName: "ai-travel-agent", // Unique service name
23.    environment: "development", // Environment (optional)
24.    otlpEndpoint: process.env.PROXY_ENDPOINT, // OTLP endpoint
25.    disableBatch: true /// Live stream for demo purposes
26.  });

28.  // Post request handler
29.  export async function POST(req: Request) {
30.    const { messages, } = await req.json();

32.    // Memory persistence omitted

34.    try {
35.      const convertedMessages = convertToModelMessages(messages);

37.      const prompt = `You are a helpful assistant that returns travel itineraries based on location,
38.       the FCDO guidance from the specified tool, and the weather captured from the
39.       displayWeather tool.
40.       Use the flight information from tool getFlights only to recommend possible flights in the
41.       itinerary.
42.       If there are no flights available generate a sample itinerary and advise them to contact a
43.       travel agent.
44.      Return an itinerary of sites to see and things to do based on the weather.
45.      If the FCDO tool warns against travel DO NOT generate an itinerary.`;

47.      const result = streamText({
48.        model: ollama("qwen3:8b"),
49.        system: prompt,
50.        messages: allMessages,
51.        stopWhen: stepCountIs(2),
52.        tools,
53.        experimental_telemetry: { isEnabled: true }, // Allows OpenLit to pick up tracing
54.     );

56.      // Return data stream to allow the useChat hook to handle the results as they are streamed through for a better user experience
57.      return result.toUIMessageStreamResponse();
58.    } catch (e) {
59.      console.error(e);
60.      return new NextResponse(
61.        "Unable to generate a plan. Please try again later!"
62.      );
63.    }
64.  }

``AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

为了将我们的 traces 发送到 Elastic ,我们需要在 OpenLit 配置中指定 OTLP endpoint ,默认情况下它会发送到本地 OpenLit 实例和控制台。鉴于这是一个前端客户端,最佳实践是通过 proxycollector 发送这些信号(如 Observability Labs 中关于前端追踪的文章所讨论)。

另一个特定于我们 AI SDK 埋点的细节是,我们需要通过 experimental_telemetry: { isEnabled: true } 启用遥测数据的生成。结合这两组配置,OpenLit 将生成 traces ,展示我们应用中不同的工具调用,以及对 Elasticsearch 的关键请求,用于持久化我们的语义记忆。

默认的埋点还会生成 metrics ,包括输入和输出的 token 数量,可用于跟踪使用情况并识别使用趋势:

当然,你也可以创建自定义 dashboards 来跟踪这些计数,下方 dashboardJSON 可在这里获取:

使用 Evaluations 评估准确性

Evaluations 使用另一个 LLM 来评估生成响应的准确性,以识别不准确、偏见、幻觉以及诸如暴力提及等有毒内容。这是通过一种称为 LLM as a Judge 的机制实现的。在撰写本文时,OpenLit 支持通过 OpenAIAnthropic 进行评估。

它可以通过以下配置进行设置和触发:

php 复制代码
``

1.  // Imports and tools omitted

3.  openlit.init({
4.    applicationName: "ai-travel-agent",
5.    environment: "development",
6.    otlpEndpoint: process.env.PROXY_ENDPOINT,
7.    disableBatch: true
8.  });

10.  const evals = openlit.evals.All({
11.    provider: "openai",
12.    collectMetrics: true,
13.    apiKey: process.env.OPENAI_API_KEY,
14.  });

16.  // Post request handler
17.  export async function POST(req: Request) {
18.    const { messages, id } = await req.json();

20.    try {
21.      const convertedMessages = convertToModelMessages(messages);
22.      const allMessages: ModelMessage[] = previousMessages.concat(convertedMessages);

24.      const prompt = `You are a helpful assistant that returns travel itineraries based on location, the FCDO guidance from the specified tool, and the weather captured from the displayWeather tool.
25.          Use the flight information from tool getFlights only to recommend possible flights in the itinerary.
26.          If there are no flights available generate a sample itinerary and advise them to contact a travel agent.
27.          Return an itinerary of sites to see and things to do based on the weather.
28.          Reuse and adapt the prior history if one exists in your memory.
29.          If the FCDO tool warns against travel DO NOT generate an itinerary.`;

31.      const result = streamText({
32.        model: ollama("qwen3:8b"),
33.        system: prompt,
34.        messages: allMessages,
35.        stopWhen: stepCountIs(2),
36.        tools,
37.        experimental_telemetry: { isEnabled: true },
38.        onFinish: async ({ text, steps }) => {
39.          const toolResults = steps.flatMap((step) => {
40.            return step.content
41.              .filter((content) => content.type == "tool-result")
42.              .map((c) => {
43.                return JSON.stringify(c.output);
44.              });
45.          });

47.         // Evaluate response when received from LLM
48.          const evalResults = await evals.measure({
49.            prompt: prompt,
50.            contexts: allMessages.map(m => { return m.content.toString() }).concat(toolResults),
51.            text: text,
52.          });
53.        },
54.      });

56.      // Return data stream to allow the useChat hook to handle the results as they are streamed through for a better user experience
57.      return result.toUIMessageStreamResponse();
58.    } catch (e) {
59.      console.error(e);
60.      return new NextResponse(
61.        "Unable to generate a plan. Please try again later!"
62.      );
63.    }
64.  }

``AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

OpenAI 会扫描回复并标记不准确、有毒或带有偏见的内容,类似如下情况:

使用 Guardrails 检测恶意活动

除了评估之外,Guardrails 还允许我们监控 LLM 是否遵守我们对回复设置的内容限制,例如不泄露财务或个人信息。可以通过以下代码进行配置:

php 复制代码
``

1.  // Imports omitted

3.  openlit.init({
4.    applicationName: "ai-travel-agent",
5.    environment: "development",
6.    otlpEndpoint: process.env.PROXY_ENDPOINT,
7.    disableBatch: true
8.  });

10.  const guards = openlit.guard.All({
11.    provider: "openai",
12.    collectMetrics: true,
13.    apiKey: process.env.OPENAI_API_KEY,
14.    validTopics: ["travel", "culture"],
15.    invalidTopics: ["finance", "software engineering"],
16.  });

18.  // Post request handler
19.  export async function POST(req: Request) {
20.    const { messages, id } = await req.json();

22.    try {
23.      const convertedMessages = convertToModelMessages(messages);
24.      const allMessages: ModelMessage[] = previousMessages.concat(convertedMessages);

26.      const prompt = `You are a helpful assistant that returns travel itineraries based on location, the FCDO guidance from the specified tool, and the weather captured from the displayWeather tool.
27.          Use the flight information from tool getFlights only to recommend possible flights in the itinerary.
28.          If there are no flights available generate a sample itinerary and advise them to contact a travel agent.
29.          Return an itinerary of sites to see and things to do based on the weather.
30.          Reuse and adapt the prior history if one exists in your memory.
31.          If the FCDO tool warns against travel DO NOT generate an itinerary.`;

33.      const result = streamText({
34.        model: ollama("qwen3:8b"),
35.        system: prompt,
36.        messages: allMessages,
37.        stopWhen: stepCountIs(2),
38.        tools,
39.        experimental_telemetry: { isEnabled: true },
40.        onFinish: async ({ text }) => {
41.          const guardrailResult = await guards.detect(text);
42.          console.log(`Guardrail results: ${guardrailResult}`);
43.        },
44.      });

46.      // Return data stream to allow the useChat hook to handle the results as they are streamed through for a better user experience
47.      return result.toUIMessageStreamResponse();
48.    } catch (e) {
49.      console.error(e);
50.      return new NextResponse(
51.        "Unable to generate a plan. Please try again later!"
52.      );
53.    }
54.  }

``AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

在我们的示例中,它将标记潜在的个人信息请求:

结论

对于在这个节日期间构建和维护 AI 应用的人来说,遥测数据至关重要。希望这个关于如何使用 OpenLit 和 Elastic 生成 OpenTelemetry 信号的简单指南能帮助你在这个季节更轻松地值班。完整代码可在此获取。

节日快乐!

原文:discuss.elastic.co/t/dec-15th-...

相关推荐
阿拉斯攀登4 小时前
向量数据库选型:Milvus vs Chroma vs Elasticsearch
数据库·elasticsearch·milvus·知识库·rag·个人知识库
江畔柳前堤9 小时前
第15章:docker故障排查与面试题
大数据·运维·git·elasticsearch·docker·容器·eureka
江畔柳前堤10 小时前
第07章:Docker 网络模型
运维·网络·git·elasticsearch·docker·容器·架构
Elasticsearch2 天前
深入解析 simdvec:Elasticsearch 如何利用神经网络和视频编解码 CPU 指令实现向量搜索
elasticsearch
Elasticsearch2 天前
一条命令。自然语言。你的 Elasticsearch 数据,直接进入终端
elasticsearch
vivo互联网技术3 天前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页
Elasticsearch3 天前
热力直达:使用 Elasticsearch 插件将 ES|QL 引入你的 Grafana 仪表板
elasticsearch
小猿姐3 天前
唯品会大规模数据库云原生实践:基于 KubeBlocks 管理数千实例的统一运维之路
运维·elasticsearch·云原生
Elasticsearch4 天前
使用 Elastic Agent Builder 和 Sarvam AI 构建多语言语音 agent
elasticsearch