1. 痛点突围:它究竟击穿了什么工程死穴?

批量投递简历的通用做法长期陷入两个极端。一种是依赖市面上的云端招聘 SaaS,将未经脱敏的个人隐私、薪酬底线和完整履历托管给第三方数据库,最终换来千篇一律、充满典型大模型废话的 Cover Letter;另一种则是机械化写爬虫脚本抓取岗位,再通过单次 Prompt 盲目生成 PDF,缺乏针对 JD(Job Description)的量化匹配审计,极易在企业第一道 ATS(Applicant Tracking System)机器筛选阶段直接丢包。

作者 Mads Lorentzen 曾是一名地球物理学者,在岗位被裁撤后构建了这套系统。他通过该系统完成了 69 次深度定制投递,拿到 20 次初筛面试,最终成功转型为 AI 工程师。这套方案的本质是将求职拆解为一个确定性的本地工程流水线,把生成任务分解为起草与代码审查两个互斥阶段,所有个人数据完全停留在本地文件系统中。

💡 架构核心洞见:把求职流抽象为本地编译器模型,将个人履历当作静态语料库,引入审查者智能体与 TeX 编译引擎形成强类型约束的确定性交付物。

2. 核心架构与底层数据流向解析

项目以 Claude Code CLI 为运行时载体,外接 Bun 驱动的微服务脚本与 TeX 编译链。整个系统分为三个解耦阶段:个人数据逆向建模(/setup)、跨源数据抓取(/scrape)与双 Agent 决策投递引擎(/apply <url>)。

[ User Files: documents/ ] ---> [ /setup: Reverse Profiler ] ---> [ profiles/ (Local Markdown) ]
                                                                          │
[ Job Portals / APIs ] --------> [ /scrape: Bun CLI Skills ] ------------>│ (Context Routing)
                                                                          ▼
                                                             [ /apply Fit Evaluator ]
                                                                 (Score: 1-10 & Gap)
                                                                          │
                                     ┌────────────────────────────────────┘
                                     ▼
                        [ Drafter Agent (LaTeX) ] <─────────┐
                                     │                      │ Feedback Loop
                                     ▼                      │ (Style & Truth Check)
                        [ Reviewer Agent (Critique) ] ──────┘
                                     │ (Approved)
                                     ▼
               [ LuaLaTeX (CV) / XeLaTeX (Cover Letter) ]
                                     │
                                     ▼
                      [ ATS Parser (pypdf/pdftotext) ] ---> [ Ready PDF Outputs ]

系统的运行逻辑始于 /setup。该命令扫描 documents/ 目录中的原生 PDF、历史文书与 LinkedIn 导出数据,自动提取职场技能点与过往项目成果,格式化落地为本地 Markdown 状态文件。求职者核心信息不需要输入给任何第三方平台。

当执行 /apply <url> 时,系统启动评估模型。首先分析目标岗位的核心诉求与候选人背景重合度,输出显式匹配度评分及能力差距清单。随后流水线进入核心的生成阶段:Drafter Agent 针对 JD 抽取针对性经历,填装进入预置的 LaTeX 模板。Reviewer Agent 随即启动硬核对抗审查,拦截过度吹嘘、事实不符以及机械复制 JD 原话的低质输出。审查通过后,系统调用 lualatex 编译 CV,调用 xelatex 编译依赖 fontspec 的求职信,最终使用 pypdf 执行机器解析回读测试,验证生成的 PDF 是否能被企业 ATS 系统无损反解为纯文本。

3. 技术选型与性能横向硬核对比

选型维度 本方案 (ai-job-search) 传统实现范式 典型竞品方案 生产环境收益
数据流架构 本地 CLI + 本地文件系统状态机 浏览器插件抓取 + 云端集中存储 Web 端无状态单次 Prompt 填表 零隐私泄露风险,求职底牌无需经由第三方中转
生成质量控制 双 Agent 互斥对抗 (Drafter + Reviewer) 单模型零样本直接输出 (Zero-shot) 规则硬模板替换关键词 彻底剔除大模型特有的套话与虚构经历
排版引擎 原生 LuaLaTeX + XeLaTeX 编译 HTML 转 PDF / Headless Chrome 打印 客户端 Canvas/Word 导出 矢量排版精准控制,规避字体缺失与布局溢出问题
ATS 兼容策略 内置 pypdf / pdftotext 回读校验 无校验机制 依靠平台宣称支持 在交付前阻断因图层异常导致解析为空白的失误
拓展性设计 Bun CLI 独立 Skill 插件化隔离 集中式 Python 单体爬虫脚本 封闭 Web 接口服务 各国本地求职站点爬虫与认证逻辑独立解耦解包

