这次我们来看一个很有意思的 AI 项目实验:做一个招聘网站,但网站上的雇主不是真人,而是 AI Agent。整个流程里,求职者在和一个“数字 HR”对话,投递简历、回答初筛问题、甚至完成一轮面试。标题里最关键的是后半句——Here's what broke,也就是“哪些环节真的跑崩了”。
这个实验的价值不在于“AI 能不能替代 HR”,而在于它把 AI Agent 放进一个真实业务闭环里,暴露了大量工程化问题:异步回调超时、上下文断裂、状态机错乱、模型幻觉、防刷与身份冒用、批量任务不可控。这些问题不是招聘网站独有,几乎所有接了大模型 API 的多 Agent 应用都会遇到。
这篇文章会把项目拆开来看:它做了什么、架构怎么组织、最容易出问题的是哪几个环节、复现这个实验需要准备什么环境、以及如果你想在自己的系统里做类似的 AI 自动化流程,应该从哪些地方开始验证和加固。
1. 项目核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | AI Agent 驱动的自动化招聘平台实验 |
| 核心对象 | 求职者与 AI 雇主代理之间的双向交互 |
| 主要功能 | 职位发布解析、简历投递处理、AI 初筛对话、候选人评估、通知触达 |
| AI 能力 | 文本理解、意图判断、多轮对话、结构化信息提取、打分评估 |
| 自动化程度 | 雇主侧基本无人值守,靠 Agent 自动完成筛选和沟通 |
| 人工介入点 | 最终录用决策、争议申诉、异常会话兜底 |
| 本地复现难度 | 中高,需要大模型 API、消息队列、任务数据库 |
| 批量任务 | 支持批量处理职位和候选人,但必须控制并发 |
| 接口 API | 职位发布、会话记录、评估结果均可通过服务接口读取 |
| 潜在风险 | 身份冒用、简历隐私、模型误判、自动化沟通失控 |
这个项目不是一个大而全的招聘 SaaS,而是一个“如果雇主方完全交给 AI,会发生什么”的工程实验。它更适合被当做一个多 Agent 业务系统的最小可行产品来研究,而不是直接商用的产品。
2. 系统在解决什么问题
传统招聘网站的信息流是这样的:雇主发布职位,求职者投递简历,HR 人工筛选并沟通。整个过程里,雇主侧的人力成本集中在前期的简历筛选、消息回复、初步面试安排。这个实验把雇主侧的大部分重复性工作扔给了 AI Agent。
实验中的 AI 雇主大概承担这样几条链路:
- 解析雇主上传的职位要求,形成结构化的筛选标准。
- 在求职者投递后,自动读取简历并抽取关键字段。
- 基于职位要求向候选人提出个性化初筛问题。
- 根据候选人的回答和简历内容生成评估摘要。
- 将匹配度高的候选人推进到下一轮,并发送通知。
从表面看,这些链路每一段都能用大模型 API 实现。但组合成一个异步系统后,问题就开始暴露:Agent 不是只处理一个候选人,而是同时处理几十个候选人;不是只完成一轮对话,而是要保持多轮上下文;不是只输出一段文字,而是要输出可解析、可入库、可追溯的结构化结果。
这就是项目真正值得研究的点:单轮 Prompt 调用是一回事,把 Agent 放进生产链路是另一回事。
3. 典型技术架构与关键链路
根据这类 AI Agent 招聘系统的主流设计思路,整套系统可以拆成五个模块。
3.1 职位解析模块
雇主输入职位描述,Agent 解析出职位名称、经验要求、技能清单、薪资范围、城市、学历要求等字段。这部分使用的是结构化输出能力,适合用 JSON Schema 约束模型返回格式。
{ "job_title": "后端工程师", "years_experience": "3-5年", "skills": ["Python", "FastAPI", "PostgreSQL"], "education": "本科及以上", "city": "上海", "salary_range": "25k-40k", "questions": [ "请描述一个你处理过的线上故障", "你如何设计一个高并发接口" ] }3.2 简历解析与匹配模块
候选人投递简历后,系统从中抽取教育经历、工作经历、技能标签、项目经历,与职位要求做匹配打分。为了让结果可复核,最好要求模型同时输出分数和理由。
{ "candidate_id": "C10086", "match_score": 67, "matched_skills": ["Python", "FastAPI"], "missing_skills": ["PostgreSQL"], "risk_flags": ["工作经历不足3年"], "recommend_next_action": "需要进一步确认项目深度" }3.3 多轮对话 Agent 模块
这是最复杂的一块。Agent 需要基于职位要求和候选人简历自动生成问题,并根据候选人的回答决定追问、澄清或者结束会话。这个模块本质上是一个有状态的多轮会话系统,每一轮都要写入消息记录,并恢复历史上下文。
3.4 评估与决策模块
所有对话结束后,Agent 汇总信息,形成候选人评估报告,并将候选人标记为“通过初筛”“待定”或“不匹配”。这个环节最容易被模型幻觉影响,因为模型可能基于简历推测出候选人根本没有提到的经历。
3.5 通知与触达模块
根据决策结果,系统向候选人发送消息:感谢参与、进入下一轮、补充材料,或者告知等待。系统还支持批量发送,但批量节奏必须控制,否则容易出现通知风暴。
4. “坏掉”的环节往往出在这几个地方
这个项目最值得读的部分不是架构,而是实验中暴露出来的故障点。从同类 AI 业务系统的高频故障来看,最容易“坏掉”的环节集中在下面五类。
4.1 异步流程中的状态丢失
招聘流程天然是异步的。候选人可能上午十点回答完问题,下午两点才点开链接补充材料。Agent 不能像单轮 API 调用那样,等用户回复后再处理。
一旦引入异步处理,就一定会遇到状态管理问题:候选人在某个环节超时未回复,Agent 怎么处理?候选人上一轮回答已经被处理,下一轮消息却带着旧状态进来,系统怎么识别?如果同一个候选人因为回调重试被创建了两个会话,后面所有决策都会错乱。
更麻烦的是,大模型 API 调用本身也是异步的。调用超时、返回格式错误、网络抖动,都需要 Agent 侧做重试。很多系统是在这一步开始出问题的:重试时使用了新的消息 ID,导致上下文连续不上。
4.2 多轮对话的上下文断裂
要让 AI 雇主看起来“懂”候选人,Agent 必须在多轮对话中记住候选人说过什么。但这里有个工程陷阱:每一次对话轮次都需要重新组装完整的上下文,如果上下文组装顺序错乱,Agent 就会遗忘前面的回答。
实验中很容易出现这样的场景:
- 第一轮,候选人说“我有 5 年 Python 经验”。
- 第二轮,Agent 问“你熟悉哪些编程语言”。
- 候选人明明在第一轮已经说过 Python,第二轮还得再说一遍。
这不是模型变笨了,而是上下文组装只带了最近几轮消息,或者系统因为消息 ID 错乱把历史记录覆盖了。排这种问题,最有效的办法不是调整 Prompt,而是先查消息表里的会话 ID 和消息顺序。
4.3 模型幻觉导致评估失真
把简历和对话内容交给大模型做评估,最危险的不是大模型分数低,而是大模型“合理编造”。模型可能根据职位要求里的“3 年以上经验”,自动推断候选人“应该有 3 年经验”,然后打高分;也可能把候选人简历里的“了解 MySQL”放大成“熟悉数据库运维”。
这类幻觉在招聘场景里是不可接受的。因为招聘决策直接影响真实用户的利益。就算是一次实验,输出错误评估也会误导后续所有流程。
项目在评估环节必须有结构化的约束:模型只能基于给定的字段做判断,不能自己引入简历里不存在的信息;判定为“不匹配”时,必须输出引用依据;关键字段缺失时,要返回“信息不足”而不是强行补全。
4.4 批量任务挤爆模型额度
招聘网站一旦上线,候选人投递不是单个请求,而是批量进入。每一个候选人都要跑一遍简历解析、匹配打分、多轮对话、评估汇总。如果批量任务没有限流,并发请求会在短时间内打满大模型 API 的额度,然后出现大量 429 限流错误和超时。
更常见的“坏掉”方式不是系统崩溃,而是队列里的任务全部失败重试,导致模型消费金额飙升。批量任务必须设计成可暂停、可恢复、可设置并发上限的任务队列,而不是同步循环。
4.5 自动化沟通容易被滥用
雇主侧全部是 AI 时,候选人面对的是一台没有情绪、没有耐心、也不会被投诉流程约束的机器。如果不限制 Agent 的沟通边界,就会出现连续追问、催促、反复发送通知等情况。在招聘这种强隐私、强权力关系的场景里,这是设计上必须警惕的问题。
5. 本地复现需要准备什么
想把实验跑起来,不需要一开始就做完整平台,可以先用最小闭环验证三个环节:职位解析、简历匹配、初筛对话。
5.1 环境需求
| 依赖项 | 建议 |
|---|---|
| 操作系统 | Linux / macOS / Windows(WSL2)均可 |
| Python | 3.10 或更高 |
| 大模型 API | OpenAI 兼容接口,或本地部署模型 |
| 数据库 | SQLite 可用于小规模验证,生产建议 PostgreSQL |
| 消息队列 | 可选,先用后台任务模拟 |
| 聊天接口 | 可选,先用脚本模拟候选人回复 |
| 向量库 | 可选,简历检索阶段再引入 |
5.2 最小依赖列表
pip install openai fastapi pydantic sqlalchemy celery如果只做单机验证,可以不引入 Celery,直接用 FastAPI 的 BackgroundTasks 模拟异步任务。
5.3 目录结构建议
ai-recruiter/ ├── app/ │ ├── agent/ │ │ ├── job_parser.py │ │ ├── resume_parser.py │ │ ├── interviewer.py │ │ └── evaluator.py │ ├── db/ │ │ ├── models.py │ │ └── session.py │ ├── schemas/ │ │ └── types.py │ └── main.py ├── tests/ ├── data/ └── requirements.txt6. 核心模块实现思路
6.1 Agent 状态机
面试过程应该是一个状态机,而不是一段自由对话。状态至少包括:INIT -> INTERVIEWING -> COMPLETED -> REVIEWING -> CLOSED。每个状态下只能执行特定动作,防止 Agent 在候选人还没回答完的时候提前评估。
from enum import Enum class InterviewState(str, Enum): INIT = "init" INTERVIEWING = "interviewing" AWAITING_ANSWER = "awaiting_answer" COMPLETED = "completed" REVIEWING = "reviewing" CLOSED = "closed"每当候选人发来消息,系统先根据会话 ID 读取当前状态,再决定下一步动作。如果状态是 AWAITING_ANSWER,Agent 不能发起新一轮提问,只能等待回答或处理超时。
6.2 消息上下文组装
写出上下文组装函数时,要保证消息按时间戳升序排列,并且每次都从原始会话记录组装,不要用增量缓存覆盖历史。
def build_context(conversation_id: str, max_rounds: int = 10): messages = get_messages_sorted(conversation_id) if len(messages) > max_rounds * 2: messages = messages[-(max_rounds * 2):] context = [] for msg in messages: role = "user" if msg.sender == "candidate" else "assistant" context.append({"role": role, "content": msg.content}) return context这里有几个要注意的坑:超过窗口的长对话要截断,但不能只截断一半,导致消息配对错乱;每次必须把系统提示词放在最前面;候选人消息和 Agent 消息要严格交替,否则大模型会分不清谁在说话。
6.3 评估结构化输出
评估模块要强制模型输出 JSON,并且所有字段都带有来源引用。
evaluation_prompt = """ 你是招聘初筛评估助手。请基于候选人简历和面试对话内容进行评估。 规则: 1. 只能使用给定材料中明确出现的信息。 2. 材料中没有提到的经历,不能推断为候选人具备。 3. 必须给出每个判定项的依据来源。 请输出 JSON: { "match_score": 0-100, "matched_skills": [], "missing_skills": [], "concerns": [], "evidence": { "skill_evidence": [], "experience_evidence": [] }, "recommendation": "pass | hold | reject" } """注意:评估结果不能直接作为最终录用结论。任何系统输出都需要有人工复核,尤其是“reject”这种负向决策。
6.4 批量任务封装
批量处理候选人时,不要写成同步 for 循环,而是放到后台任务队列里独立执行。
@app.post("/batch/review") async def batch_review(job_id: str, candidate_ids: list[str]): for cid in candidate_ids: enqueue_task("evaluate_candidate", job_id=job_id, candidate_id=cid) return {"status": "queued", "count": len(candidate_ids)}任务队列要带上 job_id 和 candidate_id,方便失败重试和结果回查。每个任务执行时独立记录日志,防止排错时全靠猜。
7. 功能测试与效果验证思路
开始正式流程之前,建议先准备一套测试数据:模拟职位一个、测试简历三份、模拟候选人角色两名,其中至少包含一份明显不匹配的简历和一份信息不完整的简历。
7.1 职位解析测试
输入一份真实风格的职位描述,检查 Agent 能不能完整输出 JSON 字段。常见问题是模型把“3 年以上经验”解析成数字 3,或者把“了解 Docker”抽取成“Docker 专家”。判断成功标准是:结构化字段与原始职位描述逐项对照无重大偏差。
7.2 简历解析与匹配测试
投递三份简历,分别覆盖“明显匹配”“部分技能缺失”“整体不匹配”三种情况。检查匹配分数是否符合人工判断。重点关注模型是否把没有写进简历的经历“脑补”出来。
7.3 多轮对话测试
用脚本模拟候选人,先给一个简短回答,第二次给一个答非所问的回答,第三次故意不回复。观察 Agent 是否能处理追问、超时和非法输入。最容易暴露问题的是答非所问时,Agent 是继续追问还是直接结束会话,以及候选人超时后系统是否卡在等待状态不释放资源。
7.4 批量压力测试
一次投递 20 个候选人的任务,观察系统在并发场景下是否出现 API 限流、数据库锁等待、任务重复执行。批量任务要求所有任务都有幂等标识,同一候选人重复执行不能产生重复评估记录。
8. 接口 API 与数据回流设计
如果要把这套能力接到真实产品里,至少需要四类接口。
8.1 职位发布接口
POST /api/jobs { "employer_id": "E1000", "job_description": "职位描述文本", "auto_review": true, "max_questions": 5 }接口返回 job_id。auto_review 开启后,系统会自动开始解析职位并准备筛选标准。
8.2 候选人投递接口
POST /api/jobs/{job_id}/applications { "candidate_name": "张三", "resume_text": "简历文本", "contact": "candidate@example.com" }候选人投递后,系统生成 application_id,并触发解析和匹配任务。接口必须支持重复投递检测,同一候选人同一职位不能生成多条申请记录。
8.3 会话状态查询
GET /api/applications/{application_id}/status { "status": "awaiting_answer", "current_question": 2, "total_questions": 5, "timeout_at": "2025-06-01T10:00:00Z" }这个接口用于前端轮询,避免候选人重复收到题目推送。
8.4 批量结果导出
GET /api/jobs/{job_id}/evaluations?status=reviewed返回该职位下所有已完成评估的候选人摘要。批量导出时建议一次最多 100 条,并且支持游标翻页,避免返回 JSON 过大导致服务超时。
9. 资源占用与性能表现
这类平台的资源瓶颈不是 Web 服务本身,而是大模型 API 的调用频率和上下文消耗。
本地复现阶段,如果使用小规模模型如 7B 量级的量化版本,显存占用通常在 4GB 到 8GB 范围,具体取决于上下文长度。如果使用云端大模型 API,本机资源几乎不参与计算,主要关注请求频率、Token 消耗和网络延迟。
多轮对话场景下,上下文窗口增长很快。每轮对话都可能累计几千 Token,运行几十轮后,API 调用成本会呈线性增长。建议在系统设计时固定最大问答轮数,并在接近上限时自动结束会话,而不是无限追加上下文。
另一个性能隐患是数据库查询频率。候选人每回复一条消息,系统就要读取历史记录、保存新消息、更新状态、调用模型,四个步骤拆成四轮数据库操作,高并发下会拖慢响应。建议合并为一次会话事务,在内存里组装好上下文后再统一提交。
10. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 候选人答过的问题又重复问 | 上下文组装只保留了最近几轮 | 查看消息表记录和组装逻辑 | 确保上下文从原始会话完整读取 |
| Agent 评估分数与人工判断差距巨大 | 模型基于推测补全了简历信息 | 检查评估输出中的 evidence 字段 | 强约束模型只能使用材料中的信息 |
| 批量任务中途停止 | API 限流或任务队列崩溃 | 查看任务日志和 API 返回状态码 | 增加重试和限流机制 |
| 候选人收到重复通知 | 通知任务未做幂等处理 | 查看通知流水表 | 为每个候选人加发送幂等键 |
| 候选人超时后系统没有释放会话 | 缺少超时状态机处理 | 检查会话状态是否停留在 AWAITING | 增加定时任务关闭超时会话 |
| 模型返回无法解析的 JSON | prompt 约束不足或模型版本不稳定 | 捕获原始返回内容 | 增加 JSON 修复与重试逻辑 |
| 同一候选人同一个职位被创建多次 | 缺少投递唯一约束 | 检查 application 表索引 | 增加唯一键约束 |
11. 这个项目值不值得继续做下去
从技术角度看,AI 雇主这个概念在短期之内还很难完全替代真人 HR,但它的价值不在于替代,而在于把招聘链路里可自动化、可数据化的部分剥离出来,降低重复劳动成本。职位解析、简历结构化、初筛问答、评估摘要,每一个环节都有明确的工程价值。
从实验角度看,这种“把 AI Agent 放进真实业务流”的项目比单纯做一个聊天机器人有价值得多。它涉及状态管理、多轮上下文、批量任务、结构化输出、幂等重试、限流与防滥用,这些都是大模型工程化的核心问题。跑通一次完整流程,比刷几十个 Demo 更能理解 Agent 应用的复杂度。
如果后续要扩展,优先做这几件事:
- 引入人工复核机制,所有负向评估都要求人工确认。
- 增加会话日志审计,候选人随时可以发起申诉。
- 增加防滥用策略,限制单候选人最大消息数。
- 增加流式输出,让候选人等待模型响应时不至于没有反馈。
- 增加评估报告导出功能,方便用人单位留档。
最后提醒一点:招聘场景涉及真实个人信息和职业决策,无论实验多成功,都不能跳过授权和合规。简历数据要脱敏存储,候选人要明确知晓对方是 AI 助手,涉及自动化拒绝或自动化推荐时,要保留完整日志以备复查。技术可以实现的部分,边界由人来控制。