大家好,我是宇哥,专注AI编程、智能体,解决小白AI编程问题。
前面第 6 篇我们做了采集器,第 7 篇做了审核后台。
现在手里有两份真实文件:
data/collected-tools-review.jsondata/review-decisions.json这一步很关键:不要把所有采集到的工具都丢到首页推荐位。
因为有些工具还在待复查,有些摘要需要人工改写,有些价格和开源边界还没确认。第 8 篇我们只做一件事:把审核通过的工具,变成第一版可解释的榜单和推荐页面。

这篇你能做出什么
跟着做完,你会得到这个目录:
tutorials/ai-tool-directory/demo/lesson-08/├── data/│ ├── collected-tools-review.json│ ├── review-decisions.json│ ├── approved-tools.json│ ├── ranking-rules.json│ └── tool-rankings.json├── prompts/│ └── workbuddy-ranking-prompt.md├── scripts/│ ├── generate-rankings.py│ ├── check-rankings.py│ └── generate_lesson08_images.py└── site/ ├── rankings.html ├── styles.css └── app.js最后你能运行:
python3 scripts/generate-rankings.py && python3 scripts/check-rankings.py我这次真实跑出来的结果是:
✅ 榜单和推荐页面生成完成输入审核决策:5 条本期入榜:3 条暂不入榜:2 条生成文件:data/approved-tools.json, data/ranking-rules.json, data/tool-rankings.json页面文件:site/rankings.html, site/styles.css, site/app.js排序闸门:只收录 approve / approve_with_edits,review_later 不入榜✅ 榜单和推荐检查通过审核决策:5 条本期入榜:3 条暂不入榜:2 条入榜工具:Playwright、Dify、n8n分数:Playwright=98、Dify=83、n8n=82排序规则:按 score 降序,且每条都有 score_breakdown看到这组输出,就说明本篇成功:榜单生成了,待复查工具没有混进去,每个分数也能解释。
适合谁,不适合谁
适合你,如果你现在想要的是:
让工具站首页有“推荐”和“榜单”的样子; 不想做黑盒排名,希望每个排序理由都能说清楚; 先用本地 JSON 跑通规则,不急着上数据库; 让 WorkBuddy 帮你写脚本,但你自己决定入榜边界。
不适合你,如果你想一步到位做:
真实用户投票榜; 带浏览量、点击量、转化率的实时榜单; 复杂协同过滤推荐系统; 收费推广位和广告投放系统。
本篇只是 MVP:审核结果 → 透明打分 → 第一版榜单页面。
准备环境
你需要准备:
WorkBuddy:用来让 AI Agent 按提示词生成脚本和页面。 Python 3:本篇只用标准库,不需要安装依赖。 第 7 篇产物: data/review-decisions.json和data/collected-tools-review.json。一个本地项目目录。
本篇真实 demo 路径是:
/root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08/你自己的电脑可以用类似路径:
ai-tool-directory/demo/lesson-08/先看最终效果
本篇的处理链路长这样:

