大家好,我是宇哥,专注AI编程、智能体,解决小白AI编程问题。
前一篇我们写了第一个采集器,已经能把 5 个工具的公开页面信息采集到:
data/collected-tools-review.json但这里千万不要急着把它们写进正式工具库。
因为采集结果里可能有这些问题:
摘要太像官网原文,需要改成自己的话; 价格标签不一定准确,需要人工确认; 开源、免费、试用这些标签容易过期; 有些工具适不适合收录,还得看你的站点定位。
所以第 7 篇我们做一个很小、但非常关键的东西:审核后台。

这篇你能做出什么
跟着做完,你会得到这个目录:
tutorials/ai-tool-directory/demo/lesson-07/├── data/│ └── collected-tools-review.json├── scripts/│ ├── generate-review-admin.py│ ├── check-review-admin.py│ └── generate_lesson07_images.py├── site/│ ├── index.html│ ├── styles.css│ └── app.js└── prompts/ └── workbuddy-review-admin-prompt.md最后你能运行:
python3 scripts/generate-review-admin.py && python3 scripts/check-review-admin.py我这次真实跑出来的结果是:
✅ 审核后台生成完成输入记录:5 条生成文件:site/index.html, site/styles.css, site/app.js审核动作:通过 / 修改后通过 / 拒绝 / 稍后复查发布闸门:未创建或覆盖 data/tools.json✅ 审核后台检查通过待审核记录:5 条页面文件:index.html / styles.css / app.js 均存在审核动作:通过、修改后通过、拒绝、稍后复查正式数据保护:未创建/覆盖 data/tools.json看到这组输出,就说明本篇成功:审核后台已生成,而且没有把采集数据直接写进正式库。
适合谁,不适合谁
适合你,如果你现在想要的是:
让 AI 工具站的数据增长变得可控; 先用本地页面审核采集结果; 让 WorkBuddy 帮你写后台雏形,但自己保留最后判断; 暂时不想上数据库、登录系统、权限系统。
不适合你,如果你想一步到位做:
多人协作审核; 带账号登录的正式管理后台; 数据库写入、权限控制和操作日志; 自动把抓取结果发布到线上页面。
这一篇只做最小闭环:读采集结果 → 人工标记 → 导出决策 JSON。
准备环境
你需要准备:
WorkBuddy:用来让 AI Agent 帮你生成脚本和页面。 Python 3:本篇只用标准库,不需要安装依赖。 第 6 篇产物: data/collected-tools-review.json。一个本地项目目录。
本篇真实 demo 路径是:
/root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07/你自己的电脑可以用类似路径:
ai-tool-directory/demo/lesson-07/先看最终效果
本篇页面不是复杂后台,而是一个本地可打开的审核页。
它的安全链路是这样:

输入是上一篇的:
data/collected-tools-review.json页面里每条记录显示:
工具名称; 来源地址; HTTP 状态; 风险等级; 候选标题; 候选摘要; 价格标签; 审核备注。
你可以给每条记录选 4 个动作:

最终导出一份:
data/review-decisions.json注意,本篇还是不改正式数据:
data/tools.json正式合并放到下一篇做。
第一步|新建 lesson-07 目录
打开你的项目目录,新建本篇目录:
mkdir -p demo/lesson-07/data demo/lesson-07/scripts demo/lesson-07/prompts demo/lesson-07/sitecd demo/lesson-07如果你跟着我的路径做,就是:
mkdir -p /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07/data \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07/scripts \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07/prompts \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07/sitecd /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-07验收点:看到这 4 个目录就算成功。
data/scripts/prompts/site/本篇完整文件结构长这样:

