实验与练习
知识测验检验理解,代码练习验证动手能力;两者都会进入错题与复习。
- C01
课程卡片
把课程数组渲染成卡片列表:标题和课时是必需信息,必须始终展示;tag 是可选字段,只在该课程有值时显示「分类:标签值」,缺失时不能留下空白占位或 undefined/null 文本。
React简单React 沙箱 - C02
条件面板
实现一个互斥状态面板:status 为 ready/loading/error/empty 时分别显示课程列表、「加载中…」、「加载失败:请重试」、「暂无数据」,任何时刻只能出现其中一个分支;四个切换按钮(模拟加载/模拟失败/空结果/恢复正常)用于驱动状态。
React简单React 沙箱 - C03
可重排列表
修复备注与课程条目的对应关系:每行可输入备注,也能点「上移·课程名」把该行上移。编辑某行备注后再移动顺序,备注必须继续跟着原来的课程走,而不是留在原来的位置上(起始代码里有一个状态错位缺陷)。
React中等React 沙箱 - C04
累积计数
实现一个计数器:页面显示「计数:N」,按钮文案包含「累加」。要求连续触发多次累加后计数仍然正确(旧状态快照导致的丢失更新是本题要修复的核心缺陷)。
React简单React 沙箱 - C05
嵌套编辑
编辑章节的标题和课时:每章有 placeholder 含「标题-」的输入框和 placeholder 含「小时-」的输入框。要求更新指定章节时其他章节不受影响,页面顶部「原始章节」摘要(来自题目原始数据)必须保持不变——它专门用来暴露误改原始数据的问题。
React中等React 沙箱 - C06
多条件筛选
实现课程筛选:关键词输入框(placeholder「搜索课程」)、难度按钮(全部/入门/进阶)、「只看收藏」开关和「清除条件」按钮组合生效,计数行「共 N 门」与列表始终一致。起始代码的条件组合逻辑有缺陷。
React中等React 沙箱 - C07
双控件同步
难度筛选有两个入口:顶部摘要栏的「筛选:全部/入门/进阶」按钮和列表工具栏的「全部/入门/进阶」按钮。两个入口必须操作同一份状态——从任何一个入口修改,顶部摘要「当前:X · 共 N 门」与列表内容都要同步。起始代码把状态拆成了两份。
React中等React 沙箱 - C08
学习计划表
实现学习计划表单:课程名称与每周时长(1-40)两个输入框,提交后追加到计划列表。需要校验输入并在字段旁显示错误、提交进行中阻止重复提交、保存失败时保留已填内容并提示。保存函数通过 prop 注入:App({ savePlan }),savePlan 接收 { name, hours } 返回 Promise<{ ok: boolean }>,默认实现约 30ms 后返回 { ok: true }。
React中等React 沙箱 - C09
派生数据
用纯函数实现课程筛选与统计(js 沙箱,入口 main.js,以 CommonJS 运行):module.exports 导出 filterCourses 与 deriveStats。统计必须每次从入参现算——派生数据一旦落地成模块级缓存,新增、删除课程或切换条件后就会拿到过期结果。起始代码在条件组合和缓存上都有缺陷。
React中等JavaScript 沙箱 - C10
reducer 提交机
用 useReducer 实现提交状态机:editing/submitting/success/failed 四个状态,非法动作不能产生矛盾状态。保存函数通过 prop 注入:App({ submitApi }),submitApi 接收草稿字符串返回 Promise<{ ok: boolean }>,默认实现约 30ms 后返回 { ok: true }。页面有「计划内容」输入框、「提交」按钮与「重置」按钮。
React较难React 沙箱 - C11
主题上下文
用 createContext 实现跨组件主题:顶部按钮「切到浅色/切到深色/跟随系统」切换,深层内容组件从 context 读取主题显示。主题持久化到 localStorage 键 reactlab-theme(值为 light/dark/system),重新渲染后恢复;「跟随系统」按全局 window.__systemTheme(light/dark,测试环境用它代替系统偏好)显示实际配色。
React较难React 沙箱 - C12
编辑状态保留
两门课程共用一个编辑器:点课程名切换对象,每门课的未保存草稿必须各自独立、互不串位,保存后的「已保存:」内容也按课程区分。起始代码用一份草稿状态服务所有课程,切换后内容会串。
React中等React 沙箱 - C13
事件订阅
把组件接到题目提供的事件中心 hub 上(模块已导出 createHub 与 hub,请勿修改这部分):挂载时订阅、事件到来时更新计数、频道切换时更换订阅,离开时必须清理。测试通过模块导出的 hub.dispatch({ n: 1 }) 派发事件。起始代码切换频道后旧订阅没有清理,一次事件会被计入多次。
React中等React 沙箱 - C14
计时器修复
修复秒表计时器:组件接受 prop tickMs(计时周期毫秒数,默认 1000,测试会传小值加速),页面显示「已运行 N 秒」,提供「暂停/继续/重置」按钮。起始代码有读取过期状态的缺陷:计时停在某个值不再前进,暂停、恢复和重置的行为也要逐一验证。
React较难React 沙箱 - C15
请求竞态
修复课程切换的请求竞态:点「React 入门」「Hooks 深入」按钮加载课程详情,快速连续切换时页面必须始终显示最后一次选择的课程,过期响应不能覆盖新结果。数据通过 prop 注入:App({ fetchCourse }),fetchCourse(id) 返回 Promise<{ id, name, lessons: string[] }>;不能用真实网络,测试用可控 Promise 模拟延迟与乱序。
React较难React 沙箱 - C16
焦点弹层
实现无障碍帮助弹层:点「打开帮助」弹出 role="dialog" aria-modal="true" 的弹层(测试靠 role 查找弹层),打开后焦点移入弹层内(「关闭」按钮),按 Esc 可关闭,关闭后焦点回到「打开帮助」触发按钮,背景不会误接收焦点。起始代码完全没有焦点管理。
React较难React 沙箱 - C17
自定义草稿 Hook
实现自定义 Hook useDraft(key, version, storage = localStorage),返回 { value, setValue, saved }:初始从 storage 的 draft:<key> 键读取 JSON { v, data }(v 等于 version 才恢复 data),setValue 立即写回同一键,写入抛错时 saved 为 false。App({ storage }) 用它管理「大纲」与「笔记」两个草稿实例(key 分别为 outline/note,version 1),多实例互不覆盖。
React较难React 沙箱 - C18
乐观收藏
实现乐观更新的收藏列表:点击「收藏 课程名」后界面立即反馈(★ 已收藏),服务端确认后保持;失败则回滚并提示「收藏失败,已回滚」。收藏函数通过 prop 注入:App({ toggleFavorite }),toggleFavorite(id) 返回 Promise<{ ok: boolean }>;测试用可控 Promise 模拟慢响应、失败与乱序。
React较难React 沙箱 - C19
可搜索组合组件
实现可搜索的选择框:placeholder「选择讲师」的输入框实时过滤讲师列表;键盘 ArrowDown 移动高亮(显示为「▶ 讲师名」,跳过禁用项)、Enter 选中高亮项;点击选项也可选中;禁用项(赵四·暂不可约)不可被点击或键盘提交;无匹配时显示「无匹配讲师」。选中后显示「已选:X」且输入框值为 X。
React较难React 沙箱 - C20
性能修复
定位页面里真正的昂贵工作:analyze(list) 对课程做重量级统计(真实场景耗时几十毫秒),通过 prop 注入以便测试计数:App({ analyze }) 接收课程数组返回 { count, hours }。要求统计只在依赖变化时重算——切换筛选要重算,但选中课程、移动高亮这类无关更新不能触发重算。筛选用「全部/入门/进阶」按钮,列表行可点击选中,统计显示「统计:共 N 门 · M 课时」。
React较难React 沙箱 - C21
大列表
把 5000 门课程的大列表做成可用的:组件接受 prop count(默认 5000),只渲染可视窗口附近的行(滚动容器高 320px、行高 32px),提供「搜索课程」过滤、「定位序号」输入 + 「定位」按钮跳转到指定课程、行内「选择」按钮选中课程。核心是滚动、定位和选择永远与正确的数据行对应,不能错位。
React较难React 沙箱 - C22
异步组件测试
实现一个「测得起来」的异步组件:App({ fetchProfile }),fetchProfile() 返回 Promise<{ name, bio }>(测试注入可控 Promise,不依赖真实网络波动)。组件要把等待、成功、失败、重试全部暴露为用户可见状态:等待时显示「加载中…」,成功显示姓名与简介,失败显示「加载失败」和「重试」按钮,点「重试」重新发起请求。
React较难React 沙箱 - C23
看板综合题
实现任务看板:待办/进行中/已完成三列,默认任务为「搭建脚手架(待办)」「写周报(进行中)」「复盘会议(已完成)」。支持:「新任务名称」输入 + 「添加任务」按钮(新增到待办);每行「移动 任务名」(待办→进行中→已完成,已完成行没有移动按钮)与「删除 任务名」按钮(按钮文案都要包含任务名);「搜索任务」输入过滤(计数行「共 N 个任务 · 匹配 M 个」);点任务标题选中,详情显示「选中:任务名(列名)」;删除选中任务后详情回到「未选中任务」;数据持久化到 localStorage,重新渲染后恢复。
React较难React 沙箱 - C24
管理台综合题
实现课程管理表格:每页 3 条,支持上一页/下一页;切换筛选条件后页码重置为 1;点击「编辑」进入行内编辑,保存调用 saveRow(id, title)(可能失败,失败保留输入并显示错误);删除后当前页数据不足时自动回到有效页。
React较难React 沙箱 - C25
动态课程页
给课程站补上动态详情页:app/courses/[courseId]/page.tsx 读取 URL 里的课程标识(Next.js 16 中 params 是 Promise,必须 await),查到课程就渲染标题、简介和课时列表;查不到就调用 notFound() 让未找到页面接管。首页 app/page.tsx 已列出全部课程链接。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c25-course-page/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:访问 /courses/next-101 看到内容;访问 /courses/nope 看到 404 页而不是报错白屏。
Next.js简单Next.js 工程 - C26
可分享筛选
把题目列表的筛选和分页写进 URL 查询参数:状态(all/todo/done)与标签(all/hooks/state/async)用链接切换,页码用上一页/下一页链接翻动,每页 3 条。要求刷新、浏览器回退、复制链接给他人打开都能恢复同一视图。searchParams 同样是 Promise,必须 await。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c26-shareable-filter/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:点筛选举证链接后 URL 带 ?status=todo&tag=hooks,刷新后列表不变;翻页时原筛选不丢。
Next.js中等Next.js 工程 - C27
渲染边界
拆分服务端与客户端:lib/stats.ts 模拟数据库访问(含秘密 token),app/page.tsx 作为服务端组件取数,交互过滤放在 app/filter-panel.tsx。starter 把数据访问直接搬进了客户端组件,构建时会把数据库依赖和秘密打进浏览器包。修好这条边界。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c27-render-boundary/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:页面正常显示统计;filter-panel 里筛选按钮可交互;终端执行 node tests/check.mjs ../solution 通过。
Next.js中等Next.js 工程 - C28
分页接口
实现 GET /api/records:用 zod 校验查询参数 page(≥1,默认 1)、page_size(1-50,默认 10)、status(可选 all/todo/done,默认 all),返回稳定结构 {code:0, data:{total, page, page_size, items}};参数非法返回 400 与 {code:40001, message}。数据层 lib/records.ts 已给出。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c28-pagination-api/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:/api/records?page=2&page_size=5 返回合法 JSON;page_size=999 被拦成 400;status=wtf 也是 400。
Next.js中等Next.js 工程 - C29
本地笔记
本地笔记应用:新增、编辑、删除、按关键词搜索,数据写入 var/data/notes.json(重启不丢)。编辑走乐观锁:每条笔记带 revision,提交时带上读到的旧 revision,对不上就拒绝保存并回显冲突提示,绝不静默覆盖。Server Actions 在 app/actions.ts("use server"),冲突通过 redirect 回编辑页 ?conflict=1 展示。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c29-local-notes/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:新增/编辑/删除/搜索都生效且重启后还在;开两个标签页编辑同一条,后提交的会看到冲突提示而不是悄悄覆盖。
Next.js较难Next.js 工程 - C30
内容更新
个人知识条目站:索引页与详情页声明 export const revalidate = 60 走页面级缓存,归档/恢复是 Server Actions。要求改完内容后索引、详情、归档页立刻一致:actions 里写库之后必须 revalidatePath 失效受影响路径,否则 60 秒内看到旧数据。数据层 lib/knowledge.ts(文件存储)已给出。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c30-content-revalidate/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:归档一条后回索引页立即消失、归档页立即出现;恢复同理;注释掉 revalidatePath 复现旧数据,再恢复。
Next.js中等Next.js 工程 - C31
MDX 正文
课程正文渲染器:lib/content.ts 存了三篇 MDX 文本(frontmatter + ## 标题 + 代码围栏 + :::tip/:::warn 提示块 + 普通段落)。在 lib/mdx.ts 实现解析:zod 校验 frontmatter(缺 title/slug 报错)、标题生成锚点 id、围栏成对校验(不闭合抛 MarkdownError),并从 h2 生成目录;app/posts/[slug]/page.tsx 渲染正文、Callout 组件与可跳转目录,无效正文(post-broken)降级为明确错误提示而不白屏。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c31-mdx-body/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:/posts/post-ai-basics 有目录且锚点可跳转;/posts/post-broken 显示错误提示,dev 终端能看到明确报错。
Next.js中等Next.js 工程 - C32
资料导入
资料导入接口:POST /api/uploads 接收 FormData(file),校验大小(≤2MB)、类型(白名单 pdf/png/txt/md)与安全文件名(取 basename、拒绝 .. 与路径分隔符),保存为随机 resourceId + 白名单扩展名,元数据写入 var/uploads/<resourceId>.json;GET /api/uploads/[resourceId] 按 resourceId 读回文件——resourceId 必须先过格式校验(UUID),防路径穿越。lib/storage.ts 是要补齐的核心。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c32-safe-upload/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:上传合法文件返回 resourceId 并能 GET 读回;超大/类型不符/文件名带 ../ 的请求得到 400;GET /api/uploads/..%2fsecret 得到 400 或 404 而不是文件内容。
Next.js较难Next.js 工程 - C33
幂等进度
学习进度用 node:sqlite(DatabaseSync)落库:progress 表以 PRIMARY KEY (user_id, lesson_id) 把「一人一课一条记录」压到数据库层,写入用 INSERT ... ON CONFLICT DO UPDATE 实现幂等——重复提交只产生一条有效记录并返回 duplicate 标记;pathCompletion(user_id, pathId) 按完成课数/路线总课数计算百分比。app/actions.ts 与 app/page.tsx 已给出,核心在 lib/db.ts。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c33-idempotent-progress/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:同一课连点多次完成按钮,页面完成度不变多、库里只有一条记录;两条路线的百分比各自正确。
Next.js中等Next.js 工程 - C34
全栈联调
综合题:学习打卡站,把 N 系列的主线串起来。功能:任务清单(读取,支持 ?filter=all|open|done 筛选,刷新恢复)、编辑任务标题(Server Action)、提交打卡(useActionState 表单,反馈成功/失败消息)、数据写 var/data/checkpoint.json 持久化。完成后用 tests/README.md 的代表路径清单走查:读、改、交、反馈、刷新恢复各一条。验收方式:本练习无法自动判分。补齐 starter 后在 examples/exercises/next-c34-fullstack-checkpoint/starter 目录执行 npm install && npm run dev,浏览器访问 http://localhost:3000 按要求走查;tests/check.mjs 是结构自检(node tests/check.mjs starter 或 solution 目录路径)。 关键走查:筛选后刷新仍在;改标题立即生效;打卡后看到成功反馈;非法输入(空标题)看到错误消息而非崩溃;重启 dev 数据还在。
Next.js较难Next.js 工程 - C35
基础模型调用
在服务端 API 路由里发起一次模型请求:用 zod 校验输入长度(1~500 字),未配置 AI_API_KEY 时走受控 mock,配置后请求 OpenAI 兼容接口。响应只返回 reply、model、mocked,密钥不能出现在浏览器代码或 API 响应里。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用简单AI 工程 - C36
结构化结果
让模型生成学习计划 JSON,并在服务端完成解析、zod 校验和一次重试。mock 第一次故意返回缺字段的 JSON,第二次才合法;两次都失败时返回 422 和可恢复错误(code、message、canRetry、issues),不能把坏结构直接渲染。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C37
流式展示
实现 SSE 流式聊天:服务端返回 delta/done/error 事件,客户端用 TextDecoder + 缓冲区 buf 按空行切分事件,delta 追加到已有文本。断流或网络中断时保留已经收到的部分,并明确提示「已保留收到的内容」;停止按钮 abort 后同样不清空。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C38
取消与重试
实现真正可取消的聊天请求:浏览器用 AbortController,服务端把 request.signal 传给模型 fetch;停止后请求以 499 结束。重试复用同一个 request_id,不重复追加用户消息,响应按 request_id 归属,旧请求的迟到结果不能覆盖新结果。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C39
会话恢复
用 sqlite 保存会话与消息:conversations 表记录标题和模型,messages 表用 order_index 保证同一会话内顺序唯一。刷新后恢复完整历史,切换会话先清空旧消息再按新 id 拉取,不能把两个会话的消息串在一起。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C40
课程检索工具
实现一个只接收受控参数的课程检索工具:query 1~80 字、track 枚举、limit 1~10,使用 .strict() 拒绝多余字段。返回带 course_code 和 lesson_id 的可定位片段;没有结果时返回 { results: [], total: 0 },绝不编造课程或来源。交付一个最小 Next.js 工程(next 16 / react 19 / zod),本练习聚焦工具实现,不直接调用模型;真实项目接入模型时,工具参数仍先过同一套 zod 校验,密钥只放服务端 AI_API_KEY / AI_BASE_URL / AI_MODEL。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C41
工具执行回路
实现有界工具执行回路:模型返回 tool_call 后,服务端校验工具白名单与参数、执行工具、把结果以 tool 角色回传,最多 MAX_ROUNDS=4 轮;超过轮次返回 max_rounds,取消时及时结束并返回 499。每一步都写入 trace。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用较难AI 工程 - C42
文档切分
实现纯函数文档切分:normalizeText 去 BOM、统一 CRLF/CR 为 LF;chunkDocument 按 Markdown 标题分节,再按 maxChars 切窗口并保留 overlap,每个片段带 title、source、heading、start、end、order。空文档返回 [],超长段落每段不超过 maxChars。交付一个最小 Next.js 工程(next 16 / react 19 / zod),核心逻辑是纯函数,不需要模型密钥;如果后续接入模型,仍以 AI_API_KEY / AI_BASE_URL / AI_MODEL 作为服务端配置。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用中等AI 工程 - C43
检索比较
用固定语料和固定问题对比 keyword 与 hybrid 两种检索配置:记录每个问题的 top3、命中位置、hit@3 和 MRR,并打印失败样本的「期望 id vs 实际 top3」证据。评估脚本必须能直接 node scripts/compare-retrieval.mjs 运行。交付一个最小 Next.js 工程(next 16 / react 19 / zod),核心逻辑是纯检索与评估脚本,不需要模型密钥;如果后续接入模型,仍以 AI_API_KEY / AI_BASE_URL / AI_MODEL 作为服务端配置。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用较难AI 工程 - C44
引用核对
实现引用表与文档删除后的级联清理:引用保存 chunk_id,打开时能返回资料片段;删除文档时先找出 chunk,把相关引用更新为 status='orphaned' 并清空 chunk_id,再删除 chunk 和文档,整个过程放在事务里。旧引用再次打开返回 410,而不是 500。交付一个最小 Next.js 工程(next 16 / react 19 / zod),本练习聚焦引用数据生命周期,不直接调用模型;真实项目接入模型时,引用只允许来自检索结果,密钥仍只放服务端 AI_API_KEY / AI_BASE_URL / AI_MODEL。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用较难AI 工程 - C45
资料指令隔离
构造一个含恶意指令的检索资料,验证应用仍按固定工具权限和任务范围处理:资料只作为 data 放进用户消息,系统提示固定;allowedTools 来自常量而不是资料;scanForInjection 只做审计标记,不改变权限。页面展示 allowed_tools 与 injection_flags。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用较难AI 工程 - C46
AI 导师综合
把课程检索、选中代码、引用、停止和笔记保存接成完整 AI 导师:按课程检索片段,把 selected_code 作为 data 放进提示,回答带可打开的引用;请求支持 AbortController 停止;笔记保存到 sqlite 并在刷新后恢复。交付一个最小 Next.js 工程(next 16 / react 19 / zod),真实模型调用位置使用受控 mock:未配置 AI_API_KEY 时走 mock,配置 AI_API_KEY、AI_BASE_URL、AI_MODEL 后走 OpenAI 兼容接口。验收:在练习目录执行 node tests/check.mjs solution 应输出 ALL CHECKS PASSED,对 starter 应至少一项 FAIL;本机 npm install && npm run dev 的人工步骤见 tests/README.md。
AI 应用较难AI 工程 - C47
索引校验脚本
实现函数 check(data):接收课程列表(list[dict],每项含 id/title/prereqs 字段),返回问题清单 list[dict],每项格式为 {"id": 课程id或None, "type": 问题类型, "message": 说明}。需要检测三类问题:重复 id(type="duplicate")、prereqs 里引用了不存在的 id(type="missing_dep")、title 为空(type="empty_title")。
Python中等Python 本机 - C48
输入模型
实现新增学习记录的入参校验:函数 validate_and_build(payload) 接收一个 dict,校验通过返回 StudyRecord 数据类实例,不合法抛 ValueError(message 说明哪个字段、什么问题)。只用标准库(dataclasses)。需要覆盖:缺字段、空文本、超长标题、无效状态、minutes 越界与非整数。
Python中等Python 本机 - C49
分页查询
实现筛选与分页纯函数 query_records(records, page=1, page_size=10, status=None, keyword=None):返回 {"total", "total_pages", "page", "page_size", "items"}。records 是 list[dict],每项含 id(int)、title(str)、status(str)。只用标准库,不启 HTTP。
Python中等Python 本机 - C50
本机联调
实现提交答案的适配函数 submit_answer(send, payload):send 是注入的伪传输函数(payload -> dict,可能抛 ConnectionError 模拟连不上本机后端)。函数负责:校验入参、网络失败自动重试(最多 3 次尝试)、把新旧两种成功响应格式归一化、把重复提交(409)当幂等成功而不是报错。纯函数,模拟输入,不发真实请求。
Python中等Python 本机 - C51
事务保存
实现 save_exam(conn, answers, mistakes):把答卷与错题写在同一个事务里(标准库 sqlite3,内存库,init_db 已提供)。任一行写入失败(如违反 NOT NULL 约束抛 sqlite3.IntegrityError)时,整个函数已做的写入全部回滚、两张表都保持空,异常继续向外抛;修正数据后重试能一次成功。
Python中等Python 本机 - C52
异步请求
实现 fetch_all(fetch, specs, timeout=1.0):fetch 是注入的异步函数(async def fetch(spec) -> dict,内部用 asyncio.sleep 模拟上游耗时,可能超时、可能抛错、可能被取消)。函数并发跑完所有 spec,返回与输入同序的结果列表。只用标准库 asyncio,不真正发起网络请求。
Python较难Python 本机 - C53
解析任务
实现文档解析任务面板 ParseBoard:上传后建立可查询的任务,失败记录原因,重试生成新的尝试(attempt+1),但同一 doc_key 在 documents() 里始终只有一份文档(重试成功是覆盖,不是重复)。纯内存实现,只用标准库。
Python中等Python 本机 - C54
后端综合
后端综合题:完成学习记录模块的三块拼图——数据类(StudyRecord 已给)、入参校验(add_record 内完成,规则同 C48:缺字段/空文本/超长标题/minutes 1-240/status 枚举)、sqlite 持久化与统计查询。标准库 sqlite3 内存库,init_db 已提供。测试覆盖全部行为:合法写入、非法拦截(不落库)、列表与筛选、统计口径。
Python较难Python 本机 - C55
HTTP 与 JSON
实现书签 HTTP 接口:POST /bookmarks 创建(校验 JSON 与方法),GET /bookmarks/{id} 读取。无效 JSON 返回 400,不存在返回 404,成功创建返回 201 与 JSON 对象。
Go简单Go 本机 - C56
存储与错误
定义 BookmarkStore 接口并用内存实现;Get 找不到时返回包装过的 ErrNotFound(支持 errors.Is 判断);HTTP 层把该错误映射为 404 并返回统一错误结构。
Go中等Go 本机 - C57
数据库约束与事务
实现带事务语义的内存书签存储:Begin 开启事务,事务内 Add 与 AddTag,Commit 时统一校验唯一约束(重复 URL 返回 ErrDuplicate),任一步失败 Rollback 后数据完全不变。
Go中等Go 本机 - C58
有限并发队列
实现有限工作队列:NewQueue(workers int) 启动固定数量 worker,Submit(task) 提交任务,Close() 等待全部完成并返回处理总数。要求 channel 关闭责任清晰、不泄漏 goroutine、并发计数正确。
Go较难Go 本机 - C59
请求取消
实现一个 HTTP 处理器 /slow:等待 ctx.Done() 或 100ms 后返回。客户端带 20ms 超时的 context 请求时必须及时放弃且服务端能观察到取消(记录到 channel)。
Go中等Go 本机 - C60
服务综合题
实现书签服务核心:GET /health 返回 {status:ok};GET /bookmarks?page=1&size=2 分页返回 {items,total,page,size};请求日志中间件记录方法/路径/状态码(可被测试捕获)。非法分页参数返回 400。
Go较难Go 本机