我用 Go 写了个 AI 面试官:出题、追问、打分全自动(上篇)
📮 本系列首发于公众号「GO语言入门之路」,共三篇:上篇(本文)讲状态机与核心提示词设计,下篇讲简历解析与多轮记忆,第三篇讲网页版 SSE 实战。
金九银十刚过去,后台收到不少读者的留言:刷了三个月八股文,一到面试被追问「为什么」「那在高并发下呢」就露馅。
问题不在题量不够,而在没有人逼你往深处挖。于是我用 Go 写了一个「AI 模拟面试教练」:你输入目标岗位,它生成面试计划、按 plan 逐题提问,答得浅就追问,面试结束输出一份结构化的评分报告。
这篇文章是这个系列的上篇,讲清楚产品设计和核心代码。下篇接简历解析与多轮记忆。
一、为什么这不是一个「一问一答」的 chatbot
很多人第一反应是:这不就是一个循环调大模型的 while 循环吗?真不是。区别在于它有一个面试状态机,每一轮要同时做三件事:
- 按计划推进:面试题不是现场随便出的,开场前已经生成好一份面试计划(plan),后面每问一题都对照 plan;
- 动态决策:用户答完一轮后,先做一次「评估」,判断这一题是挖到位了,还是该追问一层;
- 持续记录:评估结果结构化地存下来,面试结束才能聚合成分维度评分,而不是笼统一句「表现不错」。
对话流大概长这样:
输入岗位 → 生成面试计划(能力维度+题目清单)
↓
按 plan 提问 → 用户作答 → 评估(置信度+关键点覆盖度)
↓ ↓
深度不够 → 基于原题追问一轮
深度达标 → 记录评分 → 下一题
↓
全部问完 → 聚合输出评分报告(Markdown)
这个状态机的实现只有薄薄一层 Go 代码,难的在提示词设计,下面逐个讲。
二、出题:先建能力模型,再生成面试计划
AI 面试官最容易翻车的地方,是题目东一榔头西一棒子,问完 GMP 又问 React。解法是先建一个岗位能力模型(rubric),把岗位拆成维度,再让模型按维度出题。
以「高级后端工程师」为例,rubric 长这样:
| 能力维度 | 权重 | 考察要点 | 出题深度 |
|---|---|---|---|
| Go 语言内核 | 25% | GMP 调度、GC、channel 底层 | 能讲清原理 + 能分析取舍 |
| 并发与性能 | 20% | 锁、原子操作、pprof 调优 | 有真实调优案例 |
| 分布式系统 | 20% | 一致性、幂等、限流熔断 | 能设计 + 能扛追问 |
| 工程化 | 20% | 微服务治理、可观测性 | 落地经验 |
| 系统设计 | 15% | 高并发架构、容量估算 | 完整的权衡过程 |
有了 rubric,出题的 system prompt 就非常具体了(关键片段):
const planPrompt = `你是资深技术面试官。目标岗位:%s。
请输出面试计划(JSON):每个能力维度 1~2 题,每题包含
题目、考察要点(checkpoints, 3~5条)、评分标准。
要求:题目由浅入深;checkpoints 必须具体、可验证,
不许出现"考察基础"这类空话。`
注意这里要求模型自己列出 checkpoints——它们是后面「追问判断」的依据,等于把评分标准提前从模型嘴里「套」了出来。
三、追问:判断回答深浅的两把尺子
追问是面试官的灵魂,也是这个 Agent 和普通 chatbot 最大的分水岭。判断逻辑在 system prompt 里,核心是两把尺子:
| 信号 | 含义 | 追问动作 |
|---|---|---|
| 自评置信度 | 让模型给自己这个回答打 1~5 分,低于阈值说明它自己都觉得虚 | <3 分 → 必追问 |
| 关键点覆盖度 | 对照该题 checkpoints,用户命中了几条 | 覆盖率 <60% → 追问缺失点 |
| 追问过的题 | 同一题最多追问 2 轮,防止无限套娃 | 已追问 2 次 → 直接下一题 |
评估用的提示词(关键片段):
const evalPrompt = `评估用户对面试题的回答。
题目checkpoints: %s;用户回答: %s。
按 JSON 输出:confidence(1-5 自评)、
coverage(命中checkpoints比例0-1)、
hitPoints(命中的要点)、missed(缺失要点)、
suggestion(一句话改进建议)。
只输出 JSON。`
追问时把 missed 要点喂回去:「你刚才没提到 %s,能结合你的项目展开讲讲吗?」——追问是有方向的,不是复读机式地说「再详细点」。
四、打分:用 JSON Schema 锁死输出格式
面试结束要出报告,最大的坑是模型输出格式漂移:这次给你 JSON,下次塞两句解释,解析直接崩。用 response_format + JSON Schema 把输出锁成合法的 JSON,Go 侧用 struct 一一对应解析。
评分报告的 schema 设计:
| 字段 | 类型 | 说明 |
|---|---|---|
| dimensions | array | 各能力维度:name / score(0-100) / comment |
| weakPoints | array | 薄弱点清单 |
| suggestions | array | 可执行的改进建议 |
| overall | number | 总分 |
Go 侧的解析和渲染(关键片段):
type Report struct {
Dimensions []struct {
Name string `json:"name"`
Score int `json:"score"`
Comment string `json:"comment"`
} `json:"dimensions"`
WeakPoints []string `json:"weakPoints"`
Suggestions []string `json:"suggestions"`
Overall int `json:"overall"`
}
// 解析后直接渲染成 Markdown 表格,落盘 report.md
SDK 用的是官方 openai-go(2026-11-02 从官方 GitHub releases 核对的最新版本 v3.91.1,要求 Go 1.26+,核对自 go.mod)。国内模型走 OpenAI 兼容端点,换 baseURL 和模型名即可,代码不用动。
五、跑起来的效果
命令行版的完整交互大概是这样:
$ go run ./cmd/coach
目标岗位: 高级后端工程师
[Q1/Go语言内核] GMP 模型里为什么要有 P 这一层?
> (你的回答……)
[追问] 你说本地队列减少全局锁竞争,那 P 上的队列满了会怎样?
[Q2/并发与性能] 你项目里出现过哪些 goroutine 泄漏?怎么发现的?
……
面试结束。生成报告: report.md
report.md 就是按维度打分 + 薄弱点 + 建议的 Markdown,可以直接贴进笔记软件对照着补。
六、总结与预告
这篇文章的核心就三件事:先用 rubric 建能力模型生成面试计划,再用「置信度 + 关键点覆盖度」两把尺子决定追问还是放行,最后用 JSON Schema 锁死评分报告的格式。整套状态机加提示词,不到 300 行 Go 代码。
下篇接入简历解析:面试官先读你的简历,再针对性出题——「你简历里写了做过百万级 QPS 网关,那我们来聊聊它的限流设计」。
相关阅读:AI 面试官先读简历再出题:Go 简历解析实战(下篇) · 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+,核对自仓库 go.mod;官方文档:pkg.go.dev/github.com/openai/openai-go/v3) - 安装命令:
go get github.com/openai/openai-go/v3@v3.91.1
本文系 AI 辅助生成,内容已经人工核对,如有错误欢迎评论区留言指正。
- 《Go 程序设计语言》(Go 语言圣经,机械工业出版社) —— Go 官方团队出品,公认入门第一书
- 《Go 语言实战》(异步图书,人民邮电出版社) —— 实战导向,面试前巩固工程手感
- 《Go 语言编程之旅:一起用 Go 做项目》(博文视点,电子工业出版社) —— 项目驱动入门,从零写出完整应用
- Keychron K1Max 矮轴机械键盘(Mac/Win 双系统,QMK/VIA 开源改键) —— 轻薄矮轴 + 开源固件,程序员桌面常客
- 罗技 MX Master 3S 无线鼠标(Flow 跨屏,静音电磁滚轮) —— 人体工学设计,写代码一整天手不酸
以上链接含京东联盟推广代码;通过链接购买本站可能获得少量佣金,不影响你的购买价格。
每周更新 Go + AI 应用开发实战:AI 面试官完整项目、MCP、Agent 工程化,完整源码随文章首发。
微信扫码,或搜索「GO语言入门之路」关注,第一时间获取系列更新与源码,不再错过任何一篇。