第二步|复制上一篇采集结果
把第 6 篇生成的审核队列复制过来:
cp ../lesson-06/data/collected-tools-review.json data/collected-tools-review.json复制后检查一下:
python3 - <<'PY'import jsonfrom pathlib import Pathpath = Path('data/collected-tools-review.json')records = json.loads(path.read_text(encoding='utf-8'))print('文件存在:', path.exists())print('待审核记录:', len(records))print('第一条工具:', records[0]['name'])print('第一条状态:', records[0]['review_status'])PY我这里检查到的是 5 条记录,第一条还是待人工复核状态。
如果你看到的数量不是 5,也没关系,说明你前一篇采集到的数据不同;只要它是一个非空数组,并且每条都有 review_status,就可以继续。
第三步|把这段提示词复制到 WorkBuddy
新建文件:
prompts/workbuddy-review-admin-prompt.md复制下面这段提示词:
你是我的 AI 工具目录站开发助手。请只在当前 lesson-07 目录里工作,目标是把上一篇采集器产出的 data/collected-tools-review.json 做成一个本地可打开的最小审核后台。输入文件:- data/collected-tools-review.json:每条记录都有 slug/name/source_url/review_status/suggested_update/evidence。请生成:1. scripts/generate-review-admin.py - 使用 Python 标准库即可,不引入第三方依赖。 - 读取 data/collected-tools-review.json。 - 生成 site/index.html、site/styles.css、site/app.js。 - 在 app.js 里嵌入审核队列 JSON,方便本地直接打开页面。 - 页面里每条工具记录要显示:名称、来源、风险、候选摘要、价格候选、审核备注。 - 每条记录要支持 4 个动作:通过、修改后通过、拒绝、稍后复查。 - 页面要提供“导出审核结果 JSON”的文本框,方便复制保存。 - 不要自动覆盖正式 tools.json。2. scripts/check-review-admin.py - 检查输入 JSON 存在且有记录。 - 检查 site/index.html、site/styles.css、site/app.js 存在。 - 检查页面包含 4 个审核动作。 - 检查 app.js 里没有把记录默认标记为 published。 - 检查没有创建或覆盖 data/tools.json。请写清楚验证命令:python3 scripts/generate-review-admin.pypython3 scripts/check-review-admin.py这段提示词的重点不是“让 AI 写一个很炫的后台”,而是把边界说清楚:
审核后台可以生成,正式工具库不能动。
第四步|生成审核后台脚本
WorkBuddy 生成后,你应该得到:
scripts/generate-review-admin.py如果你想直接跟做,可以按下面这个骨架创建文件。
先看核心逻辑:
from pathlib import Pathimport jsonROOT = Path(__file__).resolve().parents[1]DATA = ROOT / 'data'SITE = ROOT / 'site'INPUT = DATA / 'collected-tools-review.json'records = json.loads(INPUT.read_text(encoding='utf-8'))SITE.mkdir(parents=True, exist_ok=True)这几行做了三件事:
找到当前 lesson-07 根目录; 读取上一篇采集结果; 准备生成页面目录。
然后把采集结果整理成页面需要的字段:
defnormalized_record(record): suggested = record.get('suggested_update') or {} evidence = record.get('evidence') or {}return {'slug': record.get('slug', ''),'name': record.get('name', ''),'source_url': record.get('source_url', ''),'source_type': record.get('source_type', ''),'http_status': record.get('http_status'),'review_status': record.get('review_status', 'needs_manual_review'),'risk_level': evidence.get('risk_level', 'unknown'),'title_candidate': suggested.get('title_candidate', ''),'summary_candidate': suggested.get('summary_candidate', ''),'pricing_candidate': suggested.get('pricing_candidate', ''),'tags_candidate': suggested.get('tags_candidate', []),'review_notes': evidence.get('review_notes', ''),'decision': 'review_later','editor_note': '', }这里故意把默认决策设成:
review_later而不是:
published这是为了防止“采集到就发布”的危险默认值。
第五步|生成 HTML / CSS / JS
脚本要生成 3 个页面文件:
site/index.htmlsite/styles.csssite/app.js其中 index.html 负责页面结构,styles.css 负责样式,app.js 负责审核交互和导出。
app.js 里最关键的是这 4 个动作:
const actions = ["approve", "approve_with_edits", "reject", "review_later"];const actionLabels = {approve: "通过",approve_with_edits: "修改后通过",reject: "拒绝",review_later: "稍后复查",};这 4 个动作对应的实际含义是:
页面导出时,不直接写文件,而是把 JSON 放进文本框:
functionrefreshExport() {const output = reviewQueue.map((item) => ({slug: item.slug,name: item.name,source_url: item.source_url,decision: item.decision,editor_note: item.editor_note,suggested_update: {title: item.title_candidate,summary: item.summary_candidate,pricing: item.pricing_candidate,tags: item.tags_candidate, }, })); exportBox.value = JSON.stringify(output, null, 2);}为什么不让页面自动写入本地文件?
因为普通浏览器页面直接写本地文件会涉及权限和安全限制。小白阶段先用最稳的方式:复制文本框内容,手动保存成 JSON 文件。
第六步|写验证脚本
新建文件:
scripts/check-review-admin.py检查脚本至少要做 5 件事:
1. data/collected-tools-review.json 存在,并且是非空数组2. site/index.html 存在3. site/styles.css 存在4. site/app.js 存在5. app.js 包含 4 个审核动作,而且没有默认 published核心检查可以这样写:
from pathlib import Pathimport jsonimport reROOT = Path(__file__).resolve().parents[1]DATA = ROOT / 'data'SITE = ROOT / 'site'INPUT = DATA / 'collected-tools-review.json'REQUIRED_ACTIONS = ['approve', 'approve_with_edits', 'reject', 'review_later']records = json.loads(INPUT.read_text(encoding='utf-8'))app = (SITE / 'app.js').read_text(encoding='utf-8')for action in REQUIRED_ACTIONS:assert action in app, f'缺少审核动作:{action}'assertnot re.search(r'decision"\s*:\s*"published"|review_status"\s*:\s*"published"', app)assertnot (DATA / 'tools.json').exists()print('✅ 审核后台检查通过')这段检查的重点是最后两行:
不能默认 published不能创建 data/tools.json只要这两条守住,采集数据就不会绕过人工审核。
第七步|运行验证命令
在 lesson-07 目录运行:
python3 scripts/generate-review-admin.py && python3 scripts/check-review-admin.py我这次真实输出是:

