我独自开发了一个 AI 求职代理——这是完整技术栈

Dev.to AI 2026-08-02T05:28:19.472170

技术栈

前端 —— Next.js,部署在 Vercel 上。路由用 App Router,合适的地方用服务端组件。选 Vercel 托管,是因为「推送代码即部署」的流程几乎没有摩擦,我追求的是单人开发的速度,而不是对基础设施的掌控。

后端 —— FastAPI,部署在 Render 上。我没有把所有逻辑都塞进 Next.js 的 API 路由,而是单独拆了一个 Python 后端。原因很简单:重活——简历解析、匹配管道、数据爬取——都是 Python 生态的原生强项,而且我想让它跟前端请求的生命周期隔离开。

数据库 —— Supabase + Prisma。底层是 Postgres。Prisma 负责 schema 定义和类型安全的查询;Supabase 提供托管的 Postgres,以及一部分和认证相关的数据存储。

认证 —— Clerk。注册、会话、整个身份层都由它负责。下面还会专门聊 Clerk,因为我在它身上耗掉的时间最多。

支付 —— Stripe。跑的是正式环境(live mode),订阅套餐带试用期。套餐档位由 webhook 里的 lookup key 解析决定,所以调整价格不需要改代码。

真正的「AI」 —— Gemini。这是最有意思的部分,值得单独开一节来讲。

Gemini 才是真正干活的

我最看重的一点是:AI 不是镶在边上装点门面的聊天机器人。产品里的实际决策,是 Gemini 在做。

简历阅读:解析 PDF,提取真实结构,然后打分——不是看关键词密度,而是看你写的说法有没有实际支撑。整个产品的立足点就是「诚实」:市面上大多数 AI 简历工具靠堆关键词来骗过 ATS(求职者跟踪系统),但一进面试,你连自己简历上的内容都圆不上,马上就翻车。Reclaim 反着来——它既会标出你真正强的地方,也会直接指出哪些内容你是在硬撑。

岗位匹配:把简历放进一个有 3,000 多个真实在招岗位的语料库里打分对比(这些岗位是从 Greenhouse、Lever、Ashby、Workday 等上百家公司的招聘后台抓下来的),然后告诉你,你的实际技能跟哪些岗位对得上,哪些岗位属于够不着的。

一个实际的工程决策:我会按每项任务需要的推理量,把不同任务路由到不同档位的 Gemini 模型,让每用户成本保持在合理范围。免费扫描跑在更便宜、更快的模型上;更重的解析/匹配工作用更强的模型。每次完整 onboarding 的成本大概五美分,也就是说成本从来不是约束——分发和转化才是(这个教训值得单独写一篇)。

哪里崩了(有用的部分)

Clerk webhook 尾随换行符 bug。生产环境切换时,webhook 静默地签名验证失败。原因:签名密钥进入环境时被带上了尾随换行符。密钥逐字节看是对的,但它不对。几个小时耗在看不见的东西上。教训:签名验证失败且密钥「看起来正确」时,先检查空白字符。

webhook 路径上的 P2002 唯一约束冲突。堆叠的 webhook 事件竞相创建同一条用户记录,触发了 Prisma 的唯一约束。只能让 handler 变成幂等——用 upsert 语义而不是单纯的 create。

一笔沉默的钱在漏。评分路径在给没有权限的用户调用 Gemini——为永远不会付费的人烧 API 开销。它「正常运转」(没有错误、输出正确),这正是它危险的原因:除了读日志和账单,没有任何东西会暴露成本 bug。最后把它关进了权限检查。教训:一个能工作但本不该运行的特性,是花钱却不报错的 bug。

要点

把 Python 拆出去。如果你的 AI 工作天生是 Python 的,别强行把它塞进 JS 框架的请求周期。一个独立的 FastAPI 服务,值得多一个部署目标。

查询键 > 硬编码价格 ID。Stripe 价格变动不应该需要重新部署。

可怕的 bug 是不报错的那种。尾随换行符、成本泄漏、竞态条件——它们都「正常」。读日志和账单,能抓住你的错误处理器抓不住的东西。

成本不是难点。约 0.05 美元/次 onboarding,真正的问题从来不是 AI 账单——而是让对的人来到这个网站。构建只是容易的 20%。

查看原文