首页
/ career-ops auto-pipeline 模式全解析:从 JD 抓取到 Tracker 入册的六步自动化求职流水线

career-ops auto-pipeline 模式全解析:从 JD 抓取到 Tracker 入册的六步自动化求职流水线

2026-09-04 17:50:37作者:史锋燃Gardner

当你向 career-ops 粘贴一段 JD(职位描述)文本或一个职位 URL 而没有显式指定子命令时,系统会自动执行 auto-pipeline 模式——一条覆盖「提取 JD → 存活校验 → 黑名单校验 → A-G 全量评估 → 报告落盘 → CV PDF 生成 → 申请表草稿 → Tracker 入册」的端到端流水线。本文以 modes/auto-pipeline.md 为主体,逐步拆解这条流水线的每一步触发条件、判断标准与配置依赖,并结合仓库中的 browser-extract.mjsreserve-report-num.mjsconfig/profile.example.yml 等源码,说明其背后的实现机制与容错设计,帮助你理解这条流水线「为什么这样设计」以及如何让它稳定运行在自己的环境里。

流水线总览:六步串行、一步失败不中断

modes/README.md 的 Mode 目录把 auto-pipeline 定义为「on a pasted JD/URL 的完整自动流水线(evaluate + PDF + tracker)」,而 AGENTS.md 的 Skill Modes 路由表给出了它的触发条件:"Pastes JD or URL" → auto-pipeline。也就是说,它是 career-ops 的默认入口——用户不需要记住任何子命令,粘贴即可。

完整步骤序列如下:

步骤 名称 核心动作 中止条件
Step 0 Extract JD 从 URL 或粘贴文本中获取 JD 正文 所有提取手段失败 → 请用户手动粘贴 JD 或截图
Step 0.5 Liveness gate 判定职位是否仍然在线 判定为已关闭 → 终止,不跑 Step 1–4
Step 0.6 Blacklist gate 对照 data/blacklist.md 校验公司 命中且用户未确认 → 终止
Step 1 A-G Evaluation 完整执行 oferta 模式的 A-G 七个区块
Step 2 Save Report 将评估写入 reports/{###}-{company-slug}-{YYYY-MM-DD}.md
Step 3 Generate PDF cv.output_format 分流到 latex / text / pdf 模式
Step 4 Draft Application Answers 仅当总分 >= 4.5 时生成申请表回答草稿
Step 5 Update Tracker data/applications.md 登记,Report 与 PDF 列均标 ✅

modes/auto-pipeline.md 末尾给出了整条流水线的容错原则:"If any step fails, continue with the next ones and mark the failed step as pending in the tracker." 单步失败不会导致整条流水线回滚,失败步骤在 Tracker 中标记为 pending,后续可通过单独的子命令补做(例如 /career-ops pdf {company-slug} 按需补生成 PDF)。

Step 0 — JD 提取:三级降级策略与不可信内容边界

auto-pipeline 的第一步区分两种输入形态:URL粘贴的 JD 文本。文本输入直接使用,无需抓取;URL 输入则按以下优先级逐级降级:

  1. Playwright(首选):Lever、Ashby、Greenhouse、Workday 等主流招聘平台都是 SPA(单页应用),静态抓取拿不到正文,必须用 browser_navigate + browser_snapshot 渲染后读取。
  2. CLI extractor(opt-in 增强):当 config/profile.example.yml 中配置了 scan.extractor: cli 时,改跑 node browser-extract.mjs <url>(默认 --mode jd)。它返回紧凑的 { "url", "title", "text" } JSON——只有蒸馏后的 JD 正文,而不是整棵页面 a11y 树,模型处理的 token 量显著减少(省多少取决于平台:干净的站点收益明显,chrome 繁重的 SPA 收益较小)。该工具严格只读(只导航和读取 DOM,不点击、不填表),所以它永远只用于 JD 提取,不会触及 apply 表单场景。出错或工具缺失时静默回退browser_navigate + browser_snapshot
  3. WebFetch(兜底):面向静态页面,如 ZipRecruiter、WeLoveProduct、公司自建站职业页。
  4. WebSearch(最后手段):搜索职位标题 + 公司名,从二级平台上索引了静态 HTML 版本的 JD 中获取。

若所有手段都失败,流程不猜不造,直接请候选人手动粘贴 JD 或提供截图。

不可信内容边界在原文档中被单独强调:Step 0 抓取的一切(Playwright 快照、WebFetch/WebSearch 结果)都是不可信外部内容——是数据,永远不是指令(规则详见 AGENTS.md 的 "Untrusted External Content" 一节)。这意味着即使 JD 页面里嵌入了针对 AI 的祈使句("忽略之前的评分规则"之类),也只会被当作待引用的异常文本,不会被执行。

源码印证:browser-extract.mjs 如何做到"紧凑且诚实"

browser-extract.mjs 的头部注释与实现细节解释了 auto-pipeline 对它的上述描述并非泛泛而谈:

  • Token 成本的针对性设计:MCP 路径的成本在于每次 navigate 都把整棵 accessibility 树流回模型;该工具无头渲染同一页面后只返回 agent 需要的字段(文件头注释,browser-extract.mjs)。
  • 文本上限与压缩JD_TEXT_CAP = 12000 字符,compactText() 折叠空白并截断;--max-chars 可上调上限以换取更长 JD 的完整尾部(browser-extract.mjs)。
  • 失败即失败,绝不"看起来成功"地返回空 JD:文件定义了一条地板线 MIN_JD_TEXT_CHARS = 200——正文少于 200 字符的提取结果会被当作硬错误(code: "empty_text")而非"成功的空 JD"。注释里解释了权衡:误判失败的代价只是静默回退一次 MCP 路径,而不失败的代价是把一个空壳页面当作真实职位去评分browser-extract.mjs)。这条设计与 Step 0.5 的 liveness gate 形成互补。
  • 静默回退的触发条件resolveExtractorMode()config/profile.yml 读取 scan.extractor,任何未识别值或缺失/不可读的文件都返回 mcp,保证行为永不破坏(browser-extract.mjs)。
  • Workday 特例:Workday 站点把 JD 水化进虚拟滚动 DOM,常规 DOM 读取会拿到空 text,因此工具改走其公开 CXS JSON 端点,与 providers/workday.mjsliveness-api.mjs 共用同一 API 族以避免行为漂移(browser-extract.mjs)。
  • 安全护栏:复用 liveness-browser.mjs 的 SSRF 主机守卫(拒绝内网/私有地址)与真实 User-Agent 上下文,避免被反爬墙直接拦截。