输入是第 7 篇导出的审核决策:
[{"slug":"playwright","decision":"approve"},{"slug":"dify","decision":"approve_with_edits"},{"slug":"n8n","decision":"approve_with_edits"},{"slug":"cursor","decision":"review_later"},{"slug":"vercel","decision":"review_later"}]本篇只让这两类进入榜单:
approveapprove_with_editsreview_later 不入榜。原因很简单:待复查就是待复查,不要为了页面好看提前推荐。
第一步|新建 lesson-08 目录
打开项目目录,新建本篇目录:
mkdir -p demo/lesson-08/data demo/lesson-08/scripts demo/lesson-08/prompts demo/lesson-08/sitecd demo/lesson-08如果你跟着我的路径做,就是:
mkdir -p /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08/data \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08/scripts \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08/prompts \ /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08/sitecd /root/workspace/wechat-articles/tutorials/ai-tool-directory/demo/lesson-08验收点:看到这 4 个目录就算成功。
data/scripts/prompts/site/第二步|复制第 7 篇审核结果
把上一章的两个文件复制过来:
cp ../lesson-07/data/review-decisions.json data/review-decisions.jsoncp ../lesson-07/data/collected-tools-review.json data/collected-tools-review.json复制后先检查数量:
python3 - <<'PY'import jsonfrom pathlib import Pathdecisions = json.loads(Path('data/review-decisions.json').read_text(encoding='utf-8'))collected = json.loads(Path('data/collected-tools-review.json').read_text(encoding='utf-8'))print('审核决策:', len(decisions))print('采集记录:', len(collected))print('决策类型:', sorted({item['decision'] for item in decisions}))PY我这里的输入是 5 条审核决策、5 条采集记录。决策类型包含:
approveapprove_with_editsreview_later如果你看到的工具数量不同,也没关系;只要两个文件里的 slug 能对上,就可以继续。
第三步|把提示词复制到 WorkBuddy
新建文件:
prompts/workbuddy-ranking-prompt.md复制下面这段提示词:
你是我的 AI 工具目录站开发助手。请只在当前 lesson-08 目录里工作,目标是把第 7 篇人工审核后的结果做成第一版“榜单和推荐”页面。输入文件:- data/review-decisions.json:人工审核决策,decision 可能是 approve / approve_with_edits / reject / review_later。- data/collected-tools-review.json:采集证据,包含 source_type、http_status、evidence.risk_level、suggested_update 等字段。请生成:1. scripts/generate-rankings.py - 使用 Python 标准库,不引入第三方依赖。 - 只读取 decision 为 approve / approve_with_edits 的工具。 - 生成 data/approved-tools.json、data/ranking-rules.json、data/tool-rankings.json。 - 排名规则必须透明,至少包含:审核决策、来源质量、目录站适配度、可访问性。 - 每个工具都要输出 score_breakdown,不能只给一个黑盒总分。 - 生成 site/rankings.html、site/styles.css、site/app.js。 - 页面必须显示:本期入榜数量、未入榜数量、排名卡片、分数拆解、推荐场景。2. scripts/check-rankings.py - 检查输入文件存在。 - 检查只把 approve / approve_with_edits 的工具放入榜单。 - 检查 review_later / reject 没有进入榜单。 - 检查每条榜单都有 score_breakdown。 - 检查排名按 score 从高到低排序。 - 检查页面文件存在。请写清楚验证命令:python3 scripts/generate-rankings.pypython3 scripts/check-rankings.py这段提示词最重要的不是“页面要漂亮”,而是 3 个边界:
只收录审核通过或修改后通过; 每个分数必须能拆开看; 排名只能叫站内推荐起步规则,不能写成权威评测。
第四步|设计一个能解释的评分规则
第一版不要做复杂算法,先做一个小白能看懂、也方便你以后调整的规则。

本篇规则是 4 个维度:
注意,这不是工具真实能力排名,也不是市场份额排名。它只是你的目录站第一版排序:透明、保守、可修改。
第五步|写生成脚本
新建文件:
scripts/generate-rankings.py核心逻辑先从读取两个输入文件开始:
from pathlib import Pathimport jsonROOT = Path(__file__).resolve().parents[1]DATA = ROOT / 'data'DECISIONS = DATA / 'review-decisions.json'COLLECTED = DATA / 'collected-tools-review.json'APPROVED_DECISIONS = {'approve', 'approve_with_edits'}defread_json(path):return json.loads(path.read_text(encoding='utf-8'))decisions = read_json(DECISIONS)collected = {item.get('slug'): item for item in read_json(COLLECTED)}这几行做了两件事:
读取人工审核决策; 把采集证据按 slug建索引,方便后面合并。
然后只保留入榜工具:
approved = []excluded = []for decision in decisions: action = decision.get('decision', 'review_later')if action notin APPROVED_DECISIONS: excluded.append(decision)continue approved.append(decision)验收点:Cursor 和 Vercel 在我的样例里是 review_later,所以这一步不能进入 approved。
第六步|给每个工具生成 score_breakdown
排名不要只输出一个总分。我们要输出这种结构:
{"name":"Playwright","score":98,"score_breakdown":{"review_decision":40,"source_quality":25,"directory_fit":18,"accessibility":15}}这样做的好处是,下一次你觉得“目录适配”太主观,就可以只改这一项,不用推翻整个页面。
本篇真实生成的前三名是:
这里再次提醒:这只是本地项目的第一版推荐规则,不要在页面里写成绝对排名。
第七步|生成榜单页面
脚本会生成:
site/rankings.htmlsite/styles.csssite/app.js页面至少要展示:
本期入榜数量; 暂不入榜数量; 每个工具的排名、分类、摘要; 推荐场景; 审核备注; 分数拆解。
本篇文件结构长这样:

