ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

中文简历怎么喂:把AI求职工具的语义匹配调顺,先做对三件事

中文简历怎么喂:把AI求职工具的语义匹配调顺,先做对三件事

中文简历怎么喂:把AI求职工具的语义匹配调顺,先做对三件事

【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-job-search

2026 年,ai-job-search频繁登上 GitHub Trending——一个把 Claude Code 变成"求职工作区"的开源框架:/scrape搜职位、/rank批量打分、/apply生成定制化简历与求职信、/interview做面试准备。社区里大量文章都在讲怎么配模型、调参数、写 prompt,但很多人忽略了一个更前置的问题:简历本身是怎么被"喂"进这个系统的。

这个框架的匹配链路是"输入 → 语义评分 → 输出材料",而评分质量的上限在输入端就定死了。项目作者(一位被裁的地球物理学家)用这套工作流投出 69 份申请、拿到 20 个一面并成功转行 AI 工程师,他在 README 里反复强调一个经验:输出质量的单一最大变量,是你往 profile 里塞了多少细节。

对中文用户来说,"喂简历"这件事有三层坑:格式层(PDF 文本层陷阱)、语义层(中文术语与 JD 字段的映射)、质量层(评分框架对输入的隐含要求)。这篇文章直接对着仓库源码讲清楚这三件事,读完你就能在动任何参数之前,先把输入侧调顺。

一、简历格式:为什么纯文本比 PDF 更稳

/setup到底能"读"什么

/setup是框架的入职入口,它扫描documents/目录来构建你的候选画像。这个目录能吃什么格式,直接决定了你的简历能不能被正确消化。documents/README.md 里写得很直白:

格式/setup可读性说明
.pdf可读直接用 Read 工具解析
.tex可读LaTeX 源码,结构与内容都可读
.md/.txt可读纯文本
.docx不可读必须先转成 PDF
.png/.jpg不可读扫描件不会被解析,必须用文本型 PDF

也就是说,一张用手机拍下来、或者扫描仪生成的简历图片,框架是"看不见"的——它根本没有文本层。而很多国产招聘网站导出的简历恰恰是这种格式。

为什么"ATS 视角"的 PDF 是稀缺资源

这个框架对 PDF 的警惕,比一般求职者深得多。.claude/commands/apply.md 的 Step 5d 明确写了一条铁律:ATS 解析器读的是 PDF 内嵌的文本层(text layer),不是渲染出来的页面。一份"看起来完美"的 PDF,文本层可能是一堆乱码。

仓库为此专门写了 tools/verify_pdf.py,用pypdf(优先)或 Popplerpdftotext抽取文本层做四类检查:

  • 联系信息必须是字面文本:模板里 fontawesome 图标抽出来是MOBILE-ALT、Envelope这类字形名,这是无害噪音;但只靠图标或超链接承载的邮箱,对 ATS 就是隐形的;
  • 无乱码残留:(cid:NNN)标记或�替换字符,说明字体嵌入时没有 Unicode 映射,ATS 看到的和你看到的完全是两份文件;
  • 阅读顺序正确:多栏模板会把不同区块的行交错抽出来;
  • 日期可识别:这是最阴险的一条。

中文简历最该避开的陷阱:日期与编码

.claude/skills/job-application-assistant/05-cv-templates.md 记录了一个真实事故:一份用 moderncv 模板生成的简历在 Workday 导入时,短合同的结束日期丢了、教育经历一条都没导进去,被迫手动重录。原因有二:

  1. LaTeX 的--会被合成一个 en-dash(U+2013),很多解析器只在 ASCII 连字符(U+002D)上切分日期区间,于是2016--2024在文本层里是2016–2024,解析器根本看不到一个区间。修复方式是日期参数只写单个连字符。
  2. 只写单个年份没有结束日期:\cventry{2016}导入后只有开始时间,没有关闭时间。

tools/verify_pdf.py里的--ascii-dates检查专门抓这个:它故意不做折叠,直接扫原始文本层里"年份 + Unicode 破折号"的组合。而normalize_text()函数把'映射回 U+2019、--映射回 U+2013、NFC 归一化——折叠只用于比较,绝不用于输出,因为"原始文本层"才是 ATS 真正看到的东西。

对中文用户,编码还有一层额外的雷:pdftotext若来自 Xpdf 系构建,默认按 Latin-1 输出。一份完全正常的中文 CV,在缺了-enc UTF-8的情况下读回来全是替换字符——而仓库明确要求 fallback 必须带-enc UTF-8。中文、日文这类 CJK 文本对编码错误的敏感度远高于西文。

结论很直接:往documents/cv/里喂简历,纯文本(.md/.txt)或文本型 PDF 最稳,扫描件和.docx是最差输入。如果你现有的中文简历是 Word 或扫描版,先在本地转成文本型 PDF 或纯 Markdown 再让/setup读,比事后排查匹配分数异常便宜得多。

二、中文岗位术语与JD字段的映射

框架如何理解"工作":按职能,不按职位名

