InterviewGuide AI面试平台 Windows11本地部署

发布时间:2026/10/16 6:36:34

InterviewGuide AI面试平台 Windows11本地部署 InterviewGuide 本地部署实录Java 25 Spring Boot 4 Spring AI 2.0 跑通一个 AI 面试平台本文记录我学习开源项目InterviewGuideAI 面试平台的本地部署全过程。项目地址https://github.com/Snailclimb/interview-guide环境Windows 11 Docker Desktop JDK 25从零到能访问页面含完整踩坑记录。一、项目介绍一句话上传简历 → AI 分析打分 → 基于简历做模拟面试 → 出评估报告 → 还能语音面试。这是一个把 Java 后端常用中间件几乎用全了的项目方向技术说明语言Java 25用了虚拟线程构建Gradle 9.6.1wrapper 已配腾讯云镜像框架Spring Boot 4.1模块化 starter 设计非传统单体 starterAI 框架Spring AI 2.0OpenAI 兼容模式对接阿里云百炼数据库PostgreSQL 16 pgvector向量检索做 RAG不是外挂独立向量库缓存 / 消息队列Redis 7 Redisson用 Redis Stream 做异步任务不是 Kafka对象存储MinIO / RustFSS3 兼容协议文档解析Apache Tika解析 PDF / DOCX / TXT报告导出iText 8生成 PDF数据库迁移Flyway全部表结构由迁移脚本管理前端React 18 TypeScript Vite 5 Tailwind 4包管理器 pnpm对于这个项目学习的地方会很多但是很全面建议持续学习。二、环境准备依赖版本必需备注JDK25是必须 2521 编译不过Node.js18是前端构建pnpm10推荐项目packageManager指定 10.26.2Docker Desktop任意较新版本强烈推荐一键起 PostgreSQL / Redis / MinIO2.1 JDK 25这一步是第一个容易翻车的地方。项目app/build.gradle里显式声明了java{toolchain{languageVersionJavaLanguageVersion.of(25)}}而settings.gradle里挂了这个插件plugins{idorg.gradle.toolchains.foojay-resolver-conventionversion1.0.0}这是好消息foojay 插件意味着如果你本机没有 JDK 25Gradle 会自动下载一个来构建不会直接报 “No compatible toolchain”。验证方式java-version# 期望看到类似# openjdk version 25.0.3 2026-04-21如果显示的是 21 或 17也不一定要急着改——Gradle 会自己搞定。但如果你嫌自动下载慢直接装一个 JDK 25 并把JAVA_HOME指过去最省事。我本机用的是 IntelliJ IDEA 自带的 JBRJAVA_HOME指向.../IntelliJ IDEA 2024.2.1/jbr版本就是 25直接可用。2.2 Docker DesktopWindows 上装完 Docker Desktop 后一定要确认它真的启动了。Docker Desktop 的特点是安装完不会自动常驻重启电脑后需要手动打开。任务栏右下角那个小鲸鱼图标变成「静止」状态才说明 Docker 引擎就绪。三、两条路线先想清楚要走哪条项目给了两套启动方式用途完全不同选错了会白折腾。路线 ADocker Compose 全量启动docker-compose.yml编排了6 个服务postgrespgvector redis minio createbuckets初始化容器跑完自动退出 appSpring Boot 后端 frontendReact Nginx一条命令全起来访问http://localhost就是完整应用。路线 B只起依赖 本地跑应用用 Docker 起PostgreSQL / Redis / MinIO这三个中间件前后端都在本机跑。适合开发调试、读源码、改代码即时生效。这也是我选的路线。对比一下路线 A路线 B启动命令1 条3 条改代码生效需重新 build 镜像即时热重载能否打断点麻烦方便首次构建耗时长要 build 前后端镜像短适用场景体验 / 演示 当然对于面试求职也是一个很好的练习工具开发 / 学习四、路线 B 完整步骤4.1 克隆项目gitclone https://github.com/Snailclimb/interview-guide.gitcdinterview-guide4.2 配置 .env最容易漏的一步项目根目录有.env.example复制一份cp.env.example .env然后编辑.env必须填这两项# 1. 阿里云百炼DashScopeAPI Key# 申请地址https://bailian.console.aliyun.com/# 一个 Key 同时覆盖 LLM 对话 ASR 语音识别 TTS 语音合成不用分别申请AI_BAILIAN_API_KEYsk-你的真实key# 2. Provider API Key 的加密密钥# 生产环境请换成随机长字符串部署后不要改改了库里已加密的 Key 会全部解不开APP_AI_CONFIG_ENCRYPTION_KEY换成一个足够随机的长字符串其他配置块可以先不动。.env.example里已经包含了 PostgreSQL / Redis / 存储的默认值和docker-compose.yml是对齐的。为什么必须配 AI Key因为简历分析、模拟面试出题、报告评估全靠它。不配的话应用能启动但一上传简历就失败。4.3 启动依赖服务这里有个官方 README 和实际文件不一致的坑先说要怎么走。README 推荐的是一行命令dockercompose-fdocker-compose.dev.yml up-d但是docker-compose.dev.yml里的 RustFS 服务是这么写的environment:RUSTFS_RPC_SECRET:${RUSTFS_RPC_SECRET:?Set RUSTFS_RPC_SECRET in .env}注意${VAR:?错误信息}这个语法——只要.env里没有RUSTFS_RPC_SECRETcompose 会直接报错退出一个容器都不会起来。而.env.example里恰好没有这个变量。所以我改用主 compose 文件只起依赖部分dockercompose-fdocker-compose.yml up-dpostgres redis minio createbucketscreatebuckets是一个初始化容器init container 模式它等 MinIO 健康后自动创建interview-guide这个桶、设置访问策略然后退出。跑完就消失是正常现象。检查一下状态dockercompose-fdocker-compose.ymlps应该看到 postgres / redis / minio 是running (healthy)createbuckets 是exited (0)。4.4 启动后端./gradlew :app:bootRunWindows 用户如果用的是 CMD / PowerShell用gradlew.bat :app:bootRun在 Git Bash 里./gradlew可以直接跑。首次启动会比较慢因为要下载 Gradle 发行版和全部依赖。之后就快了。启动成功的标志是日志里出现Started AppApplication in x.xxx seconds以及数据库连接池就绪HikariPool-1 - Start completed.后端地址http://localhost:8080接口文档http://localhost:8080/swagger-ui.html有个细节值得说明app/build.gradle里给bootRun任务专门写了逻辑自动读取项目根目录的.env并把变量注入 JVM。所以你不必手动export环境变量——这也是为什么第 4.2 步的.env那么重要。4.5 启动前端新开一个终端cdfrontend corepackenablepnpminstallpnpmdev前端地址http://localhost:5173corepack enable是为了让 Node 用上项目package.json里packageManager字段指定的 pnpm 版本10.26.2。不装 corepack 直接用全局 pnpm 一般也能跑但版本不一致可能报 lockfile 相关的错。4.6 怎么确认真的跑起来了别急着点页面先确认三个依赖都通了dockercompose-fdocker-compose.ymlps再加上两个自检检查项方法期望结果数据库连得上看后端启动日志有HikariPool-1 - Start completed.表结构建好了后端启动日志搜Flyway有Successfully applied N migrations存储桶存在浏览器打开 MinIO 控制台能看到interview-guide桶MinIO 控制台地址是http://localhost:9401账号密码minioadmin/minioadmin。注意这里不是默认的 9001因为我本机把宿主端口改成了 9400/9401原因见下面的坑 2。如果你本机 9000 / 9001 没有被占用保持项目默认即可控制台就是http://localhost:9001.env里的APP_STORAGE_ENDPOINT也不用改。五、踩坑记录坑1 MinIO 端口 9000 / 9001 绑定失败现象MinIO 容器起不来报端口占用。原因Windows 的Hyper-V / WSL2 会保留一段动态端口我本机保留的是8961-9060和9061-9160而 9000 / 9001 正好落在里面。这类保留端口是被系统预订的任何进程都绑不上——而且每次重启电脑保留段可能变。排查netsh interface ipv4 show excludedportrangeprotocoltcp解决把宿主端口改到保留段之外。我本机改成了 9400 / 9401minio:ports:-9400:9000# 左宿主右容器-9401:9001容器内部还是 9000 / 9001只是宿主机映射端口变了代码里访问 MinIO 的地址要同步改# .envAPP_STORAGE_ENDPOINThttp://localhost:9400这个坑的本质是「容器内端口」和「宿主机端口」是两回事改的永远是前者到后者的映射。坑 2minio/mc镜像拉不下来导致整个 compose 启动失败现象dockercompose up-d# 报错createbuckets 服务镜像拉取失败HEAD 请求返回 403原因docker-compose.yml里createbuckets原本用的是官方minio/mc镜像这是 MinIO 的命令行客户端专门用来建桶。但我当时用的镜像源返回 403拉不到换了几个源也都失败。解决minio/minio这个服务镜像自带/usr/bin/mc。既然它已经被其他服务拉下来了直接复用它就行createbuckets:image:minio/minio:latest# 原来是 minio/mcentrypoint:/bin/sh -c set -eu; /usr/bin/mc alias set myminio http://minio:9000 minioadmin minioadmin /usr/bin/mc mb myminio/interview-guide --ignore-existing /usr/bin/mc anonymous set download myminio/interview-guide 同一功能、少拉一个镜像。顺带说一句策略的事上游这里用的是mc anonymous set public意思是桶允许匿名读写——任何人都能往你的桶里写文件、删文件。应用其实只需要「匿名可读」前端用文件的直链地址下载简历所以改成download只读更稳。坑 3java -version执行完什么都没输出现象java-version# 没有任何输出直接回到命令行原因系统 PATH 里存在这个目录——C:\Program Files\Common Files\Oracle\Java\javapath这是 Oracle JDK 安装时留下的路径转发器里面是一堆指向真实 java.exe 的转发程序。JDK 被卸载或升级后这些转发器就变成了死链接——执行时静默失败不报错也不输出。排查wherejava会看到 javapath 排在前面。解决把 PATH 里这一项替换成真实 JDK 的bin目录或者直接删掉这一项。# 备份当前 PATH 后修改系统 PATH# 把 C:\Program Files\Common Files\Oracle\Java\javapath 替换为你的 JDK bin 目录改完要新开终端才生效已有终端继承的是旧环境变量。这个坑的教训是「命令没输出」和「命令报错」是两种完全不同的故障。没输出通常意味着你执行的根本不是你以为的那个程序。坑 4docker-compose.dev.yml起不来一个容器都不创建现象dockercompose-fdocker-compose.dev.yml up-d# 报错error while interpolating services.rustfs.environment.RUSTFS_RPC_SECRET: required variable RUSTFS_RPC_SECRET is missing a value: Set RUSTFS_RPC_SECRET in .env原因见 4.3 节。${VAR:?message}是 compose 的强制校验语法变量缺失时直接中断整个 compose 解析任何服务都不会启动。解决三选一——在.env里补上RUSTFS_RPC_SECRET随便一个随机字符串改用docker-compose.yml用 MinIO不需要这个变量←我选的不用对象存储容器本机自己装一个顺便记录一个容易埋雷的差异同一个项目里两个 compose 文件的 Postgres 默认密码不一样文件默认 Postgres 密码docker-compose.ymlpassworddocker-compose.dev.yml123456而且两个文件里数据库卷的名字都叫postgres_data在同一个 compose project项目目录下指向的是同一个卷。PostgreSQL 镜像的行为是只在数据目录为空时用POSTGRES_PASSWORD初始化密码。所以如果你先用 dev 版起密码 123456再切到主 compose配置里写 password数据库的密码仍然是 123456后端就会连不上。规避方式只用其中一个 compose 文件别混着用。真要切换先把卷删掉重建dockercompose-fdocker-compose.yml down-v# 注意-v 会删数据坑 5上传成功的文件前端下载报 403现象简历上传接口返回成功文件也进桶了但前端点下载拿到 403。原因应用启动时有一段ensureBucketExists()逻辑但它只负责建桶不设置桶策略。桶默认是私有的而前端是用文件地址直链下载的——私有桶直接访问必然 403。解决手动给桶设置匿名只读dockerexecinterview-minio /usr/bin/mcaliassetlocalhttp://localhost:9000 minioadmin minioadmindockerexecinterview-minio /usr/bin/mc anonymoussetdownload local/interview-guide或者用 3.2 节说的createbuckets初始化容器自动完成——这也是为什么那个容器不该被跳过。六、验证跑通第一条业务链路服务都起来之后最少验证一条端到端链路确认 AI 部分真的通了。步骤浏览器打开http://localhost:5173上传一份简历PDF 或 Word 都行观察后端日志成功的日志大概长这样简历上传成功: resumeId1, filenamexxx.pdf 处理 简历分析 task: resumeId1, messageId1791907643422-0, retryCount0 简历分析任务完成: resumeId1要理解的一点简历上传接口不会同步等 AI 分析完。它做完「校验 → 去重 → 解析文本 → 存对象存储 → 入库并投递消息」就立刻返回了AI 分析是丢进 Redis Stream 异步做的。这也是我第一次读这个项目印象最深的设计——为什么不用Async一把梭为什么不用 Kafka后面我会单独写一篇讲它的异步基建Redis Stream 的消息模型、消费者组、Pending 回收、双层重试那块是整个项目技术含量最高的部分。七、小结本文旨在记录部署过程中的经验后续的阅读顺序也将会围绕后端。强烈建议使用codex等agent工具一键部署这会省下不少时间。下一步我打算并且建议按「简历模块resume → 公共基建 → RAG → 模拟面试 → 语音面试」的顺序读下去把每个模块的设计取舍单独写成一篇。第一篇会从简历模块开始——它是整个项目里业务最简单、但基础设施覆盖最全的模块最适合拿来入门。参考项目仓库https://github.com/Snailclimb/interview-guide阿里云百炼DashScope控制台https://bailian.console.aliyun.com/项目采用AGPL-3.0许可证本文为其部署过程的学习记录
延伸阅读

