OpenTelemetry
@flue/opentelemetry 将 Flue 的实时运行时观察投影到标准 OpenTelemetry GenAI 跨度和指标中。它不配置 SDK、导出器、采样、凭证或特定于部署的刷新。
该包实现了固定在提交 4c8addb53718b544134be47e256237026fe88875 上的 Development GenAI 约定。其 Flue 到 GenAI 的投影修订版本为 5,Flue 扩展修订版本为 5;词汇表、投影和修订常量位于 @flue/runtime/telemetry 中,并与原生 Cloudflare 追踪适配器完全共享,因此为一个后端编写的负载在另一个后端上读取完全相同。更新任何修订版本需要显式的兼容性审查。
配置
安装适配器和 OpenTelemetry API,以及与你的部署目标兼容的 SDK 和导出器:
pnpm add @flue/opentelemetry @opentelemetry/api
首先配置 SDK,然后注册一个检测实例:
import { createOpenTelemetryInstrumentation } from '@flue/opentelemetry';
import { instrument } from '@flue/runtime';
const instrumentation = createOpenTelemetryInstrumentation();
const disposeInstrumentation = instrument(instrumentation);当应用拥有它们时,传递配置的跟踪器、计量器或结构化 Logger 实例。生成的 Node 应用在准入和活动工作排空后自动处置在评估 app.ts 时创建的注册。仅在该生命周期之外注册时才自己调用 await disposeInstrumentation(),然后单独刷新或关闭应用拥有的 SDK/导出器。
跟踪模型
- 提示或技能操作成为
invoke_agent <agent>。 - 委托任务成为任务拥有的
invoke_agent <agent>。 - 提供商推理成为
chat <requested-model>客户端跨度。 - GenAI 工具执行成为
execute_tool <name>。 - 调用者 shell 执行成为
flue.operation shell。 - 上下文压缩成为带有子聊天跨度的
flue.compaction。
提供商聊天跨度仅涵盖提供商推理。投影直接读取规范模型遥测:语义 request.providerName 成为 gen_ai.provider.name,而 request.providerId 保持 Flue 注册身份。本地工具是智能体调用下的兄弟跨度,并通过 gen_ai.tool.call.id 与模型输出关联。
gen_ai.conversation.id 标识一个持久化的 Flue 会话。它不是提交、分派、操作、跟踪、会话名称或提供商亲和性密钥。当没有精确的标准字段存在时,Flue 关联字段保留在文档化的 flue.* 属性下。
保护内容
内容默认启用 — 模型消息、推理、系统指令、工具定义、参数/结果以及异常消息和堆栈跟踪都作为跨度属性发送。显式的 instrument(...) 调用是同意(故意偏离更广泛的 OTel GenAI 约定,即内容在环境变量选择后默认关闭)。在将数据导出到未清除对话数据的后端之前,请审查接收后端的保留和访问控制,并应用以下两个控制之一。
// 无内容跨度
const instrumentation = createOpenTelemetryInstrumentation({ content: false });
// 代码中的策略
const instrumentation = createOpenTelemetryInstrumentation({
content: {
transform(content, scope) {
if (scope.contentType === 'exception_stacktrace') return undefined; // 剥离堆栈
return redactSecrets(content);
},
},
});
分离的转换值每种内容类型通过 transform 一次;返回 undefined 省略该内容,抛出的转换发出 [flue] 失败哨兵而不是未编辑的值。scope 携带内容类型、事件类型、执行身份和 traceId/spanId。对于字节预算,在转换内部切片或使用导出的 truncateContent(content, { maxBytes })。转换后,每个跨度 56 KiB 的内容预算在带内强制执行(默认大小为 workerd 的 64 KiB 跨度属性上限):跨度携带的所有内容——消息、系统指令、工具定义和负载、异常消息/堆栈——共享一个池,并保留空间以便响应内容在大型提示旁边有空间。不受 workerd 限制约束的后端可以通过 createOpenTelemetryInstrumentation() 上的 contentBudgetBytes 提高(或收紧)该池——例如 contentBudgetBytes: 200_000 将更完整的提示和工具结果发送到非 workerd 的可观测性后端。(在 Cloudflare 目标上,createCloudflareTracing() 的 contentBudgetBytes 仅是收紧控制:workerd 的 64 KiB 跨度属性上限是任何设置都无法提高的平台限制。)负载在其结构序列化为对象/数组的地方保持有效的 JSON(最旧的消息在 role: "flue" 哨兵消息之后首先丢弃,过大的字符串叶节点以 [flue:truncated, …] 后缀裁剪)——过大的原始字符串作为字符串裁剪,不再解析为 JSON。没有侧通道截断标记属性;请在负载中搜索 [flue]。
工具参数/结果使用标准的 gen_ai.tool.call.* 属性来处理每种负载形状,因此支持标准的后端可以显示它们:对象和数组负载记录为 JSON 字符串,适合剩余内容预算的字符串负载逐字节记录,其他标量记录为其 JSON 形式。固定的约定将这些属性类型化为 any,并在跨度上允许 JSON 字符串形式。
指标和日志
检测发出客户端操作、令牌使用、智能体调用和工具持续时间直方图。指标维度排除执行 ID;审查你的应用控制的智能体、工具、提供商和模型名称是否具有适当的基数。输入令牌总数包括缓存读取和缓存创建输入令牌。
日志需要显式的 Logger 注入。失败的推理操作在 WARN/13 发出标准 gen_ai.client.operation.exception 事件。错误类型始终记录;异常消息和抛出位置堆栈跟踪(exception.stacktrace)依赖内容门控 — 默认包含,由你的 transform 转换,在 content: false 下缺失。Logger 缺失不影响跟踪或指标。
传播和恢复
Flue 在直接智能体准入时验证并持久化 traceparent 和可选的 tracestate。Baggage 不持久化。持久化直接智能体处理激活其提取的准入上下文,执行拦截器在智能体、模型流、工具和任务工作周围激活拥有的跨度。dispatch(...) 当前不传播跟踪上下文。
恢复不重放提供商或工具执行。存储的流块不创建聊天跨度或使用观察,合成中断工具修复不创建 execute_tool 跨度。
流限制
Pi 不暴露权威的原始提供商流项目时序。因此 Flue 省略首次块时间和每输出块时间指标,而不是从语义文本/推理增量或恢复块推导不准确的值。
不支持的操作
Flue 不为智能体创建、规划、嵌入、检索、内存操作、远程智能体客户端或评估发出虚构的跨度。这些操作保持缺失,直到 Flue 暴露真正的相应边界。
验证
在测试中使用内存 OpenTelemetry 导出器来验证层次结构、名称、类型、状态、属性、指标和你的内容策略(包括 content: false 或你的转换确实移除了你期望的内容)。托管后端渲染是特定于后端的;标准正确的 OTel 输出是可移植的契约。