框架对检索策略的设计有一个核心认知:同一个底层职能,在不同公司、不同市场有完全不同的职位名。.claude/skills/job-scraper/search-queries.md 开头就要求:

Organize by function, not job title. The same underlying work carries different titles across companies and markets (a "Data Scientist" role at one employer may be posted as "Insights Analyst" or "Data Consultant" at another).

评估侧同样如此——.claude/skills/job-application-assistant/04-job-evaluation.md 的 Experience Match 维度明确写着:匹配的是工作的职能与性质,而不是字面上的职位名("Data Consultant" 和 "Data Scientist" 可以是功能上完全相同的岗位)。

这对中文求职者是个好消息:国内 JD 里"数据挖掘工程师""算法工程师""BI 分析师""商业分析"经常描述同一类工作,框架的设计本来就不要求你押中某一个精确标题。你在/setup --section search里要做的,是描述"你每天真正想做什么",而不是背一串职位名。

检索词的多语言规则:翻译,不要机翻

search-queries.md有一条容易被中文用户忽略的规则:每个查询类别都要用 Languages 表里的每一种语言写一遍,并且要按语义翻译,而不是逐字机翻——它举的例子是"Frontend Developer"应该翻译成"Desarrollador Frontend",而不是逐字对译。

放到中文场景:一个中英双语求职者,/scrape的查询应当同时覆盖"机器学习"和"machine learning"、"大模型"和"LLM"、"后端开发"和"backend developer"。这一步不做,搜索面直接砍半。

这里还有一层更隐蔽的关联:查询语言与你声明的 Languages 表强相关。框架有个 Language Gate(后面细讲)会按你的语言表硬性过滤岗位——搜索词生成和语言过滤用的是同一份数据,语言表填得不诚实,检索和评分两头都会错。

Language Gate:中文简历必须如实填写的语言表

这是整个框架里对"中文用户"影响最大的一个机制。04-job-evaluation.md 的 Language Gate 在评分之前运行,逻辑只有三行:

JD 的语言要求 vs. 你的 Languages 表裁决
要求一种你根本没声明的语言(如"需要流利日语"而你表里没有日语行)FAIL,硬停,不评分、不起草
要求你声明过的语言,但要求等级("流利""native""C1+")读起来明显高于你声明的等级FLAG 后继续,不自动拒绝,但必须把差距显式呈现给你裁决
要求你声明过的语言、且等级不高于声明,或 JD 没写等级PASS

注意第一行的措辞:未声明的语言被当作硬性拒绝,而不是一个可以含糊过去的缺口。对中文用户这意味着两件事:

  1. 如果你把"中文"漏填了,一份要求"流利中文"的 JD 会被静默砍掉,而你根本不知道;
  2. 反过来,诚实声明自己的真实等级(比如英语 B1/B2)比虚标"fluent"更划算——虚标只会让你在 FLAG 名单上反复被要求人工裁决,而诚实声明 + 岗位要求更低时直接 PASS。

/setup的 Path C(访谈模式)和 Path A(文档模式)都会主动收集语言表,包括从 LinkedIn 导出的 Languages 区段。这是少数几个"填错代价极大、填对零成本"的字段。

关键词映射:用 JD 的原文词,别用同义词

/apply的最后一道关卡是 ATS 关键词覆盖检查(Step 5d),它把 JD 里的每个必选/优选词与抽取出的 CV 文本层逐一比对,给出四种状态:

状态含义
covered词原样出现(或微不足道的变形)
synonym-only概念存在,但用的是别的词
missing (have it)你确实有这个技能,但 CV 里没写
missing (gap)真缺口,保持缺失,绝不硬塞

规则原文有一句关键指导:"Prefer the posting's exact term over a synonym when it is truthfully applicable - ATS keyword matches are often literal."(当 JD 的原文词在事实上成立时,优先用原文词——ATS 的关键词匹配经常是字面匹配。)

放到中文 JD:岗位写"高并发",你的简历写"大流量系统",那是synonym-only——概念对上了,字面没对上;如果"高并发"确实是你真实做过的事,改写成"高并发系统"成本为零,收益是字面命中。岗位写"熟悉 Kubernetes",简历写"容器编排经验",同理。这个"事实成立就改用原文词"的规则,是中文简历语义映射里性价比最高的一步,因为它不需要你造假,只需要你把真话换一种更贴 JD 的说法。

与之配套的还有两个细节:

  • CV 语言是一个 profile 级设定(CV language:行,默认 English),所有 CV 保持一致;而求职信永远跟随每份 JD 的语言。给国内公司投递时,把CV language改成中文,并在 05-cv-templates.md 要求的范围内把模板里硬编码的英文章节标题(Professional Experience、Education等)一并翻译——该文件专门警告过:"CV 主体全中文化了,章节标题却还是英文模板默认值,读起来非常不专业,而且特别容易被遗忘,因为正文翻译才是显眼的部分。"
  • 多词短语缺词的误报:pypdf有时会在标点周围插入空格,导致一个词被拆成两截。中文分词尤其容易踩这个坑("机器学习"被抽成"机器 学习"),仓库的建议是在下结论前用另一个抽取器复核。