这套技术选型展现了务实的极客逻辑。它放弃了开发臃肿的 Electron 前端或 Web 控制台,直接把 Claude Code 作为交互界面,以 Bun 执行高频的跨站点无依赖调用。通过双 Agent 对抗将生成与检验分立,攻克了大模型输出易泛化、易幻觉的致命痛点。

4. 手把手极客实操:从零构建最小闭环

环境准备与工具链安装

必须具备 Python 3.10+、Bun 运行时以及完整的 TeX 发行版。macOS 用户可通过 Homebrew 安装:

# 基础依赖与 TeX 编译链安装
brew install [email protected] bun poppler
brew install --cask mactex-no-gui
pip install pypdf

构建本地私有仓库与 CLI 工具编译

官方仓库包含求职者的敏感履历,不要直接使用公共 Fork。通过私有仓库模式跟踪上游变更,并依次安装门户抓取技能工具:

# 创建本地隔离工作区
mkdir my-private-job-search && cd my-private-job-search
git init
git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git
git pull upstream main

# 批量构建独立 CLI 插件依赖
for tool in jobbank-search jobdanmark-search jobindex-search jobnet-search linkedin-search freehire-search; do
  (cd .agents/skills/$tool/cli && bun install)
done

最小化投递流水线执行脚本

下方脚本演示通过 Claude Code 终端执行单岗位自动评定与编译生成的标准流程:

# 启动 Claude Code 交互上下文
claude

# 1. 引导读取 documents/ 目录,将历史 PDF 与经验蒸馏至 profiles/ 目录
/setup

# 2. 调用抓取技能探查目标岗位,指定关键词与过滤深度
/scrape --keyword "AI Engineer" --location "Copenhagen"

# 3. 对目标 JD 触发双 Agent 评估、生成与 TeX 编译闭环
/apply https://example.com/jobs/senior-ai-engineer-1024

预期输出产物目录结构:

applications/2026-06-example-senior-ai-engineer/
├── evaluation.md         # JD 量化匹配度评分、差距分析与提炼要点
├── cv.tex                # 针对该职位动态定制的简历 TeX 源码
├── cv.pdf                # LuaLaTeX 编译产物,完全矢量排版
├── cover_letter.tex      # 依 JD 诉求构建的前瞻性求职信 TeX 源码
├── cover_letter.pdf      # XeLaTeX 编译产物
└── ats_check_report.txt  # pypdf 提取出的纯文本与解析状态日志

5. 生产落地踩坑指南与避坑建议 (Gotchas)

真实落地使用时,这套高度依赖本地编译器与语言模型的自动化系统存在几个明确的边界暗坑。

⚠️ 避坑预警 1:LaTeX 编译引擎差异导致字体扩展崩溃 简历模板中广泛使用了 fontawesome5 矢量图标库。如果错误调用 pdftotext 驱动的传统 pdflatex 命令进行构建,在现代 MiKTeX 或精简版 TeX 发行版中会抛出字体扩展限制错误(Font expansion error)并终止进程。CV 必须锁定使用 lualatex 编译;而求职信类文件 cover.cls 依赖 fontspec 实现高级排版,必须强制绑定使用 xelatex。极简 TeX 环境用户必须手动补全 fontawesome5 与 fontspec 宏包。

⚠️ 避坑预警 2:GitHub 默认 Public Fork 导致隐私数据泄露 GitHub 平台机制规定,针对 Public 开源仓库发起的 Fork 操作默认全部强制公开。/setup 提取出的 profiles/ 状态文件会直接记录真实姓名、家庭地址、历史薪酬流水及离职原由。如果开发者盲目执行 gh repo fork 并将生成内容推送至远端,个人隐私将公开展现在 GitHub 上。正确做法是在本地建立裸仓库,将其设为 Private 属性,仅将原始仓库挂载为 upstream 获取逻辑更新。

⚠️ 避坑预警 3:Claude CLI 上下文窗口暴涨与 Token 消耗陷阱 在单次会话内连续执行多轮 /apply 时,Claude Code CLI 会持续将前序生成的巨大 TeX 源码、JD 全文以及评审交互记录保存在当前 Session 内存中。当连续投递超过 5 个岗位后,单次问答触发的 Token 账单将呈指数级攀升,并显著拖慢响应速度。必须在完成单次 /apply 产物交付并校验无误后,手动输入 /clear 重置会话上下文,阻断长尾历史对后续 JD 生成质量的负面干扰。