A39第 1 / 1 课时未开始内容版本 1.0.0 · 核验于 2026-10-26

AI 导师综合实现

AI 导师综合实现 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。

学习目标

读完本课你能:完整说出本站 AI 导师从「用户输入」到「存为笔记」的数据流;解释课程上下文、选中代码、检索工具、引用、笔记五块能力分别在哪一层实现;据此定位「回答不对劲」时该检查哪一段。

问题场景

在 R08 的阅读页里选中一段 useState 代码,问「这里为什么要用函数式更新」。AI 的回答正好结合了你正在学的课、贴着你选的代码,还带了指向 R08 的引用链接,答完你点「存为笔记」,笔记中心里它已关联好课程。这套体验不是一个大提示词堆出来的,是五块能力各就各位的结果——本课把它们拼回全景。

核心解释

整条数据流(全部是本站真实实现):

用户输入 + context{courseSlug, exerciseSlug, selectedCode}
  → POST /api/ai/chat(懒创建会话,标题取消息前 30 字)
  → buildSystemPrompt:基础规则 + 课程上下文 + 选中代码
  → 组装历史(最近 20 条)
  → streamChatCompletion(流式 + 工具循环,最多 3 轮)
  → refs 事件 + done 事件 → ai_message / ai_call 落库
  → 前端「存为笔记」→ POST /api/notes(带课程关联与「AI助手」标签)

三块注入,分清轻重:

  1. 课程上下文进系统提示,但只注入「编号 + 标题 + 一句优先结合本课」——不塞正文:
// lib/ai/tools.ts(节选):轻量上下文,正文按需检索
if (opts.courseSlug) {
  const row = db.prepare("SELECT code, title FROM course WHERE slug = ?").get(opts.courseSlug);
  if (row) {
    lines.push(`当前学习者正在学习课程 ${row.code}《${row.title}》。回答优先结合这节课的内容。`);
  }
}
if (opts.selectedCode) {
  lines.push(
    "学习者主动选中了以下代码,回答时围绕它展开:\n```\n" +
      opts.selectedCode.slice(0, 3000) +
      "\n```"
  );
}
  1. 正文按需检索:模型提出 search_courses,executeTool 在白名单内执行——标题命中 +10、编号精确 +20、摘要 +6、知识点 +6、正文 +3,取前 4 门,命中片段随 refs 事件推给前端渲染成引用;要完整正文用 get_lesson 再取(截断到 6000 字)。这就是「上下文不必大,检索要准」。

  2. 选中代码是用户主动给的信号,直接注入并截断(请求体收 4000、注入用 3000),并明确告诉模型「围绕它展开」。

兜底与收尾:工具名不在 ASSISTANT_TOOLS 白名单 → 返回错误给模型而不是执行;finish_reason === "tool_calls" 且轮次未到 MAX_ROUNDS(3)→ 自动跑下一轮;结束时把引用随事件送达;ai_message 存全文、引用与状态,ai_call 记账(A34)。存笔记在 features/assistant/assistant-chat.tsx:前端把回答内容组织好请求 /api/notes,带课程关联与「AI助手」标签——AI 只产内容,落库动作始终由用户点出来。

示例拆解

拿「回答不对劲」当排错练习,按数据流切段定位:

症状 先查哪段 常见原因
回答不结合当前课程 buildSystemPrompt 注入 courseSlug 没传到 / 课程 slug 不在库
引用与问题无关 search_courses 打分 query 太泛 / 命中为零
工具名伪造被执行? 白名单校验 不可能:不在 ASSISTANT_TOOLS 直接拒绝
回答到一半断 工具循环轮次 / abort MAX_ROUNDS 用尽 / 用户取消
笔记丢了课程关联 前端 POST /api/notes 参数 关联字段没带上

验证方法:打开浏览器 Network 面板看 /api/ai/chat 的 SSE 事件序列,start → text* → tool → refs → done 每一段都能对上本课的图。

动手任务

  1. 在任一课程页问一个本课概念问题,用 Network 面板数一数事件类型,确认 refs 命中了当前课程。
  2. 选中正文里一段代码再提问,对比回答是否围绕选区展开;再清空选区问同一个问题,对比差异。
  3. 把一次回答「存为笔记」,去笔记中心确认:内容在、课程关联在、标签在。

常见错误

  • 把整课正文塞进系统提示:上下文暴涨、费用涨(A34)、还稀释重点——正文该走检索,提示里只放指针。
  • 工具结果不截断就回传:get_lesson 返回 6000 字封顶是刻意的,全量回传会挤爆后续轮次的上下文。
  • 选中代码不说明来源:只贴代码不说是「用户选中的当前代码」,模型会去猜文件名和项目背景。
  • AI 静默写笔记:任何落库动作都该由用户显式触发,这是 A29「写入需确认」在产品层的延续。

检查与复盘

  • 能不看资料画出从输入到笔记的完整数据流,并标出每段数据存在哪张表
  • 能说出课程上下文(轻注入)与课程正文(检索)为什么分开处理
  • 排错时先按数据流切段,再进具体函数

参考资料

读完这一课了?

标记完成后,工作台会安排接下来的学习。

Command Palette

Search for a command to run...