码道 —— 专属学习答疑对话AI:从 0 到 1 打造一个纯前端智能学习助手

用 HTML5 + CSS3 + JavaScript 三件套,把一个普通的大模型流式接口,变成一个真正"为学习而生"的对话产品。本文完整记录了这个项目的构思、实现、踩坑与交付全过程。
在这里插入图片描述
在这里插入图片描述
运行效果:
在这里插入图片描述


一、前言:为什么会想做一个学习答疑 AI

我们都有过这样的经历:课堂上老师讲到一个概念,当时听懂了,课后做题却发现完全不会;翻教材抓不住重点,网上一搜,得到的是一大堆良莠不齐的内容,筛选信息比学习本身还耗时间。今天的大模型能力已经足够强大,可以胜任"答疑",但一个通用的聊天窗口并不是为"学习"设计的:

常见的问题有三个。 第一,回答是"大段文字墙",没有重点、没有结构,读起来像阅读理解;第二,回答缺少"学习场景"的要素——没有关键要点提炼、没有生活化例子、没有下一步可以追问的方向;第三,对话是"一次性"的,昨天问的问题和今天问的问题完全割裂,无法形成知识体系。

所以我产生了做一个"学习原生"的 AI 对话产品的想法:它不止于"回答正确",更要"教得明白"。于是有了本项目——专属学习答疑对话 AI。

它希望做到三件事:

  1. 结构化:每次回答都像一份"学习卡片",有标题、有概述、有要点、有例子,一眼抓住重点;
  2. 可追问:回答末尾给出"值得继续深入的问题",点击即可接着学,形成追问闭环;
  3. 零门槛:纯前端实现,浏览器打开即用,不需要安装任何东西、不需要后端服务。

这个项目本质上回答了一个问题:如何把一个通用的大模型 API,通过提示词工程 + 前端工程,变成一个"学习体验"远优于裸聊天窗口的产品?

二、项目目标与设计理念

2.1 产品定位

项目名称定为"专属学习答疑对话 AI",面向学生和自学者,覆盖数学、物理、英语、编程等学科,支持概念解释、原理推导、解题思路、代码示例、学习方法等多类问题。

2.2 三个设计原则

原则一:结构化优先。 这是整个项目的灵魂。AI 的回答不应是一坨连续的文本,而应当被组织成「回答类型标签 → 精炼标题 → 一句话概述 → 详细正文 → 关键要点 → 生活例子 → 追问建议」的完整信息架构。结构化的好处是:大脑更容易记忆、回顾时更容易定位、知识点之间的关系更清晰。

原则二:学习路径驱动。 好的老师从不只给答案,而是给你"继续学习的入口"。所以每条回答都设计了 related_questions(追问建议),把一次答疑变成一条不断延伸的学习路径。

原则三:渐进式体验。 流式输出时给用户即时的"打字机"反馈;拿到完整结构后再升级为精美的卡片视图。整个过程平滑无感,不打断思考节奏。

2.3 功能清单

  • 流式对话:SSE 逐字输出,可随时停止生成;
  • 深度思考可视化:展示模型的推理过程,点击可展开;
  • 结构化学习卡片:六种回答类型自动加徽章,正文支持 Markdown;
  • 多轮上下文:自动携带历史,追问无缝衔接,最多保留 20 轮;
  • 零依赖 Markdown 渲染器:标题、列表、代码块、表格、公式美化;
  • 现代 UI:深浅主题一键切换、移动端自适应、欢迎屏快捷提问;
  • 容错降级:模型偶尔不守规矩输出非 JSON 时,自动降级为普通文本,绝不白屏。

三、技术选型:为什么坚持用纯前端

3.1 原生三件套 vs 现代框架

在做技术选型时,我认真地比较了 React/Vue 与原生 HTML5+CSS3+JavaScript 的取舍。结论是:这个项目完全不需要框架。

