乐于分享
好东西不私藏

拿简历PDF喂了LLM,搞了个带GitHub评分和扣分项的评估工具

拿简历PDF喂了LLM,搞了个带GitHub评分和扣分项的评估工具

不是那种糊弄人的AI筛选,是真正把简历拆开、对照代码库、给出一份带证据链的评估报告


上个月帮朋友团队看简历,几十份PDF翻得眼花。后来发现他们内部其实有个叫Hiring Agent的开源项目,能把简历解析、结构化、再结合GitHub信息给出一份评分报告。我本地跑了一遍,觉得挺有意思,干脆写篇文章详细拆解一下。


这玩意儿到底在干什么

简单说,你把一份简历PDF丢进去,它做四件事:

  1. 把PDF转成Markdown文本(保留了标题层级和段落)
  2. 用LLM按模块提取JSON(教育背景、工作经历、技能、奖项……每一个模块单独调用)
  3. 如果简历里有GitHub链接,它会去抓profile和最近的项目代码库
  4. 最后生成一份评估报告:每个维度有评分、有证据引用、有加分项和扣分项

而且它支持本地跑(Ollama)或者用Google Gemini,不需要把简历上传到某些不可控的云服务。


代码结构长什么样

项目是Python写的,核心模块分得挺清楚:

  • pymupdf_rag.py —— PDF转Markdown的工具,依赖PyMuPDF。
  • pdf.py —— 用Jinja模板组装提示词,按章节逐个调用LLM。
  • github.py —— 获取GitHub个人资料和仓库列表,把项目分类,让LLM挑出最相关的7个。
  • evaluator.py —— 严格执行评分规则,有公平性约束(比如不能因为性别、学校名字给加分)。
  • score.py —— 端到端的入口,开发模式下会写CSV方便调试。

还有几个辅助文件:

  • models.py —— Pydantic数据模型,定义了LLM返回的JSON结构。
  • llm_utils.py —— 处理不同提供商的初始化和返回结果清洗。
  • transform.py —— 把LLM偶尔抽风输出的非标准JSON转成标准格式。
  • prompts/ 目录 —— 全是Jinja模板,每个模块(basics.jinjaeducation.jinjawork.jinja……)都有自己的提示词模板,方便调优。

工作流一步步走

第一步:PDF解析

pymupdf_rag.py 把PDF每一页的内容转成类似Markdown的纯文本,保留标题和段落结构。这一步不依赖LLM,纯本地处理。

第二步:分模块解析

pdf.py 拿到文本后,会按章节切分,然后逐个调用LLM。比如先解析基本信息(姓名、邮箱、GitHub链接),再解析教育经历、工作经历、项目、技能、奖项。每个模块都有独立的Jinja模板,提示词里明确要求返回JSON格式。

好处是每个模块可以独立调优,某个模块抽风不会影响其他模块。

第三步:GitHub增强

如果解析出来的基本信息里有GitHub个人主页链接,github.py 就去抓:

  • 用户公开资料(bio、location、公司等)
  • 仓库列表(按语言分类,过滤掉fork)
  • 然后让LLM根据项目描述和技术栈,选最相关的7个项目

这一步不是为了堆数量,而是筛选出最能代表候选人能力的项目。

第四步:综合评估

evaluator.py 把上面所有数据汇总,用一套严格的评分规则打分。规则写在提示词里,包括:

  • 每个维度(技术深度、项目复杂度、代码质量、文档习惯等)有明确的评分标准
  • 必须有证据引用(比如“GitHub上XX项目的commit记录显示……”)
  • 加分项和扣分项要具体说明原因
  • 禁止使用性别、年龄、学校排名等偏见过滤

最后生成一份可读的Markdown报告。

第五步:输出与缓存

score.py 是总入口,跑完会打印报告。开发模式(config.pyDEVELOPMENT_MODE = True)下,还会把提取的中间结果缓存到cache/目录,并在resume_evaluations.csv里追加一行,方便批量对比调试。


本地安装和配置

前提是Python 3.11.13(项目里锁了这个版本,建议保持一致)。

第一步:克隆并建虚拟环境

git clone https://github.com/interviewstreet/hiring-agent
cd hiring-agent
python -m venv .venv
source .venv/bin/activate   # Windows用 .venv\Scripts\activate
pip install -r requirements.txt

第二步:选LLM后端

  • 用Ollama(本地):去官网安装,然后拉模型,比如ollama pull gemma3:4b。配置低的机器可以拉1b版,配置高的可以拉12b。
  • 用Google Gemini:得有API key。

第三步:配置环境变量

cp .env.example .env

编辑.env,设置LLM_PROVIDER(ollama或gemini)和对应的DEFAULT_MODELGEMINI_API_KEY(如果用的话)。

GITHUB_TOKEN是可选的,但建议填上,不然GitHub API有频率限制。

第四步:跑起来

python score.py /path/to/resume.pdf

如果简历里有GitHub链接,它会自动抓取并缓存,第一次可能会慢一点。


几个让我觉得设计得好的地方

  • 缓存机制 —— 开发模式下,PDF解析结果和GitHub数据都会缓存,调试的时候不用反复请求LLM和GitHub API,省时间省钱(如果是付费API)。
  • 模块化提示词 —— 每个章节单独模板,改提示词不用动代码,还能针对不同岗位类型(比如前端/后端/算法)调整模板。
  • 严格评分+证据链 —— 不是只给一个总分,而是每条评分都写了“为什么给这个分”,比如“该候选人在XX仓库中有完善的单元测试,代码注释清晰,因此加分”。
  • 本地运行支持 —— 用Ollama的话,所有数据不出本地,对数据敏感的公司特别友好。

可能踩的坑

  • PDF格式要规范 —— 如果是扫描件或图片型PDF,pymupdf_rag提取出来是乱码,目前项目没有集成OCR,所以只能用文字型PDF。
  • GitHub Token限流 —— 不填token的话,匿名请求一小时只能60次,如果有多个简历要跑,建议填上。
  • 大模型输出不稳定 —— 虽然用了Pydantic约束,但有些模型(尤其是小尺寸的)偶尔返回格式不对,transform.py会尽力修复,但偶尔还是会失败,这时候可以换个模型试试。
  • 内存占用 —— 用12b模型本地跑,建议16G以上内存,4b模型相对友好。

适合谁用

  • 小团队想自动化初筛简历,但又不想把数据交给第三方SaaS。
  • 对候选人的GitHub代码质量有要求的岗位(技术岗)。
  • 想批量评估简历、做横向对比的HR或技术负责人。
  • 对AI提示词工程感兴趣,想拿这个项目当样例来学习。

最后说两句

这个项目不是那种“一键淘汰90%简历”的黑盒工具,它更像一个结构化的信息汇总器 + 初步评估助手。最终决策权还是在你手上,但它能帮你把简历里的信息跟实际代码产出联系起来,减少拍脑袋打分。

我本地跑了几份简历,发现它真的会去读你的commit message和代码文件结构,有些细节自己写简历都忘了,它倒给扒出来了。挺实在的。

项目地址:https://github.com/interviewstreet/hiring-agent
有兴趣的可以自己clone下来跑跑看,记得改改提示词模板里的评分标准,匹配自己的岗位要求。


题外话:如果你跑通了,可以试着把prompts/templates/resume_evaluation_criteria.jinja里的评分维度改成你团队最看重的几点,效果会更贴切。