Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4
2081 字
10 分钟
面面通:我搭了一个 AI 全栈项目,不是 Chat 套壳

从一个问题开始#

去年有个朋友问我:“你做了一个 AI 聊天网站?”

我说不是。

他又问:“那你是接了个大模型的 API,套了个壳?”

我说也不是。

他第三次问的时候,我意识到一个问题——市面上几乎所有的”AI 项目”给人的印象就是 Chat 套壳。

但面面通不是。

准确说,它最开始是一个AI 模拟面试工具。但做着做着发现,面试完了要改简历,改完简历要准备论文——干脆把这几件事串成一个完整的产品。

于是它变成了:

  • AI 模拟面试(多轮问答 + 5 维评分 + 编程考核)
  • 简历优化(上传 → AI 分析 → 岗位定向改写 → Word 导出)
  • 论文润色与降重(中英文润色 + AI 降重 + 查重改写)
  • 文献知识库(上传文献 → 检索 → 引用标注 → 导出剥离)
  • 智能题库 + 错题本 + 配额管理

不是聊天壳子,是一套真实 SaaS 产品的复杂度。

但老实说,“功能多”本身没什么稀奇。真正让我花时间写这一组文章的,是里面有几个很容易被低估的工程问题:

  • AI 调用不能散在各个 Service 里,不然一加供应商、一加配额,七八个地方都要改。
  • 面试不是普通聊天,AI 可能问问题、发笔试邀请、结束面试、生成评分,前端和后端都要接住这些状态。
  • 论文引用不能靠 AI 自觉,必须有知识库边界、证据分类和引用标记。
  • Word 导出不是替换文本,DOCX 里一堆 run、表格、文本框,稍微粗暴一点模板就崩。

如果画成地图,大概就是下面这四个坑位:

面面通系列工程难点地图

所以这篇先做总览,后面几篇再拆具体模块。


长什么样#

先看整体架构:

用户(Web / 小程序)
Vue 3 前端(19 个页面,12 个共享 composables)
Spring Boot REST API(39 个 Service,7 大业务模块)
AI 网关层(多供应商路由 / 用户自有 Key / 配额)
MySQL + IndexedDB(服务端 / 客户端双层存储)
DeepSeek / 通义千问 / 自定义端点

架构图

功能上每个模块能做的事情:

模块具体能力
AI 模拟面试多轮技术问答、5 维度评分、编程笔试环节、SSE 流式对话、面试报告
智能题库分类浏览、随机刷题、即时判分、错题本自动收录
简历优化DOCX 解析、AI 简历评分、岗位定向优化、格式保留导出 Word
论文润色中英文可选、段落级润色、本地格式检查、差异对比
论文降重AI 降重 + 查重改写 + 交互式 Diff 预览
文献知识库PDF/DOCX 上传、语义搜索、证据分类、引用芯片渲染导出
用户配置自定义 API Key、模型切换 Flash/Pro、每日配额、管理员后台

技术选型#

选型上没有用太多花哨的东西,主打一个实用优先

后端是 Spring Boot 3 + MyBatis-Plus + MySQL。原因很朴素:文档多、生态成熟、排坑成本低。一个人做项目时,技术新颖不一定是优点,出问题能不能快速查到答案才是。

前端是 Vue 3 + TypeScript + Vite,状态用 Pinia,路由用 Vue Router。论文知识库的数据放在浏览器本地,所以用了 Dexie 包 IndexedDB,再用 MiniSearch 做客户端全文检索。

流式输出靠 SSE。面试对话、论文润色、简历深度分析这些场景,都需要边生成边展示;等 AI 全部返回再刷新页面,体验会很硬。

还有几块比较特殊:

  • pdf.js + mammoth:负责 PDF/DOCX 文本解析。
  • CodeMirror6:负责面试里的在线编程编辑器。
  • Piston:负责隔离执行代码题。
  • 阿里云文档智能:辅助做简历字段识别。

这里面没有哪个技术是为了”显得高级”才选的。基本都是被需求推着走:要本地知识库,就得碰 IndexedDB;要流式体验,就得接 SSE;要保留 Word 格式,就得下到 OOXML 那一层。


项目的组织方式#

后端:按业务模块分#

