resume-agent 运行手册
一、这是什么
resume-agent 是一个纯本地的简历面试助手 Web 应用:用户上传 Word/PDF 简历后,
接入自己配置的任意 OpenAI 兼容大模型,进行简历四维诊断与改写,并生成分类面试题
(客观笔试 + 主观问答)。特点:
- 后端零依赖:纯 Node.js
http,无任何 npm 包,无需npm install。 - 前端漫画风:单页 UI(
public/),REST + SSE 通信。 - 方法论外置:提示词不写死在代码里,而是运行时读取同级 Skill
缺失时回退内置精简版。 - 本地优先 / 隐私友好:API Key 仅本地混淆存储,明文不出后端。
二、功能概览
| 功能 | 入口 | 说明 |
|---|---|---|
| 简历上传解析 | POST /api/upload |
支持 pdf/docx/dotx/txt/md;返回 resumeId、纯文本、解析统计、告警 |
| 文本直贴 | POST /api/resume/text |
无文件时直接粘贴文本(≥20 字) |
| 模型设置 | POST /api/settings/models 等 |
增/删/切模型,支持「无需 Key」模式;Key 落盘前 AES-256-GCM 混淆 |
| 简历优化 | POST /api/optimize(SSE) |
四维诊断 + 六轴雷达 + 技能缺口 + 模板推荐 + 待核实清单 |
| 面试题生成 | POST /api/interview(SSE) |
客观题(含选项/答案/解析)+ 主观题(含回答框架/要点/追问) |
| 健康检查 | GET /api/health |
返回服务状态、是否已配模型、方法论是否接入 |
优化输出结构(四大维度 + 六轴雷达)
overall : { score:0-100, grade:"A".."E", summary }
radar : 6 轴,各 0-100
ATS兼容性 / 结果导向 / 量化程度 / JD匹配度 / 结构清晰度 / 表达专业度
dimensions: 4 项(每项含 issues 列表)
format 格式优化 满分 25
content 内容优化 满分 35
skill 技能优化 满分 25
template 模板优化 满分 15
skills : { matched, missing, weak, roadmap[gap+steps] }
templateRec: { name, reason, color, rules[] }
todo : 需用户补充确认的信息(数字口径、真实性存疑处)
面试输出结构
objective : 客观笔试题(可选类型:单选/多选/判断/填空/简答/代码)
{ level:"L1"|"L2"|"L3", type, tag, q, options[], answer, analysis }
subjective: 主观问答题
{ type:"项目深挖"|"行为面试"|"技术原理"|"系统设计"|"自我介绍"|"反问环节",
q, focus[], framework, good[], bad[], followup[] }
难度配比默认 L1 基础 40% / L2 进阶 40% / L3 挑战 20%;提供简历时主观题 ≥60% 基于简历原文。
三、系统架构
组件关系
┌─────────────────────────┐ REST + SSE ┌──────────────────────────┐
│ 浏览器(public/ 单页) │ ───────────────────────▶ │ Node http 后端 │
│ index.html + app.js │ ◀─────────────────────── │ server.js + lib/* │
│ (漫画风 UI) │ JSON / text/event-stream│ │
└─────────────────────────┘ └───────────┬──────────────┘
│ 读取
▼
┌──────────────────────────┐
│ resume-interview-assistant│
│ Skill/references/*.md │
│ (四维方法论/命题规范/评分卡)│
└──────────────────────────┘
关键数据流
优化流程
1. 上传 → /api/upload → parser.parseFile(PDF 走 ToUnicode CMap 中文反查,docx 走手写 ZIP 读取器)→ 文本存入内存 resumes Map(3 小时 TTL)→ 返回 resumeId。
2. 调用 /api/optimize({ resumeId, targetRole?, jd? })→ 解析激活模型 → 开启 SSE →
llm.chatStream 边流式累加边推送 status/delta。
3. 流式结束后 prompts.extractJson 解析 → 推送 result(overall+radar+dimensions+…)
或 error。前端渲染四维卡片 + 六轴雷达。
面试流程:同上,但 interviewUser 携带 counts(客观/主观题数,分别限 1–60 / 1–30),
结果含 objective + subjective 两组。
设计要点
- 提示词与代码解耦:
lib/prompts.js运行时拼接 system 提示词,方法论文本来自同级
Skill 的resume-optimization.md/interview-questions.md/scoring-rubric.md;
Skill 改 → 应用行为即变,无需改代码。 - 内存态简历:解析结果只在服务端内存保留 3 小时,过期的
resumeId会被sweep()清理。 - SSE 线格式:
event: <name>\n\ndata: <json>\n\n,事件名status/delta/result/error。
四、运行方式
前置:Node.js ≥ 18(用到 async/await、crypto.randomBytes),无需装包。
cd C:\skill\resume-agent
node server.js # → http://127.0.0.1:5173
PORT=8080 node server.js # 自定义端口
- 仅绑定
127.0.0.1(本机);默认端口被占用时自动 +1 递增(最多 +12)。 - 停止:
Ctrl + C。
验证:
curl -s http://127.0.0.1:5173/api/health
# → {"ok":true,"hasModel":false,"activeModel":null,"skillRefFound":true,"resumes":0}
在本工具内常驻(开发服务器)
用 Bash 工具 run_in_background=true 启动,使其成为持久前台任务。勿用 shell &,
否则进程会随父 shell 退出被回收,预览连不上。
五、使用方式(终端用户视角)
- 启动服务并打开
http://127.0.0.1:5173。 - 配置模型:点右上角「模型设置」→ 填 Base URL、模型 ID、API Key(本地无 Key 服务可勾
「无需 Key」)→ 保存并设为启用;可用「测试连接」验证。 - 上传简历:拖入或选择 PDF/Word,或直接在文本框粘贴。解析后显示预览与统计。
- 简历优化:(可选填目标岗位 / JD)→ 点「优化」→ 实时看到流式进度,最终展示
总评 + 六轴雷达 + 四维问题清单 + 技能缺口补强路线 + 模板推荐 + 待核实项。 - 生成面试题:选客观/主观题数 → 点「生成面试」→ 得到客观题(含答案与解析)与
主观题(含考察点、回答框架、加分/扣分点、追问)。
> 第 2 步完成前,优化/面试接口会返回「请先配置模型」;上传解码、设置、健康检查等无需模型。
六、漫画风视觉规范(当前态,用于改版)
整套风格由 public/style.css 的 :root 变量驱动。换主题时只改这些变量和
app.js 里列出的颜色字面量,不要重命名 class。
糖果色板(当前值):
--brand: #ff7a59 /* 珊瑚橘 · 主操作色 */
--brand-dark: #fa5a3a
--brand-light: #ffb39c
--brand-bg: #fff1ea
--c-blue: #4dabf7 /* 维度芯片配色 */
--c-yellow: #fcc419
--c-green: #51cf66
--c-purple: #b197fc
--ink: #2f2a3d /* 漫画墨色(深蓝紫) */
--outline: #2f2a3d /* 漫画硬描边 */
--bg: #fdf3e6 /* 奶油底 */
--paper: #ffffff /* 卡片纸面 */
--line: #e7ddcb /* 浅暖分隔线 */
视觉特征(保留以维持「漫画感」):
- 背景:奶油底
--bg+ 漫画网点radial-gradient(rgba(255,122,89,.10) 1.6px, transparent 1.7px),尺寸22px。 - 卡片:白纸
--paper+2.5px solid var(--outline)+ 硬投影4px 4px 0 rgba(47,42,61,.12)(贴纸感);悬停translateY(-3px)。 - 按钮:
2px solid var(--outline)+3px 3px 0投影;按下translate(1px,1px)。 - 字体:圆体栈
var(--sans)="Comic Sans MS","Chalkboard SE","Comic Neue","Segoe Print","YouYuan","Yuanti SC",...。 - 入场动画
popIn弹跳。
app.js 需同步的颜色字面量(改主题时一并改):
- 维度芯片:
['#ff7a59', '#4dabf7', '#fcc419', '#51cf66'] - 雷达 SVG:
stop-color="#ff7a59"/"#4dabf7",网格stroke="#ece3d4",坐标轴stroke="#f3ecdf",数据点fill="#ff7a59",标签fill="#736c84",多边形stroke="#ff7a59" - 模板默认色:
const c = t.color || '#ff7a59';
七、关键文件清单(职责)
| 文件 | 职责 |
|---|---|
server.js |
入口:路由表、简历内存暂存(3h TTL)、端口选择/自增、请求分发、CORS |
lib/http-utils.js |
请求体读取、JSON 响应、SSE 三件套(sseInit/sseSend/sseDone)、静态服务 + 防目录穿越 |
lib/store.js |
模型配置持久化;API Key 用 AES-256-GCM 混淆(密钥 data/.obfkey);maskKey() 一律脱敏;内置 PRESETS |
lib/llm.js |
OpenAI 兼容调用(含 stream=true SSE 转发)、连通性测试、模型列表 |
lib/prompts.js |
拼装 system/user 提示词;运行时读取同级 Skill resume-interview-assistant/references/*.md;缺失则回退内置 |
lib/parser.js |
docx(手写 ZIP 读取器 + inflateRaw)与 pdf(ToUnicode CMap 中文反查)/ txt → 纯文本;stats.garbled 为布尔 |
public/index.html |
单页外壳、内联 SVG favicon(珊瑚色 #ff7a59)、挂载 app.js |
public/style.css |
漫画风 UI,:root 变量为样式唯一真源(见上) |
public/app.js |
全部前端逻辑与动态渲染;维度调色板为 colors[] 字面量 |
data/.obfkey data/settings.json |
混淆密钥 / 模型配置(Key 已混淆) |
八、UI 改风规则(不破坏 app.js)
前端依赖 style.css 中稳定的 class 名。安全改风:
- 只改
style.css(优先改:root变量)与上文列出的app.js颜色字面量。
绝不重命名已有 class——app.js依赖它们(card、btn、model-chip、tabs、
issues、questions等)。 - 改完后重跑冒烟测试(目标 12/12)并自查:
style.css大括号配平、node --check public/app.js通过、无残留旧色。
九、必记坑
- Git-Bash / MSYS 路径坑:把
/c/tmp/x.js作为 node 参数 传入会被改写成
C:\c\tmp\x.js(错误)。node 文件参数一律用C:/tmp/x.js(正斜杠 + 盘符);shell 内cd /c/...不受影响。 maskKey用****(如sk-m****7890),不是•。测试断言要查****,并断言响应里绝不出现明文 Key。parser.stats.garbled是布尔(true= 解码疑似乱码)。中文正常解码应为=== false,不是=== 0。- SSE 线格式:
event: <name>\n\ndata: <json>\n\n。事件名status/delta/result/error。 - 明文 API Key 永不出后端;
store.toClient()会脱敏。明文只存在于「用户刚提交的那次请求」和「实际调用模型的那一刻」。 - 真实优化/面试需已配置模型;不涉及大模型的冒烟(上传解码、设置增/脱敏、health)无需模型。
- PDF 需有文本层(非扫描件/图片型)。无文本层时返回
warnings并建议改用 Word 或粘贴文本。
十、测试方法
- 健康检查:
curl /api/health(无需模型)。 - 冒烟(无需模型) 示例:
bash curl -s -X POST http://127.0.0.1:5173/api/settings/models \ -H 'Content-Type: application/json' \ -d '{"name":"mock","baseUrl":"http://127.0.0.1:9999/v1","model":"mock","noKey":true}' curl -s http://127.0.0.1:5173/api/settings # 返回的 Key 必须为 **** 脱敏,且无明文
上传.docx/.pdf并断言中文正确解码;检查stats.garbled === false。 - E2E(需模型):
POST /api/optimize→ 期望overall+radar(6)+dimensions(4);
POST /api/interview→ 期望objective+subjective数组。 - 参考成绩:漫画风改造前全量 E2E 26/26;改造后冒烟 12/12(后端零回归)。
> 完整文件树、接口路由表与数据流细节见 references/architecture.md。