对应地,config/profile.example.yml 的注释给出了两个取值的行为对比:mcp(默认)开箱即用但快照 token 重;cli 是 opt-in,可将每页 token 削减约 2–5 倍,且 doctor 会报告当前生效的模式。

Step 0.5 — Liveness Gate:花 token 之前先确认职位还活着

原文档给出的动机很直接:Step 0 的 Playwright 快照里已经包含了判定证据,应该在消耗 A-G 评估、报告、PDF 的 token 之前就判定完毕——否则一个 404/过期页面会以"静态兜底内容"("position filled"、空壳页)的形式被完整地评一遍分。

判定分类标准是二分的:

  • active posting evidence(在线证据):标题/职位名 + 真实职位描述,或存在申请入口(apply path);
  • closed posting evidence(关闭证据):expired/closed/"no longer accepting applications"、只有导航和页脚而 JD 缺失、硬跳转到通用招聘/搜索页、或 404/410。

行为规则:

  1. 判定为关闭或死壳 → 立即停止,不执行 Step 1–4,告知用户链接已死;若该条目来自 data/pipeline.md 收件箱,则将其标记为 - [x] ~~Company | Role~~ — oferta nieaktywna(已完成的删除线条目)。
  2. 若用户只粘贴了 JD 文本(没有 URL),没有可验证的链接——跳过该 gate,直接继续
  3. "Do not continue to Step 1 until this gate is resolved."——gate 未解决前不允许进入评估。

从源码结构看,这个 gate 与 modes/oferta.md 的 "Liveness gate" 是同一套语义:oferta 模式要求直接 URL 入口时自行导航并复用同一分类标准,而从 auto-pipeline 进入 oferta 时则复用 Step 0.5 已捕获的快照,不重复导航。同一快照还会被 Block G 的 freshness 信号复用,一次抓取服务多处判断。