你可以直接在浏览器打开:
site/rankings.html如果页面能看到 3 张排名卡片,并且每张卡片下面都有“审核 / 来源 / 适配 / 可访问”这几个分数,就说明页面生成成功。
第八步|写验证脚本
新建文件:
scripts/check-rankings.py验证脚本至少检查 6 件事:
1. review-decisions.json 存在2. tool-rankings.json 存在3. 只有 approve / approve_with_edits 进入榜单4. review_later / reject 没有进入榜单5. 每条榜单都有 score_breakdown6. rankings.html / styles.css / app.js 都存在检查排序时可以这样写:
scores = [item.get('score', 0) for item in rankings]if scores != sorted(scores, reverse=True):raise SystemExit(f'榜单没有按分数降序排列:{scores}')这行的意思是:页面展示顺序必须和分数顺序一致。否则读者看到的榜单就会乱。
第九步|运行验证命令
在 lesson-08 目录下运行:
python3 scripts/generate-rankings.py && python3 scripts/check-rankings.py我的真实输出是:
✅ 榜单和推荐页面生成完成输入审核决策:5 条本期入榜:3 条暂不入榜:2 条生成文件:data/approved-tools.json, data/ranking-rules.json, data/tool-rankings.json页面文件:site/rankings.html, site/styles.css, site/app.js排序闸门:只收录 approve / approve_with_edits,review_later 不入榜✅ 榜单和推荐检查通过审核决策:5 条本期入榜:3 条暂不入榜:2 条入榜工具:Playwright、Dify、n8n分数:Playwright=98、Dify=83、n8n=82排序规则:按 score 降序,且每条都有 score_breakdown
看到这几个点,就算通过:
入榜是 3 条; 暂不入榜是 2 条; Cursor、Vercel 没有进入榜单; 分数按 98、83、82 降序排列; 每条都有 score_breakdown。
常见报错和排查
1. 缺少 review-decisions.json
如果看到:
缺少输入文件:data/review-decisions.json先检查你有没有从第 7 篇复制文件:
ls data/review-decisions.json没有的话,执行:
cp ../lesson-07/data/review-decisions.json data/review-decisions.json2. 入榜工具数量不对
如果检查脚本提示“入榜工具不匹配”,通常是你的过滤条件写错了。
检查这行是不是只包含两个状态:
APPROVED_DECISIONS = {'approve', 'approve_with_edits'}不要把 review_later 加进去。
3. 分数顺序不对
如果输出类似“榜单没有按分数降序排列”,检查排序代码:
approved.sort(key=lambda item: (-item['score'], item['name'].lower()))前面的负号表示按分数从高到低排。
4. 页面打开是空白
先看文件是否生成:
ls site/rankings.html site/styles.css site/app.js再检查浏览器控制台。如果 app.js 报 JSON 错误,通常是你手动拼字符串时少了引号或逗号。最稳的方式是用 Python 的 json.dumps(..., ensure_ascii=False) 写入页面数据。
完整代码 / 配置汇总
本篇最重要的 4 个输出文件是:
data/approved-tools.jsondata/ranking-rules.jsondata/tool-rankings.jsonsite/rankings.html其中 ranking-rules.json 是后面最值得保留的文件。它记录了你为什么这么排,而不是只留下一个看不懂的页面。
本篇真实 demo 已保存到:
tutorials/ai-tool-directory/demo/lesson-08/这一篇你学会了什么
这一篇我们没有做复杂推荐算法,而是先做了一个适合小白项目的稳定闭环:
从审核决策里过滤入榜工具; 把待复查工具挡在榜单外; 用 4 个维度生成透明分数; 输出 JSON,方便后续页面、SEO 和运营继续复用; 生成一个本地可打开的第一版榜单页面。
这就是做目录站时很重要的一步:推荐位不是随便摆,最好从第一天就有规则。
下一篇预告
下一篇我们做第 9 篇:
用WorkBuddy做AI工具站09:做SEO页面和站点地图会继续使用本篇的:
data/tool-rankings.jsonsite/rankings.html目标是把榜单、分类、工具详情变成更适合搜索引擎理解的页面结构,并生成第一版站点地图。
资料来源
本系列第 7 篇 demo 输出: review-decisions.json、collected-tools-review.json本篇真实验证命令: python3 scripts/generate-rankings.py && python3 scripts/check-rankings.py
夜雨聆风