Skip to content

实现步骤

第一步:准备课程资料

课程资料放在:

text
apps/study-agent/src/data/course-materials.ts

每条资料包含:

  • id
  • title
  • topic
  • content

这让 Tool 可以用稳定字段搜索和返回摘要。

第二步:实现搜索工具

searchCourseTool 的职责只有一个:根据 query 返回相关资料。

设计重点:

  • 输入 schema:querytopK
  • 输出 schema:命中资料数组。
  • 空 query 返回空数组。
  • 不调用外部网络。

第三步:实现练习题工具

generateExerciseTool 根据 topic 和 difficulty 生成练习题。教学版用模板生成,真实项目可以让模型生成,但仍建议保留输出结构。

第四步:实现学习计划工具

createStudyPlanTool 把目标、天数和资料片段变成每天安排。它是确定性逻辑,因此放在 Tool 里比放在 prompt 里更容易测试。

第五步:组装 Agent

studyAgent 负责对话和工具选择。instructions 要明确:

  • 先搜索课程资料。
  • 不知道就说明缺少资料。
  • 输出要面向初学者。
  • 需要计划时调用计划工具。
  • 需要练习时调用练习工具。

第六步:组装 Workflow

studyPlanWorkflow 固定执行:

mermaid
flowchart LR
  A[输入 goal + days] --> B[normalizeGoal]
  B --> C[retrieveMaterials]
  C --> D[buildPlan]
  D --> E[输出计划]

第七步:注册 Mastra

src/mastra/index.ts 统一注册:

  • agents
  • tools
  • workflows
  • storage

Mastra Studio 能否看到这些模块,主要取决于这里是否注册正确。

第八步:补上结构化输出边界

当前教学项目中,学习计划和练习题由 Tool / Workflow 返回结构化数据,而不是让 Agent 自由输出 JSON。这样做有两个好处:

  • 离线模式可以运行同一套业务结构。
  • 真实模型只负责解释、选择工具和组织回答,核心对象由 TypeScript 代码产生。

如果后续要让模型生成更开放的结构化结果,可以在 .generate() 中加入 structuredOutput.schema。但要额外验证工具调用是否仍然正常,并用 Zod 对 response.object 做二次校验。

第九步:设计安全和人工确认

Study Agent 默认只有读取本地资料、生成计划、生成练习题,不执行破坏性操作,因此不默认启用 approval。

一旦增加这些功能,就应该先设计人工确认:

新能力风险推荐机制
写入日历修改外部系统Tool requireApproval
发送学习报告邮件对外发送内容Tool requireApproval
删除学习记录不可逆操作Tool requireApproval + 明确拒绝分支
购买课程或调用付费 API成本风险Approval + 成本 guardrail

第十步:准备评估样例

最终项目至少应保留一组手工或脚本化验收样例:

样例期望
用 3 天理解 Mastra Agent、Tool 和 Workflow返回 3 天计划,并引用相关资料
给我 Workflow 练习题调用练习工具,topic 和题目匹配
继续上一轮计划同一 memory thread 下能延续上下文
问一个课程资料外的问题明确说明资料不足,不编造

这组样例未来可以迁移到 Mastra Scorers;当前先用人工检查和离线脚本保证核心行为稳定。

本项目提供了可运行版本:

bash
npm run final:eval

它把样例拆成 toolUseCorrectnesstopicCoverageexpectedSignalsforbiddenSignals 和结构完整性等 scorer。后续接真实模型时,先保留这批确定性 scorer,再逐步加入 LLM judge。

第十一步:规划 RequestContext 和 Streaming

当前最终项目没有前端和多用户权限,因此没有默认实现 RequestContext。但真实应用应提前设计这些请求级变量:

变量用途不应做什么
user-tier控制可用工具、模型和 RAG topK不写入长期 Memory
language切换回答语言和资料偏好不把完整请求头交给模型
tenant-id数据隔离和工具配置不暴露给 prompt
debug是否返回 stream 事件细节不给普通用户显示内部事件

前端接入时建议优先使用 .stream()

  • 正常 UI 消费 textStream
  • 调试 UI 消费 fullStream,显示 tool-calltool-resultfinish
  • Workflow 页面消费 workflow stream 事件,显示 step 进度和失败位置。

第十二步:预留模型策略和服务化边界

最终项目保持最小可运行,但正式应用需要提前决定:

设计点教学版处理扩展方向
模型选择MASTRA_MODEL 一个默认值增加 fast / reasoning / fallback 策略
embedding教学版关键词检索ModelRouterEmbeddingModel 和向量库
前端接入Studio 调试使用 Mastra Server endpoint 或 Client SDK
鉴权不默认实现middleware 映射 resourceId
自定义 API不默认实现只补健康检查、导出、业务聚合接口

这一步不急着写代码。更重要的是先列清楚「哪些由 Agent 负责,哪些由服务端负责,哪些由前端负责」。否则 vibe coding 很容易把同一段业务逻辑生成到多个地方。