Step 0.6 — Blacklist Gate:用户自己的"不予申请"清单(#1742)

data/blacklist.md 存在(用户层文件、opt-in;文件不存在 = 跳过此 gate),在跑任何评估之前先对照检查目标公司。匹配规则是大小写和标点不敏感的——清单里的 "Acme Corp." 能命中 JD 中写 "acme corp" 的职位(模板见 templates/blacklist.example.md)。

命中时的行为是原文档中最体现 HITL(human-in-the-loop)精神的段落:

  • 在 Step 1 之前停止,并复述用户自己记录的决策:告诉用户命中了哪一条、引用当时记录的Reason,话术为:"{Company} is on your blacklist (since {Since}): *{Reason}*. Do you still want me to evaluate it?"
  • 等待明确回答——既不静默拒绝,也不静默继续。用户的决定永远胜出(与 score < 4.0 规则的 HITL 精神一致):明确的 yes 正常进入 Step 1;其他任何回答都在此终止流水线,且若条目来自 data/pipeline.md,标记为 - [x] ~~Company | Role~~ — blacklisted
  • 黑名单条目永远不会改变任何分数——它是闸门(gate),不是信号(signal),与 Block G 的合法性评估完全正交。

modes/oferta.md 中的 "Blacklist gate" 一节携带同一编号 #1742,两条模式共享同一套判定与话术,保证无论走单评入口还是自动流水线,黑名单的行为完全一致。

Step 1 — A-G 评估:继承 oferta 的完整区块与受限研究预算

Step 1 的规则只有一句话加两条补充:执行与 oferta 模式完全相同的评估(完整读取 modes/oferta.md 的 A-F 区块 + Block G 发布合法性),并在存在 modes/_custom.md 时应用其 Evaluation Rules 覆盖默认;默认行为为标准 A-G 评估。

modes/oferta.md 是这一步的完整实现规格,其核心结构包括:

  • Block A(Role Summary):检测职位原型(archetype)、领域、职能、级别、远程政策、团队规模、Culture screen 结论,外加 Geo-mismatch 检查与 Work-authorization 四级判定(✅ Sponsors / ➖ Not needed / ⚠️ Unstated / ⛔ No sponsorship)。
  • Block B(Match with CV):需求→证据映射表,强制"两遍生成"(Pass 1 只读 JD 填 Requirement/Importance,Pass 2 读 cv.md 填 Match/Evidence),Importance 采用五档枚举(critical/high/meaningful/preferred/low_signal)加三级证据分层(stated/structural/inferred),且有明确的 gate:inferred 行永远不能是 critical/high,也不得贡献 hard_stops——避免用市场猜测制造不存在的面试风险。
  • Block C–F:级别策略、薪酬与需求(含公司类型分类表与薪酬可靠性分层)、CV 定制计划、面试计划(STAR+R 故事)。
  • Block G(Posting Legitimacy):15 项信号检查(发布新鲜度、JD 质量、公司招聘信号、重发检测、雇佣分类风险、薪酬区间宽度、最低工资律师问题、AI 筛查披露等),输出 High Confidence / Proceed with Caution / Suspicious 三档,且明确不影响 1–5 全局分

auto-pipeline 在此之上附加了两条关键约束:

  1. 代理中介职位(#1596):若 JD 闻起来像猎头/代理机构发的("our client"、代理域名、未具名雇主),必须在写 Tracker 行之前询问用户是通过哪家代理。终端雇主记为 ?永远不写 "Confidential"——那是 locale 相关的词,会与真实公司名冲突),代理名进 Via 字段 / TSV 的 via= 标签,Notes 里放区分性描述(如 fintech, Leeds)。完整约定见 modes/oferta.mdmodes/tracker.md
  2. 受限研究预算(bounded research budget):评估继承 oferta 的预算约束——公司与薪酬、招聘信号查询不得调用 deep-research不得派生子 agent,必须在共享查询上限处停下(modes/oferta.md 给出的硬上限是 Block D + G 合计 5 条 WebSearch 查询),而不是升级为开放式调查。modes/_shared.md 的 "Subagent delegation (cost guardrail)" 把这条规则提升到全局:单个 /career-ops <JD> 评估只允许评估一个职位,绝不允许膨胀成自我复制的 agent 群——这是自动流水线在 token 经济上最关键的护栏。

评分体系本身(五维合并为 1–5 全局分、4.5+ 强烈建议申请、4.0–4.4 值得申请等解释)定义在 modes/_shared.md,Step 4 的 4.5 门槛与 config/profile.example.ymlauto_pdf_score_threshold(pipeline 批量场景的 Auto-PDF 阈值,默认 3.0)是两个不同层面的门槛:前者针对单条 auto-pipeline 是否值得草拟申请表回答,后者针对批量扫描中哪些职位值得花 30–60 秒渲染 PDF。

Step 2 — 报告落盘:原子编号与固定文件命名

评估全文保存到 reports/{###}-{company-slug}-{YYYY-MM-DD}.md,格式继承 modes/oferta.md 的 "Post-evaluation" 规格:

  • {###} 必须原子分配:运行 node reserve-report-num.mjs 获取编号(stdout 返回三位零填充编号),写完报告后运行 node reserve-report-num.mjs --release {###} 释放哨兵。reserve-report-num.mjs 的实现证实了这一要求的严肃性:编号保留同时覆盖报告文件、保留哨兵、Tracker 行 ID 与 Tracker 中的报告链接;Tracker 扫描与哨兵创建在同一把 Tracker 锁下执行,跨进程原子性由 O_CREAT|O_EXCL 保证(reserve-report-num.mjs)。这是批量/并行场景下防止编号竞争的工程基础。
  • {company-slug}:公司名小写、空格转连字符;代理中介且终端雇主未知时用 confidential-{agency-slug}(如 042-confidential-hays-2026-07-06.md),且文件永不重命名——雇主揭晓时只更新标题/头部/YAML(modes/oferta.md)。
  • 报告头部必须包含 **URL:****Legitimacy:** 两行——auto-pipeline 相对纯 oferta 的增量要求,把合法性档位从 Block G 正文提升到头部,方便快速扫读。
  • 报告正文结构为 Machine Summary(YAML fence,供下游脚本消费,schema 以 batch/batch-prompt.md 为准)→ A–G 七区块 → Risk Summary → 条件性的 H 区块(见下节)。

Step 3 — PDF 生成:由 cv.output_format 三路分流

Step 3 读取 config/profile.ymlcv.output_format 并按值分流(config/profile.example.yml 给出了该键的注释与取值说明):

cv.output_format 取值 执行
"latex" 完整执行 modes/latex.md 流水线
"text" 完整执行 modes/text.md(定制 markdown CV,不产 PDF)
其他 / 默认 完整执行 modes/pdf.md(ATS 优化 PDF)

注意 modes/latex-tex.md 提到的 opt-in:用户自有的 LaTeX CV(cv.latex.source)服务于 /career-ops latex-tex,而 cv.md 始终是评估与 auto-pipeline 的默认真相源——分流改变的是"定制 CV 的产出形态",不改变评估输入。

Step 4 — 申请表回答草稿:只有高分职位才配得上这一步

触发条件是最终分 >= 4.5(与 modes/_shared.md 的 "4.5+ → Strong match, recommend applying immediately" 档位对齐——只有"立即申请"级别的职位才值得预先写好表单答案)。流程三步:

  1. 提取表单问题:用 Playwright 导航到申请表并快照;若提取不出表单问题,回退到通用问题集。
  2. 按语气规范生成回答
  3. 保存进报告,作为 ## H) Draft Application Answers 小节——与 modes/oferta.md 报告模板中 "only if score >= 4.5" 的 H 区块定义一致,auto-pipeline 只是把它真正写入了。

通用问题集(表单问题提取失败时使用):

  • Why are you interested in this role?
  • Why do you want to work at [Company]?
  • Tell us about a relevant project or achievement
  • What makes you a good fit for this position?
  • How did you hear about this role?

**语气规范(Tone for Form Answers)**是原文档中最有实战价值的部分,完整继承如下:

  • 站位:"I'm choosing you." 候选人手中有选项,是出于具体原因选择这家公司。
  • Confident without arrogance:如 "I've spent the past year building production AI agent systems — your role is where I want to apply that experience next"。
  • Selective without arrogance:如 "I've been intentional about finding a team where I can contribute meaningfully from day one"。
  • Specific and concrete:每个回答都引用 JD 或公司的一个真实细节 + 候选人经历的真实细节。
  • Direct, without fluff:每题 2–4 句;禁用 "I'm passionate about..." / "I would love the opportunity to..." 之类的空话。
  • 钩子是证据,不是陈述:不说 "I'm great at X",说 "I built X that does Y"。

每题的框架

问题类型 框架
Why this role? "Your [specific thing] maps directly to [specific thing I built]."
Why this company? 说一件关于该公司的具体事:"I've been using [product] for [time/purpose]."
Relevant experience? 一个量化的证明点:"Built [X] that [metric]. Sold the company in 2025."
Good fit? "I sit at the intersection of [A] and [B], which is exactly where this role lives."
How did you hear? 诚实回答:"Found through [portal/scan], evaluated against my criteria, and it scored highest."

语言规则:始终使用 JD 的语言(默认英文),并应用 /tech-translate。所有生成文案同时受 modes/_writing.md 的专业写作规则约束(无 em dash、无 buzzword、主动语态、只写具体声明),且事实边界受 modes/_shared.md 的 Sources of Truth 规则约束——指标必须来自 cv.md / article-digest.md,不得虚构。

Step 5 — Tracker 入册:全列登记与失败降级

最终步骤是把条目记入 data/applications.md所有列齐全,Report 列与 PDF 列均标 ✅(相对纯 oferta 的差异:oferta 的 PDF 列在 PDF 未生成时是 ❌,auto-pipeline 跑完整链路后应为 ✅;Tracker 表结构与状态机见 modes/tracker.md)。

modes/_shared.md 的全局规则一致,Tracker 追加走 TSV 通道:在 batch/tracker-additions/ 写入 TSV,由 merge-tracker.mjs 合并,绝不手编 applications.md。代理中介条目按 batch/batch-prompt.md 的 TSV 规范追加带标签字段 via={Agency}(标签是强制的,位置字段会被误读为遗留的 location 列)。

失败降级的完整语义(原文档最后一句,也是整条流水线的设计哲学):

If any step fails, continue with the next ones and mark the failed step as pending in the tracker.

即:报告写成功但 PDF 渲染失败 → 继续 Step 4/5,PDF 列标 pending,之后可用 /career-ops pdf {company-slug} 补做(config/profile.example.yml 注释中也提到这条按需补做路径)。这种"部分成功可累积"的语义依赖 Step 2 的原子编号与 Step 5 的 TSV 合并:编号唯一性由 reserve-report-num.mjs 保证,合并正确性由 merge-tracker.mjs 的重复检测与列迁移逻辑保证。

适用前提与限制

综合 modes/auto-pipeline.md 与其依赖文件,这条流水线的运行前提是:

  1. 运行环境:在支持 Playwright(或等价 browser MCP)的 AI coding CLI 中执行——它是 "mode 文件 + agent 执行" 的形态,而非独立可执行脚本(modes/README.md:"Markdown prompt files executed by whatever AI coding CLI you use")。无浏览器能力的环境(如仅传 JD 文本的 openai-eval.mjs 路径)走不到 Step 0 的 URL 抓取与 Block G 的快照类信号。
  2. 配置依赖config/profile.yml 是全部模式共用的个人数据真相源;scan.extractor: cli 是 opt-in 优化,缺省为 mcpspend_tier(economy/standard/premium)决定评估所用模型档位,但三档产出同一 A-H 报告结构modes/_shared.md)。
  3. 数据边界:抓取内容一律视为数据而非指令;黑名单、存活判定、分数门槛都是"闸门"而非评分输入;评估研究有 5 条 WebSearch 的硬上限且禁止嵌套子 agent。
  4. 不做什么:整条流水线永不代替候选人提交申请modes/_shared.md 的 NEVER 清单第 3 条);Step 4 只产出草稿答案,保存进报告而非填入线上表单。

延伸阅读路径

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384