Coze智能体开发:使用扣子罗盘SDK进行数据上报

本文指导你如何安装并使用扣子罗盘 SDK 进行数据上报。

准备工作

环境准备

扣子罗盘 Node SDK @cozeloop/ai 适用于 Node.js 18 及以上版本。安装之前,可执行以下命令确认你的 Node.js 版本。

推荐使用 fnm 管理 Node.js 版本。

# 查看 Node 版本  

node -v

SDK 授权

在使用扣子罗盘 Node SDK 前,确保你已经完成了授权。详情请参考SDK 鉴权

安装扣子罗盘 SDK

执行以下命令安装扣子罗盘 SDK。

npm install @cozeloop/ai

# or

pnpm install @cozeloop/ai

默认直接安装最新版本的 SDK。如果你想使用历史版本,单击此处查看历史版本记录和 README。

初始化扣子罗盘 ApiClient

初始化扣子罗盘 ApiClient 之后,才可以访问 SDK 提供的 API。

初始化时推荐通过环境变量动态获取访问密钥,以免硬编码引发数据安全风险。 设置完成环境变量后,你可以直接访问 SDK API 实现相应功能。

以下示例代码展示了如何使用扣子罗盘 ApiClient,并请求某个 API。

const apiClient = new ApiClient({

  /**

  * Api baseURL, default value is:

  * * process.env.COZELOOP_API_BASE_URL

  * * https://api.coze.cn

  */

  baseURL: 'https://api.coze.cn',

  /**

  * Personal Access Token (PAT) or OAuth2.0 token, or a function to get token.

  * use process.env.COZELOOP_API_TOKEN when unprovided

  */

  token: '',

  /** Custom axios instance */

  axiosInstance: axios,

  /**

  * Partial [axios request-config](https://github.com/axios/axios?tab=readme-ov-file#request-config), excludes url, method, baeURL, data and responseType.

  */

  axiosOptions: {},

  /** Custom headers */

  headers: {},

});

const resp = await apiClient.post('/v1/api_url', {/** data */});

扣子罗盘 SDK 的主要能力组件如 Tracer、PromptHub 等都依赖 ApiClient实例或 ApiClient 配置参数。

示例代码

示例代码:https://github.com/coze-dev/cozeloop-js/tree/main/examples/cozeloop-ai-node/src

Trace 上报

Tracer 初始化

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/index.ts

参考以下代码初始化全局 Tracer 实例。(请尽早,比如在应用启动时。)

// initialize tracer globally

cozeLoopTracer.initialize({

  /** workspace id, use process.env.COZELOOP_WORKSPACE_ID when unprovided */

  workspaceId: 'your_workspace_id',

  apiClient: {

   baseURL: 'https://api.coze.cn',

   token: 'your_api_token',

  },

  /** Allow ultra long text report */

  ultraLargeReport: true,

});    

Root Span上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/root.ts

建议将一次完整的用户请求串联成一个 Trace。在服务入口处,上报一个 Root Span,并在此注入相关的业务 ID 便于 Trace 定位和统计分析。

import { cozeLoopTracer } from '@cozeloop/ai';

export async function runRoot() {

  // We recommend concatenating a complete user request into a trace,

  // so the recommended approach is to report a root span at the entrance of the entire execution

  await cozeLoopTracer.traceable(

   async () => {

     // execute your method

     const result = await doSomething();

     return result;

   },

   {

     name: 'TestRootSpan',

     type: 'RootSpanType',

     // you can set your own baggage fields (eg. userId),

     // these fields will be automatically passed through and set in all sub-spans

     baggages: {

       user_id: 'uid-123',

       message_id: 'msg-123',

       thread_id: 'thread-123',

       custom_id: 'custom-123',

     },

   },

  );

}

自定义 Span上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/basic.ts

扣子罗盘支持在任何关键节点进行自定义 span 上报,并自由设置关键信息和自定义 tag。每个traceable所包装的span实例将透传给内部业务方法,使用者可以在方法中消费。

import { cozeLoopTracer } from '@cozeloop/ai';

