Mastra 客户反馈摘要 Agent 模板:基于 get-feedback 工具与 Observational Memory 构建自学习反馈分析 Agent
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
本篇指南基于 Mastra monorepo 中的官方模板 template-customer-feedback-summarization 展开:你将了解如何一键创建一个能对话式分析客户反馈的 AI Agent,掌握get-feedback分页工具的完整参数设计、两个 LLM-as-Judge 质量评分器(actionability / completeness)的加权打分实现,以及通过lastMessages与 Observational Memory 让 Agent 跨会话记住用户偏好、追踪反馈趋势的完整配置方式。
模板解决什么问题
客户反馈散落在支持工单、应用商店评论、问卷、社交媒体等多个渠道,人工汇总费时且难以跟踪趋势。该模板提供了一个名为 "Customer Feedback Summarizer" 的 AI Agent:
- 检索反馈:通过
get-feedback工具按来源、客户层级、日期范围过滤,并支持分页批量拉取; - 分类与评估:Agent 自行阅读每一条反馈,按类型(bug、feature request、praise、complaint、question)、情感与紧急度归类,识别主题;
- 生成高管级报告:输出包含 Overview、Key Findings、Critical Issues、Recommendations 四个板块的结构化摘要;
- 跨会话记忆:借助 Observational Memory 追踪历史分析中形成的模式,识别随时间变化的趋势,并适应用户展现出的偏好。
模板定位是"可对话的分析"——你可以问它"总结所有客户反馈"、"企业客户的严重问题有哪些"、"对比本月与上月的主题",也可以在聊天中直接粘贴新反馈让它纳入分析。由于 Agent 在会话间保留上下文,它会随着使用越来越贴合你的需求。
快速开始
环境要求:Node.js>= 22.13.0(见 package.json 中engines字段),推荐使用packageManager指定的 pnpm。
npx create-mastra@latest --template customer-feedback-summarization cd customer-feedback-summarization创建.env文件:
OPENAI_API_KEY=your-api-key启动开发服务器:
npm run devdev脚本实际执行mastra dev,会启动 Mastra Studio,默认地址为http://localhost:4111。仓库中另有build(mastra build)与start(mastra start)两个脚本用于生产构建与运行。
项目结构
整个模板代码量很小,核心全部位于src/mastra/下:
templates/template-customer-feedback-summarization/ ├── src/mastra/ │ ├── index.ts # Mastra 实例:Agent、存储、日志、可观测性装配 │ ├── agents/ │ │ └── feedback-summarizer.ts # Agent 定义:模型、工具、评分器、记忆、指令 │ ├── tools/ │ │ └── get-feedback.ts # get-feedback 工具:过滤 + 分页 │ ├── scorers/ │ │ └── feedback-scorers.ts # actionability / completeness 两个评分器 │ └── data/ │ └── feedback.ts # 75 条静态示例反馈数据 ├── package.json └── tsconfig.json依赖方面,模板只引入了 Mastra 生态的核心包:@mastra/core、@mastra/evals、@mastra/libsql、@mastra/loggers、@mastra/memory、@mastra/observability,外加zod做 schema 校验。
核心 Agent:feedback-summarizer
Agent 定义在 feedback-summarizer.ts,这是整个模板的心脏。完整配置如下(节选关键部分):
export const feedbackSummarizer = new Agent({ id: 'feedbackSummarizer', name: 'Customer Feedback Summarizer', description: 'Analyzes and summarizes customer feedback to produce actionable insights...', model: 'openai/gpt-5.2', tools: { getFeedbackTool }, scorers: { actionabilityScorer: { scorer: actionabilityScorer, sampling: { type: 'ratio', rate: 1 }, }, completenessScorer: { scorer: completenessScorer, sampling: { type: 'ratio', rate: 1 }, }, }, memory: new Memory({ options: { lastMessages: 20, observationalMemory: { model: 'openai/gpt-5-mini', }, }, }), instructions: `You are an expert customer feedback analyst. ...`, });几个值得关注的配置点:
- 双模型策略:主 Agent 使用
openai/gpt-5.2负责分析,而 Observational Memory 的观察提取使用更轻量的openai/gpt-5-mini——把"记住偏好"这类后台任务交给便宜模型,控制成本; lastMessages: 20:控制每轮注入上下文的最近消息数量,即会话内记忆的深度;sampling: { type: 'ratio', rate: 1 }:两个评分器以 100% 的采样率对每次运行打分,保证输出质量可被持续度量(生产环境可调低采样率);memory与storage的关联:Agent 配置了 Memory 后,需要实例级存储来持久化消息与观察记录——这正是 index.ts 中LibSQLStore的职责。
instructions:一份"反馈分析师"工作手册
该模板的instructions并不是一句简单的角色描述,而是一份完整的工作规范,值得逐段学习。它规定:
工作流程(被要求总结或分析反馈时):
- 调用
getFeedbackTool取数。工具是分页的——检查返回的has_more,必要时继续翻页,覆盖完整数据集; - 亲自通读反馈:逐条分类(bug、feature request、praise、complaint、question),评估情感与紧急度,提炼主题;
- 综合成一份清晰、可执行的摘要。
输出格式(四段式):
- Overview:反馈总数、日期范围、覆盖的来源、整体情感分布;
- Key Findings:按频次和紧急度排序的前 3–5 个主题,每个主题说明客户在说什么、影响面多大、情感倾向如何;
- Critical Issues:高/严重紧急度的条目,按客户层级(enterprise > pro > free)和严重度排优先级;
- Recommendations:具体、可执行的动作,按预期影响排序,且每条建议都要回指到具体的反馈数据。
跨会话观察的使用方式:当存在过往分析产生的观察记录时,Agent 被要求将当前发现与历史模式对比(例如"账单投诉较上一批增多")、追踪旧问题是否已解决或复发、适应用户展现的格式偏好,并主动指出趋势。
语气规范:要求直接、数据驱动(用数字和百分比),明确禁止"企业黑话"——指令里给出的正反例很典型:应说 "checkout is broken for 20% of enterprise users",而非 "there are some opportunities in the checkout experience";引用反馈时选最具代表性的例子,而不是最戏剧化的;企业客户的严重 bug 权重高于免费用户的功能建议。
此外,指令还覆盖了用户在聊天中直接粘贴新反馈的场景:将其放入既有分析上下文中处理,并与已有模式和趋势做对比。
get-feedback 工具:过滤、分页与输出契约
工具实现位于 get-feedback.ts,使用@mastra/core/tools的createTool定义。它的描述本身就是一份"使用说明书":
'Retrieves customer feedback from the database. Can filter by source, customer tier, or date range. Supports pagination via limit and offset. Use these to batch through large result sets without overwhelming the context window.'
输入参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source | enum | 无 | 按来源过滤,可选support_ticket/app_review/survey/social_media |
customer_tier | enum | 无 | 按客户层级过滤,可选free/pro/enterprise |
start_date | string | 无 | 起始日期(YYYY-MM-DD,含当日) |
end_date | string | 无 | 截止日期(YYYY-MM-DD,含当日) |
limit | number | 40 | 单页最大返回条数 |
offset | number | 0 | 跳过的条数,用于翻页 |
输出契约
outputSchema定义了结构化的分页元数据:
feedback:本页的反馈条目数组,每条含id、text、source、date、customer_tier;total:过滤后(分页前)的匹配总数;returned:本页实际返回条数;limit/offset:当前分页参数回显;has_more:是否还有后续页——Agent 正是靠这个字段决定要不要继续翻页;filters_applied:以{key: value}形式回显实际生效的过滤条件,便于 Agent 在摘要中说明数据口径。
分页实现
execute逻辑非常直白,这也是该工具"可直接映射到真实数据库"的关键:
execute: async input => { let filtered = [...feedbackData]; const filtersApplied: Record<string, string> = {}; if (input.source) { filtered = filtered.filter(item => item.source === input.source); filtersApplied.source = input.source; } if (input.customer_tier) { filtered = filtered.filter(item => item.customer_tier === input.customer_tier); filtersApplied.customer_tier = input.customer_tier; } if (input.start_date) { filtered = filtered.filter(item => item.date >= input.start_date!); filtersApplied.start_date = input.start_date; } if (input.end_date) { filtered = filtered.filter(item => item.date <= input.end_date!); filtersApplied.end_date = input.end_date; } const total = filtered.length; const limit = input.limit ?? 40; const offset = input.offset ?? 0; const page = filtered.slice(offset, offset + limit); return { feedback: page, total, returned: page.length, limit, offset, has_more: offset + limit < total, filters_applied: filtersApplied, }; }四个过滤条件各自独立、可任意组合(AND 语义),日期比较直接利用YYYY-MM-DD字符串的字典序等价于时间序的特性;has_more由offset + limit < total判定。当前数据来自静态 fixture(见下节),把这段filter+slice换成WHERE+LIMIT/OFFSET查询即可接入真实数据源。
静态示例数据
示例数据定义在 feedback.ts:FeedbackItem接口约束了source与customer_tier为联合类型,feedbackData数组包含 75 条覆盖 2025-10-02 至 2025-12-15 的模拟反馈,内容刻意分布了 bug、计费投诉、功能请求、正面评价等多样类型,且企业级客户占比高——正好用于演示"enterprise > pro > free"的优先级策略。文件头部的注释也明示:真实应用中这些数据应来自数据库、API 或文件上传。
质量评分器:让"写得可执行"可度量
feedback-scorers.ts 定义了两个评分器,在 Agent 中注册后,每次运行都会自动评估输出质量。
actionabilityScorer:可执行性评分
该评分器回答一个问题:这份摘要是否给出了产品团队能立刻执行的具体建议,而不只是模糊观察?它基于@mastra/core/evals的createScorer以链式 API 组装,分为三步:
preprocess:用getAssistantMessageFromRunOutput从运行输出中提取 assistant 文本,得到assistantText;analyze:由 judge 模型(openai/gpt-5.2)按outputSchema输出结构化分析结果,包含五个维度——hasRecommendations:是否存在建议板块;recommendationCount:建议条数;areSpecific:建议是具体(如"修复使用折扣码时的结账崩溃")还是含糊(如"改进结账体验");arePrioritized:建议是否按优先级/影响排序;tiedToFeedback:建议是否回指具体反馈数据;confidence:0–1 的置信度,用于缩放最终得分。
generateScore:加权求和,权重设计体现了"具体性最值钱"的评价观:
| 条件 | 得分 |
|---|---|
| 存在建议(基础分) | +0.2 |
| 建议数 ≥ 3 | +0.2(1–2 条则 +0.1) |
| 建议具体(最重要项) | +0.3 |
| 建议有优先级 | +0.15 |
| 建议回指反馈数据 | +0.15 |
最终分数为min(加权总分 × confidence, 1);若完全没有建议板块则直接记 0 分。generateReason步骤还会把上述各维度拼成人类可读的评语(如 "Found 4 recommendation(s). Recommendations are specific and actionable."),方便在 Studio 中查看评分依据。
completenessScorer:完整性评分
第二个评分器一行搞定:
export const completenessScorer = createCompletenessScorer();它直接复用@mastra/evals/scorers/prebuilt的内置完整性评分器,评估 Agent 的摘要是否覆盖了输入的全部反馈条目而没有遗漏——这与"可执行性"互补:一个管"说得有用",一个管"看得全面"。两个评分器同时挂在 Agent(100% 采样)与 Mastra 实例上,形成对该模板输出质量的双重自动度量。
实例装配:存储、日志与可观测性
index.ts 展示了把 Agent 跑起来的完整骨架:
export const mastra = new Mastra({ agents: { feedbackSummarizer }, scorers: { actionabilityScorer, completenessScorer }, storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:./mastra.db', }), logger: new PinoLogger({ name: 'Mastra', level: 'info' }), observability: new Observability({ configs: { default: { serviceName: 'mastra', exporters: [new MastraStorageExporter(), new MastraPlatformExporter()], spanOutputProcessors: [new SensitiveDataFilter()], }, }, }), });各部分的作用:
LibSQLStore:以本地文件file:./mastra.db为存储后端,持久化会话消息与 Observational Memory 的观察记录——没有它,lastMessages跨请求的历史和"跨会话追踪趋势"都无法成立;PinoLogger:以info级别输出运行日志;Observability:通过MastraStorageExporter与MastraPlatformExporter导出追踪数据,并用SensitiveDataFilter处理 span 输出中的敏感信息,保证分析链路可观测且不泄露反馈原文中的隐私片段。
Observational Memory:跨会话的"学习"机制
README 强调的核心卖点——"agent remembers context across sessions, so it gets more useful over time"——由 Agent 上的这段 Memory 配置驱动:
memory: new Memory({ options: { lastMessages: 20, observationalMemory: { model: 'openai/gpt-5-mini', }, }, });两者的分工不同:
lastMessages: 20是会话内机制:每次运行时把该线程最近 20 条消息注入上下文,解决"本次对话记得住"的问题;observationalMemory是跨会话机制:由独立的轻量模型(此处为gpt-5-mini)从对话中提取"观察"——用户偏好、反复出现的主题、历史结论等——持久化到存储中,供后续会话读取。结合 instructions 中"Working with observations from past sessions"一节,Agent 被要求拿这些观察去对比历史模式、追踪问题是否复发、主动指出趋势。
从 monorepo 的@mastra/memory源码看,Observational Memory 以处理器(processor)形式挂接在消息流上,围绕线程(thread)维度管理观察记录,并通过专门的激活与缓冲机制决定何时触发观察提取(参见 observational-memory 处理器实现 及其配套测试)。模板层面你只需给出一个模型配置,其余生命周期由框架托管——这正是"配置一行、能力跨会话"的用法。
配合实例级的LibSQLStore,观察记录得以落盘:同一个 Studio 用户(即同一 thread 归属)多次提问"总结反馈"时,Agent 便能说出"账单类投诉较上一批增多"这类带时间维度的结论,而不是每次都从零开始。
使用方式与真实数据接入
在 Studio 中交互
- 打开 Studio,导航到 "Customer Feedback Summarizer" Agent;
- 尝试如下提问(README 推荐的问题模式,均可触发
get-feedback工具带过滤条件的调用):- "Summarize all customer feedback"(全量总结)
- "What are the critical issues from enterprise customers?"(按
customer_tier: 'enterprise'过滤) - "Show me only the feature requests from pro users"(按层级 + 类型筛选)
- "Compare support tickets to app reviews"(按
source分组对比)
- Agent 会用
get-feedback工具取数(自动翻页),逐条分析后生成带 findings 与 recommendations 的结构化摘要; - 直接把新反馈粘贴进聊天,Agent 会将其纳入既有分析并与已有趋势对比;
- 跨会话时,Observational Memory 持续记录模式,支撑趋势类问题。
README 还指出,该 Agent 演示运行在 Mastra Studio 中,但也可以把 Agent 接入自建的 React、Next.js 或 Vue 应用——官方文档提供了 Mastra Client SDK 以及 AI SDK UI、CopilotKit、Assistant UI 等 agentic UI 库的接入路径。
接入真实数据源
get-feedback工具当前读取的是静态 fixture。要接入真实数据,按 README 的指引,只需更新 get-feedback.ts 中的execute函数,把内存过滤替换为数据库或 API 查询:
source/customer_tier过滤 → SQL 的WHERE条件;start_date/end_date→ 日期范围查询;limit/offset→LIMIT/OFFET分页;has_more、total等输出字段保持不变,Agent 侧的翻页逻辑与 instructions 完全无需改动。
工具描述中刻意保留的limit、offset、has_more分页接口,就是为这种映射设计的——这也是该模板"接口先行、数据后接"的设计思路:先让 Agent 学会分批取数、控制上下文窗口,再无缝替换底层数据源。
小结与参考路径
这个模板用不到 5 个源文件演示了一条完整的 Mastra Agent 工程化路径:Agent(模型 + 工具 + 评分器 + 记忆)→createTool(带分页契约的取数工具)→createScorer(可执行的加权 LLM 评分)→Mastra实例(存储 + 日志 + 可观测性)→Memory(会话内 + 跨会话两层记忆)。值得直接复用与仿写的要点:
- 用一份结构化的
instructions(流程、输出格式、语气规范、跨会话观察用法)约束 Agent 行为,而非只给一句角色设定; - 工具的输出 schema 显式返回分页元数据(
total/has_more/filters_applied),把"翻不翻页"的决策依据交给 Agent; - 用双评分器(可执行性 + 完整性)以 100% 采样率自动度量输出质量,权重向"具体性"倾斜;
- 主分析模型与观察提取模型分档配置,兼顾质量与成本。
主要参考文件:
- 模板 README
- Agent 定义
- get-feedback 工具
- 示例反馈数据
- 评分器实现
- Mastra 实例装配
- 依赖与脚本
- Observational Memory 处理器
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考