@qapm/sse-monitor v1.1.2
RUM大模型体验分析web-sdk使用文档
sdk版本:1.1.2
1、接入参数说明
| 字段名 | 是否必填 | 类型 | 说明 | 默认值 |
|---|---|---|---|---|
| app_key | 是 | string | 上报的ID,需在RUM产品创建并获取,https://console.cloud.tencent.com/monitor/app | |
| llm_ver | 是 | string | 大模型版本号,可通过 setLLMVer 动态设置 | |
| include_url_reg | 是 | array | 需要监控的URL正则表达式数组 | |
| use_fetch | 否 | boolean | 是否监控 window.fetch 的流式请求 | true |
| use_xhr | 否 | boolean | 是否监控 window.XMLHttpRequest 的流式请求 | true |
| user_event_source | 否 | boolean | 是否监控 window.EventSource | true |
| user_id | 否 | string | 用户ID,可通过 setUserID 动态设置 | |
| qapm_base_url | 否 | string | 性能数据上报地址 | https://app.rumt-zh.com |
| version | 否 | string | 前端版本号 | |
| host_ip | 否 | string | 接口服务端IP,可通过 setHostIP 动态设置 | UNSUPPORTED |
| log_level | 否 | string (枚举) | 日志级别:none(关闭)、error、warn、info、debug、log | none |
| onMessage | 否 | function | 每次收到消息后的回调函数 | null |
| onAfterRequest | 否 | function | sse请求结束后的回调函数 | null |
2、接入方式
(1)使用script标签的方式接入
<script src="https://qapmcdn-1253358381.cos.ap-guangzhou.myqcloud.com/web-sdk/latest/sse.qapm.js"></script>
<script>
const option = {
app_key: "5f68970f-10248",
llm_ver: "deepseek-7b",
include_url_reg: [/conversation/, /https\:\/\/fibona\.woa\.com\/v1\/component\/session\/\d+$/],
use_fetch: true,
use_xhr: true,
use_event_source: true,
user_id: "smithabc",
qapm_base_url: "https://app.rumt-zh.com",
version: "1.0.0",
host_ip: "10.2.3.40"
}
window.QAPM.initLLMMonitor(option)
</script>(2)npm安装后,使用import接入
安装依赖:
npm install @qapm/sse-monitor引入:
import {
initLLMMonitor
} from "@qapm/sse-monitor"
const option = {
app_key: "5f68970f-10248",
llm_ver: "deepseek-7b",
include_url_reg: [/conversation/, /https\:\/\/fibona\.woa\.com\/v1\/component\/session\/\d+$/],
use_fetch: true,
use_xhr: true,
use_event_source: true,
user_id: "smithabc",
qapm_base_url: "https://app.rumt-zh.com",
version: "1.0.0",
host_ip: "10.2.3.40"
}
initLLMMonitor(option)3、可用接口
(1)设置用户ID
import {
setUserID
} from "@qapm/sse-monitor";
setUserID("OA::smithdeng");
或者
window.QAPM.setUserID("OA::smithdeng");(2)设置模型版本
import {
setLLMVer
} from "@qapm/sse-monitor";
setLLMVer("hunyuan-7b");
或者
window.QAPM.setLLMVer("hunyuan-7b");(3)设置模型接口的服务端IP
import {
setHostIP
} from "@qapm/sse-monitor";
setHostIP("10.2.3.40");
或者
window.QAPM.setHostIP("10.2.3.40");(4)自定义上报
使用此接口可以自定义上报数据, sseEvent的数据结构请参考 数据结构 章节。
import {
perfEvent
} from "@qapm/sse-monitor";
const sseEvent = {
category: "PERF_NET_SSE",
tags: {
d1: "https://fibona.woa.com/v1/component/session/1234567890",
d2: "fibona.woa.com",
d3: "deepseek-7b",
d4: "false",
d5: "false",
d12: "10.2.3.40",
d15: "true",
d16: "true",
d20: "user_id::smithabc",
d21: "talk_id::1234567890",
d22: "ask_content::你好",
d23: "answer_content::你好",
},
values: {
v1: 1,
v2: 1,
v3: 0,
v4: 0,
v5: 0,
v6: 0,
v7: 1
}
}
perfEvent(sseEvent, true);
或者
window.QAPM.perfEvent(sseEvent, true);4、回调函数
(1)每次收到消息后的回调函数,onMessage
在初始化adk的时候,可以传递一个onMessage的回调函数,该回调函数会在每次收到消息后被调用,参数如下: | 参数名 | 类型 | 说明 | | ---------------- | -------- | ------------------- | | cookie | string | 返回document.cookie | | reqHeader | Object | 请求的header | | reqBody | Object | 请求的body | | respHeader | Object | 响应的header | | respBody | Object | 响应的body | | message | string | 每次收到的消息 | | sseOption | Object | 初始化sdk的参数 | | sseEvent | SSEEvent | 采集的sse性能数据 |
注意:onMessage必须要返回sseEvent。
import {
initLLMMonitor
} from "@qapm/sse-monitor"
const option = {
app_key: "5f68970f-10248",
llm_ver: "deepseek-7b",
include_url_reg: [/conversation/, /https\:\/\/fibona\.woa\.com\/v1\/component\/session\/\d+$/],
use_fetch: true,
use_xhr: true,
use_event_source: true,
user_id: "smithabc",
qapm_base_url: "https://app.rumt-zh.com",
version: "1.0.0",
host_ip: "10.2.3.40",
onMessage: (cookie, reqHeader, reqBody, respHeader, respBody, message, sseOption, sseEvent) => {
const now = Date.now();
try {
console.log('onMessage', message)
// 开放自定义日志上下文字段,v20-v29
if (message.includes("start") && !sseEvent.values.v20) {
sseEvent.values.v20 = now; // 首包时间戳
}
if (message.includes("think_start") && !sseEvent.values.v21) {
sseEvent.values.v21 = now; // 开启深度思考,思考的开始时间戳
}
if (message.includes("think_end") && !sseEvent.values.v22) {
sseEvent.values.v22 = now; // 开启深度思考,思考的结束时间戳
}
if (message.includes("content_start") && !sseEvent.values.v23) {
sseEvent.values.v23 = now; // 正文的开始时间戳
}
if (message.includes("content_end") && !sseEvent.values.v24) {
sseEvent.values.v24 = now; // 正文的结束时间戳
}
} catch (e) {
console.log('onMessage error', e)
}
return sseEvent;
}
}
initLLMMonitor(option)(2)sse请求结束后的回调函数,onAfterRequest
在初始化adk的时候,可以传递一个onAfterRequest的回调函数,该回调函数会在每次请求结束后被调用,参数如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| cookie | string | 返回document.cookie |
| reqHeader | Object | 请求的header |
| reqBody | Object | 请求的body |
| respHeader | Object | 响应的header |
| respBody | Object | 响应的body |
| sseOption | Object | 初始化sdk的参数 |
| sseEvent | SSEEvent | 采集的sse性能数据 |
onAfterRequest必须要有返回值,如果在onAfterRequest中返回了sseEvent,则会覆盖原有的sseEvent,如果返回了false,则不会上报该sseEvent。
其中sseEvent为用户暴露如下字段: | 参数名 | 类型 | 说明 | | ---------------------------- | ------ | ---------- | | sseEvent.tags.d15-d19 | string | 指标聚合 | | sseEvent.tags.d20-d29 | string | 日志上下文 | | sseEvent.values.v1-v29 | number | 日志上下文 |
import {
initLLMMonitor
} from "@qapm/sse-monitor"
const option = {
app_key: "5f68970f-10248",
llm_ver: "deepseek-7b",
include_url_reg: [/conversation/, /https\:\/\/fibona\.woa\.com\/v1\/component\/session\/\d+$/],
use_fetch: true,
use_xhr: true,
use_event_source: true,
user_id: "smithabc",
qapm_base_url: "https://app.rumt-zh.com",
version: "1.0.0",
host_ip: "10.2.3.40",
onAfterRequest: (cookie, reqHeader, reqBody, respHeader, respBody, sseOption, sseEvent) => {
try {
console.log('onAfterRequest', cookie, reqHeader, reqBody, respHeader, respBody, sseOption, sseEvent)
const reqJson = reqBody;
// 开放自定义指标聚合字段,d15-d19
sseEvent.tags.d15 = reqJson.openDeepThink || "false"; // 是否开启了深度思考
sseEvent.tags.d16 = reqJson.openWebSearch || "false"; // 是否开启了联网搜索
// 开放自定义日志上下文字段,d20-d29
sseEvent.tags.d20 = "talk_id::" + reqJson.talkId || ""; // 对话ID
sseEvent.tags.d21 = "ask_content::" + reqJson.askContent || ""; // 对话的问题
sseEvent.tags.d22 = "answer_content::" + respBody || ""; // 回复的正文内容
// 上报到灯塔
// uploadToLightHouse(sseEvent);
} catch (e) {
console.log('onAfterRequest error', e)
}
return sseEvent;
}
}
initLLMMonitor(option)5、数据结构
(1)sseEvent的数据结构
interface SSEEvent {
/** 事件分类(固定为性能监控类) */
category: "PERF_NET_SSE";
tags: {
/** 请求 URL */
d1: string;
/** 请求 HOST */
d2: string;
/** 模型版本 */
d3: string;
/** 是否错误 */
d4: "true" | "false";
/** 是否卡死 */
d5: "true" | "false";
/** 主机 IP(不支持时显示 UNSUPPORTED) */
d12: string | "UNSUPPORTED";
/** 开放字段d15-d19,用于指标聚合*/
d15 ?: string;
d16 ?: string;
d17 ?: string;
d18 ?: string;
d19 ?: string;
/** 开放字段d20-d29,用于日志上下文展示*/
d20 ?: string;
d21 ?: string;
d22 ?: string;
d23 ?: string;
d24 ?: string;
d25 ?: string;
d26 ?: string;
d27 ?: string;
d28 ?: string;
d29 ?: string;
};
values: {
/** 总token数 */
v1: number;
/** 消息耗时分段统计 */
v2: number; // [0,500)ms 的消息数量
v3: number; // [500,1000)ms 的消息数量
v4: number; // [1000,3000)ms 的消息数量
v5: number; // [3000,10000)ms 的消息数量
v6: number; // [10000,60000)ms 的消息数量
/** 耗时累计统计 */
v7: number; // 连接打开时间戳
v8: number; // 首条消息时间戳
v9: number; // 最后消息时间戳
v10: number; // 接收到response header 的时间戳,仅xhr支持
/** 耗时累计统计 */
v12: number; // [0,500)ms 总耗时
v13: number; // [500,1000)ms 总耗时
v14: number; // [1000,3000)ms 总耗时
v15: number; // [3000,10000)ms 总耗时
v16: number; // [10000,60000)ms 总耗时
/** 数据传输量 */
v17: number; // 请求数据总量(字节)
v18: number; // 响应数据总量(字节)
/** 开放字段v20-v29,用于日志上下文展示*/
v20 ?: number;
v21 ?: number;
v22 ?: number;
v23 ?: number;
v24 ?: number;
v25 ?: number;
v26 ?: number;
v27 ?: number;
v28 ?: number;
v29 ?: number;
/** 消息耗时分段统计 */
v30 : number; // [60000ms,+∞)ms 的消息数量
/** 耗时累计统计 */
v31 : number; // [60000ms,+∞)ms 总耗时
};
}(2)初始化sdk的参数的数据结构
interface LLMMonitorOptions {
app_key: string;
llm_ver: string;
include_url_reg ? : RegExp[];
use_fetch ? : boolean;
use_xhr ? : boolean;
use_event_source ? : boolean;
user_id ? : string;
qapm_base_url ? : string;
version ? : string;
host_ip ? : string;
log_level ? : string;
onMessage ? : (
cookie: string,
reqHeader: Object,
reqBody: Object,
respHeader: Object,
respBody: Object,
message: string,
sseOption: LLMMonitorOptions,
sseEvent: SSEEvent
) => Object;
onAfterRequest ? : (
cookie: string,
reqHeader: Object,
reqBody: Object,
respHeader: Object,
respBody: Object,
sseOption: LLMMonitorOptions,
sseEvent: SSEEvent
) => Object;
}