AI 面试官先读简历再出题:Go 简历解析实战(下篇)
📮 本系列首发于公众号「GO语言入门之路」。上篇见 我用 Go 写了个 AI 面试官:出题、追问、打分全自动(上篇)。
上篇我们搭好了 AI 模拟面试教练的骨架:出题、追问、打分全自动。但很多读者反馈一个问题:通用题太泛了,面试官应该先看我的简历,再针对我的项目问。
这就是下篇要解决的:接入简历解析(PDF 文本提取 → 模型摘要 → 针对性出题),加上多轮记忆(面试可以今天面一半、明天接着面)。
一、简历解析:为什么不让模型直接读 PDF
大模型 API 吃的是文本,而简历大多是 PDF。两条路:
| 方案 | 做法 | 评价 |
|---|---|---|
| 多模态上传 | 把 PDF 当图片/文件直接传给多模态模型 | 贵、慢,而且很多兼容端点不支持文件上传 |
| 本地提取文本 | 纯 Go 库提取文本,再把文本喂给模型 | 便宜、快、可控,我们的选择 |
选本地提取后,库怎么选又是第二个坑:
| 库 | 特点 | 结论 |
|---|---|---|
ledongthuc/pdf |
纯 Go、无 CGO、API 简单 | ✅ 选用,交叉编译无压力 |
pdfcpu |
功能全,但偏文档处理 | 提取文本不是它的主战场 |
调用 pdftotext |
准确率高 | 引入外部二进制依赖,部署麻烦 |
二、提取 + 摘要:让模型只读精华
直接拿提取出的几千字简历原文塞进出题提示词有两个问题:费 token,而且长文本会稀释出题指令。所以提取之后先让模型生成一份结构化摘要,只把摘要注入出题提示词:
// internal/resume/resume.go
func Summarize(ctx context.Context, s Summarizer, pdfPath string) (*Summary, error) {
text, err := ExtractText(pdfPath) // 纯 Go 提取,逐页拼接
if err != nil {
return nil, err
}
// 摘要而非全文进提示词:省 token,也避免长文本稀释指令
var sum Summary
err = s.ChatJSON(ctx, system, fmt.Sprintf("输出结构化摘要(JSON):"+
"skills、projects(名称/技术栈/量化亮点)、suspect_points(需要验证的可疑点)…\n%s",
truncate(text, 6000)), "resume_summary", "简历结构化摘要", summarySchema, &sum)
return &sum, err
}
注意 suspect_points 这个设计:让模型自己列出简历里可疑的点——量化数据是否夸张、技能与年限是否匹配。这些点就是简历深挖题的弹药。
三、针对性出题:面试官的"你简历里写了……"
有了摘要,出题提示词里追加一段指令即可(关键片段):
// internal/coach/prompts.go
if resume != "" {
user += fmt.Sprintf(`另附候选人简历摘要,请额外生成 2~3 道基于简历的
深挖题(source 标 "resume"):针对简历中的项目经历、技术栈和量化成果提问,
验证其真实性。禁止问候选人明显不具备的技能。简历摘要:%s`, resume)
}
效果就是面试时你会看到带 (简历深挖) 标记的题目,比如:「你简历里写了做过百万级 QPS 的订单网关,那我们来聊聊它的限流设计」。这类题在真实面试里杀伤力最大,也是通用八股文给不了的。
四、多轮记忆:今天面 3 题,明天接着面
真实面试不会 10 分钟草草结束,但命令行版很可能被 Ctrl+C 打断。所以每答完一题就把面试状态落盘,下次 coach continue 从断点续面:
// internal/coach/state.go
func Save(st *State, path string) error {
b, _ := json.MarshalIndent(st, "", " ")
tmp := path + ".tmp"
os.WriteFile(tmp, b, 0o600)
return os.Rename(tmp, path) // 原子替换,写一半断电不损坏状态
}
State 里存了面试计划、当前题号、已完成的问答记录(含每轮评估),恢复后连之前的评估上下文都在——模型做最终打分时能"记得"你前面所有的回答。
五、工程结构与验证方式
工程结构如下,完整工程正在整理开源中,仓库地址将随后续更新放出:
cmd/coach/ 命令行入口(交互问答循环)
internal/coach/ 面试状态机:计划/评估/追问判断/状态持久化
internal/llm/ openai-go v3 封装(JSON Schema + 纯文本)
internal/resume/ PDF 文本提取 + 简历结构化摘要
internal/report/ 评分报告 Markdown 渲染
跑法:
export OPENAI_API_KEY=你的Key
go run ./cmd/coach new --pos "高级后端工程师" --resume ./resume.pdf
# 面到一半退出,下次:
go run ./cmd/coach continue
没有 Key 也能验证:所有 LLM 调用都走 llm.Client 接口,测试里用 Mock 客户端驱动完整状态机(追问 → 套娃上限 → 强制放行 → 状态恢复),go test ./... 全绿才敢发出来。
六、踩坑清单
| 坑 | 现象 | 解法 |
|---|---|---|
| 扫描件简历 | 提取出来是空字符串 | 检测空文本并报错提示需先 OCR |
| 追问无限套娃 | 同一题被追问十几轮 | MaxFollowUpsPerQuestion=2 硬上限 |
| 追问没方向 | 模型复读"再详细点" | 把 missed checkpoints 换成本轮考察标准 |
| 状态写坏 | 断电后无法续面 | 临时文件 + os.Rename 原子落盘 |
| 简历稀释指令 | 题目质量下降 | 只注入摘要,且截断到 6000 字符 |
七、总结
下篇做完了两件事:简历解析让出题从「通用八股」变成「针对你的项目深挖」,多轮记忆让面试可以跨天进行。整套工程不到 800 行 Go,核心逻辑全部有测试覆盖。
相关阅读:我用 Go 写了个 AI 面试官:出题、追问、打分全自动(上篇) · AI 面试官网页版实战:Go + SSE 流式输出(三)
版本说明
- openai-go:v3.91.1(2026-11-02 核对自 github.com/openai/openai-go 的 releases 页;module 路径
github.com/openai/openai-go/v3,要求 Go 1.26+) - ledongthuc/pdf:官方仓库无 releases/tag,版本号未核实,安装请用
go get github.com/ledongthuc/pdf@latest
本文系 AI 辅助生成,内容已经人工核对,如有错误欢迎评论区留言指正。
- 《Go 程序设计语言》(Go 语言圣经,机械工业出版社) —— Go 官方团队出品,公认入门第一书
- 《Go 语言实战》(异步图书,人民邮电出版社) —— 实战导向,面试前巩固工程手感
- 《Go 语言编程之旅:一起用 Go 做项目》(博文视点,电子工业出版社) —— 项目驱动入门,从零写出完整应用
- Keychron K1Max 矮轴机械键盘(Mac/Win 双系统,QMK/VIA 开源改键) —— 轻薄矮轴 + 开源固件,程序员桌面常客
- 罗技 MX Master 3S 无线鼠标(Flow 跨屏,静音电磁滚轮) —— 人体工学设计,写代码一整天手不酸
以上链接含京东联盟推广代码;通过链接购买本站可能获得少量佣金,不影响你的购买价格。
每周更新 Go + AI 应用开发实战:AI 面试官完整项目、MCP、Agent 工程化,完整源码随文章首发。
微信扫码,或搜索「GO语言入门之路」关注,第一时间获取系列更新与源码,不再错过任何一篇。