export async function runCustom() {

  // Wrap any function to make it traceable

  await cozeLoopTracer.traceable(

   async parentSpan => {

     // Manually set input

     cozeLoopTracer.setInput(parentSpan, 'xxx');

     // Invoke any function, if it throws error, error will be caught and automatically set span as error

     const result = await doSomething();

     // Or, you can manually set error

     cozeLoopTracer.setError(parentSpan, 'custom error message');

     // You can also trace nested span, the parent-child relationship of span will be automatically concatenated

     await cozeLoopTracer.traceable(

       async childSpan => {

         // Set custom tags

         childSpan.setAttribute('custom-tag', 'xxx');

         await doSomething();

       },

       {

         name: 'TestCustomChildSpan',

         type: 'MyCustomType',

       },

     );

     // Automatically set return value as output

     return result;

   },

   {

     name: 'TestCustomParentSpan',

     type: 'MyCustomType',

   },

  );

}

Model Span上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/llm.ts

模型调用往往是最关键的节点,可将 span type 设置为 SpanKind.Model,并上报 Model的相关信息,在上报 input 和 output 时建议使用和遵循 SDK 提供的 LoopTraceLLMCallInput 和 LoopTraceLLMCallOutput 类型,以便在平台获得更好的观测体验。

import { SpanKind } from '@cozeloop/ai';

import {

  COZELOOP_TRACE_BUSINESS_TAGS,

  cozeLoopTracer,

  type LoopTraceLLMCallInput,

} from '@cozeloop/ai';

export async function runModel() {

  // Wrap model invoke function to make it traceable

  await cozeLoopTracer.traceable(

   async span => {

     const input: LoopTraceLLMCallInput = {

       messages: [

         {

           role: 'user',

           content: 'hi',

         },

       ],

       tools: [

         {

           type: 'function',

           function: {

             name: 'test-tool',

             description: 'tool-description',

             parameters: {

               type: 'object',

               properties: {

                 name: { type: 'string' },

               },

             },

           },

         },

       ],

       tool_choice: {

         type: 'auto',

         function: {

           name: 'test-tool',

         },

       },

     };

     // Manually set input, if the input satisfies the LoopTraceLLMCallInput structure,

     // the results will be better displayed in the CozeLoop platform

     cozeLoopTracer.setInput(span, input);

     // Invoke/stream model

     const result = await fakeLLMCall();

     // Set model related tags

     cozeLoopTracer.setTags(span, {

       [COZELOOP_TRACE_BUSINESS_TAGS.MODEL_NAME]: 'custom-model',

       [COZELOOP_TRACE_BUSINESS_TAGS.MODEL_PROVIDER]: 'cozeloop',

       [COZELOOP_TRACE_BUSINESS_TAGS.CALL_OPTIONS]: {

         temperature: 0.5,

         max_tokens: 1000,

       },

       [COZELOOP_TRACE_BUSINESS_TAGS.INPUT_TOKENS]: 100,

       [COZELOOP_TRACE_BUSINESS_TAGS.OUTPUT_TOKENS]: 200,

       [COZELOOP_TRACE_BUSINESS_TAGS.TOKENS]: 300,

       // If you use streaming return, record the microsecond timestamp returned by the first Token,

       // and the SDK will automatically calculate the time spent on the first Token

       [COZELOOP_TRACE_BUSINESS_TAGS.START_TIME_FIRST_RESP]: 1741305600123456,

     });

     // Manually set output, if the output satisfies the LoopTraceLLMCallOutput structure,

     // the results will be better displayed in the CozeLoop platform

     cozeLoopTracer.setOutput(span, result);

     return result.choices;

   },

   {

     name: 'TestModelSpan',

     type: SpanKind.Model,

   },

  );

}

超大文本上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/large-text.ts

在 Tracer 初始化时,如果将 ultraLargeReport 设置为 true,则启用超大文本上报。当 Input / Output 内容超过 1 MB 时,将通过文件形式进行上报,并可在平台上查看完整内容;如果未启用该选项,超出大小限制的内容将会被丢弃。

import {

  cozeLoopTracer,

  SpanKind,

  type LoopTraceLLMCallInput,

} from '@cozeloop/ai';

function generateLargeString(sizeInMB: number) {

  const repeats = sizeInMB * 1024 * 1024;

  return 'x'.repeat(repeats);

}

// You can enable the reporting of ultra-long texts by setting

// ultraLargeReport to true when you initialize tracer