39 个 Service 分布在 7 个包里,每个包各自内聚:

service/
├── ai/gateway/ ← AI 网关(多供应商 + 适配器模式)
├── interview/ ← 面试(流程 + prompt + 对话 + 解析)
├── paper/ ← 论文(润色 + 降重 + 证据分类)
├── resume/ ← 简历(分析 + 模板导出)
├── document/ ← 文档(DOCX 格式保留导出)
├── coding/ ← 编程(题目 + Piston 执行)
├── exam/question/ ← 题库
├── user/ ← 用户 + 配额
└── auth/ ← 认证

每个模块的 Service 内部还拆了多个职责组件。比如面试模块拆成了 4 个文件:

InterviewService → 主流程
InterviewPromptBuilder → prompt 构建
InterviewTranscriptManager → 对话管理
InterviewReportParser → 报告 JSON 解析

这样拆的好处是单个文件不会超过 400 行,每个类的职责一眼能看懂。

前端:composable 复用#

前端 19 个页面共享了 12 个 composables:

// composables 目录
useInterviewStream.ts // SSE 面试流处理
useModelToggle.ts // 模型切换分段控制器
usePaperKbPanel.ts // 知识库面板逻辑
usePaperStore.ts // 论文页面状态
usePaperExport.ts // 论文导出
useCitationChips.ts // 引用芯片渲染
useStreamPolish.ts // 流式润色
useQuota.ts // 配额
useResponsive.ts // 响应式
useScrollReveal.ts // 滚动动画
useWarnToast.ts // 警告提示
useTabIndicator.ts // Tab 指示器

useModelToggle 在三个页面(面试 / 简历报告 / 简历上传)被复用,usePaperKbPanel 在三个论文工具页面共享同一套知识库面板逻辑。一个 composable 里改了 bug,三个页面同时受益。

个人觉得这是前端架构里最值得借鉴的做法:不要急着写新页面,先看看已有的 composable 能不能复用。


开发时间线#

整个项目从初始化到现在大概 158 个 commit,几个关键节点:

初期:搭建 Spring Boot + uni-app 骨架,做完基础的题库和面试对话

中期:加了完整的简历优化 + DOCX 导出,然后做了 Web 端 Vue 3 重构

后期:论文模块(润色 + 降重)和文献知识库引用系统

近期:AiGateway 网关层重构(7 个 Service 统一接入多模型),前端 composable 提取,管理员后台

整个过程中最花时间的不是写新功能,而是重构。面试服务拆成 4 个文件花了 3 天,AiGateway 网关层的迁移断断续续搞了一周。但做完之后扩展新功能明显快了——后面加论文润色服务时,只需要调 AiGateway 就好了,不用再写一遍 API 调用代码。


对我自己来说的价值#

做这个项目最大的收获不是技术上的,而是产品闭环的体感

  • 面试 + 简历 + 论文 三个看起来不相关的场景,通过”用户求职/学术”这个主线串起来之后,自然产生了联动需求(简历分析完直接关联面试方向、论文润色时自动引用已上传文献)
  • 单模块功能和完整产品链路之间的差距很大——搭好了一个 AI 面试,不代表用户就愿意用,还需要配额、历史记录、导出、权限控制这些东西
  • 重构是必要的,但要有节奏。“用的时候再重构”比”先重构再上线”更安全

这个系列会写什么#

这组文章不会按功能菜单一项项介绍,那样太像产品手册了。我更想记录几个开发时真正卡过我的点:

  • AiGateway 网关层:7 个 Service 怎么统一接入多模型、用户 Key 和配额。
  • AI 面试引擎:为什么我用 Prompt 当协议,而不是把面试流程全部写死在代码里。
  • 论文知识库引用:怎么让 AI 只能引用用户上传过的文献,而不是张口编论文。
  • DOCX 格式保留导出:AI 改写完简历后,怎么尽量不把 Word 模板弄崩。

面面通的完整代码在 GitHub 上。下一篇先讲 AiGateway:那次重构花了一周,但后面加新 AI 功能明显舒服多了。

面面通:我搭了一个 AI 全栈项目,不是 Chat 套壳
https://qiandaos.top/posts/mianmiantong-series/01-project-overview/
作者
千岛寒流
发布于
2026-06-13
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00