扫描器决策 — Tier 1 高保真 vs Tier 2 兜底
Next.js / FastAPI / 微信小程序 / 静态站 4 个栈走 Tier 1 高保真识别(95% 准确);其他栈走 Tier 2 兜底产最小可用描述符,保证永不返「不支持」。
Heroku buildpacks 试图识别一切栈,但凡识别不出就报「unsupported language」。这是个错的设计 — 因为用户的代码已经 commit 了,工具应该想办法跑起来,不是甩个错。
我们做扫描器时定了一个原则:**永远返回描述符**,即使是兜底版本。这迫使我们做 Tier 1 / Tier 2 两层架构。
Tier 1 — 高保真栈识别
4 个栈做了专门的描述符产出器:Next.js / FastAPI / 微信小程序 / 静态站。准确率 ~95%(基于内部回归集 1000+ 项目)。
怎么识别 Next.js
- package.json 有 next 依赖 → 强信号
- 存在 next.config.js / next.config.ts → 确认
- app/ 或 pages/ 目录 + 内含 route.tsx/jsx → 路由模式
- 标准产物:runtime=node + start=next start + build=next build
扫描器只产「我们确定」的字段,不确定的留 gap(如 health_path、required_env)交给 AI 引导填。
Tier 2 — 通用兜底
其余栈(node / python / go / java / php / ruby / other 任意一个)走兜底产出器。识别 runtime 大类(看 package.json / requirements.txt / go.mod / 等),猜 start 命令,留所有具体字段为 gap。准确率 ~70%,但保证产物。
# Tier 2 兜底输出示例(用户没用 Tier 1 栈)
schema_version: '1.0'
runtime: python # 看到 requirements.txt → python
runtime_version: '3.x' # 不确定具体版本
build:
install: pip install -r requirements.txt
command: '' # gap — AI 引导问
start:
command: '' # gap — AI 引导问
port: 0 # gap
health_path: '/' # 默认值
gaps:
- field: start.command
hint: '怎么启动这个服务?如 gunicorn -w 4 app:app'
- field: start.port
hint: '服务监听哪个端口?'为什么不做更多 Tier 1?
框架变化太快。今年识别 Next.js 14,明年 Next.js 15 改了。每加一个 Tier 1 都是维护负担。我们选择保持精瘦 — Tier 1 只覆盖中文国内市场最高频的 4 个栈,其他全走 Tier 2。
完美的栈识别覆盖不到 100%,但 Tier 2 永远是 100% — 这就是关键。
Tier 2 → Tier 1 升级
当某个 Tier 2 栈的用户量足够大(用户量自统计),我们考虑升级到 Tier 1。这是数据驱动的,不是技术驱动 — 不会因为「我们觉得 Svelte 很酷」就专门做 Svelte Tier 1。