Feedback
Feedback 记录捕获 human-in-the-loop 信号,例如点赞、评分、评论和纠正。当你需要将用户、QA、Studio 或系统审查数据附加到 trace 或 span,并与其他可观测性信号一起查询这些数据时,请使用 feedback。
与 metrics 和 scores 不同,feedback 通常由人员或审查工作流提供。数值型 feedback 值可以聚合、分组、随时间绘制图表,并查询百分位数。
何时使用 feedback何时使用 feedback的直接链接
- 收集用户对 agent 响应的满意度评分。
- 将 QA 评论或纠正存储在其审查的 trace 旁边。
- 按 agent、环境或实验构建评分仪表盘。
添加 feedback添加 feedback的直接链接
当你希望从应用代码为已持久化的 trace 或 span 添加注释时,使用 mastra.observability.addFeedback()。该辅助方法在可观测性入口上是可选的,因此请检查当前激活的可观测性实现是否支持它。所有客户端方法参见客户端 SDK 可观测性参考。
if (!mastra.observability.addFeedback) {
throw new Error('Feedback is not supported by the active observability implementation')
}
await mastra.observability.addFeedback({
traceId: 'trace-123',
spanId: 'span-456',
feedback: {
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'The answer solved my issue.',
},
})
当你只传入 traceId 和 spanId 时,addFeedback() 会先从配置的可观测性存储中重新水合目标,然后再发出 feedback 事件。当 feedback 在被追踪的执行结束后添加时,请配置 MastraStorageExporter。如果 trace 在存储中不可用,Mastra 会记录一条警告并丢弃该 feedback 事件。
在实时追踪的执行期间,你可以传入其 correlationContext,从而无需从存储中重新水合 trace 即可发出 feedback。当活动请求在其追踪上下文结束之前收集 feedback 时,这条路径非常有用。
找到消息对应的 trace找到消息对应的 trace的直接链接
Feedback 通常针对用户已经阅读过的消息收集,因此你需要该消息的 traceId。Assistant 消息在 content.metadata 中携带它,无论是在流结果中,还是稍后从 memory 中召回该消息时:
const agent = mastra.getAgent('weatherAgent')
const memory = await agent.getMemory()
const { messages } = await memory!.recall({ threadId, perPage: false })
const message = messages.find(m => m.id === messageId)
const traceId = message?.content.metadata?.traceId
该值与运行结果中报告的 traceId 是同一个 trace,因此在生成时收集的 feedback 和稍后针对已存储消息收集的 feedback 会锚定到同一个 trace。在 tracing 禁用期间生成的消息没有 traceId。
在 useChat 中读取 trace IDread-the-trace-id-in-usechat的直接链接
chatRoute()和 handleChatStream()会将运行的 traceId 传递给你的 messageMetadata 回调。在 start 部分返回它,这样客户端无需服务器查询即可在实时消息上获得它:
chatRoute({
path: '/chat/:agentId',
messageMetadata: ({ part, traceId }) => (part.type === 'start' ? { traceId } : undefined),
})
const { messages } = useChat<UIMessage<{ traceId?: string }>>()
const lastMessage = messages.at(-1)
const traceId = lastMessage?.role === 'assistant' ? lastMessage.metadata?.traceId : undefined
如果你使用 messageMetadataSchema 验证 metadata,请向其添加 traceId: z.string().optional()。将 traceId 与用户的投票一起发送到你自己的路由,然后在那里调用 addFeedback()。在添加 feedback 之前,请确认调用者拥有具有该 traceId 的消息,因为该值来自客户端。
创建 feedback创建 feedback的直接链接
每个 createFeedback() 都需要 feedbackType 和 value。当 feedback 应锚定到 trace 或特定 span 时,添加 traceId 或 spanId。将 feedbackSource 用作可选字符串 metadata,例如 user、qa、studio 或 system。
对于存储级写入,请包含 timestamp,因为该方法直接写入存储。
const observability = await mastra.getStorage()!.getStore('observability')
await observability!.createFeedback({
feedback: {
feedbackId: 'feedback-rating-1',
timestamp: new Date(),
traceId: 'trace-123',
spanId: 'span-456',
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'The answer solved my issue.',
tags: ['production'],
},
})
await observability!.createFeedback({
feedback: {
feedbackId: 'feedback-comment-1',
timestamp: new Date(),
feedbackSource: 'qa',
feedbackType: 'comment',
value: 'Needs a citation before shipping.',
experimentId: 'support-agent-eval',
},
})
列出 feedback列出 feedback的直接链接
使用 listFeedback() 分页浏览原始记录,或使用 delta 模式轮询。
const result = await observability!.listFeedback({
filters: {
feedbackType: 'rating',
feedbackSource: 'user',
timestamp: { start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) },
},
pagination: { page: 0, perPage: 20 },
orderBy: { field: 'timestamp', direction: 'DESC' },
})
console.log(result.feedback, result.pagination?.hasMore)
过滤器包括目标字段(如 traceId 和 spanId)、feedback 字段(如 feedbackType、feedbackSource 和 feedbackUserId),以及共享上下文字段(如 entityName、environment、experimentId 和 tags)。所有过滤字段参见 FeedbackFilter。通过 HTTP 时,相同的字段作为查询参数传递,例如 GET /api/observability/feedback?traceId=trace-123&environment=production。参见列表查询参数。
await observability!.listFeedback({
filters: {
traceId: 'trace-123',
feedbackType: ['rating', 'thumbs'],
tags: ['production'],
},
})
删除 feedback删除 feedback的直接链接
使用 deleteFeedback() 按 id 删除 feedback 记录。当评论包含敏感数据时,这非常有用。每个请求最多接受 1,000 个 feedbackIds,并且删除是幂等的。可选的 organizationId 字段按组织过滤,可选的 resourceId 字段按资源过滤。你可以单独提供任一过滤器,也可以同时使用两者。在 Studio 中,trace 或 span 的 Feedback 标签页上的每条评论都有删除操作。使用 deleteTraces() 删除 trace 时,也会删除与其关联的 feedback。参见删除 traces。
await observability!.deleteFeedback({
feedbackIds: ['feedback-1', 'feedback-2'],
})
已删除的记录也会从 feedback 分析中消失。ClickHouse 使用轻量删除来隐藏行,但不保证立即物理移除,因此开源部署必须配置可观测性保留期以物理清除它们。每个请求在删除成功后会被标记为已应用;如果删除失败,请求会保持未应用状态,不会阻止对仍然可见的 feedback 进行更新,你可以再次调用删除 API 重试。在 ClickHouse 上,下一次审查更新也会重试删除,如果重试成功则将 feedback 报告为未找到,如果再次失败则保存新状态并返回删除的错误。开源部署没有后台协调器。为每个可观测性信号配置保留期,使删除请求在其保护的信号行之后过期。如果任何信号没有边界,删除请求也会保持无边界,以防止已删除的数据被重新引入。在 ClickHouse 上,删除 API 不会触及单独的 delta 游标表。其行包含标识符而非 feedback 载荷,并在两天内过期。
查询 feedback 分析查询 feedback 分析的直接链接
OLAP feedback 查询针对数值型 value 字段操作。将它们用于评分、编码为 1 和 -1 的点赞、数值型 QA 分数或其他数值型 feedback 类型。
const rating = await observability!.getFeedbackAggregate({
feedbackType: 'rating',
feedbackSource: 'user',
aggregation: 'avg',
comparePeriod: 'previous_day',
})
const byAgent = await observability!.getFeedbackBreakdown({
feedbackType: 'rating',
groupBy: ['entityName'],
aggregation: 'avg',
filters: { environment: 'production' },
})
const ratingsOverTime = await observability!.getFeedbackTimeSeries({
feedbackType: 'rating',
aggregation: 'avg',
interval: '1h',
groupBy: ['feedbackSource'],
})
所有字段、过滤器、返回类型和百分位数查询参数参见 feedback 参考。
本地运行时在 /api/observability/feedback 暴露列表路由,并在其相关路径下提供分析。参见 HTTP 路由表和列表查询参数。Mastra Platform 提供单独的、无版本号的托管查询 API。关于区域端点、认证和项目作用域,参见 Feedback API。
将 feedback 导出到 Mastra Platform将 feedback 导出到 Mastra Platform的直接链接
MastraPlatformExporter会自动将发出的 feedback 事件转发到 Mastra Platform,因为托管查询 API 不提供创建路由。
如果你的应用在 agent 或 workflow 响应之后仅使用其 traceId 添加 feedback,请同时配置 MastraStorageExporter 和 MastraPlatformExporter。存储导出器使 trace 对 addFeedback() 的重新水合保持可用,而 Platform 导出器会转发生成的 feedback 事件,而不将 trace 添加到应用的本地存储中。
关于组合导出器配置,参见 Mastra Platform 上的可观测性。
将 feedback 导出到外部平台将 feedback 导出到外部平台的直接链接
Feedback 流经可观测性事件总线,因此支持 feedback 的导出器会自动转发它。PostHog 导出器会将 feedback 作为原生 $ai_feedback 事件发送,这些事件会出现在 PostHog 中关联的 trace 上。