export async function runLargeText() {

  await cozeLoopTracer.traceable(

   async span => {

     // Reporting of ultra-long texts will only take effect when the

     // input / output satisfies the LoopTraceLLMCallInput / LoopTraceLLMCallOutput structure

     const input: LoopTraceLLMCallInput = {

       messages: [

         {

           role: 'user',

           content: generateLargeString(2),

         },

       ],

     };

     // Manually set input

     cozeLoopTracer.setInput(span, input);

     // execute your method

     const result = await doSomething();

     return result;

   },

   {

     name: 'TestLargeTextSpan',

     type: SpanKind.Model,

   },

  );

}

多模态上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/multi-modality.ts

Model Span 的 Input / Output 可能包含图片或文件。当 Input / Output 遵循 SDK 提供的 LoopTraceLLMCallInput 和 LoopTraceLLMCallOutput 类型时,多模态资源将被自动处理和上报。图片和文件应使用标准的 MDN 格式或公网可访问的 URL

import {

  cozeLoopTracer,

  SpanKind,

  type LoopTraceLLMCallInput,

} from '@cozeloop/ai';

export async function runMultiModality() {

  await cozeLoopTracer.traceable(

   async span => {

     // Reporting of multi modality will only take effect when the

     // input / output satisfies the LoopTraceLLMCallInput / LoopTraceLLMCallOutput structure

     const input: LoopTraceLLMCallInput = {

       messages: [

         {

           role: 'user',

           content: '',

           parts: [

             // current support base64 encoded image and file

             {

               type: 'image_url',

               image_url: {

                 url: 'data:image/png;base64,XXX',

               },

             },

             {

               type: 'file_url',

               file_url: {

                 name: 'test.txt',

                 url: 'data:text/plain;base64,XXX',

               },

             },

           ],

         },

       ],

     };

     // Manually set input

     cozeLoopTracer.setInput(span, input);

     // execute your method

     const result = await doSomething();

     return result;

   },

   {

     name: 'TestMultiModalitySpan',

     type: SpanKind.Model,

   },

  );

}

跨服务上报

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/tracer/transfer-between-services.ts

  1. 当需要得到当前上下文,并提供给下游服务时:
  • 【CozeLoop SDK 协议上下文】你可以通过injectWithCozeLoopHeaders来将上下文信息注入headers:

import { context, injectWithCozeLoopHeaders } from '@cozeloop/ai';

const headers: Record<string, string> = {};

injectWithCozeLoopHeaders(context.active(), headers);

  • 【标准W3C协议上下文】你可以通过propagation.inject来将上下文信息注入headers:

import { propagation } from '@opentelemetry/api';

import { context } from '@cozeloop/ai';

const headers: Record<string, string> = {};

propagation.inject(context.active(), headers);

  1. 当需要接收来自上游服务的上下文时:
  • 【CozeLoop SDK 协议上下文】你可以使用extractWithCozeLoopHeaders并传入带有 CozeLoop SDK 协议的 headers 来得到 Context:

import { context, extractWithCozeLoopHeaders, cozeLoopTracer } from '@cozeloop/ai';

const extractedContext = extractWithCozeLoopHeaders(

  context.active(),

  headers,

);

context.with(extractedContext, () =>

  cozeLoopTracer.traceable(

   () => {

     doSomething();

   },

   {

     name: 'XXX',

     type: 'XXX',

   },

  ),

);

  • 【标准W3C协议上下文】你可以使用propagation.extract并传入带有标准W3C协议的 headers 来得到 Context:

import { propagation } from '@opentelemetry/api';

import { context, extractWithCozeLoopHeaders, cozeLoopTracer } from '@cozeloop/ai';

const extractedContext = propagation.extract(context.active(), headers);

context.with(extractedContext, () =>

  cozeLoopTracer.traceable(

   () => {

     doSomething();

   },

   {

     name: 'XXX',

     type: 'XXX',

   },

  ),

);

完整示例如下:

import { setupServer } from 'msw/node';

import { http, HttpResponse } from 'msw';

import axios, { type AxiosRequestConfig } from 'axios';

import { ROOT_CONTEXT } from '@opentelemetry/api';

import {

  cozeLoopTracer,

  injectWithCozeLoopHeaders,

  context,

  extractWithCozeLoopHeaders,

} from '@cozeloop/ai';

