布里兹SDK
用于 AI 应用的基于 OpenTeleometry 的可观察性 SDK,由 布丽兹。 。 。 . 追踪受欢迎的AI库,包括OpenAI,Anthropic,Vercel AI SDK等.
目录
- 特征
- 安装
- 快速启动
- 模块系统支持
- 支持的图书馆
- PII 化妆
- 会话跟踪
- 副剂
- 静音信件
- 一个进程中的多种服务
- 自定义事件和日志
- 环境变量
- 禁用 Span 导出
- 丢弃垃圾邮件
- 运行在您自己打开的远程设置旁
- 无服务器( Cloud Run, Lambda)
- 高级配置
- 测试和开发
- 软件包.json 示例
- 实例
- 解决问题
- 捐款
- 链接
- 许可证
特征
- 🔍 单打设置 - 通过你的AI库
Brizz.initialize()他们被追踪 - 📊 OpenTeleometry 原生语言 - 符合标准的追踪、衡量标准和记录
- 🛡️ PII 化妆 - 敏感数据的可选掩码
- 🔄 会话跟踪 - 与集团有关的行动和痕迹
- 📦 在任何地方运行 - 无害环境管理、共同JS、捆绑商和
tsx
安装
npm install @brizz/sdk
# or
yarn add @brizz/sdk
# or
pnpm add @brizz/sdk
快速启动
首先,设置环境变量:
BRIZZ_API_KEY=your-api-key
BRIZZ_BASE_URL=https://telemetry.brizz.dev # Optional
BRIZZ_APP_NAME=my-app # Optional
BRIZZ_LOG_LEVEL=info # Optional: debug, info, warn, error, none
然后在您的应用程序中初始化 SDK, 通过您想要追踪的库 :
import { Brizz } from '@brizz/sdk';
import OpenAI from 'openai';
Brizz.initialize({
apiKey: process.env.BRIZZ_API_KEY,
appName: 'my-ai-app',
instrumentModules: { openAI: OpenAI },
});
运行你的应用程序的方式,你已经做 - node app.js, (中文(简体) ), tsx app.ts,或者你自己的开始脚本.
重要: 调用
Brizz.initialize()在做任何AI电话之前。 如果使用dotenv,使用时import "dotenv/config"导入前@brizz/sdk。 。 。 .
模块系统支持
在无害环境管理、共同司法系统、捆绑商和 tsx - 进口 @brizz/sdk 打电话
Brizz.initialize()。 。 。 .
内置模块(Next.js, Webpack)可能需要动态导入, 以便您可以交出
解析模块到 instrumentModules数字 :
// For problematic bundlers
const { default: OpenAI } = await import('openai');
Brizz.initialize({
apiKey: 'your-api-key',
instrumentModules: {
openAI: OpenAI,
},
});
支持的图书馆
通过您使用的库 instrumentModules 和SDK追踪:
- 开放AI - 说吧
openai软件包 - 安东尼 - 说吧
@anthropic-ai/sdk软件包 - 维塞尔 AI SDK - 说吧
ai软件包(基因文本、流文本等)- 通过AI SDK自己的遥测——通过
instrumentModules: { ai, aiOtel }从第一次呼叫中追踪ai@7(与@ai-sdk/otel已安装); 运行ai@6更早,通过experimental_telemetry: { isEnabled: true }每次通话
- 通过AI SDK自己的遥测——通过
- 兰彩 - 说吧
langchain财务报告和审定财务报表@langchain/*软件包 - 拉玛因德克斯 - 说吧
llamaindex软件包 - AWS 贝德洛克 - 说吧
@aws-sdk/client-bedrock-runtime - 矢量数据库 - Pinecone、Qdrant、ChromaDB
任择文书
一些仪器船作为 可选同伴依赖关系 所以他们只是 需要的时候就过来了 安装匹配软件包以启用它们 :
| 追踪 | 安装 |
|---|---|
微调 AI SDK v7+ (单位:千美元)ai@7)——跨度捕捉所需 | npm install @ai-sdk/otel |
Google GenAI / 双子座 (单位:千美元)@google/genai()——见 双子座 | npm install @traceloop/instrumentation-google-generativeai |
Google Vertex AI (谷歌Vertex AI) 互联网档案馆的存檔,存档日期2013-10-02 (单位:千美元)@google-cloud/vertexai(中文(简体) ) | npm install @traceloop/instrumentation-vertexai |
| MCP 磁共振 (模式背景协议) | npm install @arizeai/openinference-instrumentation-mcp @modelcontextprotocol/sdk |
如果一个包没有安装,SDK会继续工作,只是跳过
仪器 在自动路径上,跳跃是安静的 debug 日志; 当您
明确选择通过 instrumentModules,在 error
所以错位是可见的.
Vercel AI SDK 整合
打开 ai@7 ,并安装 @ai-sdk/otel - v7 移动了 AI SDK 跨度收藏
所以没有它你的 generateText 编号 : streamText 电话生成不
横跨。 没必要穿了 ai@6。 。 。 .
打开 ai@6 并且更早, 遥测默认关闭, 所以允许每次呼叫。 打开 ai@7 它是默认的, 旗帜是可选的 :
import { generateText, streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
// For generateText
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello, world!',
experimental_telemetry: { isEnabled: true }, // Required on ai@6 and earlier
});
// For streamText
const stream = streamText({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Hello!' }],
experimental_telemetry: { isEnabled: true }, // Required on ai@6 and earlier
});
这使得能够自动追踪:
- 模拟呼叫和答复
- 库存使用和费用
- 工具呼叫和处决
- 数据流
对于脚本,无服务器功能和捆绑的无害环境管理,通过您导入的模块注册
遥测前 Brizz.initialize() 返回。 你的第一个AI SDK电话被追踪:
import { Brizz } from '@brizz/sdk';
import * as ai from 'ai';
import * as aiOtel from '@ai-sdk/otel';
Brizz.initialize({ appName: 'my-app', instrumentModules: { ai, aiOtel } });
// Calls to ai.generateText() and ai.streamText() are traced immediately.
没有这些模块,布里兹就会在后台上加载已安装的软件包. 一个叫
在注册完成前开始,没有找到。 打开 ai@6,仅通过 ai 并启用
experimental_telemetry 每个电话.
如果您的应用程序注册了自己的 @ai-sdk/otel 收集器和它的长度 已经到达布里兹,
把布里兹的收藏家关了 所以每次通话都会追踪一次
Brizz.initialize({
appName: 'my-app',
instrumentModules: { ai },
disableAiSdkCollector: true,
});
ai.registerTelemetry(new aiOtel.OpenTelemetry()); // after Brizz.initialize()
disableAiSdkCollector: true 也工作没有 instrumentModules,使用背景
登记。 在设置了遥测提供者后, 总是创建自己的收藏家 .
维塞尔夜
维塞尔 eve 代理发布标准 OpenTelemetry GenAI 跨度,所以 Brizz 摄入
他们的踪迹,信息内容, 和成本,只要你指向前夕的出口商 在你的布里兹端点.
@brizz/sdk/eve 给你一条线 registerOTel 读取的配置 BRIZZ_DSN - 它电线
出口商和使每个代理人运行的会话分组作为单一对话渲染:
// agent/instrumentation.ts
import { defineInstrumentation } from 'eve/instrumentation';
import { registerOTel } from '@vercel/otel';
import { createEveOtelConfig } from '@brizz/sdk/eve';
export default defineInstrumentation({
setup: ({ agentName }) => registerOTel(createEveOtelConfig({ serviceName: agentName })),
});
然后在环境中设置您的 DSN—— 一个被粘贴的证书:
BRIZZ_DSN=https://<bearer>@<gateway-host>/<service-name>
createEveOtelConfig 从DSN中取出持证人和终点,而忽略其服务部分
节日 agentName 保留服务名称。 更喜欢自己作曲? 这些部件也出口:
import { createEveTraceExporter, createEveSessionProcessor } from '@brizz/sdk/eve';
registerOTel({
serviceName: agentName,
traceExporter: createEveTraceExporter(),
// 'auto' keeps the default exporter processor.
spanProcessors: [createEveSessionProcessor(), 'auto'],
});
@brizz/sdk/eve 是一个独立且无副作用的导出: 它没有初始化完整的 SDK, 所以
它不会重复 跨度前夕已经发出.
Google GenAI (格米尼语)
@google/genai 是Google统一为双子座的SDK
(双子座开发者API和Vertex AI). 安装对等依赖, 然后构建客户端
从班上 instrumentGoogleGenAI 返回 :
import { Brizz } from '@brizz/sdk';
import { instrumentGoogleGenAI } from '@brizz/sdk/google-genai';
import * as genai from '@google/genai';
Brizz.initialize({ appName: 'my-app' });
// Call after Brizz.initialize(). The returned class is instrumented — build the client from it.
const GoogleGenAI = instrumentGoogleGenAI(genai);
const ai = new GoogleGenAI({ vertexai: true, project, location });
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash',
contents: 'Hello, world!',
});
这个痕迹 generateContent 编号 : generateContentStream - 信息、工具呼叫、象征性使用,以及
成本——不按召用仪器.
与其他融合不同, @google/genai 实值 没有 有线通过 instrumentModules。 。 。 .
这是一个只使用无害环境管理的软件包,一个节点ES模块命名空间是只读的,所以不能被补丁到
地点—— instrumentGoogleGenAI 返回已设置的仪器 GoogleGenAI 换成班级 构造
你那个班的客户就完了.
PII 化妆
跨度属性的可选掩码 .
// Enable default masking
Brizz.initialize({
apiKey: 'your-api-key',
masking: true,
});
// Custom masking configuration
Brizz.initialize({
apiKey: 'your-api-key',
masking: {
spanMasking: {
rules: [
{
attributePattern: 'gen_ai\\.(prompt|completion)',
mode: 'partial', // 'partial' or 'full'
patterns: ['sk-[a-zA-Z0-9]{48}'],
},
],
},
},
});
当启用时,默认覆盖了一组被整理的常见秘密图案. 为需要蒙上口罩的任何东西添加自定义规则.
会话跟踪
在会话背景下进行分组相关业务:
会话背景管理器( 建议)
这个 startSession 函数创建会话跨度并提供 Session 对象 :
import { startSession } from '@brizz/sdk';
// Basic usage - all LLM calls within the callback are automatically linked
const result = await startSession(
'session-123',
async (session) => {
// Add custom properties (optional)
session.updateProperties({ userId: 'user-456', model: 'gpt-4' });
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: userQuery }],
});
return response;
},
{ feature: 'chat' }, // optional: extraProperties propagated to all spans
);
会话方法 :
session.updateProperties({ key: value })- 在会话间距上添加自定义属性session.setInput(text, context?)- (可选)手动跟踪输入文本;可选上下文包 附加仪表板上背景面板上提供的倒转元数据session.setOutput(text, context?)- (可选)手动跟踪输出文本;可选上下文包 附加仪表板上背景面板上提供的倒转元数据session.setTitle(text)- 设置会话标题(通常使用mode: 'title'(中文(简体) )session.addExternalLink(url, options?)- (可选)在会话中附加一个外部链接(例如:数据犬追踪或仪表板);它出现在会话细节面板上. 也可以作为顶级addExternalLink(url, options?)。 。 。 .
每回合上下文示例:
await startSession('session-123', async (session) => {
session.setInput('Why is my bill high?', { selected_invoice: 'INV-9182' });
const response = await openai.chat.completions.create({ ... });
session.setOutput(response.choices[0].message.content, {
message_id: 'msg-42',
sources: ['doc-abc'],
});
});
何时使用人工输入/输出跟踪 :
在大多数情况下,布里兹会自动捕捉您的 LLM 调用中的投入和输出. 使用
setInput编号 :setOutput 特殊情景:
- 多剂流动: 只跟踪用户的输入/输出,而不是中间代理通信
- 结构化数据提取:从复杂的 JSON 请求中跟踪特定字段
- 后处理: 在返回用户前跟踪已转换的回复
await startSession('session-456', async (session) => {
// Extract just the query from a structured request
const requestData = { query: "What's the weather?", context: {...} };
session.setInput(requestData.query);
const response = await openai.chat.completions.create({...});
// Extract answer from structured response
const responseJson = JSON.parse(response.choices[0].message.content);
session.setOutput(responseJson.answer);
return responseJson;
});
外部链接示例 :
import { addExternalLink, startSession } from '@brizz/sdk';
startSession('session-123', (session) => {
// Top-level function — resolves the active session from context.
addExternalLink('https://app.datadoghq.com/trace/abc', { title: 'Datadog trace' });
});
// Outside a session — pass the id explicitly.
addExternalLink('https://sentry.io/issues/456', { sessionId: 'session-123', linkType: 'sentry' });
会话标题生成
如果您使用 LLM 调用生成会话标题, 请将它包起来, 将它的跨度显示为“ 生成标题 ” 排行而不是交接:
import { startSession, startSessionTitle } from '@brizz/sdk';
await startSession('session-123', async (session) => {
const response = await openai.chat.completions.create({...});
// Title generation — shown as one row, not as turns
await startSessionTitle(async (title) => {
const t = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Summarize this chat in 3 words' }],
});
title.setTitle(t.choices[0].message.content);
});
});
// Or use mode: 'title' on startSession directly
await startSession('session-123', async (session) => {
const t = await openai.chat.completions.create({...});
session.setTitle(t.choices[0].message.content);
}, undefined, { mode: 'title' });
// Or use startSessionTitle outside a session (pass sessionId explicitly)
await startSessionTitle(async (title) => {
title.setTitle('My Title');
}, { sessionId: 'session-123' });
访问活动会话
使用 getActiveSession() 从 a 中的任意位置检索当前会话 startSession 范围
不需要通过您的调用堆栈传递会话对象 :
import { startSession, getActiveSession } from '@brizz/sdk';
function deepHelper() {
const session = getActiveSession();
session?.updateProperties({ step: 'helper' });
}
await startSession('session-123', async () => {
deepHelper(); // accesses session without it being passed as a parameter
});
// Outside a session, returns undefined
getActiveSession(); // undefined
轻量级会话助手
@brizz/sdk/session 输出会话和上下文助手而不装入 SDK 其余部分,
它保持模块重的设置,如Jest测试套房快速而小:
import { callWithSessionId, getActiveSession } from '@brizz/sdk/session';
保留 Brizz.initialize() 主体 @brizz/sdk 启动时输入。 在它运行之前什么也没有发出.
函数折叠器模式
对于只需要用会话标识标记痕迹的简单案件:
import { withSessionId, emitEvent } from '@brizz/sdk';
async function processUserWorkflow(userId: string) {
// All traces within this function will include the session ID
const result = await generateText({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Hello' }],
experimental_telemetry: { isEnabled: true },
});
return result;
}
// Create a wrapped function that always executes with session context
// withSessionId(sessionId, fn, thisArg?, extraProperties?)
const sessionedWorkflow = withSessionId('session-123', processUserWorkflow, undefined, {
feature: 'workflow',
});
// Call multiple times, each with the same session context
await sessionedWorkflow('user-456');
await sessionedWorkflow('user-789');
立即执行模式
import { callWithSessionId } from '@brizz/sdk';
// Execute function immediately with session context
await callWithSessionId('session-123', processUserWorkflow, null, 'user-456');
识别用户、组织和信件
附上最终用户、他们的组织以及带有打出装置的每个消息代号。 在会话中召唤他们——他们适用于转弯时段:
import { startSession, setUser, setOrganization, setMessageId } from '@brizz/sdk';
await startSession(sessionId, async () => {
setUser({ id: user.id, email: user.email, role: user.role, plan: user.plan });
setOrganization({ id: org.id, name: org.name, plan: org.plan, domain: org.domain });
setMessageId(message.id); // your own id, to reference this message later
return agent.run(prompt);
});
仅 id 需要时间。 每个字段映射到自己的属性(brizz.user.id, (中文(简体) ), brizz.organization.plan, (中文(简体) ), brizz.message.id(中文(简体) ). 对于任何超出指定字段的,通过 traits 记录——每个条目改为 brizz.user.<key> 编号 : brizz.organization.<key>数字 :
setUser({ id: user.id, traits: { department: 'sales', signup_source: 'referral' } });
setOrganization({ id: org.id, traits: { industry: 'fintech' } });
会话对象上也有同样的设置符(session.setUser(...)和作为范围包装(callWithUser 编号 : withUser) (中文(简体) ).
记录反馈
抓住最终用户对具体回复的反应——QQ/QQ,评分,理由. 用你转弯时的代号来表示:
import { startSession, setMessageId, recordFeedback } from '@brizz/sdk';
await startSession(sessionId, async () => {
setMessageId(message.id); // the id you'll reference this reply by
const reply = await agent.run(prompt);
recordFeedback('thumbs_up'); // defaults to the current message
});
仅 type 需要; score, (中文(简体) ), reason, (中文(简体) ), comment,以及 source 可选的,以及 attributes 添加免费形式 brizz.feedback.<key> 条目。 反馈由 messageId 和(或) sessionId,因此,您可以稍后——甚至在答复后数分钟或数天——通过明确传递id:
recordFeedback('thumbs_down', { messageId: message.id, sessionId, reason: 'inaccurate' });
记录量表
报告一个数字,你自己的系统已经计算出一个交互——一个eval分数,一个客户评分,一个延迟,一个成本. 它成为真正的布里兹度量度量度量度度量度量度量度量度量度量度量度量度量度量度量度量度量度量度值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值值.
import { startSession, recordMetric } from '@brizz/sdk';
await startSession(sessionId, async () => {
const reply = await agent.run(prompt);
const score = await myEvaluator.score(prompt, reply);
recordMetric({
name: 'quality_score',
value: score,
unit: 'score',
minValue: 0,
maxValue: 1,
polarity: 'positive',
});
});
polarity 告诉布里兹哪个方向是好的——上升 quality_score 是一个进步,一个上升 hallucination_rate 是一个回归. minValue 编号 : maxValue 描述天平,所以五分之四不读为一分之四.
计分经常发生在事后. 过 sessionId 从任何地方附加一个度量衡 timestamp 说 当测量的事物发生的时候所以一个夜间工作 得分在它描述的转弯 而不是评价运行:
recordMetric({
name: 'quality_score',
value: await judge.score(session),
sessionId: session.id,
timestamp: session.endedAt,
comment: 'graded by the nightly LLM judge',
attributes: { evaluator: 'gpt-4o', rubric: 'v2' },
});
attributes 是平面标签 你可以切分度量。 重报相同的度量值取代了先前的值,所以重取分数胜于原值.
离线评价工作常常在一个过程中给几个服务的对话打分. 过 serviceName 在其所属服务下报告每个计量标准,以及 traceId 当您有对话的线索而不是其会话编号时:
for (const row of evalResults) {
recordMetric({
name: 'resolved',
value: row.resolved,
serviceName: row.service, // e.g. 'support-agent'
traceId: row.traceId, // 32 hex characters
});
}
一个度量标准需要一个会话标识或跟踪标识才能降落在对话上;一个既无,又无警告.
默认情况下,每一次谈话都有一个值。 每转一圈,通过一次 scope: 'trace':每个痕量都保持自己的价值,在对话的那一回显示,会话读作它的转折平均值. 追踪是 traceId 以示警告
await startSession(sessionId, async () => {
const reply = await agent.run(prompt);
recordMetric({ name: 'frustration_rate', value: frustration(prompt), scope: 'trace', polarity: 'negative' });
});
记录分类呼叫
当你通过自己的HTTP代码调用分类模型时,请将调用包入 decisionCall 因此,它出现在对话中 与它的问题,答案,符号和成本。 回调的回调值被传递,它所抛出的一个错误被记录并重新显示:
import { decisionCall } from '@brizz/sdk';
const response = await decisionCall(
{ provider: 'microsoft', model: 'microsoft-decision-1', state, questions },
async (call) => {
const r = await client.decide(state, questions);
call.setAnswers(r.answers);
call.setUsage({ inputTokens: r.usage.input, outputTokens: r.usage.output });
call.setCost(0.0001); // optional, USD
return r;
},
);
state 是一个字符串或任何JSON值; questions 答案是随着你的传阅而发出的。 可选 requestModel 是您要求的模型名称, 当它与 model。此调用将加入当前会话, 并带有当前自定义属性; 要设置它们进行一个调用, 请将其包入 callWithSessionId 或者说 callWithProperties。 。 。 .
为了记录一个已经发生的电话, 立即传递一切, 有可选的 startTime 编号 : endTime (单位:千美元)Dates): (中文(简体) )
import { recordDecisionCall } from '@brizz/sdk';
recordDecisionCall({
provider: 'microsoft',
model: 'microsoft-decision-1',
state,
questions,
answers: r.answers,
inputTokens: 555,
outputTokens: 6,
startTime: startedAt,
});
自定义属性
添加自定义属性到遥测上下文 :
import { withProperties, callWithProperties } from '@brizz/sdk';
// Wrapper pattern - properties applied to all calls
const taggedFn = withProperties({ env: 'prod', feature: 'chat' }, myFunction);
await taggedFn(args);
// Immediate execution - properties applied once
await callWithProperties({ userId: 'user-123' }, myFunction, null, args);
处理方法背景
使用包装方法时 this,您有几种选择:
备选案文1:箭头函数(建议)
class ChatService {
async processMessage(userId: string, message: string) {
// This method uses 'this' context
return `Processed by ${this.serviceName}: ${message}`;
}
}
const service = new ChatService();
// Wrap with arrow function to preserve 'this' context
const sessionedProcess = withSessionId('session-123', (userId: string, message: string) =>
service.processMessage(userId, message),
);
备选案文2:使用约束()
// Pre-bind the method to preserve 'this' context
const sessionedProcess = withSessionId('session-123', service.processMessage.bind(service));
备选案文3:明确本参数
// Pass 'this' context explicitly as third parameter
const sessionedProcess = withSessionId(
'session-123',
service.processMessage,
service, // explicit 'this' context
);
说明: 箭头函数方法(备选1)因其更为明确而被推荐,避免被指
警告,并且不会 this 具有约束力的问题.
副剂
标记作为副剂工作,所以它显示自己在对话中的行道,而不是混入会话的主要记录. 尼斯廷作曲,同名代理的两跑会停留两道.
三种形式,相同的第一个论点——一个名字, { name, id, parentId },或 { token }数字 :
import { setAgent, startAgent, withAgent } from '@brizz/sdk';
// startAgent — scoped: runs the callback now, returns its return value
await startAgent('research', () => researchAgent.generate({ prompt: task }));
// withAgent — wraps a function; every call is its own run, so its own lane
const research = withAgent('research', runResearch);
await research(topicA);
await research(topicB);
// setAgent — imperative, no scope: marks everything created after it, and
// returns the handle. The natural form at the top of a job or route handler.
export async function handleJob(job) {
setAgent({ token: job.brizzAgent });
await boardCreator.generate({ prompt: job.goal });
}
const { token } = setAgent('board-creator'); // grab the token to send onward
setAgent 镜像 setUser 编号 : setSessionId - 没有自动重置,所以使用 startAgent 当你想要关闭瞄准镜时.
递出一个子代理以编码在别处运行——一个队列消息,一个RPC参数,一个数据库行——是符号: 随工作一起发送,再从另一边重新输入代理. 它携带会话和跟踪上下文,因此脱去的跑会加入同一种对话.
await startAgent('board-creator', ({ token }) => sendToWorker({ goal, brizzAgent: token }));
已经追踪到自己的探员身份了吗? 传出他们而不是一个空名:
await startAgent({ name: 'research', id: runId, parentId: callerRunId }, () => run());
id 您的id 用于此运行( 每个运行独有, 或者两个运行共享一条道) 和 parentId 覆盖附件代理。 任何省略之处都填入——新鲜 id 每个运行时,附件代理作为父母。 不要给 withAgent a 一个 id:它会把每一个呼叫 包裹的功能在一个道.
静音信件
保持内部或无关的LLM调用——总结,标题生成,分类,护栏检查——出被俘谈话. 呼叫仍然运行,其遥测(纬度,符号,成本)被记录下来;只有内容被忽略了——即时,回复,工具调用.
import { callWithMute, withMute } from '@brizz/sdk';
// Hide both sides of an internal call
await callWithMute({}, () => agent.run('Summarize this conversation for internal logging.'));
// Keep the assistant reply, drop the prompt
await callWithMute({ output: false }, () => agent.run('…a long internal prompt…'));
// Keep the tool calls, drop the prompt and the reply
await callWithMute({ tools: false }, () => agent.run('…a long internal prompt…'));
// Pre-wrap a function to reuse the same muting
const muteTitle = withMute({}, agent.run, agent);
tools 涵盖工具呼叫及其结果。 别管它了,就跟着它 output。 。 。 .
部署环境
可选择指定更好的过滤和组织的部署环境:
Brizz.initialize({
apiKey: 'your-api-key',
appName: 'my-app',
environment: 'production', // Optional: 'dev', 'staging', 'production', etc.
});
一个进程中的多种服务
appName 命名整个进程。 当一个过程运行 几个代理
应作为单独的服务出现在布里兹, 范围服务名称代替:
import { callWithServiceName, withServiceName, setServiceName } from '@brizz/sdk';
// Everything traced inside the callback reports as 'checkout-agent',
// including auto-instrumented LLM calls
await callWithServiceName('checkout-agent', async () => {
return openai.chat.completions.create({ ... });
});
// Pre-wrap a handler
const handleSupport = withServiceName('support-agent', supportHandler);
// Imperative form, for when the enclosing span already exists
// (an MCP or HTTP instrumentation opens its span before your handler runs)
setServiceName('billing-agent');
在其中任何一个外创建的垃圾邮件和事件保持配置 appName。 。 。 .
自定义事件和日志
Emit 自定义事件和结构化日志 :
import { emitEvent, emitEventWithSessionId, logger } from '@brizz/sdk';
// Emit custom events
emitEvent('user.signup', {
userId: '123',
plan: 'pro',
source: 'website',
});
emitEvent('ai.request.completed', {
model: 'gpt-4',
tokens: 150,
latency: 1200,
});
// Emit with a known session ID, outside any session scope
emitEventWithSessionId('session-123', 'user.feedback.submitted', {
rating: 5,
});
// Structured logging
logger.info('Processing user request', { userId: '123', requestId: 'req-456' });
logger.error('AI request failed', { error: err.message, model: 'gpt-4' });
环境变量
# Required
BRIZZ_API_KEY=your-api-key
# Optional Configuration
BRIZZ_BASE_URL=https://telemetry.brizz.dev # Default telemetry endpoint
BRIZZ_APP_NAME=my-app # Application name
BRIZZ_APP_VERSION=1.0.0 # Application version
BRIZZ_ENVIRONMENT=production # Environment (dev, staging, prod)
BRIZZ_LOG_LEVEL=info # SDK log level
BRIZZ_DISABLE_SPAN_EXPORTER=true # Skip span export (see "Disable Span Export")
BRIZZ_SET_GLOBAL_TRACER_PROVIDER=false # Keep Brizz spans on their own provider (see below)
# OpenTelemetry Standard Variables
OTEL_SERVICE_NAME=my-service # Service name
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true # Capture AI content
禁用 Span 导出
保留 Brizz.initialize() 在代码中不发送任何跨度——对dev/测试环境有用.
启用时, SDK 跳过导出器和处理器设置, 因此不导出跨度 。 计量和
日志继续工作.
Brizz.initialize({ apiKey: 'your-api-key', disableSpanExporter: true });
或者通过 var: BRIZZ_DISABLE_SPAN_EXPORTER=true。 。 。 .
丢弃垃圾邮件
导出前过滤间隔 beforeSendSpan返回时 false 放下一个跨度, true 留着它。 用于剥离噪音路径(健康检查、内部工具)或排除特定最终用户的遥测.
Brizz.initialize({
apiKey: 'your-api-key',
beforeSendSpan: (span) => {
// OpenInference (LangChain JS, LangGraph JS) packs per-call
// `config.metadata` into a JSON-stringified `metadata` attribute.
const raw = span.attributes['metadata'];
if (typeof raw !== 'string') return true;
try {
return JSON.parse(raw).customer_id !== 'cust_42';
} catch {
return true;
}
},
});
标出调用, 这样过滤器有匹配的内容 :
await llm.invoke([new HumanMessage('Hello')], {
metadata: { customer_id: 'cust_42' },
});
同步和同步过滤器都得到支持. 例外被抓住 跨度通过.
运行在您自己打开的远程设置旁
如果您的应用程序注册了自己的 OpenTelemetry TracerProvider (例如,对于APM),通过
setGlobalTracerProvider: false数字 :
Brizz.initialize({ apiKey: 'your-api-key', setGlobalTracerProvider: false });
布里兹保持自己的供货商的周期,只发给布里兹. 你的供应商,宣传员 和采样保持原样, 布莱兹记录每一次谈话 即使你的设置不 样本请求.
给自己搭建的布丽兹追踪器提供商一个仪器:
import { getTracerProvider } from '@brizz/sdk';
new LangChainInstrumentation({ tracerProvider: getTracerProvider() });
或者通过 var: BRIZZ_SET_GLOBAL_TRACER_PROVIDER=false。 。 。 .
无服务器( Cloud Run, Lambda)
在响应发送后CPU被节制时,排队的遥测可能永远不会离开实例.
等着 Brizz.flush() 答复前:
await Brizz.flush();
res.json(result);
在"云跑"上,启用"CPU总是分配"的作品也.
高级配置
Brizz.initialize({
apiKey: 'your-api-key',
appName: 'my-app',
baseUrl: 'https://telemetry.brizz.dev',
// Custom headers for authentication
headers: {
'X-API-Version': '2024-01',
'X-Environment': 'production',
},
// Disable batching for immediate export (testing)
disableBatch: false,
// Custom exporters for testing
customSpanExporter: new InMemorySpanExporter(),
customLogExporter: new InMemoryLogExporter(),
// Disable internal NodeSDK (advanced usage)
disableNodeSdk: false,
// Skip Brizz's AI SDK collector when the app registers its own
disableAiSdkCollector: false,
// Log level for SDK diagnostics
logLevel: 'info', // debug, info, warn, error, none
});
测试和开发
在测试和开发时,您可使用内质导出:
import { InMemorySpanExporter } from '@opentelemetry/sdk-trace';
const spanExporter = new InMemorySpanExporter();
Brizz.initialize({
apiKey: 'test-key',
customSpanExporter: spanExporter,
logLevel: 'debug',
});
// Later in tests
const spans = spanExporter.getFinishedSpans();
expect(spans).toHaveLength(1);
expect(spans[0].name).toBe('openai.chat');
软件包.json 示例
SDK是从您的应用程序代码中初始化的,所以您的脚本保持不变:
{
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js",
"debug": "node --inspect src/index.js"
}
}
实例
看看这个 实例 完整工作示例目录 :
- 基本用途 - 简单的AI应用程序设置
- 维塞尔 AI SDK - 与Vercel的AI SDK合并
- 会话跟踪 - 相关业务分组
- 自定义事件 - 创建商业衡量标准
- PII 化妆 - 数据保护配置
解决问题
共同问题
"找不到申报文件"
- 确保建立SDK:
pnpm build - 检查
dist/包含.d.ts文件
仪器不起作用
- 保证
Brizz.initialize()在任何AI呼叫前运行 - 通过您想要追踪的库
instrumentModules - 检查
BRIZZ_API_KEY设定 - 对于 Vercel AI SDK: 打开
ai@7,安装@ai-sdk/otel打开; 打开ai@6之前,添加experimental_telemetry: { isEnabled: true }到函数调用
CJS/ESM兼容性问题
- 在 CommonJS 中使用动态导入 :
const ai = await import('ai') - 对于捆绑者,使用手动仪器
instrumentModules
调试模式
启用调试日志处理故障问题 :
BRIZZ_LOG_LEVEL=debug node your-app.js
捐款
看我们的 贡献指南 (c) 发展结构和准则.
链接
许可证
Apache-2.0 - 见 自由主义 文档.