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助手」标签)
三块注入,分清轻重:
- 课程上下文进系统提示,但只注入「编号 + 标题 + 一句优先结合本课」——不塞正文:
// 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```"
);
}
-
正文按需检索:模型提出
search_courses,executeTool在白名单内执行——标题命中 +10、编号精确 +20、摘要 +6、知识点 +6、正文 +3,取前 4 门,命中片段随refs事件推给前端渲染成引用;要完整正文用get_lesson再取(截断到 6000 字)。这就是「上下文不必大,检索要准」。 -
选中代码是用户主动给的信号,直接注入并截断(请求体收 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 每一段都能对上本课的图。
动手任务
- 在任一课程页问一个本课概念问题,用 Network 面板数一数事件类型,确认
refs命中了当前课程。 - 选中正文里一段代码再提问,对比回答是否围绕选区展开;再清空选区问同一个问题,对比差异。
- 把一次回答「存为笔记」,去笔记中心确认:内容在、课程关联在、标签在。
常见错误
- 把整课正文塞进系统提示:上下文暴涨、费用涨(A34)、还稀释重点——正文该走检索,提示里只放指针。
- 工具结果不截断就回传:
get_lesson返回 6000 字封顶是刻意的,全量回传会挤爆后续轮次的上下文。 - 选中代码不说明来源:只贴代码不说是「用户选中的当前代码」,模型会去猜文件名和项目背景。
- AI 静默写笔记:任何落库动作都该由用户显式触发,这是 A29「写入需确认」在产品层的延续。
检查与复盘
- 能不看资料画出从输入到笔记的完整数据流,并标出每段数据存在哪张表
- 能说出课程上下文(轻注入)与课程正文(检索)为什么分开处理
- 排错时先按数据流切段,再进具体函数
参考资料
- Next.js 文档:Route Handlers —— 本站 AI 接口的宿主形态
- OpenAI 文档:Function calling —— 工具循环的协议基础
- Next.js 官方文档 —— 服务端与 API 组织的官方指南
读完这一课了?
标记完成后,工作台会安排接下来的学习。