import { doSomething } from './utils';

function setupMockServer() {

  const mockServer = setupServer(

   http.post(/\/mock\/service\/api\/endpoint/, async req => {

     // Simulate collecting headers in the request

     const headers: Record<string, string> = {};

     req.request.headers.forEach((value, key) => {

       headers[key] = value;

     });

     // Simulate a new context environment (for example, in a cross-service scenario) by

     // setting context to ROOT_CONTEXT, you don't need to take this step in real cross-service calls

     return await context.with(

       ROOT_CONTEXT,

       // Simulate service execution

       async () => await mockService({ headers }),

     );

   }),

  );

  return {

   start: () => mockServer.listen({ onUnhandledRequest: 'bypass' }),

   close: () => mockServer.close(),

  };

}

async function mockService(req: { headers: Record<string, string> }) {

  // Read the information of the current context from the headers

  const extractedContext = extractWithCozeLoopHeaders(

   context.active(),

   req.headers,

  );

  // Use the extracted context

  return await context.with(

   extractedContext,

   async () =>

     await cozeLoopTracer.traceable(

       async () => {

         const result = await doSomething();

         return HttpResponse.json({

           code: 0,

           msg: '',

           data: {

             result,

           },

         });

       },

       {

         name: 'ChildSpan',

         type: 'TransferBetweenServicesType',

       },

     ),

  );

}

export async function runTransferBetweenServices() {

  const mockServer = setupMockServer();

  mockServer.start();

  const result = await cozeLoopTracer.traceable(

   async span => {

     span.setAttribute('custom-tag', 'xxx');

     const headers: AxiosRequestConfig['headers'] = {};

     // Generate the information in the current context as headers

     injectWithCozeLoopHeaders(context.active(), headers);

     const resp = await axios.post(

       'http://mock/service/api/endpoint',

       {},

       {

         headers,

       },

     );

     return resp.data;

   },

   {

     name: 'ParentSpan',

     type: 'TransferBetweenServicesType',

     // The baggage fields will be automatically passed through

     baggages: {

       user_id: 'uid-123',

       message_id: 'msg-123',

       thread_id: 'thread-123',

     },

   },

  );

  mockServer.close();

  return result;

}

Prompt 拉取与格式化

完整示例:https://github.com/coze-dev/cozeloop-js/blob/main/examples/cozeloop-ai-node/src/prompt/hub.ts

在使用 SDK 拉取 Prompt 前,需要在扣子罗盘的 Prompt 开发页面获取 Prompt Key 和版本号。

扣子罗盘 SDK 提供接口来拉取在扣子罗盘中创建并提交的 Prompt。通过 hub.get() 方法可以获取指定 Key 的 Prompt(支持指定版本或使用最新版本),然后使用 hub.formatPrompt() 方法完成变量替换。设置 traceable 为 true 后,SDK 会自动记录 Prompt 的获取和渲染过程,便于后续分析和优化(需完成 Tracer 初始化)。

以下是完整的示例代码。

import { type Message, type PromptVariables, PromptHub } from '@cozeloop/ai';

// 1. 设置 ApiClient

const apiClient = new ApiClient({

  baseURL: 'https://api.coze.cn',

  token: 'your_access_token',

});

const hub = new PromptHub({

  workspaceId: 'your_workspace_id',

  apiClient,

  // 是否开启自动trace上报

  traceable: true,

});

// get prompt with version 0.0.1

const prompt1 = await hub.get('your_prompt_key', '0.0.1')

// get prompt with latest version

const prompt2 = await hub.get('your_prompt_key')

// format prompt to messages with variables

const messages = hub.formatPrompt(prompt1, { key: 'value' });

《CDA数据分析师技能树系列图书》系统整合数据分析核心知识,从基础工具(如Python、SQL、Excel、Tableau、SPSS等)到机器学习、深度学习算法,再到行业实战(金融、零售等场景)形成完整体系。书中结合案例讲解数据清洗、建模、可视化等技能,兼顾理论深度与实操性,帮助读者构建系统化知识框架。同时,内容紧跟行业趋势,涵盖大数据分析、商业智能、ChatGPT与DeepSeek等前沿领域,还配套练习与项目实战,助力读者将知识转化为职场竞争力,是数据分析师从入门到进阶的实用参考资料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王国平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值