更多相关文章

2026/10/16 6:36:34

ZYNQ与AD9361工程搭建实战:从Vivado配置到SDK裸机初始化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 6:36:34

Android 音频开发(二):MediaPlayer 与 Media3 ExoPlayer 播放实战

前言上一篇我们从一条语音消息入手,介绍了 PCM、采样率、位深度、声道数,以及音频从采集到播放的基本流程。理解音频数据之后,接下来就要解决一个实际问题:如何在 Android 中播放声音?在日常开发中,音频播放…

2026/10/16 8:57:19

基于MATLAB的多特征融合火灾检测系统GUI实现

控制室里的监控画面往往是最枯燥的,但一旦画面里出现不该有的红色,谁都不敢大意。之前给某个厂区做安防监控需求评估时,对方问能不能用现有摄像头自动识别早期火情,不需要换硬件,最好快速出一版可演示的原型。当时我第…

2026/10/16 8:57:19

VL53L4CD ToF测距传感器结合CircuitPython:从参数配置到多传感器实战

1. 项目概述与核心价值距离传感器在嵌入式项目里一直是"存在感很强但总被低估"的角色。做智能垃圾桶的翻盖、做避障小车、做人员靠近检测,都会用到测距。早期大家习惯用红外或超声波,各有各的痛点——超声波在吸音材料面前直接失灵&#xff0c…

2026/10/16 8:57:19

STM32+ESP8266小车遥控实战:AP模式直连与HTTP控制

简介:本资源是一套基于STM32F103系列与HAL库开发的WiFi遥控智能小车完整工程,面向嵌入式初学者及课程设计实践者,聚焦ESP8266模块在串口透传模式下的远程控制实现。项目通过USART1连接ESP8266(需预先配置为AP热点ESP8266_TEST&…

2026/10/16 8:57:19

Keil MDK 5.06安装与ARM Compiler 5.06部署实战指南

简介:本资源为Keil uVision 5.06 ARM编译器官方安装包,专为嵌入式开发工程师及高校电子/自动化专业学生设计,解决ARM Cortex-M系列MCU项目开发中核心工具链缺失、版本陈旧或激活受限等实际问题,广泛适用于消费电子、工业控制与智能…

2026/10/16 8:52:18

手写BP神经网络:NumPy实现反向传播与XOR分类全解析

两年前第一次被问到“能不能不用现成框架,手写一个 BP 神经网络”的时候,我嘴上能把原理讲得头头是道,可真要在一个空白的 Python 文件里从零敲出来,卡了一整个下午。回来之后我决定彻底解决这个问题:用 NumPy 从头实现…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