系列收官:把这个 Go 写的 AI 面试官改成你的 Agent(八)


📮 本系列首发于公众号「GO语言入门之路」,系列聚合目录。前文见 第四篇 ~ 第七篇:SQLite 记忆。

八篇了。从第一晚 200 行的命令行脚本,到今天飞书 + 网页双端、语音作答、7×24 部署、历史落库的完整产品——代码量翻了几倍,但有一个数字始终是零:核心状态机被改动的次数。

你可能根本不想做面试教练。没关系,这篇收官之作就是给你一把手术刀:fork 这个仓库,动哪几层、怎么动,把它改成属于你的垂直场景 Agent。

八篇演进回顾:加的一直是"外壳",不是"内脏"

先把全貌摆出来。回看整个系列,每篇新增的其实只有一类东西——I/O 适配层:

篇 新增能力 动的层
一 CLI 核心:出题、追问、打分 状态机 + LLM 封装
二 简历 PDF 解析,针对性出题 状态机输入 + 一个新包
三 Web 版 + SSE 流式点评 web/ 适配层(新增)
四 飞书机器人,长连接零公网 IP bot/ 适配层(新增)
五 语音作答(ASR) bot/ + asr/(新增)
六 systemd 部署 + token 成本监控 deploy/ + 计数器
七 SQLite 历史落库 +「历史」指令 store/(新增)

这个演进的秘密在于第一篇文章立下的架构决定:internal/coach 状态机只依赖 llm.Client 接口,不认识 HTTP、不认识飞书、不认识麦克风。之后每接一个新端,都是"外面包一层、里面一行不动"。改造别人的 Agent 项目,先看它的状态机有没有被 I/O 污染——这是判断代码值不值得 fork 的第一标准。

四层解剖:你的改动落在哪一层

整个项目四层,自下而上:

  1. LLM 与存储底座:internal/llm(openai-go v3 封装,JSON Schema/流式/用量统计)、internal/store(modernc.org/sqlite,纯 Go 无 CGO)、internal/asr。这层几乎不用动。
  2. 领域状态机:internal/coach。计划 → 评估 → 追问 → 报告的状态流转,加上全部提示词(集中在 prompts.go)。这是改造的主战场。
  3. 会话路由与指令:internal/bot。IM 交互逻辑:谁正在面试、指令解析、列表序号缓存。
  4. I/O 适配:internal/web、internal/bot/lark.go。换平台动这里。

依赖方向严格单向:上层可以知道下层,反过来不行。第七篇的 Store 接口定义在 bot 侧而不是 store 侧,也是同一个原则。

改造对照表:三个垂直场景各动哪几层

这是本篇的收藏点。三个典型 fork 方向,逐层标注改动量:

层 英语口语陪练 公务员结构化面试 技术 Quiz 刷题机
coach/prompts.go 全换:面试官→口语教练,评估尺子从"要点覆盖"换成"语法/流利度/用词" 大改:换成结构化题型(综合分析/应急应变等),rubric 固定为评分标准 全换:去掉追问逻辑相关的评估项
coach 状态机 不用动 不用动 小改:去掉追问分支
Schema 换字段(fluency/grammar/pronunciation) 换字段(按公考评分要素) 简化
bot 指令 不用动 不用动 「历史」改名「错题本」即可
ASR 语音 必需(已经是核心链路) 可选 不需要
store 不用动 不用动 不用动

看出规律了吗:三个场景里 store、bot、状态机全部复用,要写的只有提示词和 JSON Schema。这正是"产品级 Agent"和"玩具 demo"的分水岭——demo 把提示词焊死在流程里,产品把领域知识集中在可替换的一层。

动手示例:把"技术面试官"改成"口语陪练"

以第一个场景为例,实际改动从 prompts.go 的评估提示词开始——评估尺子变了,追问判断的依据就跟着变:

// 改前(技术面试):评估依据是 checkpoints 覆盖度
// user := 面试题 / 考察要点 / 候选人回答 → confidence、coverage、missed…

// 改后(口语陪练):评估依据是语言质量三要素
const system = `你是严格的英语口语教练,只依据语言事实评估,不许给安慰分。`
user := fmt.Sprintf(`话题:%s
学员表达:%s
按 JSON 输出评估:fluency(流利度1-5)、grammar(语法准确度1-5)、
vocabulary(用词丰富度1-5)、errors(列出 3 处最需要改的错误)、
suggestion(一句可执行的练习建议)、depth_ok(本话题是否练到位)。只输出 JSON。`,
    topic, speech)

配套做两件事:EvalSchema 换成新字段;ShouldFollowUp 的阈值从 coverage 换成三要素均分(比如 < 3.5 就追问"能不能换个说法再说一遍")。改完跑 go test ./internal/coach/——Mock 客户端会告诉你状态机有没有被改坏。

三个值得带走的设计决策

最后沉淀三条这个系列反复验证过的经验:

  1. 接口定义在消费侧。bot 定义 Store、定义 Interview,实现方单向依赖。换存储、换状态机都是新增而不是修改。
  2. 所有能力可选注入。meter 传 nil 就不统计用量,store 传 nil 就没有历史——每个功能都能独立关闭,调试和降级都简单。
  3. 副作用不许反噬主流程。落库失败附一行警告,报告照样发出;ASR 没配置就优雅拒绝语音。Agent 上线后最贵的故障都是"次要功能拖死主要功能"。

系列完结

八篇,从 coach new --pos 的第一行输出,到飞书里一句「历史」调出三周前的面试报告。完整代码正在 GO2AI-CN 组织下整理开源(仓库名:ai-interview-coach),开源后欢迎 fork 改造成你自己的 Agent。

这个系列到此完结。后续内容将转向 MCP 协议与 Agent 工程化的新系列——把面试教练里埋的伏笔(工具调用、记忆、多 Agent)一个个展开讲透。

相关阅读:系列聚合目录 · 上篇:状态机与核心提示词 · 第七篇:SQLite 记忆

版本说明

  • openai-go:v3.97.0(2026-11-09 核对自 github.com/openai/openai-go 的 releases 页;module 路径 github.com/openai/openai-go/v3,要求 Go 1.26+)
  • modernc.org/sqlite:v1.61.1(2026-11-06 核对自 Go Module Proxy)
  • larksuite/oapi-sdk-go/v3:v3.12.2(2026-11-05 核对自 GitHub tag 列表)

本文系 AI 辅助生成,内容已经人工核对,如有错误欢迎评论区留言指正。

🛒 站长推荐(京东联盟)

以上链接含京东联盟推广代码;通过链接购买本站可能获得少量佣金,不影响你的购买价格。

📮 关注公众号「GO语言入门之路」
GO语言入门之路 公众号二维码

每周更新 Go + AI 应用开发实战:AI 面试官完整项目、MCP、Agent 工程化,完整源码随文章首发。

微信扫码,或搜索「GO语言入门之路」关注,第一时间获取系列更新与源码,不再错过任何一篇。

wx

关注公众号

©2017-2026 鲁ICP备17023316号-1 Powered by Hugo · 隐私政策