原因有三。其一,项目规模可控:核心就是"一个聊天界面 + 一个流式请求 + 一个卡片渲染",状态管理并不复杂,引入框架反而带来构建链路的复杂度;其二,交付物极简:原生项目意味着一个 index.html 拷到任何静态托管(GitHub Pages、AtomGit Pages、OSS、COS)就能跑,无需 npm install、无需构建;其三,学习价值高:写原生能让你真正理解 DOM、事件、异步流这些前端根基,而不是被框架的抽象遮蔽。

JavaScript 采用 ES6+,模块之间用全局命名空间(window.API_MODULE、window.MARKDOWN_MODULE)沟通,同时在文件内部封装 module.exports 以便 Node 环境做单元测试——一套代码,两个环境复用。

3.2 大模型 API 选型

模型调用采用 GitCode 大模型平台提供的 OpenAI 兼容接口(https://api-ai.gitcode.com/v1/chat/completions),模型为 deepseek-ai/DeepSeek-V4-Flash。选择它的理由:

  • 接口标准:OpenAI 兼容格式,生态成熟、文档丰富,前端实现有大量可参考的经验;
  • 原生支持流式:SSE 输出,天然适合聊天场景的逐字渲染;
  • 支持推理预算:thinking_budget 参数允许模型先"深度思考"再作答,配合 reasoning_content 字段,我们可以把思考过程也变成产品体验的一部分;
  • 参数灵活:temperature / top_p / frequency_penalty 均可调,方便针对"教学场景"收敛更稳定、更克制的语气。

3.3 为什么不做 Python 后端

任务给了一份 Python 参考代码(requests 流式请求)。为什么不直接照抄成 FastAPI 后端?因为:这个场景下,后端是多余的。模型接口的公网可及性、CORS 的宽松配置,使得浏览器直接调用成为可能;砍掉后端意味着:部署成本为零、维护成本为零、任何人都可以 fork 后改一行配置就跑起来。当然,这样做的代价是 API Key 会暴露在浏览器中,关于这一点我在后文的"部署与安全"章节会坦诚讨论。

四、核心任务:把 Python 流式调用翻译成 JavaScript

4.1 Python 参考代码解析

任务提供了一份简洁的 Python 参考实现,核心逻辑是:

def query(payload):
    response = requests.post(API_URL, headers=headers, json=payload, stream=True)
    for line in response.iter_lines():
        if not line.startswith(b"data:"):
            continue
        if line.strip() == b"data:[DONE]" or line.strip() == b"data: [DONE]":
            return
        yield json.loads(line.decode("utf-8").lstrip("data:").rstrip("/n"))

chunks = query({...model..., "stream": True, ...})
for chunk in chunks:
    print(chunk["choices"])

这段代码有三个关键动作:

  1. 以 stream=True 发起请求,拿到一个永不结束的字节流;
  2. 逐行扫描,只认 data: 前缀的行,遇到 [DONE] 结束;
  3. 把每一行 data: 后的 JSON 取出来解析,供上层消费。

在 Python 里这很简单——iter_lines() 帮你做好了按行切分、编码解码的所有脏活。但在浏览器里,我们要用手动方式完成同样的工作,这就是本项目的第一个技术难点。

4.2 浏览器端的对应实现

我在 js/api.js 中实现了与 Python 参考代码一一对应的功能:

PythonJavaScript
requests.post(..., stream=True)fetch(url, {method:'POST', body}) + resp.body.getReader()
resp.iter_lines()读取 Uint8Array → TextDecoder 解码 → 手动按 \n 切分
line.startswith(b"data:")line.trim().startsWith('data:')
json.loads(...)JSON.parse(...) + 容错清理
data:[DONE] 判断payload === '[DONE]' → 触发 onEnd

其中最关键也最容易被忽略的是按行切分的缓冲处理。TCP/HTTP 流并不保证"一行"刚好落在一个 reader.read() 的返回里,很可能一次 read() 返回半行、下一次返回剩余部分,甚至一次返回多行。因此我维护了一个 buffer 字符串:每次把新解码的文本追加进 buffer,然后循环 indexOf('\n') 取出完整行,处理完再清掉;最后还要处理"流结束时没有换行符结尾的残余内容"。这部分是纯手工实现的 iter_lines()。

4.3 让接口更"现代"的设计

在翻译之外,我对 API 层做了三个面向浏览器的增强:

第一,AbortController 原生支持"停止生成"。 用户在界面上点击"停止"时,controller.abort() 会中断 fetch,我们捕获 AbortError 后正常收尾。这是 Python 参考代码没有的能力,但对聊天产品至关重要——如果回答开始胡说八道,用户应该有权立刻终止。

第二,解析函数做成纯函数。 parseSSEChunk(line) 不依赖任何全局状态,输入一行原始文本,输出 {content, reasoning, done} 或 null。纯函数的好处是:可以在 Node 里直接做单元测试,api.js 通过 UMD 风格同时兼容浏览器和 Node 两种环境。

第三,显式分离正文与思考。 GitCode 接口的 delta 里同时有 content(正式回答)和 reasoning_content(思考过程)两个字段。我在解析层就把它们剥离开,分别回调 onContent 和 onReasoning,让上层 UI 可以有两种完全不同的呈现方式。

有了这个 API 层,Python 参考代码的能力就 100% 迁移到了浏览器,并且得到了增强。但此时我们还只是"能拿到文本流",离"学习产品"还有很远——接下来是最核心的一步:提示词工程。

五、系统提示词工程:让模型输出结构化 JSON

5.1 为什么需要 JSON

如果只是把流式文本显示出来,那和用一个裸的 ChatGPT 没有任何区别。我要的是:模型按我的信息架构来组织回答。最直接、最可控的办法就是在系统提示词里"约法三章",要求模型每一次回答都只输出一个合法 JSON 对象,然后由前端解析并分区域渲染。

结构化的回报是巨大的:

  • 前端渲染更精美:标题是标题、要点是列表、示例是卡片,不需要用正则从散文里猜结构;
  • 学习效率更高:学生先看到"一句话概述"判断是否命中自己的疑问,再决定要不要深入正文;
  • 交互更丰富:related_questions 可以直接变成可点击的追问按钮,形成交互闭环。

5.2 JSON 字段的信息架构设计

我设计的 JSON 结构包含 7 个字段,每个字段都对应一个产品决策,而不是拍脑袋:

{
  "answer_type": "概念解释 | 原理推导 | 解题思路 | 代码示例 | 学习方法 | 综合答疑",
  "title": "不超过15字的精炼标题",
  "summary": "一句话总结核心结论(≤40字)",
  "content": "Markdown 格式的详细解答正文",
  "key_points": ["3~5条关键知识点,每条≤25字"],
  "example": "一个具体的生活例子或通俗类比",
  "related_questions": ["2~3个值得追问的问题"]
}

逐字段说明设计动机:

  • answer_type(枚举):用一个受控枚举而不是自由文本。六个固定取值好处有二:前端可以用固定的颜色徽章体系,视觉上区分不同回答类型——"代码示例"回答和"概念解释"回答一眼可分;模型也不用纠结措辞,选一个最贴切的即可,避免"类型"这种 metadata 的任意漂移。
  • title(≤15字):像新闻标题一样精炼。这个约束很反直觉但很有效——如果不在提示词里强制,模型会输出一长串"关于xxx现象的一些深入探讨与分析"。限制了长度,标题才真正起到"扫描"的作用。
  • summary(≤40字):一句话说清核心结论。它是回答的"电梯演讲",让学生在花 3 秒读完后判断"这个问题是不是我要的"。
  • content(Markdown):详细解答正文。这里是真正的知识输送区,逻辑推演、分步讲解、示例代码都放这里,允许使用小标题、列表、代码块等 Markdown 语法。
  • key_points(3~5条):面向"记忆"的浓缩。多项认知科学研究都表明,分层级、要点化的信息比线性文本更利于记忆提取。这里是学生复习时的快速索引。
  • example(生活化):面向"理解"的类比。抽象概念落地的最好方式是一个具体的例子——向小朋友解释"浮力"最好的方式是"把空塑料瓶按进水池,手会感觉到一股向上的力"。
  • related_questions(2~3个):面向"延伸"的路径。这既是学习设计的体现,也天然成为前端交互的素材(可点击追问)。

5.3 提示词的工程细节

提示词里我埋了几个容易被忽视、但对"模型守规矩"至关重要的细节:

  1. 明确禁止 JSON 之外的输出:明确要求"不要输出 Markdown 代码块标记(如 ```json 包裹)、不要输出注释"。很多模型在输出 JSON 时习惯用代码块包裹,前端还得费劲剥壳;直接在提示词层消灭它。
  2. 标注转义要求:明确说明"字符串内的换行必须使用 \n 转义,不要使用真实换行"。这是血泪教训——JSON 规范不允许字符串值中出现未转义的真实换行,一旦模型在 content 里放了真实换行,JSON.parse 直接失败。把这条写进提示词,模型的遵从率显著上升。
  3. 给出字段级约束:每个字段后面都写了"不超过多少字 / 从哪些类型中选 / 可以省略"等边界条件。大模型对明确、量化的约束比模糊的形容词(如"简洁一点")遵从度高得多。
  4. 兜底条款:提示词最后一条写了"如果用户明确要求你输出作文、诗歌等,你仍然要把内容放到 content 字段中,并遵守整体 JSON 结构"。这确保了用户问"写一首关于宇宙的诗"时,系统不会被"必须输出 JSON"的硬约束卡死,而是把诗放进正文区,整体照常工作。

这段提示词是整个项目"产品化"的点睛之笔——同样的模型权重,不同的提示词,产出完全不同等级的产品体验。

六、前端架构设计

项目代码量约 1900 行,我按"职责单一"拆成了清晰的模块:

├── index.html          # 页面骨架:侧边栏 + 聊天区 + 输入区
├── css/
│   └── style.css       # 全部样式:CSS 变量主题 + 组件 + 响应式
├── js/
│   ├── config.js       # 配置:API 地址、密钥、模型参数、系统提示词
│   ├── api.js          # 网络层:请求体构建 + SSE 解析(纯函数,可单测)
│   ├── markdown.js     # 渲染层:零依赖 Markdown 渲染器(安全转义)
│   └── app.js          # 应用层:交互、状态、流式渲染、卡片组装
└── test/               # 三层测试

各层依赖关系是单向的:app.js → api.js → config.js,app.js → markdown.js。网络层与渲染层完全独立、可被 Node 直接测试,这也为后面的测试体系打好了基础。

config.js 把系统提示词独立成一个大字符串,而不是散落在请求代码里——提示词是"产品配置"而不是"代码",单独管理意味着后续调优(比如换一个 JSON 结构、加一门学科)不需要动业务代码。

七、SSE 流式解析与增量渲染的细节

7.1 解析器实现

parseSSEChunk 是全项目单测覆盖最高、也最"较真"的函数。它的输入输出约定是:

  • 空行、非 data: 前缀行 → 返回 null(忽略);
  • data: [DONE] → 返回 { done: true };
  • 合法 JSON 且含 choices → 返回 { content, reasoning, done: false };
  • 残缺 JSON → 返回 null(不抛异常,因为流式过程中"半行"是常态)。

每一条都对应真实会遇到的边界情况,比如流中途断掉、服务端发心跳空行、finish_reason 所在的空 delta 消息等。

7.2 增量 JSON 解析:边收边渲染

拿到文本流之后,最朴素的做法是"全文收完再解析",但那样用户在几秒内只能看到光秃秃的"生成中……",体验很差。

我的策略是边收边试:

  1. 每收到一段 content 增量,就追加进累积 buffer;
  2. 立刻用"宽容清理 + JSON.parse"尝试解析一次;
  3. 解析失败(大多数时候,因为 JSON 还没闭合)→ 用打字机效果把原始文本显示出来,保证用户有即时反馈;
  4. 一旦解析成功 → 用结构化视图渲染标题、概述、要点等字段(此时 content 可能已完整),并把正文区升级为 Markdown 渲染;
  5. 后续增量继续追加——如果模型输出稳定,后续多次解析会拿到更完整的字段;如果偶发失败,则沿用最后一次成功的结构,不覆盖。

这个策略的体验效果是:回答一开始像"打字机"在写作文本;当 JSON 闭合的那一瞬间,界面"唰"地升级成带徽章、要点的卡片;之后正文部分继续像打字机一样渲染 Markdown。用户全程有反馈,且最终呈现是精致的结构化卡片——两全其美。

7.3 思考过程的处理

模型在正式回答前会先产生大段 reasoning_content。这段思考内部语言不适合直接糊在正文里,我把它放进一个默认折叠的"深度思考"区域,点击可展开查看模型的推理路径。这对学习者其实是额外的价值——"看 AI 怎么想"本身就是在学习一种解题思路。系统提示词没有禁用思考(thinking_budget: 2048),因为我判断在这个产品里,展示思考过程是加分项。

八、结构化学习卡片的渲染

8.1 DOM 结构

一条助手回答的卡片结构如下:

.msg.assistant
├── .msg-avatar(机器人头像)
└── .msg-body
    ├── .thinking(可折叠思考区)
    └── .ai-card
        ├── .type-badge(回答类型徽章,六色体系)
        ├── .card-title
        ├── .card-summary
        ├── .card-content(Markdown 正文)
        ├── .card-keys(关键要点清单)
        ├── .card-example(例子卡片)
        └── .card-related(追问按钮组)

8.2 渲染策略的两个细节

详情一:插入锚点的动态查找。 卡片在"流式态"和"完成态"之间切换时,底部的"生成中…"提示条(.stream-hint)会被移除。要点/示例/追问区块的插入位置依赖这个锚点,如果锚点已不存在还硬用 insertBefore(node, anchor),就会抛出 NotFoundError。修复方案是:插入前先 querySelector 找锚点,找不到就 appendChild。这个 bug 是浏览器自动化测试抓出来的,后面会细说。

详情二:追问按钮的交互闭环。 related_questions 渲染为可点击的 “chips”,点击后直接作为新问题发送,且历史上下文会一并带上。于是"追问"不再是用户手打,而是"点一下"——交互成本降到最低,学习路径可以一路延伸下去。我在浏览器测试里专门验证了这条链路:点击追问 → 第二轮用户消息出现 → 第二轮回答正常返回。

8.3 容错降级

再强的提示词也不能保证模型 100% 服从。我做了三级降级:

  1. 模型返回合法 JSON → 精致卡片;
  2. 模型返回了文本但非 JSON → 降级为普通文本消息完整展示(绝不丢内容);
  3. 模型什么都没返回 → 展示一条温和的提示。

另外,前端还做了"清理 JSON 包裹"的容错:万一模型还是用 ` ```json … ````包裹了输出,解析前会先剥掉围栏。三层防线保证用户永远不会面对一个白屏或一个报错弹窗。

九、零依赖 Markdown 渲染器

9.1 为什么自己写

Markdown 渲染的"工业标准"是 marked.js,但我决定自己写一个约 120 行的轻量渲染器。动机:零依赖是硬需求(项目目标是"拷到静态托管就能跑"),CDN 引入会让项目在离线/内网环境下立即失效;而我们的正文场景相对收敛——标题、粗斜体、行内代码、代码块、有序/无序列表、引用、链接,这些语法手写实现并不困难,还能顺便做定制(比如公式美化、代码块换主题色)。

9.2 安全:先转义,再渲染

所有面向用户的 HTML 注入风险都必须在渲染层堵死。 我的实现顺序是:先对全文做 HTML 转义(& < > " ' 全部编码),再按语法规则生成结构标签,<script>、<img onerror> 这类注入 payload 在转义阶段就失效了。单元测试里专门有一条 XSS 转义 用例守住这条底线。

9.3 公式美化

学习场景绕不开数学公式。完整方案是接入 KaTeX,但同样受"零依赖"约束。折中方案:识别 \(...\)(行内)和 $$...$$(块级)包裹的公式,用强调色 + 衬线字体 + 居中块级样式渲染成"公式感"的视觉样式,同时保留原始 LaTeX 文本。效果上聊胜于无,而且为未来无缝升级 KaTeX 预留了同一套标记。我在 README 的展望里明确写了"引入 KaTeX 是真公式渲染的下一步"。

十、UI/UX 设计

10.1 视觉与主题系统

整体走"学习工具"气质:干净的卡片式布局、indigo 渐变主色、白色与浅紫灰的背景基调。全部颜色抽成 CSS 自定义属性(变量),深浅两套主题通过 body.dark 切换变量取值即可,主题切换按钮一行 classList.toggle 搞定,且用 localStorage 记住用户偏好。

10.2 移动端与细节打磨

  • 宽度不足 860px 时,侧边栏收起为抽屉,配合半透明遮罩(mask)弹出;
  • 消息区自动滚动跟随(流式输出期间持续 scrollTop = scrollHeight);
  • 输入框支持 Enter 发送、Shift+Enter 换行、Esc 在生成中停止;
  • 打字状态下"生成中"提示条有三点动画,营造呼吸感;
  • 回答类型徽章用六种低饱和度配色区分学科气质(蓝=概念、绿=解题、橙=代码……)。

十一、测试:三层验证体系

一个纯前端项目最容易出现"在自己电脑上能跑,换个环境就废"的问题。所以我给项目配了三层测试:

11.1 单元测试(离线)

test/parser.test.js(Node 直接运行,21 个断言)覆盖:SSE 解析器的各种边界(空行、[DONE]、残缺 JSON、空 choices、带空格前缀)、请求体构建、Markdown 渲染的每一项语法、XSS 转义、公式美化。重点:js/api.js 和 js/markdown.js 都要能被 Node require,这要求网络层与渲染层不依赖 DOM——这个约束反推了架构的干净。

11.2 端到端冒烟(联网)

test/e2e-smoke.js 真实调用模型接口:「发问 → 流式累积 → JSON 解析 → 校验 7 个字段」全链路。它验证的是外部世界的约定没有变——API 格式、模型行为、JSON 结构,任何一个变化都会在这里暴露。

11.3 浏览器级验证(可选)

test/browser-check.js 用 puppeteer 驱动真实 Chromium:打开页面 → 点快捷提问 → 等流式完成 → 断言卡片结构 → 点追问按钮 → 收集控制台错误。这层测试抓到了上一节提到的 insertBefore 崩溃,也验证了"全程无控制台报错"。

三次测试跑完,才叫"一个合格的前端交付"。

十二、踩坑记录

把一个通用接口变成产品的过程中,值得记录的坑有五个:

  1. insertBefore 锚点失效:流式提示条被移除后再被当作插入锚点,报 NotFoundError。修复:动态查找锚点,找不到就 append。教训:DOM 引用不要长期持有,临时再查。
  2. JSON 字符串内的真实换行:模型在 content 字段里输出真实换行导致 JSON.parse 崩溃。修复分两层:提示词层明确转义要求 + 前端层降级兜底。
  3. reasoning_content 与 content 混淆:思考过程和正文混在一起显示会惨不忍睹。修复:解析层分离,UI 层折叠展示。
  4. 半行/多行缓冲:字节流切分不能用"整块直接 parse"。修复:手工实现按行缓存队列。
  5. CORS 与本地 file:// 协议:file:// 下部分浏览器 fetch 受限。修复:README 明确建议用本地静态服务器(python3 -m http.server),生产推荐静态托管。

十三、部署与安全

13.1 部署

原生三件套的部署是最轻松的部分:index.html + css/ + js/ 一整个目录传到任意静态托管即可。开发期用 python3 -m http.server 8000 或 npx serve。

13.2 一句必须说的实话:API Key 会暴露

纯前端方案下,config.js 里的 apiKey 对任何打开开发者工具的用户都是透明的。这是纯前端 + 直连模型的固有代价,我在 README 里明确写了,并给出两条建议:个人学习项目可以接受;若要做正式商用服务,必须加一个服务端代理——密钥只存在服务端,浏览器请求服务端,服务端做鉴权、限流、转发,这同时也解决了调用计费的归属问题。这是诚实的技术边界,不藏着掖着。

十四、项目结构与文件职责一览

├── index.html          # 零依赖入口,承载侧边栏/聊天区/输入区三块骨架
├── css/style.css       # CSS 变量深浅主题、六色徽章、卡片/气泡/输入区、响应式
├── js/
│   ├── config.js       # API_URL / apiKey / 模型参数 / systemPrompt(产品配置集中地)
│   ├── api.js          # buildRequestBody / parseSSEChunk(纯函数) / streamChat
│   ├── markdown.js     # renderMarkdown / escapeHtml / 公式美化
│   └── app.js          # 消息渲染、增量JSON解析、结构化卡片、主题/清空/追问交互
├── test/
│   ├── parser.test.js  # 21 项离线单元测试
│   ├── e2e-smoke.js    # 真实 API 链路冒烟
│   └── browser-check.js# puppeteer 浏览器级验证
└── README.md           # 完整说明:快速开始 / 配置 / 提示词JSON / 测试 / 部署

十五、未来规划

项目已经跑通,但"学习助手"的想象空间远不止于此。我在 README 的展望里列了这些方向:

  • 接入 KaTeX 实现真正的数学公式渲染,覆盖理工科解题场景;
  • 学科知识库检索:给模型挂上 RAG(检索增强),让回答基于课本/讲义而非纯记忆;
  • 错题本与记忆曲线:把追问过的知识点记入用户画像,用间隔重复提醒复习;
  • 多端同步:目前数据在 localStorage,后期可接轻量后端做真正的多端同步;
  • 语音交互:结合 Web Speech API,让"答疑"在通勤路上也能发生;
  • 服务端代理化:解决密钥暴露与计费归属,同时支撑多用户并发。

十六、总结

回顾整个开发,这个项目最有价值的产出其实不是代码,而是一个清晰的认知:大模型只是"原料",产品体验取决于你如何设计它的输出契约。

同样是 deepseek-ai/DeepSeek-V4-Flash,裸的聊天窗口给出的是信息瀑布,而这个项目通过一份系统提示词 + 一个增量渲染管线,让它给出了"标题 → 概述 → 正文 → 要点 → 例子 → 追问"的学习卡片。模型的能力被格式约定和前端呈现放大成了一个完整的教学产品。这正是"码道"所倡导的:用工程能力,把 AI 的能力翻译成真正的用户体验。

如果你也想做一个自己的 AI 产品,我的建议是:先别急着上框架、上后端,从"你希望 AI 以什么结构回答问题"开始设计——把输出契约想清楚了,前端、提示词、测试一切都顺理成章。这套思路,对任何"AI + 场景"的产品都适用。

项目地址:https://atomgit.com/gcw_XKgDEJsW/zhuanshuxuexidayiduihuaAI

感谢阅读,欢迎 star、fork,也欢迎在评论区交流你在构建 AI 产品时踩过的坑。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