ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Vibe Coding实战:用AI自然语言构建掌机数据库检索工具

Vibe Coding实战:用AI自然语言构建掌机数据库检索工具 我整理了 624 台掌机的硬件参数、发布年份、品牌等数据决定用 Vibe Coding 的方式把这些零散数据变成一个可检索、可筛选的掌机数据库工具。整个过程没有从零手写一整套前端框架而是通过自然语言描述需求让 AI 生成代码再在验证和调试中逐步完善。这篇文章完整记录这个项目的技术路径数据如何设计、提示词如何写、代码如何生成和修整以及遇到问题时应该从哪些环节排查。如果你也想把手里的数据集变成一个小工具并且想尝试用 AI 辅助编程提速这篇内容可以作为一份可直接参考的工程笔记。Vibe Coding 并不是一个黑箱魔法它只是把“写代码”这件事的重心向前移你需要准确描述目标、给出可验证的行为、并在 AI 生成的代码上做迭代审查。掌机数据库这个项目非常典型因为它不涉及复杂业务本质上是“一个数据文件 筛选渲染页面”。正因如此它是练习 Vibe Coding 的好场景能让你清楚看到哪些环节需要人判断哪些环节可以交给 AI 快速生成。1. 为什么选择 Vibe Coding 来构建这个工具1.1 Vibe Coding 的核心工作方式Vibe Coding 是指程序员通过自然语言向 AI 编程工具描述需求由 AI 生成代码并在人机交互中不断修正的一种协作编程方式。这里的“Vibe”强调的是意图流动你用一句话描述“我想做一个掌机图鉴页面”AI 会补全出 HTML、CSS、JavaScript甚至后端接口。这里的重点不是“让 AI 替代程序员”而是把编码变成“需求表达 - 生成代码 - 运行验证 - 反馈修正”的循环。一个典型的 Vibe Coding 回合包括四个动作用户用自然语言描述功能或问题。AI 工具根据上下文生成代码或修改建议。用户运行代码观察页面表现或程序输出。用户把错误信息或不符合预期的现象再次发给 AI要求修改。这个循环里的关键变量是“上下文”。AI 并不知道你整理的数据长什么样所以第一步必须把数据结构、示例数据、期望交互方式都喂给它否则生成出来的代码很可能无法和现有数据对接。1.2 从数据到工具的转化路径掌机数据库项目完全符合“数据 - 结构化 - 展示工具”的常见路径。整个转化流程可以拆成四层原始数据层从公开资料、百科、评测文章中整理出来的 624 条掌机记录包含品牌、型号、年份、硬件参数等。数据文件层经过清洗后的 JSON作为前端数据源。逻辑层搜索、筛选、排序、分页等交互逻辑。展示层页面布局、卡片渲染、详情弹窗等。Vibe Coding 在这四层都能介入。比如可以用 AI 生成一个清洗脚本从 Excel 里读取数据并输出 JSON也可以用 AI 生成前端筛选逻辑。但数据字段怎么设计、哪些数据值得保留、边界条件是什么这些还是要靠人来判断。AI 更适合处理“已经清楚要做什么”的任务而不是帮助你判断产品规则。1.3 适合使用 Vibe Coding 的场景掌机数据库这类“数据展示型工具”是 Vibe Coding 的高适配场景因为它目标明确、依赖少、逻辑简单。除此之外数据转换脚本、内部管理后台原型、接口 Mock、报表页面、简单的自然语言处理演示都能用 Vibe Coding 快速起步。不适合的场景也很明显涉及高频交易、复杂权限、强一致性的系统不能直接把 AI 生成代码当生产核心。AI 可能忽略边界条件、安全问题、并发控制这些仍然需要资深开发者审查。另外一个常见误区是认为 Vibe Coding 不需要懂代码。实际操作中你不能简单地“复制粘贴”至少得能看懂代码结构知道怎么启动项目、读错误日志、定位哪一段逻辑没有生效。2. 先把 624 台掌机的数据整理成结构化数据集2.1 数据字段设计要记录哪些关键信息在动手让 AI 生成页面之前我先确定每台掌机需要保留哪些字段。字段设计直接决定工具的搜索和筛选维度。掌机数据不是越多越好而是要和“用户想查什么”匹配。我只选择了 12 个字段涵盖品牌、硬件、发售信息去掉描述型长文本避免前端渲染负担过大。字段表如下字段名类型说明示例idstring唯一标识gb-1989-originalbrandstring品牌Nintendomodelstring型号Game Boyrelease_yearnumber发布年份1989cpustring处理器信息Sharp LR35902memorystring内存信息8KB RAMstoragestring存储介质Game Pak cartridgescreenstring屏幕参数2.6 inch STN LCDresolutionstring分辨率160x144weight_gramsnumber重量克数220batterystring电池续航4 x AA batteries, ~15hplayersnumber最大玩家数1设计字段时要注意三个原则第一筛选字段尽量用规范值例如品牌用英文或统一中文不要混用第二数值型字段要转成 number否则前端排序和范围筛选举步维艰第三不要提前加入太多派生字段例如“阵营”“是否掌机”这类这些可以后续通过代码计算而不是在数据里手工维护。2.2 数据清洗与格式转换从 Excel 到 JSON最初的数据存在 Excel 里格式并不规整。有的单元格是“1989年”有的是“Oct 1989”还有空值。用 Vibe Coding 写一个转换脚本很合适把“原始表结构”和“目标 JSON 结构”描述清楚让 AI 生成 Python 脚本再手动审查关键转换逻辑。下面是实际用到的清洗脚本框架它读取一个 CSV 文件处理年份和重量字段最后输出 JSON。import csv import json def clean_year(raw): if not raw: return None # 提取四位数字年份 import re m re.search(r(19|20)\d{2}, str(raw)) return int(m.group()) if m else None def clean_weight(raw): if not raw: return None s str(raw).replace(g, ).strip() try: return int(float(s)) except ValueError: return None rows [] with open(handhelds.csv, encodingutf-8) as f: reader csv.DictReader(f) for r in reader: rows.append({ id: f{r[model].strip().lower().replace( , -)}-{r[release_year]}, brand: r[brand].strip(), model: r[model].strip(), release_year: clean_year(r[release_year]), cpu: r[cpu].strip(), memory: r[memory].strip(), storage: r[storage].strip(), screen: r[screen].strip(), resolution: r[resolution].strip(), weight_grams: clean_weight(r[weight_grams]), battery: r[battery].strip(), players: int(r[players]) if r[players].strip().isdigit() else 1, }) with open(handhelds.json, w, encodingutf-8) as f: json.dump(rows, f, ensure_asciiFalse, indent2)这段代码的关键点在于 clean_year 和 clean_weight 两个处理函数。它们把不规整的文本转换成 number 类型。如果你把原始数据直接丢给 JSON前端排序时就会出现“2009”和“1995”正确比较而“1989年”和“Oct 1989”无法参与范围筛选的问题。清洗脚本做完后应当手动抽查几条记录确认年份、重量、玩家数都变成了数字而不是字符串。2.3 数据质量检查避免脏数据干扰后续开发数据文件生成后不能直接开始写页面先做一次质量检查。624 条数据虽然不多但人工逐条看会累而且容易漏。我用一个简短的 Python 脚本检查三类问题空值、重复值、数值字段异常。import json with open(handhelds.json, encodingutf-8) as f: data json.load(f) required_fields [id, brand, model, release_year] null_items [] dup_ids {} for item in data: for field in required_fields: if not item.get(field): null_items.append((item.get(id), item.get(model), field)) dup_ids[item[id]] dup_ids.get(item[id], 0) 1 print(空值问题:, len(null_items)) for n in null_items[:5]: print(n) print(重复id:, {k: v for k, v in dup_ids.items() if v 1})检查时重点关注release_year 是否为空。同一 model 是否出现多次可能需要合并成不同版本。brand 是否有同义异名例如“Nintendo”和“任天堂”混用。weight_grams 是否出现 0 或负数。这一步能在开发前发现大部分脏数据。如果跳过后续 AI 生成的筛选逻辑会因为这些异常出现“显示 0 克”“年份倒序错乱”等奇怪现象排查时反而更浪费时间。3. 用 Vibe Coding 搭建掌机数据库工具的完整流程3.1 从一个清晰的提示词开始数据准备好了下一步是让 AI 生成页面。第一次提示词很重要它决定了 AI 能否一次生成接近需求的代码。我的初始提示词是这样的我有一个 handhelds.json 文件里面是 624 台掌机的数据。 请帮我生成一个单页 HTML 文件要求 1. 使用原生 HTML/CSS/JavaScript不需要构建工具。 2. 在页面上展示所有掌机卡片每张卡片显示品牌、型号、发布年份、屏幕、重量。 3. 顶部有一个搜索框可以按型号或品牌模糊搜索。 4. 提供品牌筛选下拉框数据中出现的品牌自动生成选项。 5. 提供一个年份范围筛选最小年份和最大年份从数据中读取。 6. 搜索或筛选后卡片列表实时刷新。 7. 卡片点击后弹出详情展示所有字段信息。 请使用 fetch(handhelds.json) 加载数据。这里要把格式要求、功能列表、加载方式全部写清楚。AI 一旦猜错数据加载方式后面会浪费很多轮修改。提示词中最好给出示例 JSON 片段至少包含一条完整记录让 AI 知道字段名和类型。{ id: gb-1989-original, brand: Nintendo, model: Game Boy, release_year: 1989, cpu: Sharp LR35902, memory: 8KB RAM, storage: Game Pak cartridge, screen: 2.6 inch STN LCD, resolution: 160x144, weight_grams: 220, battery: 4 x AA batteries, ~15h, players: 1 }把示例 JSON 放在提示词里AI 就能正确写出 item.release_year、item.weight_grams 这样的字段访问而不是想当然地用 Python 或 SQL 语法。3.2 生成前端页面与交互逻辑AI 第一轮生成的页面往往可以运行但样式和交互细节还需要调整。下面是一个经过迭代后的核心结构它不是一次性生成的而是在几轮“运行 - 反馈 - 修改”之后才稳定下来。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title掌机数据库/title style/* 样式省略核心是卡片网格布局 *//style /head body header h1掌机数据库 span idcount/span/h1 input idsearch typetext placeholder搜索品牌或型号 select idbrandFilter/select input idyearMin typenumber placeholder最小年份 input idyearMax typenumber placeholder最大年份 /header main idcards/main div idmodal classmodal hidden/div script let allData []; async function loadData() { const res await fetch(handhelds.json); allData await res.json(); initFilters(); renderCards(); } function initFilters() { const brands [...new Set(allData.map(d d.brand))].sort(); const brandSelect document.getElementById(brandFilter); brandSelect.innerHTML option value全部品牌/option brands.map(b option value${b}${b}/option).join(); const years allData.map(d d.release_year).filter(Boolean); document.getElementById(yearMin).value Math.min(...years); document.getElementById(yearMax).value Math.max(...years); } function filteredData() { const query document.getElementById(search).value.trim().toLowerCase(); const brand document.getElementById(brandFilter).value; const minYear parseInt(document.getElementById(yearMin).value) || 0; const maxYear parseInt(document.getElementById(yearMax).value) || 9999; return allData.filter(item { const matchQuery item.model.toLowerCase().includes(query) || item.brand.toLowerCase().includes(query); const matchBrand !brand || item.brand brand; const matchYear item.release_year minYear item.release_year maxYear; return matchQuery matchBrand matchYear; }); } document.addEventListener(input, renderCards); document.addEventListener(change, renderCards); function renderCards() { const list filteredData(); document.getElementById(count).textContent list.length 台; document.getElementById(cards).innerHTML list.map(item article classcard onclickshowDetail(${item.id}) h2${item.brand} ${item.model}/h2 p${item.release_year || 未知} 年/p p${item.screen || 未收录}/p p${item.weight_grams || 未知} g/p /article ).join(); } function showDetail(id) { const item allData.find(d d.id id); if (!item) return; const modal document.getElementById(modal); modal.innerHTML div classmodal-content span classclose onclickhideModal()times;/span h2${item.brand} ${item.model}/h2 table trtd发布年份/tdtd${item.release_year}/td/tr trtdCPU/tdtd${item.cpu}/td/tr trtd内存/tdtd${item.memory}/td/tr trtd存储/tdtd${item.storage}/td/tr trtd屏幕/tdtd${item.screen}/td/tr trtd分辨率/tdtd${item.resolution}/td/tr trtd重量/tdtd${item.weight_grams ? item.weight_grams g : 未知}/td/tr trtd电池/tdtd${item.battery}/td/tr trtd玩家数/tdtd${item.players}/td/tr /table /div; modal.classList.remove(hidden); } function hideModal() { document.getElementById(modal).classList.add(hidden); } loadData(); /script /body /html这段代码的核心是把“数据加载”和“渲染”分离。loadData 负责读 JSON 并初始化筛选器filteredData 生成筛选结果renderCards 把结果绘制到页面。AI 生成的初版往往把所有逻辑揉在一起我用“输入事件 - 重新渲染”这个思路反复要求它重构最终得到更清晰的结构。3.3 后端或纯静态方案如何选择掌机数据库这个项目完全可以做成纯静态页面一个 HTML 文件加一个 JSON 文件不需要后端服务器。原因很简单数据一次性加载不需要鉴权不需要服务端逻辑也没有动态更新需求。纯静态方案部署成本低可以直接放到对象存储或静态托管平台上。什么时候才需要引入后端如果你的数据量非常大不能一次性加载或者需要用户登录、收藏、评论等交互或者要做实时更新那才需要后端服务。用 Vibe Coding 生成后端并不难但会牵涉到接口设计、数据库、部署等额外复杂度。对演示型和个人工具类项目先做纯静态版本跑通后再按需升级是更稳妥的路线。这里也附带一个选择依据表方案优势劣势适用场景纯静态 HTML JSON简单、部署快、无服务器成本不适合大量数据、无用户系统数据展示、工具、原型FastAPI / Flask 后端可动态筛选、鉴权、数据更新需要维护服务器和依赖需要登录、动态数据Node.js Express生态丰富团队熟悉 JS需要进程管理和部署环境已有 JS 技术栈时云函数 / Serverless按需付费免运维冷启动、排查日志不方便低频接口、自动化脚本3.4 迭代式调试把“编辑提示词”当成本身的一部分Vibe Coding 最需要练习的不是第一次提问而是遇到问题后的反馈方式。比如页面加载后筛选器下拉框没有出现品牌我首先检查浏览器控制台看到allData是空的说明 JSON 没加载成功。这时直接把错误信息和现象发给 AI控制台报错 Access to fetch at file:///.../handhelds.json from origin null has been blocked by CORS policy 页面显示数量为 0下拉框为空。 可能是什么原因如何修改AI 会回答 CORS 限制建议用本地 HTTP 服务器而不是直接双击 HTML。这就是一个典型迭代循环。把具体错误信息、操作步骤、期望结果全部写清楚AI 给出的修复方案才准确。不要只说“不工作”那样 AI 只能猜。4. 关键代码与数据结构详解4.1 数据文件的数据结构handhelds.json 的结构是所有前端逻辑的基础。它是一个包含 624 个对象的数组每个对象代表一台掌机。为了保证 JSON 文件体积可控我使用紧凑格式但保留可读字段名。[ { id: gb-1989-original, brand: Nintendo, model: Game Boy, release_year: 1989, cpu: Sharp LR35902, memory: 8KB RAM, storage: Game Pak cartridge, screen: 2.6 inch STN LCD, resolution: 160x144, weight_grams: 220, battery: 4 x AA batteries, ~15h, players: 1 } ]这个数据结构有两点需要注意。第一id 用于前端定位详情弹窗必须保证唯一。如果出现两个相同型号但不同年份的掌机id 也要不同。第二release_year 虽然示例里是数字但清洗后的 JSON 中可能出现 null前端渲染时要用||做兜底否则会显示 undefined。4.2 筛选与搜索逻辑筛选逻辑的核心是 filteredData 函数。它的输入是全局数据 allData 和当前页面控件状态输出是过滤后的数组。这里的实现用了三个条件拼接搜索框对 model 和 brand 做大小写不敏感的子串匹配。品牌下拉框使用全等匹配。年份范围使用 number 数组和输入框值直接比较。代码中的陷阱是年份输入框可能为空使用parseInt(...) || 0和|| 9999来兜底。如果不加兜底用户清空输入框时会出现 NaN 比较导致筛选结果全部消失。这个细节在初始提示词里没有是查看渲染结果后发现“清空年份就看不到数据”的问题后补上的。4.3 页面渲染与参数说明renderCards 函数负责把筛选结果变成 HTML。它的核心是list.map(...).join()把每个 item 映射成一段 HTML 字符串后拼接。这里有两个性能相关的参数值得关注参数默认行为影响innerHTML 赋值每次全量重绘列表数据量 624 时速度仍可接受但超过 2000 会有卡顿事件委托直接在 document 上监听 input/change避免为每个输入框单独绑定事件减少内存占用onclick 内联使用全局 showDetail 函数简单易读但不适合内容需要转义的场景如果你的数据量增长到上万条建议把 innerHTML 换成 DOM API 创建元素并加上分页或虚拟滚动。对 624 条掌机数据来说当前实现已经足够。真实项目里要注意使用 innerHTML 插入用户可控内容时是否有 XSS 风险。本例中 model、brand 等字段都来自自己的数据文件风险较低但如果你后续接入外部动态数据必须对 HTML 特殊字符进行转义。5. 运行验证与常见问题排查5.1 本地启动与验证步骤由于页面通过 fetch 加载 JSON不能直接双击 HTML 文件运行否则 CORS 会拦截请求。推荐用本地静态服务器启动。如果你安装了 Python 3可以在项目目录运行python3 -m http.server 8000然后打开http://localhost:8000。如果你使用 VS Code可以安装 Live Server 扩展它会更方便。验证时按以下顺序检查页面标题和数量显示打开后应看到“624 台”说明 JSON 加载成功。品牌筛选下拉框包含至少 8 个品牌。搜索框输入“Game Boy”列表应只显示匹配的掌机。年份范围调整为 2000 到 2010列表只显示该时段产品。点击任意卡片弹窗能展示完整字段。如果某一步失败按下面的排查表处理。5.2 数据加载失败、筛选不生效等问题的排查整理了一张常见问题表覆盖这个项目中最容易出错的地方问题现象常见原因检查方式解决方案页面数量为 0控制台报 CORS 错误使用了 file:// 协议打开查看 Network 面板用 http.server 或 Live Server 启动品牌下拉框没有选项数据未加载成功或 brand 字段名不一致打开控制台执行Object.keys(data[0])检查 JSON 字段名是否与代码一致年份筛选无效release_year 是字符串在控制台执行typeof data[0].release_year重新运行清洗脚本转成 number搜索无响应没有绑定 input 事件检查 listener 是否绑定在 document确保页面加载后添加事件监听弹窗关闭后再次打开报错onclick 引用了错误 id检查模板字符串中 id 是否带引号使用onclickshowDetail(${item.id})转义数字显示 NaN字段为空但代码直接参与算术检查数据样本用 5.3 常见坑汇总这里专门列出我在这个项目里踩过的三个 Vibe Coding 相关坑。第一提示词没有给出数据示例AI 生成了一段模拟数据的代码导致页面调试时真实数据永远无法加载。当时我让 AI 生成页面但没贴 JSON 示例AI 认为我需要它自己造数据。后来重新写提示词把一条真实数据贴进去并强调“不要修改 JSON 字段名”代码才正常。建议在 Vibe Coding 中所有涉及数据结构的提示词都附上最小示例。第二为了让页面丰富我要求 AI 加上“掌机销量排行”但数据中根本没有销量字段。AI 没有指出这个矛盾而是编了一个虚假的销量值。这提醒我们Vibe Coding 生成的内容可能存在幻觉当你要求一个数据中不存在的字段时AI 会猜测。正确的做法是先检查数据字段再添加功能而不是让 AI 自由发挥。第三初始页面把筛选逻辑和渲染逻辑放在一起导致每次输入搜索词时页面闪烁严重。原因是每次输入都会触发整个列表重绘。AI 生成的初版往往不会考虑性能细节需要你主动提出“把筛选函数抽离出来”“使用事件委托”。这说明 Vibe Coding 仍需要工程师具备基本的性能意识否则生成的代码能运行但体验较差。6. 从个人项目到可分享作品的优化建议6.1 性能优化大数据量下的渲染策略624 条数据在浏览器里没有任何压力但如果你后续把数据库扩展到几千甚至几万条就要考虑以下几点使用DocumentFragment或一次性的innerHTML拼接避免多次 DOM 操作。对搜索输入做 debounce防止每次按键都执行完整 filter。对年份范围、品牌筛选这些高频选择可以考虑预生成索引不过数据量不大时收益有限。如果确实需要虚拟滚动可以引入较小的第三方库但会给纯静态页面增加依赖需要权衡。对于掌机数据库这种工具还有一个更实际的优化方向按需加载图片。如果每个掌机都要展示图片624 张图全量加载会非常慢。建议用懒加载或者先用无图片的纯参数模式后续再补充图片 CDN。6.2 部署与分享静态托管或服务器部署掌机数据库是纯静态页面部署方式非常灵活。最省事的方式是放到 GitHub Pages、Netlify、Vercel 等静态托管平台上。部署时只需把 HTML 和 JSON 上传上去平台会自动分配一个网址。如果涉及到自定义域名需要额外配置 DNS但这一步不是必须的。如果要部署到自己的服务器推荐用 Nginx 托管静态文件。下面是一个最小 Nginx 配置片段server { listen 80; server_name example.com; root /var/www/handheld-db; index index.html; location / { try_files $uri $uri/ /index.html; } }production 环境和学习环境的主要差异不只是“能访问”还包括数据文件是否需要启用 Gzip 压缩。是否配置 HTTPS。是否设置缓存头让浏览器复用 JSON。是否有访问日志和简单的监控。对一个参赛作品来说GitHub Pages 已经足够。6.3 使用 Vibe Coding 的工程实践清单从这次项目中我提炼出一份可复用的 Vibe Coding 实践清单适合做类似数据小工具时参考阶段实践项目开始前把数据集整理成稳定、干净的 JSON 或 CSV开始前写下至少 5 个用户会用到的筛选或搜索场景提示词附上最小数据示例明确字段名和类型提示词指出“不要修改数据文件结构”生成代码后先在本地启动用真实数据验证而不是只看语法遇到 bug把错误日志、操作步骤、期望结果一起发给 AI功能增强新功能涉及的字段检查是否存在于数据中审查重点检查空值兜底、XSS 转义、事件绑定、性能瓶颈部署前确认 JSON 路径、缓存策略、移动端样式这份清单的核心是AI 负责把想法快速变成代码而你必须负责验证“数据在真实环境下是否完整跑通”。如果没有这一步Vibe Coding 很容易变成“看起来能运行换一台机器就崩溃”。从这次掌机数据库项目可以得出的一个判断是Vibe Coding 真正的价值不在于把所有代码交给 AI而在于缩短“想法 - 可点击原型 - 可分享作品”的周期。你仍然需要理解数据、理解用户场景、理解基本的浏览器环境和部署方式。这些能力决定了你能否把 AI 生成的内容落到工程可用的状态。下一步可以在这个工具上继续扩展的方向包括给每个掌机增加评测摘要加入玩家评分做年代分布图、品牌占比图把数据导入到一个支持中文模糊搜索的搜索引擎实现更强大的查询。对刚接触 Vibe Coding 的开发者来说找一个自己感兴趣的数据集按这篇文章的思路做一个图鉴工具是熟悉这套工作方式最有效的练习。
返回列表