受控词表:中文检索时的隐性约束

如果你用仓库自带的freehire-search(多市场技术岗聚合器)搜中文市场的岗位,.agents/skills/freehire-search/SKILL.md 有两条硬约束:facets 是受控词表,不允许发明值(--region/--country/--city/--seniority/--category/--skill都有预定义枚举,比如--skill go,kubernetes),且地理位置是 facet 不是自由文本。也就是说,这套工具的检索粒度是英文词表驱动的,中文长尾岗位更多要靠search-queries.md里的site:查询兜底——这也是框架设计上的分工:CLI 负责结构化数据源,WebSearch 兜底长尾。

三、调参前先检查的输入质量清单

社区文章爱讲temperature、并发、模型选择,但仓库的设计文档反复指向同一个事实:评分框架的每一分,都是从你的 profile 里榨出来的。04-job-evaluation.md 的评分权重是:

  • Technical Skills:30%
  • Experience Match:25%
  • Behavioral Fit:15%
  • Career Alignment:30%

(Location 是 Pass/Fail,不参与加权;Language Gate 和 Eligibility Gate 在评分前硬过滤。)

三个维度加起来 85% 的权重直接依赖输入质量。动任何调参旋钮之前,先过一遍这份清单——每一条都能在源码里找到依据:

1. 事实三源一致性(Grounding Audit 的前置条件)

/apply的起草者(drafter)与评审者(reviewer)都会执行 Factual Grounding Audit:草稿里的每个日期、雇主、职位名、量化指标,必须能被 .claude/skills/job-application-assistant/01-candidate-profile.md、cv/main_example.tex 和根目录 CLAUDE.md 的 Candidate Profile 三源联合体中的任意一个支持。三源之间互相矛盾,会作为 profile-consistency warning 报告给你;草稿与三源不符,会被标记为 grounding 编辑。中文简历常见的坑是三个文件各写一版(Word 版、PDF 版、口头补充版日期对不上)——先把三处对齐,是调参的绝对前提。

2. Languages 表如实填写(决定生死)

如前述,未声明语言 = 硬拒。这一步的投入产出比最高。

3. 角色描述写"做了什么",不要只写职位名

README 的 "Profile depth matters" 一节给出了唯一一个被反复强调的经验法则:输出质量的单一最大变量是 profile 的详细程度。它的例子是——"Built ML pipelines for customer churn prediction in Python using scikit-learn"给系统的素材,远多于"Python, machine learning"。中文场景同理:"用 PyTorch 做过推荐系统,处理过日均亿级请求"比"熟悉深度学习"有价值一个数量级。特别是中文简历里常见的四字形容词("沟通能力强""抗压性好"),对语义评分基本是零信号,框架的 Behavioral 维度靠的是 02-behavioral-profile.md 里结构化记录的行为特质,而不是 CV 上的自我评价。

4. Deal-breakers 和 Career Goals 不能空

评分框架里 "Deal-breakers" 是自由文本,04-job-evaluation.md 说得很清楚:"Strong parental-leave terms"、"minimum salary X"、"no on-call"——每一条都是一行 profile、零代码、在/rank和/apply里有真实否决权。中文用户常见的"不加班""不接受异地""薪资底线 X"都应该落成这行字,而不是只存在于对话里。

5. 关键词覆盖遵循诚实规则

missing (gap)永远保持缺失,绝不硬塞(never stuff)。JD 要求的技能你确实没有,正确做法是在求职信里诚实承认差距并给出桥接表述("not in my daily toolkit yet; a natural extension of X"),而不是往 CV 里堆词——因为评审者 agent 会做 grounding 审计,假词活不过第二轮。

6. 数据闭环:结果要回填

最后一条常被忽略:/outcome记录每份申请的结果(面试阶段、offer、拒绝、沉默),并把已投递的 CV、求职信、JD 原文归档到documents/applications/<company>_<role>/;而/setupPath A 会从这些归档里校准评分框架(哪些角色类型和行业真正拿到了面试、哪些反复无回应)。中文求职者尤其应该利用这条:国内招聘的"已读不回"比例高,/outcome followup还能帮你把沉默超过 10 天的申请捞出来。跑三轮申请后再回炉/setup,比闷头调 prompt 有效得多。


三件事的顺序就是优先级:先保证简历以可解析的文本形态进系统(格式层),再按 JD 原文词与语言表对齐语义(映射层),最后过一遍输入质量清单让评分框架有料可榨(质量层)。这三层做对了,temperature高低、模型选谁、并发调多少,才有讨论的意义。反过来,输入侧一塌糊涂,任何参数调优都是在给一个有缺陷的管道加马力。

这套框架的定位从来不是"AI 替你投简历",而是"AI 做你的求职信息预处理器"——预处理的边界,就是你的输入质量。

【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-job-search

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进