@ countly/ai- sdk- mastra
计算 AI 的可观察性适配器 马斯特拉。 。 。 .
部分 计数AI SDK ——提供-不可知的LLM可观察每个AI堆.
安装
npm install @countly/ai-sdk-mastra
@countly/ai-sdk-core 自动拖入.
同伴依赖关系
@mastra/core >= 1.26.0 < 2
@mastra/observability >= 1.11.0 < 2
该会场于0.0.6起 (这是 >= 1.0.0 二者皆为愿相.
快取抓取读取 usage.inputDetails 编号 : usage.outputDetails,形状
@mastra/observability 只有从1.11.0。 与 auto-install-peers=true,一个
旧对子安装干净然后报告 零缓存符号 - 哪个
错误的价格 每一个快速调用 准确的方向隐藏
超标此放行会删除 。 安静,不是错误。 因此发言,因此
线人 mastra-peer-floor 任务,它证明 已声明的最小实际输出
缓存符号,而不是仅仅声明它确实存在.
如果你不能移动到这些版本,针 @countly/[email protected] 并接受
而不是在下层运行0.0.6.
快速启动
说明:出口者必须包裹在
new Observability({...})穿过马斯特拉家observability:字段。 直接传递作为exporters:马斯特拉不会成功 出口者不会有跨度.
import { Mastra } from "@mastra/core/mastra";
import { Observability } from "@mastra/observability";
import { CountlyMastraExporter } from "@countly/ai-sdk-mastra";
new Mastra({
observability: new Observability({
configs: {
default: {
serviceName: "my-ai-app",
exporters: [
new CountlyMastraExporter({
appKey: "YOUR_APP_KEY",
url: "https://your-countly-server.com",
requestContextDeviceIdKey: "countlyDeviceId",
}),
],
},
},
}),
});
在请求处理器中:
import { RequestContext } from "@mastra/core/request-context";
app.post("/chat", async (req, res) => {
const ctx = new RequestContext();
ctx.set("countlyDeviceId", req.user.id);
await mastra.getAgent("intent").stream(messages, { requestContext: ctx });
});
用户代号如何到达事件
桥是马斯特拉的跑道 不是我们的SDK 我们读到一个公共领域 Mastra 在每个输出的跨度:
Your handler Mastra runtime @countly/ai-sdk-mastra
───────────── ────────────── ──────────────────────
ctx = new RequestContext()
ctx.set("countlyDeviceId", id)
run scope carries ctx
agent.stream(msg, { ↓
requestContext: ctx spans created during run
}) (AGENT_RUN, MODEL_GEN, TOOL_CALL)
↓
ExportedSpan.requestContext = {
countlyDeviceId: id adapter reads
} span.requestContext
↓
event.deviceId = id
POST /i?device_id=id
- 通过
requestContextDeviceIdKey(例如:."myUserId"(中文(简体) ) - 设定为
null返回到getDeviceId()编号 :deviceId/ 处理 UUID - 超过 Mastra 版本要求
>=1.0- 稳定的v1可观察表面
捕捉到的东西
- 活动追踪
exportTracingEvent(单位:千美元)span_started, (中文(简体) ),span_updated, (中文(简体) ),span_ended(中文(简体) ) - 当根间断结束时自动跟踪补全
- 一个
[CLY]_llm_interaction百分比model_generation间距 它自己的模式, 供应商、使用、成本、完成理由和持续时间(见下文) - 在代理工作流程内调用工具(
function_call财务报告和审定财务报表mcp_tool_call类型), 和作为父母提出要求的一代 - 工作流程步骤 ——每个
createStep节点inputData作为工具参数(见下文) - 马斯特拉自己的 计分结果和用户反馈 (单位:千美元)
onScoreEvent编号 :onFeedbackEvent编号 :addScoreToTrace,作为[CLY]_llm_interaction_feedback行数 - 调试用法
usage.inputDetails编号 :usage.outputDetails并读取缓存, 缓存写入和推理为 子集 占投入/产出总数的百分比.usage_input包括两个缓存桶,所以缓存溢价是 记了一次 - 用法被间距ID去除( 以前是两次计算), 并且从未使用痕迹
报告为 删除 与
usage_state: "not_reported"而不是零化 - 报告失败出错 世代相传 (报告失败的工具或步骤) 它自己的工具行,而不是模型失败)
- 跨代理运行的用户汇总
每代一行
马斯特拉追踪不是转弯 马斯特拉的根迹 agent_run 财务报告和审定财务报表
workflow_run,因此一个用户转出数个痕迹——一个单一的痕迹可以
包含几代人 不同 模特们.
- 每个
model_generation间距变为完全一个交互行,并带有 拥有model, (中文(简体) ),provider, (中文(简体) ),usage_*, (中文(简体) ),cost_*, (中文(简体) ),finish_reason财务报告和审定财务报表latency_total因此,每个电话的费用是正确的,而不是整个定价 以第一型号的速度转. - 将上下文反常化到每行 :
run_id, (中文(简体) ),generation_index(0基,起动时间订购),,run_latency_total(根相间 结束至结束持续时间),workflow_name, (中文(简体) ),agent_name, (中文(简体) ),thread_id, (中文(简体) ),deviceId, (中文(简体) ),trace_id和文本预览. - 一个没有代数的追踪 发出没有交互行. 工作流程
树根,
rag_*管道、内存操作、绊线中断和直接 被执行的工具是管弦乐,而不是LLM调用. 他们的工具栏还在飞去, 父创建到运行( n)parent_event_key: "run") (中文(简体) ).
⚠️ 行卷起起. 一个转弯,以前释放了一个交互行现在 每代发射一发——约2x用于单剂转动,多用于一发 多剂或多型一. 大小相应摄入. 相反,迅速 计数 滴数 以从未有一代人的遗迹的份数发誓 601行被观测到的流量),这是变化的点.
🔴 api_host_type 实值 "unknown" 每个马斯特拉行
每个 马斯特拉行报告 api_host_type: "unknown" 并省略 api_host选择
适配器中的bug —— Mastra 不告诉我们终点, 我们也不会猜测
一个.
@mastra/core 声明 serverAddress 财务报告和审定财务报表 serverPort 打开
ModelGenerationAttributes,但也没有指定代码路径。 证实反对
已安装文物,而不是类型申报: @mastra/core 1.55.0 国家
(这个工作空间能解决的)和 1.24.1,以及 @mastra/observability 1.1.1.1, (中文(简体) ),
serverAddress 显示 仅限 内 dist/observability/types/tracing.d.ts 内
源图 — 在已发射的 JavaScript 中零出错 。 这算什么 model_generation
运行时实际携带的跨度为:
| 何时 | 包含的属性 |
|---|---|
| 创建间距 | model, (中文(简体) ), provider, (中文(简体) ), streaming, (中文(简体) ), parameters |
| 结束 | finishReason, (中文(简体) ), responseId, (中文(简体) ), responseModel, (中文(简体) ), usage |
没有其它属性包含 URL, 主机或区域, 所以没有退站
改为:. providerMetadata 无法帮助: Mastra 消耗在内
extractUsageMetrics 它在出口商的家中 DEFAULT_KEYS_TO_STRIP,所以这个
从未达到出口的跨度,而且无论如何都没有任何终点.
后果明确表明:
- 仪表板的 "按主机类型"卡片为马斯特拉交通所空. 网关对 销售商直接对Azure 无法突破.
"unknown"这里的意思是 "马斯特拉没有报告"没有 "电话去了 不寻常的地方"。不要读它作为一个结论.
分类已经有线(describeApiHost因此它开始工作
瞬间,Mastra 充斥着这个属性——我们方面不需要改变。 每一个
适配器读取它的客户端 baseURL 直接报告真实的主机; 参见
能力矩阵。 。 。 .
run_id - 分组转弯
每一行转一圈 run_id,按此顺序解决:
getPromptId()轮到你自己的身份了.requestContextPromptIdKey从追踪读取requestContext。 。 。 .- 马斯特拉自己运行的ID( M)
span.metadata.runId) (中文(简体) ). - 追踪的根部横跨id.
第1条和第2条 仅限 可以与代理共享工作流程跟踪的
追踪它的产物,因为这些是不同的痕迹 traceId编号.
如果没有工作流程,工作流程就会变成几个运行。 设置值 在此之前
引用代理或工作流程: Mastra 克隆 requestContext 间距
构造器,所以一个步骤内设置的值只在该步骤本身的跨度上可见
(出口者回到扫描孩子的长度,以准确说明这种情况).
flush() 对 shutdown()
flush() 排出网络缓冲器,但确实 没有 释放出仍在运行的痕迹——
ObservabilityBus 报告一个直播转弯将产生
当根最终结束时,零纬度过早的成功加一行重复.
shutdown() 所遗所遗所遗所遗所物
status: "incomplete",因此一个在中转时退出的过程将失去任何东西和索赔
没什么.
掌握工作流程步骤
如果你和马斯特拉合作 工作流程 (单位:千美元)createWorkflow 编号 : createStep, (中文(简体) ),
步骤只在工作流程时到达出口国 在马斯特拉注册
实例 运行 通过这个例子。导入和单独运行的工作流程
(单位:千美元)myWorkflow.createRun())没有与之相接的可观察性——只有代理运行它
引用被追踪,步骤决定(路线、交接、收集投入)
无形相.
登记工作流程并通过 getWorkflow数字 :
const mastra = new Mastra({
agents: { intentAgent, pluginsAgent },
workflows: { myWorkflow }, // ← register it
observability: new Observability({ /* … exporter … */ }),
});
// Run THROUGH the instance so its spans inherit observability:
const run = await mastra.getWorkflow("myWorkflow").createRun();
await run.stream({ inputData, requestContext: ctx });
一旦登记,每个 叶子 createStep 作为工具行的表面 :
tool_name=该步骤entityId(连字符常态化为下划线等.potential-handoff→potential_handoff),因此,它与函数/多功能共聚 同名工具行.[CLY]_llm_tool_usage_parameter台阶按键排出行数inputData—— 说{ handoff_to, confidence, user_input, … }成为已命名的参数 你可以在分析中分解.- 结构包装步骤被跳过 . A 类
.then(nestedWorkflow)编号 :.branch([… nestedWorkflow])表面为workflow_step谁entityId是嵌入式工作流程的id; 这些被排除在外,所以只有真正的决策步骤 成为一行. - 一步是管弦乐,不是模型选择的工具,所以它的行是父行
页:1 运行 (单位:千美元)
parent_event_key: "run", (中文(简体) ),prompt_id=:run_id)而不是(a) 给一代人 他们的标签workflow_name= 根工作流程的entityName(和agent_name当agent_run间距存在于跟踪中). - A 类
workflow_run根产生无[CLY]_llm_interaction- 没有LLM是 因此没有一代人可以报告.[CLY]_llm_interaction现在意味着 严格来说就是LLM一代 之前的版本在这里排出一行 没有模型,provider: "unknown"(a) 零代币和0美元的费用,但实际是端到端的延迟; 真实流量占所有排行的三分之一 夸大了快速计数, 将工作流程时间与临时时间混合 百分数.
嵌入式工作流程也被追踪:只登记您运行的顶级工作流程—— 联合国
.then()编号 :.branch()儿童被自动追踪作为运行的一部分.
配置
所有适配器都接受同样的 CountlyAIConfig 对象 :
| 外地 | 默认 | 说明 |
|---|---|---|
appKey | 所需经费 | 计数应用密钥 |
url | 所需经费 | 计算服务器 URL |
requestContextDeviceIdKey | "countlyDeviceId" | requestContext 键控设备/用户代号. null 关闭它. |
requestContextThreadIdKey | "threadId" | requestContext 密钥 。 回到马斯特拉 span.metadata.threadId。 。 。 . null 关闭它. |
requestContextWorkflowNameKey | "workflowName" | requestContext 键键 。 掉回根头 workflow_run是因为 entityName。 。 。 . null 关闭它. |
requestContextPromptIdKey | —— 说 | requestContext 键控 转弯时的编号 变成 run_id。 。 。 。 . |
getPromptId | —— 说 | 与函数相同; 排名高于 requestContextPromptIdKey。 。 。 . |
observabilityLevel | 0 | 0 = 仅限度量, 1 = + 工具调用, 2 = + 文本预览和工具参数 |
tags | [] | 成本归属和过滤标签 |
environment | "production" | 环境标签 |
costModel | —— 说 | 自定义定价超标 |
flushInterval | 10000 | 缓冲间距( ms) |
maxBatchSize | 20 | 自动擦出前最大事件 |
paramValueLength | 1024 | 在工具参数的序列值上加盖 |
debug | false | 日志传输出错和投放/未识别跨度 |
disabled | false | 禁用所有遥测 |
反馈
马斯特拉的 本地语言 信号不需要接线: 出口商执行
onScoreEvent, (中文(简体) ), onFeedbackEvent 财务报告和审定财务报表 addScoreToTrace所以每个计分结果
和每个 recordedSpan.addFeedback() 变成一个 [CLY]_llm_interaction_feedback
排成一行与产生它的跑道相对.
对于来自 你们自己的UI,抓住 prompt_id 各笔捐款
通过 onPrompt 调回,然后记录反馈
与 createFeedbackTracker (从此软件包再出, 因此没有额外的安装
所需:
import { CountlyMastraExporter, createFeedbackTracker, type PromptInfo } from "@countly/ai-sdk-mastra";
const countly = { appKey: "YOUR_APP_KEY", url: "https://your-countly-server.com" };
let lastPrompt: PromptInfo | undefined;
const exporter = new CountlyMastraExporter({
...countly,
requestContextDeviceIdKey: "countlyDeviceId",
onPrompt: (info) => { lastPrompt = info; }, // fires once per exported generation
});
// wire the exporter into new Observability({...}) as shown in Quick Start
const feedback = createFeedbackTracker(countly, { sdk_adapter: "mastra" });
await mastra.getAgent("intent").generate(messages, { requestContext: ctx });
// ...later, when the user rates the answer:
feedback.track({
prompt_id: lastPrompt!.prompt_id, // rates the whole TURN (== run_id)
rating: "thumbs_up", // or "thumbs_down", or any custom string
score: 0.9, // optional 0-1 numeric score
category: "helpful", // optional: hallucination, irrelevant, harmful, ...
comment: "Great answer", // optional free-form text
deviceId: user.id, // attribute to the same user as the interaction
});
// ...or rate ONE generation of a multi-generation turn:
feedback.track({
prompt_id: lastPrompt!.event_id, // that row's own id
run_id: lastPrompt!.run_id,
rating: "thumbs_down",
});
PromptInfo 携带 prompt_id (中文) run_id,所以这种流量不变
从以前的版本, run_id,这代人自己的 event_id, (中文(简体) ),
generation_index附加时 provider 编号 : model 编号 : status 编号 : thread_id 编号 :
agent_name 编号 : workflow_name 编号 : trace_id。只有当一代人
实际记录的——从不为管弦乐追踪.
每个 track() 调用发送a [CLY]_llm_interaction_feedback 活动
prompt_id 链接返回运行( 或一代) event_id),与
parent_event_key 记录其中的反馈漏斗和
在"伯爵"中,每个模型的满意程度崩溃. 在真正的应用中,存储ID
与已发送的消息( 或返回给客户端) 一起读取
用户对答案进行评分。 反馈按交互事件分类; 调用
feedback.flush() 立即发送,或 feedback.shutdown() 进程退出.
完整文档
见 计数 AI SDK 仓库 联 合 国 计划v2电线合同 (每代一行、法治A尺寸、法治B措施及其 usage_state 编号 : cost_priced 标记和普通信封) 适配器能力矩阵,可观察性水平(0/1/2),成本计算,隐私控制,和 Coldly 插件集成(Drill, Funnels, Cohorts, APM, Crash Analytics).
许可证
麻省理工学院