这份文档帮你把项目讲清楚、讲出深度,而不是背功能清单。 原则:先讲"解决了什么真问题",再讲"怎么解决的",最后用 2-3 个能深挖的技术点证明工程能力。
我做了一个本地优先的 AI 简历工作台,叫 ResumeForge(简历通)。 它解决的是求职者资料散、简历版本乱、AI 生成简历会编造经历这三个真实痛点。 技术上是 FastAPI + React + SQLite 的单机应用,前端运行时依赖只有 6 个,后端纯 Python 零编译。 核心设计是把"事实"和"表述"拆开管——AI 只负责把已确认的事实改写成漂亮的简历,改写不了事实本身, 所以它写出来的每一句话都能追溯到你的资料库。
求职期的数据是散的、乱的、危险的:
- 散:JD 在收藏夹,简历有七八版
简历-最终版2.docx,投递进度在备忘录,面试问题面完就忘。 - 乱:改了三版简历,不知道哪一版投给了哪家公司。
- 危险:AI 能把简历写漂亮,也能把你没做过的事写进去——面试官追问两句就露馅。
ResumeForge 的答案是围绕一条主线做闭环:
录入岗位 → 维护资料 → AI 生成 / 自行编写简历 → 导出投递
↑ ↓
└── 面试深挖 / 模拟面试(检验) ← 求职进度 / 投递台(执行反馈)←┘
关键差异点在于它不做黑盒:匹配度不给你一个百分比(那会给你虚假的精确感),只给五类结论(已匹配 / 表达缺口 / 证据不足 / 真实缺口 / 待确认);生成结果会和资料库逐条比对,不一致就报警。
| 层 | 选型 | 为什么 |
|---|---|---|
| 前端 | React 18 + TypeScript + Vite + Ant Design 5 | 运行时依赖只有 6 个,无 Redux / 无 Tailwind,状态用页面级 hook |
| 后端 | FastAPI + SQLAlchemy 2 + Alembic + Pydantic 2 | 异步、类型安全、可离线测试 |
| 存储 | SQLite(本地优先) | 单用户单机,零部署成本;多数据集 = 多个真实库文件 |
| AI | OpenAI 兼容协议 + Anthropic 原生,双协议 | 用户自带 Key,一个 Provider 接口切换 |
| 导出 | 服务端 PDF(fpdf2 嵌入中文字体)+ 浏览器打印 + Word(python-docx) | 三种都复用同一套版式口径 |
| 浏览器自动化 | 自研 CDP 客户端(WebSocket) | 驱动用户自己的 Chrome/Edge 投递,纯 Python 零编译 |
工程数据:2700+ 测试用例、后端覆盖率门槛 80%、19 个 Alembic 迁移、GitHub Actions 三平台 CI(Linux ×2 / Windows)。
前后端严格三层,任何功能走同一条路:页面 → 路由 → 服务 → ORM → SQLite。前端从不直接拼 URL,后端路由从不写业务。
React 页面 ──前端封装 api/*──▶ FastAPI 路由 api/* ──▶ 业务 services/* ──▶ ORM models/* ──▶ SQLite
(界面) (统一请求层) (参数校验/编排) (纯逻辑,可离线测) (表结构)
这条链路的两个工程价值:业务逻辑与框架解耦(services 层可以脱离 FastAPI 跑单测),契约集中(前后端枚举逐字镜像,改一处有测试兜住)。
挑 2-3 个你最有把握的展开。每个都能讲出"难点 → 方案 → 结果"。
- 难点:大模型最危险的失败不是写不好,是编造。把一个没做过的项目写进简历,比排版难看严重得多。
- 方案:单独建"事实台账"表,每条主张记录"原始事实 + 简历表述 + 承担程度 + 核实状态"。只有"已确认"的条目才进生成上下文;未确认说法进"禁止使用"清单;生成结果与资料库逐条比对,不一致给防虚构警告;正文有【待补】标记时导出被拦并指出位置。
- 结果:AI 只能"改写事实",不能"创造事实"。这条是产品的灵魂,也是最能体现"我理解 LLM 边界"的地方。
- 可追问点:为什么不让 AI 自己确认台账条目?→ 那等于让模型给自己发通行证。
- 难点:自动投递要驱动真实浏览器、理解陌生招聘网站表单——这是最不可控、最易因站点改版而失效的环节。
- 方案:把最不可测的两件事封在两层之后。浏览器桥接层(
services/browser/)只管 CDP 传输和"页面什么时候真的就绪";站点适配器层(services/sites/)只认一个站点、提供选择器与流程。业务层只调"站点无关"接口,两层都能用假传输层离线测试——测试不需要真的联网或开浏览器。 - 结果:站点改版只影响对应适配器文件;整条链路在没有招聘网站账号的 CI 里也能全绿。
- 可追问点:怎么判断"页面加载好了"?→ 不信任
readyState(SPA 卡片是 XHR 异步渲染的),只认"目标选择器匹配到内容或明确无结果";"这一页是不是目标页"用"目标地址的每个查询参数都能在当前位置取到相同值"判,而不是地址整串相等。
- 难点:一个规则在多处各写一遍,必然前后端漂移;加表加列会拒收用户手里的旧备份。
- 方案:关键判断只留一份实现——投递准入
admission_of()、进度合并resolve_status()、回收站TRASH_SPECS注册表;数据库用 Alembic 版本化迁移,升级前自动备份,旧备份先迁移再校验,所以"加表"不再是不兼容改动。 - 结果:匹配度分析、投递服务、前端展示都读同一份结论,阈值不会漂移;19 个迁移每个都有"建表 / 幂等 / 可回滚"的测试钉住。
- 前端运行时依赖只有 6 个(antd 系 + dayjs + react 系 + router),没有状态管理库、没有 CSS 框架。
- 后端依赖全部纯 Python 或有 wheel,首次安装零编译(Windows 新手不用装 Visual C++ Build Tools)。
- 提示词独立成文件、版本化;发行包只从
git archive出包并重新校验必需文件。
从 0.1 到 0.10,四个多月、87 个提交,功能是沿主链逐渐长出来的,不是一次性堆上去:
| 版本 | 时间 | 里程碑 |
|---|---|---|
| 0.1–0.2 | 2026-08 | 基础骨架:资料、岗位、简历生成 |
| 0.3–0.5 | 2026-09 上旬 | 岗位文本/JD 规则解析、附件识别、一致性校验 |
| 0.6–0.8 | 2026-09 中 | 导出管线、搜索/收藏、写作增强、事实台账 |
| 0.9 | 2026-09-20 | 投递台、求职进度、模拟面试、面试深挖、版面诊断 |
| 0.10 | 2026-09-21 | 岗位采集筛选、批次可见性、跨平台 CI 全绿 |
讲演进时强调:每一版都有真实用户反馈驱动——CHANGELOG 里大量条目是"用户在 X 场景下发现 Y 失效,我复现后修掉"。这比"我会写代码"更有说服力。
| 面试官问 | 你的应答方向 |
|---|---|
| 为什么用 SQLite,不上 MySQL/PostgreSQL? | 单用户本地工具,零部署成本是核心卖点;ORM 已隔离方言,未来切多用户只需补迁移与并发适配。 |
| AI 会编造经历怎么办? | 这正是核心设计——事实台账 + 逐条比对 + 导出闸门,见亮点 1。 |
| 单机应用有什么工程难度? | 难点不在并发,在数据安全(备份/迁移/旧库兼容)和外部世界的不可控(招聘站点改版、浏览器行为),见亮点 2/3。 |
| 为什么不用无头浏览器(Playwright/Puppeteer)? | 要投的是真实站点,需要真实浏览器与登录态;且驱动用户自己的 Chrome/Edge 更贴近真实投递环境。 |
| 项目有什么短板? | 诚实说:前端 E2E 测试覆盖还不全、无多用户协作、站点适配器目前主要适配单一站点——并说明这是"单用户本地优先"定位下的取舍,以及下一步会补什么。 |
我做的不只是一个"套壳大模型"的工具,而是认真处理了 AI 落地时最难的两个问题——可信(不让它编造)和可靠(外部依赖层层隔离、数据迁移平滑无损)。这两个问题的解法,是我最能拿得出手的工程能力。