资讯动态

从零搭建AI Agent面试复盘系统:框架选型、记忆与并发实践

发布时间:2026/10/2 5:17:53 来源:尧图企业网站定制
面试做到第十场之后我意识到一个尴尬的事实候选人离开时最常问的问题不是我算法题做得对不对而是您能说说我具体哪里答得不好吗。作为面试官我常常只能给出整体思路还行但深度不够这种模糊反馈。这既不是敷衍而是真的一时难以逐条复盘——人的注意力在多轮对话里天然会丢失细节。当时我正好在系统研究AI Agent开发主流agent框架、agent学习路线都过了一遍脑子里突然冒出一个想法能不能训练一个Agent当面试官把这个复盘苦差事接过去。于是《码上面试》这个项目就立项了。它要做的事情很简单让一个AI Agent扮演结构化面试官出题、追问、记录作答过程、分层打分最后产出一份让候选人看得懂的反馈报告。这篇文章是项目学习记录的第一篇我尽量把从零搭建过程中最核心的框架选型、记忆设计、并发方案和踩坑经历讲透。如果你正准备入行Agent开发或者想用Agent做一个真实可用的产品这篇应该能帮你省下不少试错时间。1. 项目的真正起点候选人说不清我哪里答得不好这个项目的起点不是我想要做一个Agent而是我发现现有的模拟面试工具解决不了两个具体问题候选人复盘困难面试官评估不透明。1.1 面试双方都存在的信息黑洞先说候选人这边。市面上已有的刷题网站、面试题库本质上都是题库正确答案的单向展示。候选人对着答案看一遍觉得自己会了真到面试现场被追问两个为什么就卡壳。因为题库不会记录你的回答过程更不会告诉你你刚才在复杂度分析上停顿了12秒说明这块不熟。而面试官这边问题更隐蔽。一场45分钟的技术面至少要覆盖简历深挖、算法题、系统设计、行为面试四个模块。面试官一边听回答一边要在脑子里维护他刚才说的技术栈和简历是否一致这个边界条件他漏了没有两份动态笔记。人脑的短期记忆容量有限这个过程中信息丢失几乎不可避免。《码上面试》想做的就是用Agent把这个动态笔记显性化Agent全程记录候选人的每句话实时维护一个评估状态表面试结束后直接导出结构化报告。1.2 为什么这个场景必须用Agent而不是普通聊天机器人我在调研阶段试过用普通Prompt套一个ChatGPT壳子做模拟面试效果很差。原因是面试场景有三个特点普通对话应用根本扛不住多轮状态管理面试官要记住这道算法题已经追问过两次候选人提过Redis后面系统设计题要关联追问这些状态必须跨轮次维护。结构化评估面试官的产出不是聊天记录而是算法能力7分、系统设计6分、沟通表达8分这种多维评估表需要把自由对话映射到固定评分维度上。工具调用需求出题要从题库拉取、计时要用定时器、搜简历要看候选人历史信息这些都不是纯文本对话能搞定的。满足这三个条件正好是Agent框架擅长的事情。Agent和普通ChatBot的关键差别在于Agent有感知-决策-行动的闭环能调用工具、维护状态、动态规划下一步动作。面试官这个角色本质上就是一个不断做决策的Agent——听完一句话决定是追问、换题还是结束面试。这也是我后来在harness和agent区别上反复纠结的起点Agent是思考的大脑而运行它需要一套靠谱的容器和状态管理机制。2. 框架选型阶段主流Agent框架我几乎都试了一遍既然决定做Agent第一道坎就是选框架。那阵子主流的agent框架我基本都试了包括LangChain/LangGraph、MetaGPT、AutoGen、CrewAI还有国内的低代码平台扣子。2.1 用LangGraph搭流程死在状态管理细节上LangGraph的核心是用图来描述工作流节点是出题追问评分边是状态转移条件。我一度觉得这正是我想要的——面试流程确实是一个有向图。但实际用下来发现两个问题第一LangGraph的StateGraph需要你定义全局状态Schema每个节点都要声明读写了哪些字段。面试场景的状态字段特别多当前题目、追问次数、候选人答案缓存、评分草稿……图稍微一复杂调试时你要同时盯住当前在哪条边上和状态到底改没改两个维度心智负担很重。第二LangGraph的节点是普通Python函数但框架本身对节点内部如何调用LLM没有约束。这意味着我要自己处理重试、超时、解析LLM输出这些琐碎事框架带来的帮助有限。# LangGraph初版状态定义简化 class InterviewState(TypedDict): current_question: str follow_up_count: int candidate_answer: str scores: dict history: list # 越加越多的字段...2.2 AutoGen和CrewAI的多角色启发AutoGen的多Agent对话机制很有意思。理论上可以让面试官Agent和候选人Agent互相聊生成完整的面试对话记录。但我试了三十多轮对话之后发现两个Agent自由对话很容易发散——本来在聊算法题聊着聊着开始讨论人生哲学。面试场景需要强约束的对话节奏不是自由研讨会。CrewAI的角色编排思想我保留了一些。它把Agent定义成角色目标背景故事非常契合面试官记录员评分员这种多角色分工。但CrewAI的底层实现里Agent之间的协作依赖任务队列自定义工具需要写比较多的样板代码我嫌重。2.3 关于harness和agent框架的复盘这里我想多说两句harness和agent区别。网上解释这两个概念的文章很多但落到实践里我的理解是Agent是那个有记忆、会推理、能决策的智能主体Harness是承载这个主体的运行环境负责调度LLM调用、管理工具注册、维护上下文窗口、处理错误重试。市场上大多数框架都把两者揉在一起比如LangGraph本身就是状态机HarnessAgent决策逻辑的混合物。我的选择是不刻意区分要不要Harness而是自研一个最轻量的面试状态机作为运行骨架底层LLM调用和工具注册采用标准化接口方便以后换框架。最终的技术决策是核心编排层用Python自研一个有限状态机加上会话管理器LLM调用走统一的异步客户端题库和评分模块做成独立服务。这样做牺牲了框架自带的一些便利但换来了对面试流程的完全控制。框架优势在本项目中的短板最终取舍LangGraph状态图清晰全局状态Schema越写越重借鉴思路不自找麻烦AutoGen多Agent对话自由对话发散、节奏失控舍弃CrewAI角色定义清晰工具开发样板多保留角色思想扣子/Coze上手快、配置简单定制程度受限仅做原型验证自研状态机完全可控、轻量需要自己维护基础能力最终采用3. 记忆系统设计让面试官Agent记得住你刚才说的是错的Agent记忆是我在这个项目里花时间最多的一块。面试场景对记忆的要求远比普通客服机器人苛刻因为面试官的每一个后续决策都依赖之前对话的准确还原。3.1 三层记忆模型短期、工作、长期分开存我最后采用的方案是三层记忆各自解决不同问题短期记忆Short-term存当前正在进行的这道题目的完整问答长度控制在最近6轮对话左右超出部分做摘要压缩。工作记忆Working Memory存当前面试的全局状态包括已面试的模块、各模块得分草稿、候选人在前面提到过的技术栈关键词。这块是Agent决策的核心依据。长期记忆Long-term面试结束后的结构化画像存进数据库下次候选人再来面试时Agent会优先加载这份画像用于连续性追问。这个分层不是拍脑袋想出来的是我在实测里发现全部塞进上下文和只留最近几轮都不行之后的折中方案。全部历史塞进Prompt一是token账单哗哗涨二是上下文一长模型对早期信息的召回能力急剧下降。只留最近几轮则会让Agent变成金鱼记忆——候选人十分钟前提过的技术栈换了道题就忘了。3.2 工作记忆的结构化设计面试官Agent最怕的不是记不住而是记混乱。我在工作记忆里维护了一个JSON结构每次LLM输出都会解析后回写dataclass class WorkingMemory: session_id: str candidate_name: str current_module: str # algo / sys_design / behavior current_question_id: str follow_up_count: int mentioned_techs: list[str] # 候选人主动提到的技术栈 question_scores: dict # 每道题的实时评分草稿 red_flags: list[str] # 候选人暴露出的知识点盲区这个结构的价值在于它把Agent的内部状态从一坨对话历史变成了可查询、可更新的结构化数据。Agent每次要决定下一步动作时不是重新阅读所有聊天记录而是先查工作记忆里的几个关键字段再结合最近几轮对话做判断。3.3 长期记忆的持久化与回流面试结束后短期记忆和工作记忆会合并归档成一份候选人长期画像写入SQLite。画像里包含技术栈掌握度、表达特点、上次面试遗留的待提升点、面试官备注。下次同一候选人再来面试时Agent启动时会先加载画像摘要并用一句话作为开场白上次你提到在分布式事务这块想深入一下今天我们会重点考察准备好了吗这个细节直接让产品的体验感上升了一个档次候选人会觉得这个面试官是记得我的。3.4 记忆读取的优先级规则记忆不是越多越好读取顺序也很讲究。我设置了一条硬规则Agent做决策时的信息拼装顺序是长期画像摘要 - 工作记忆关键字段 - 最近3轮对话原文 - 当前题目描述超过这个范围的旧信息除非主动查询否则不进入上下文。这条规则解决了一个真实出现的bug早期版本里Agent有时会因为候选人十分钟前说过做过Java项目而强行在系统设计题里追问Java相关内容但候选人实际已经转Go一年了。旧信息优先级太高会造成严重的上下文污染。降级之后Agent只有在当前题目确实涉及语言选型时才会主动查长期画像。4. 并发问题提前想AI Agent怎么扛住模拟面试的压力做Agent项目的人前期大多只关注能不能跑通很少想扛不扛得住。但模拟面试这个场景天然是多人并发的一个候选人面试进行到一半另一个候选人随时可能开启新会话。我提前思考了并发问题踩了几个雷这里直接说结论。4.1 面试场景的并发特征和普通API不一样先说清楚面试Agent的并发不是电商秒杀那种高吞吐短请求而是多路长会话同时进行每路会话内部是序列化的多轮交互。每一轮交互用户要等Agent思考加生成耗时长、状态多。这种场景下真正要防的不是请求量爆炸而是以下几点LLM API限流底层模型服务OpenAI、Claude或国产模型都有每分钟Token上限多个会话同时推进时随时可能触顶。有状态会话的内存开销每个面试会话都要维护工作记忆和对话历史如果全部放在进程内并发高了内存先爆。推理延迟叠加Agent的决策往往要调用两三次模型一次决定动作、一次生成追问、可能还有一次评分单轮延迟本来就高一旦并发上去用户体验会迅速恶化。4.2 状态外置是并发的前提我踩的第一个坑是把工作记忆放在Python进程的全局字典里。本地测试三个会话没问题模拟到第八个会话时进程重启导致所有会话状态丢失——候选人答了一半Agent突然失忆这在面试场景是绝对不能接受的。解决方案是状态外置。所有会话状态存到RedisAgent进程本身变成无状态的工作节点# 状态存储设计 Redis Key格式: session:{session_id}:memory Redis Key格式: session:{session_id}:history Redis Key格式: session:{session_id}:lock # 防止同一会话并发跳闸这样即使某个Agent工作节点挂了另一个节点可以从Redis恢复会话状态继续服务。这也是Agent和Harness分离思路的实践产物Agent是逻辑状态在数据层运行环境可以随时替换。4.3 用任务队列压平模型调用高峰面试场景里最耗时的操作不是生成打字而是多个模型调用之间的串行等待。我最初的设计是同步顺序执行Agent先决定下一步动作等LLM返回再执行工具再让LLM生成追问。一套流程下来单个追问至少5到8秒。后来改成异步编排Agent把生成追问和记录上一轮答案两个动作拆开。记录和评分走后台队列异步执行追问只在用户等待的关键路径上同步阻塞。这样单轮延迟从8秒降到3秒左右并发能力直接翻了倍。这里的经验是Agent的每一步不一定要同步返回。能用后台Job处理的步骤就尽量从请求链路上拆出去。面试结束后的完整评分报告我甚至全部丢到Celery任务里异步生成用户先看到面试已结束评分生成中三十秒后刷新就能看到报告。这个体验优化非常值。4.4 给Agent加一个Token预算器最后一个并发层面的实用技巧给每个会话框定Token预算。我在会话启动时预设一个总预算比如15万Token每次模型调用后都扣减。预算低于阈值时Agent自动切换策略从长篇追问降级为简短反馈防止单个会话把整天的API额度烧光。这个设计很糙但非常管用。做Agent项目的人最容易忽略的一点是LLM API的消耗不是线性可预期的——候选人的回答长度、模型的追问意愿都会让Token消耗产生剧烈波动。有一个预算器兜底至少不会出现运行三小时、账单上千块的事故。5. 踩坑清单第一版上线前我修的三个顽固BugAgent项目最折磨人的Debug点往往不是语法错误而是模型行为不可控。我修了下面三个最顽固的问题希望能帮你省点时间。5.1 追问循环失控Agent钻进不停追问的死胡同第一个版本里候选人的回答稍微含糊一点Agent就会反复追问同一个知识点甚至连续追问五轮都不推进到下一题。一开始我在Prompt里写你有权追问候选人以深入了解其掌握程度结果模型把追问当成最高优先级完全忘了面试还要往前推进。修法有两步一是在工作记忆里增加follow_up_count计数器同一题目追问超过三次就强制切换话题二是给动作决策单加一个显式的选项列表——追问、换题、结束面试并要求LLM每次必须从列表里选一个动作而不是自由发挥。ACTION_CHOICES [follow_up, next_question, end_interview] # 追问计数达到阈值时从动作空间里移除 follow_up if memory.follow_up_count 3: allowed_actions.remove(follow_up)这个动作空间约束的思路我后来用在了所有Agent决策点上比单纯改Prompt可靠得多。5.2 上下文爆炸Prompt里永远有删不干净的历史这个坑很典型。早期我图省事把整场面试的对话历史直接塞到Prompt里让Agent自己找重点。结果是一轮面试进行到20分钟时单次请求的输入Token已经上万延迟和费用双高模型的注意力也明显下降——它开始忽略早期信息甚至把候选人第3题的回答安到第8题上。修法是采用滑动窗口加摘要。短期记忆只保留最近6轮对话原文更早的内容每10轮生成一次摘要摘要单独存放在工作记忆里。Agent读上下文时看到的是摘要最近对话不再是无脑全量拼接。5.3 评分不一致同一个回答两次得分差出两分面试Agent的评分模块让我头疼了一周。同一个候选人回答换个时间跑评测分数能从6分跳到8分。原因是早期我把评分功能直接交给面试官Agent兼任它在一边追问一边打分的双重任务里效率很低。我最后的做法是把评分拆成独立环节面试过程中面试官Agent只负责问答和记录不评分面试结束后由一个独立的评分Agent读取全部对话记录依据标准评分Rubric打分。两个角色彻底分离后一致性明显改善。这里还有个副产品因为评分Agent不吃时间的限制我可以把评分Rubric写得更详细——每个评分维度分五档每档有明确的特征描述。实测下来评分Agent对Rubric的遵循程度远远好于让面试官Agent边对话边评分。5.4 一点关于Agent安全的补充做Agent工具调用的时候我给自己定了一条简单规则Agent只允许调用白名单工具所有工具的入参和出参都过一遍校验层。面试Agent用到的工具不多——拉题库、计时、存记忆每个工具都有固定Schema不存在自由填写的余地。这一步其实花不了多少时间但对后面扩展Agent能力很有必要你想加新工具的时候不用整天担心Agent会不会把库里的数据搞乱。写到这里这版《码上面试》已经能稳定支撑二三十路并发的模拟面试了。回头看看这个项目最耗时间的不是写代码而是不断和不可控的模型行为搏斗。框架选型里的纠结、记忆分层的反复设计、并发方案的提前布局都是在为让Agent的行为变得可控这一件事服务。第二篇我打算写让Agent调用真实技术题库工具的部分包括把面试官手里零散的题目文档整理成结构化题库以及工具调用链路的稳定性问题。如果你也在做Agent项目欢迎交流。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