OpenAI SDK (JS/TS) 的可观测性
在找 Python 版本?请查看这里。
Langfuse JS/TS SDK 提供了围绕 OpenAI SDK 的包装函数,让你能够轻松为 OpenAI 调用添加可观测性。这包括追踪延迟、流式响应的首 token 时间、错误和模型用量。
import OpenAI from "openai";
import { observeOpenAI } from "@langfuse/openai";
const openai = observeOpenAI(new OpenAI());
const res = await openai.chat.completions.create({
messages: [{ role: "system", content: "Tell me a story about a dog." }],
});Litefuse 会自动追踪:
- 所有 prompt/completion,并支持流式与函数调用
- 总延迟和首 token 时间
- OpenAI API 错误
- 模型用量(token)和成本(USD)(了解更多)
工作原理
安装 Langfuse SDK
该集成与 OpenAI SDK 版本 >=4.0.0 兼容。
npm install @langfuse/openai openai注册凭据
将你的 Litefuse 凭据加入环境变量。请确保你的项目根目录有一个 .env 文件,并使用 dotenv 等包加载这些变量。
LANGFUSE_SECRET_KEY = "sk-lf-..."
LANGFUSE_PUBLIC_KEY = "pk-lf-..."
LANGFUSE_BASE_URL = "https://litefuse.cloud"初始化 OpenTelemetry
Langfuse TypeScript SDK 的追踪建立在 OpenTelemetry 之上,因此你需要设置 OpenTelemetry SDK。LangfuseSpanProcessor 是将 trace 发送到 Litefuse 的关键组件。
import { NodeSDK } from "@opentelemetry/sdk-node";
import { LangfuseSpanProcessor } from "@langfuse/otel";
const sdk = new NodeSDK({
spanProcessors: [new LangfuseSpanProcessor()],
});
sdk.start();使用包装后的客户端调用 OpenAI 方法
环境配置好后,像往常一样从包装后的客户端调用 OpenAI SDK 方法。
import OpenAI from "openai";
import { observeOpenAI } from "@langfuse/openai";
const openai = observeOpenAI(new OpenAI());
const res = await openai.chat.completions.create({
messages: [{ role: "system", content: "Tell me a story about a dog." }],
model: "gpt-4o",
max_tokens: 300,
});完成!现在你已经在 Litefuse 中拥有 OpenAI 调用的完整可观测性。
查看 notebook 获取该集成的端到端示例:
故障排查
事件的排队与批处理
Langfuse SDK 会在后台对事件进行排队和批处理,以减少网络请求数量并提升整体性能。在长时间运行的应用中,无需任何额外配置即可工作。
如果你运行的是短生命周期应用,需要在应用退出前 flush Litefuse,以确保所有事件都已发送。
await langfuseSpanProcessor.forceFlush();
// If you have previously initialized a Langfuse client, you can use that for the flush call
await langfuse.flush();了解更多关于事件排队与批处理的内容请见这里。
Assistants API
本集成不支持对 Assistants API 进行追踪,因为 OpenAI Assistants 在服务端有状态,难以在不发起额外 API 请求的情况下捕获。我们在这个 FAQ 中提供了一些关于如何更好追踪 Assistants API 用法的信息。
高级用法
自定义 trace 属性
你可以将以下属性添加到 observeOpenAI 函数的 langfuseConfig 中,以使用更多 Litefuse 功能:
| 属性 | 说明 |
|---|---|
generationName | 设置 generationName 以标识特定类型的生成。 |
langfusePrompt | 传入已创建或获取的 Litefuse prompt,将其与生成关联起来 |
generationMetadata | 通过 generationMetadata 设置希望在 Litefuse 中看到的额外信息。 |
sessionId | 当前的 会话。 |
userId | 当前的 user_id。 |
tags | 设置 tag 以对 trace 进行分类和过滤。 |
示例:
const res = await observeOpenAI(new OpenAI(), {
generationName: "Traced generation",
generationMetadata: { someMetadataKey: "someValue" },
sessionId: "session-id",
userId: "user-id",
tags: ["tag1", "tag2"],
}).chat.completions.create({
messages: [{ role: "system", content: "Tell me a story about a dog." }],
model: "gpt-3.5-turbo",
max_tokens: 300,
});添加自定义属性需要使用 observeOpenAI 函数包装 OpenAI SDK,并将属性作为第二个
langfuseConfig 参数传入。由于这里的 Langfuse 客户端是单例,所有调用都使用同一个客户端,
你不必担心会错误地启动多个客户端。
关联到 Litefuse prompt
通过 Litefuse Prompt management,你可以高效地管理和版本化 prompt。你可以通过将 langfusePrompt 属性传给 observeOpenAI 函数,将 OpenAI 的生成关联到某个 prompt。
import { observeOpenAI } from "@langfuse/openai";
import OpenAI from "openai";
const langfusePrompt = await langfuse.prompt.get("my-prompt"); // Fetch a previously created prompt
const res = await observeOpenAI(new OpenAI(), {
langfusePrompt,
}).completions.create({
prompt: langfusePrompt.prompt,
model: "gpt-3.5-turbo-instruct",
max_tokens: 300,
});生成的结果现在与 Litefuse 中的 prompt 关联起来,让你可以追踪 prompt 的使用情况和性能。
在使用 chat prompt 时,你必须将编译后的 prompt messages 类型断言为 OpenAI.ChatCompletionMessageParam[],或使用类型守卫工具函数,因为 Litefuse 的 message role 可以是任意字符串,而 OpenAI 的类型定义则更为严格。
流式响应中的 OpenAI token 用量
OpenAI 仅在 stream_options 中将 include_usage 参数设为 true 时,才会在流式响应中返回 token 用量。如果你希望直接获得 OpenAI 提供的 token 用量,可以在 stream_options 参数中设置 { include_usage: true }。
import OpenAI from "openai";
import { observeOpenAI } from "@langfuse/openai";
const openai = observeOpenAI(new OpenAI());
const stream = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "How are you?" }],
stream: true,
stream_options: { include_usage: true },
});
let result = "";
for await (const chunk of stream) {
// Check if chunk choices are not empty. OpenAI returns token usage in a final chunk with an empty choices list.
result += chunk.choices[0]?.delta?.content || "";
}