文字版如下:
✅ 审核后台生成完成输入记录:5 条生成文件:site/index.html, site/styles.css, site/app.js审核动作:通过 / 修改后通过 / 拒绝 / 稍后复查发布闸门:未创建或覆盖 data/tools.json✅ 审核后台检查通过待审核记录:5 条页面文件:index.html / styles.css / app.js 均存在审核动作:通过、修改后通过、拒绝、稍后复查正式数据保护:未创建/覆盖 data/tools.json如果你看到这些输出,本篇 demo 就跑通了。
然后打开:
site/index.html你会看到一个本地审核页。你可以给每条工具选择“通过 / 修改后通过 / 拒绝 / 稍后复查”,再点击刷新导出结果。
第八步|保存审核结果
页面底部有一个“导出审核结果 JSON”的文本框。
你复制里面的内容,新建文件:
data/review-decisions.json然后保存进去。
这一份文件大概长这样:
[{"slug":"cursor","name":"Cursor","source_url":"https://cursor.com","decision":"review_later","editor_note":"摘要需要改成自己的话,价格信息下一步再确认","suggested_update":{"title":"Cursor: AI coding agent","summary":"Built to make you extraordinarily productive, Cursor is the best AI coding agent.","pricing":"paid","tags":["website","pricing","summary","tags"]}}]注意:上面只是说明结构。你自己的导出文件,要以页面文本框里的内容为准。
常见报错和排查
1. 找不到 collected-tools-review.json
如果运行时报:
缺少 data/collected-tools-review.json先检查你有没有从第 6 篇复制文件:
ls data应该能看到:
collected-tools-review.json如果没有,就回到第二步重新复制。
2. 页面打开后没有数据
先重新生成页面:
python3 scripts/generate-review-admin.py再检查 site/app.js 里面是否已经嵌入数据:
python3 - <<'PY'from pathlib import Pathtext = Path('site/app.js').read_text(encoding='utf-8')print('source_url 出现次数:', text.count('source_url'))PY如果出现次数大于 0,说明数据已经进了页面文件。
3. 检查脚本提示创建了 data/tools.json
本篇不应该创建:
data/tools.json如果你看到这个文件,先不要继续。删除它,再检查 WorkBuddy 生成的脚本有没有写入正式工具库的逻辑。
rm data/tools.jsonpython3 scripts/check-review-admin.py等检查通过后再继续。
4. 页面能看,但导出内容没变化
检查按钮是不是绑定了 refreshExport()。
在 site/app.js 里应该能看到:
exportBtn.addEventListener("click", refreshExport);如果没有,让 WorkBuddy 帮你补上这句,再重新打开页面。
完整代码 / 配置汇总
本篇完整 demo 已保存到:
tutorials/ai-tool-directory/demo/lesson-07/关键文件:
prompts/workbuddy-review-admin-prompt.mdscripts/generate-review-admin.pyscripts/check-review-admin.pysite/index.htmlsite/styles.csssite/app.jsdata/collected-tools-review.json验证命令:
cd tutorials/ai-tool-directory/demo/lesson-07python3 scripts/generate-review-admin.py && python3 scripts/check-review-admin.py成功标准:
✅ 审核后台检查通过正式数据保护:未创建/覆盖 data/tools.json这一篇你学会了什么
这一篇我们没有追求复杂后台,而是先把数据流里最危险的一步拦住:
采集结果不能直接进正式工具库,必须先经过审核队列。
你现在已经有了:
一个本地可打开的审核页面; 4 种清晰的人工决策; 一份可导出的审核结果 JSON; 一个防止误写正式数据的检查脚本。
这就让 AI 工具站从“能采集”往“能运营”迈了一步。
下一篇预告
下一篇是:
用WorkBuddy做AI工具站08:做榜单和推荐第 8 篇我们会继续使用本篇导出的审核决策,把通过或修改后通过的工具,做成一个简单榜单:例如“新鲜工具榜”“适合小白榜”“AI 编程工具榜”。
目标不是做复杂算法,而是先做一个透明、可解释、能被用户理解的推荐规则。
资料来源
本系列前文 demo: collected-tools-review.json、tool-source-map.json、source-policy.jsonPython 标准库文档: json、pathlib、html浏览器本地页面能力:HTML / CSS / JavaScript 基础交互
夜雨聆风