1. 从“码上面试”这个项目名说起我为什么要啃Agent这块硬骨头第一次看到“码上面试”这四个字我脑子里蹦出来的不是某个具体产品而是一个很朴素的念头能不能让机器替我把那些重复性的面试准备工作干掉比如根据一份JD自动生成一套有梯度的技术题比如模拟一个面试官追着候选人的项目经历往下问比如把候选人的回答按维度打分并给出追问建议。这些事听起来像是“AI能做的事”但真动手做你会发现它和“调个API问一句话”完全是两码事。这就是我启动《码上面试》Agent项目的起点。它不是那种“输入问题、输出答案”的问答机器人而是一个有目标、有状态、能调用工具、能根据反馈调整下一步动作的智能体。关键词里的Agent、agent开发、agent框架、agent记忆、多agent协作基本勾勒出了这个项目的技术版图。我打算用几篇学习记录把从零搭一个Agent的过程、踩过的坑、以及那些文档里不会写的经验原原本本记下来。这篇是第一篇重点解决三个问题Agent到底是什么、和普通LLM应用差在哪一个面试场景的Agent需要哪些核心模块以及我最终选了什么框架、为什么这么选。如果你也是大模型开发工程师或者正在从“调API”往“做Agent”转型这篇内容应该能帮你少走一些弯路。我不会堆概念而是拿“码上面试”这个真实项目当靶子边拆边讲。先说一个我自己的判断Agent的门槛不在模型而在工程。模型能力是底座但真正决定一个Agent能不能用的是记忆怎么管、工具怎么调、状态怎么流转、错误怎么兜底。这些才是接下来要展开的核心。2. Agent和普通LLM应用的分水岭从“一问一答”到“自主推进”2.1 一个面试场景暴露了普通LLM应用的天花板假设我要做一个最简单的面试题生成器。用普通LLM应用的思路就是拼一个Prompt“你是一个资深面试官请根据以下JD生成5道题”然后调模型拿结果。这个方案能跑但问题很快暴露。第一它没有状态。候选人回答了第一题我想让第二题基于第一题的回答追问普通应用做不到因为它每次调用都是独立的上一轮的上下文要么全塞进Prompt很快就爆token要么就丢了。第二它不会用工具。面试里我想查一下候选人提到的某个开源库的真实用法或者想调一个代码执行环境验证他写的算法普通应用只能“说”不能“做”。第三它不会自己决定下一步。真实面试是动态的候选人答得好就深挖答得差就换方向这种决策逻辑普通应用要么写死要么靠人。这三个问题——状态、工具、决策——正好就是Agent和普通LLM应用的分水岭。Agent的本质是让模型在一个循环里持续地“观察-思考-行动”直到达成目标。它不是一个函数而是一个有生命周期的进程。2.2 Agent的核心循环Observe、Think、Act我把Agent的运行机制拆成一个不断转动的三角观察Observe、思考Think、行动Act。观察是接收环境信息比如用户的输入、工具返回的结果、上一步的动作反馈思考是模型基于当前状态决定下一步做什么是回答、是调工具、还是结束行动是执行思考的结果可能是生成一段文本也可能是调用一个函数。这个循环听起来简单但工程上的难点全在细节里。比如“思考”这一步模型输出的不能是自由文本而必须是结构化的动作指令否则程序没法解析。再比如“行动”之后结果怎么塞回上下文塞多少塞哪些直接决定了Agent能跑多长、多稳。我在“码上面试”里就吃过亏早期版本把每一轮完整对话都塞回去跑到第七八轮就开始胡言乱语后来改成只保留关键状态和最近几轮才稳定下来。提示判断一个应用是不是Agent最简单的标准是看它有没有“自主决定下一步”的能力。如果每一步都是人写死的流程那它只是工作流不是Agent。2.3 为什么面试场景特别适合用Agent来做面试这个场景天然具备Agent需要的几个特征。它有明确目标评估候选人有动态状态对话历史、评分记录需要外部工具题库检索、代码执行、简历解析还需要多轮决策追问还是换题。这些特征叠加起来用传统工作流做会非常臃肿用Agent做反而顺理成章。更重要的是面试场景对“可解释性”要求高。候选人答完我得能说清楚为什么给这个分、为什么问这个问题。这就要求Agent的每一步决策都要有记录、可追溯。这一点在后面讲记忆和状态管理时会重点展开因为它直接影响了我的架构设计。3. 拆解“码上面试”Agent的四大核心模块3.1 记忆体系短期、长期、永久三层怎么分Agent记忆是热词里反复出现的一个点也是我踩坑最多的地方。一开始我以为记忆就是“把历史对话存起来”后来发现完全不是。面试场景里记忆至少分三层。短期记忆是当前这场面试的上下文包括候选人刚说的这句话、上一轮的评分、当前进行到第几题。它的特点是生命周期短、读写频繁、容量有限。我的做法是用一个滑动窗口加摘要最近三轮保留原文更早的压缩成一句话摘要。长期记忆是跨场次的信息比如这个候选人上次面试的表现、他简历里的关键项目。它需要持久化存储通常是向量库加结构化字段。这里有个坑长期记忆不能无脑检索否则会引入无关信息干扰当前判断。我的策略是先用结构化条件过滤比如候选人ID再做语义检索。永久记忆是Agent自身的“知识”比如面试评分的标准、常见追问套路、岗位能力模型。这部分相对静态适合放在系统Prompt或者独立的配置里不随对话变化。记忆类型生命周期存储方式典型内容读写频率短期记忆单场面试内存/滑动窗口最近对话、当前评分极高长期记忆跨场次向量库数据库候选人历史、简历要点中永久记忆长期不变配置文件/Prompt评分标准、能力模型低这个分层不是拍脑袋定的而是根据“读写频率”和“变化频率”两个维度切出来的。高频变化的放内存低频变化的放配置中间层用数据库兜底。这样既保证了性能又保证了可追溯。3.2 工具调用让Agent真的能“动手”面试Agent如果只会聊天价值有限。我给它接了几个工具题库检索根据岗位和技术栈找题、代码执行跑候选人写的算法、简历解析从PDF里抽结构化信息。工具调用的核心难点不在“调”而在“什么时候调”和“调完怎么用”。什么时候调靠的是模型在思考阶段的决策。这里我用的是Function Calling机制把每个工具的描述和参数schema告诉模型模型自己决定要不要调、调哪个、传什么参数。实测下来工具描述写得越清楚模型调用的准确率越高。比如“题库检索”这个工具我一开始只写“搜索题目”模型经常在不该调的时候调后来改成“根据岗位名称和技术关键词检索面试题仅当需要出题时调用”误调率明显下降。调完怎么用是另一个坑。工具返回的结果往往很长直接塞回上下文会挤爆窗口。我的做法是加一层“结果摘要”把工具返回的原始数据压缩成关键信息再喂给模型。比如代码执行返回一大段日志我只提取“是否通过、报错信息、耗时”三个字段。注意工具调用一定要有超时和重试机制。我遇到过代码执行工具卡死导致整个Agent挂起的情况后来加了5秒超时和一次重试稳定性好了很多。3.3 状态管理Agent的“记忆”和“状态”不是一回事很多人把记忆和状态混为一谈其实它们解决的是不同问题。记忆是“记住什么”状态是“现在在哪”。面试Agent的状态包括当前进行到第几题、当前题目类型、候选人当前得分、是否进入追问环节。这些状态需要显式管理不能全靠模型从对话历史里推断。我的做法是用一个状态机来管理面试流程。状态机定义了几个核心状态开场、出题、等待回答、评分、追问、结束。Agent的每一步动作都会触发状态转移转移规则一部分写死比如评分完必须进入下一题或追问一部分交给模型决策比如是否追问。这样既保证了流程可控又保留了灵活性。状态机的另一个好处是可观测。每个状态转移都打日志出了问题能快速定位是哪一步决策错了。这在调试阶段特别有用因为Agent的行为不像普通程序那样确定没有日志基本没法排查。3.4 决策与编排单Agent还是多Agent热词里有“多agent协作”和“agent框架与编排”这也是我纠结很久的问题。面试场景涉及出题、评分、追问、总结多个环节看起来很适合拆成多个Agent各司其职。但我最后选择了单Agent加多工具的方案原因是多Agent的通信成本太高而且容易出现“互相甩锅”的情况。单Agent的方案是一个主Agent负责整体决策通过调用不同工具来完成具体任务。比如出题时调题库工具评分时调评分工具其实是一段专门的Prompt加结构化输出。这样架构简单调试方便状态也好管理。当然如果场景再复杂一些比如需要同时处理多个候选人的面试那多Agent可能更合适。但就“码上面试”当前的需求单Agent够用。这里给一个选型建议能用单Agent解决的就别上多Agent。多Agent的复杂度是指数级上升的通信协议、状态同步、错误传播每一个都是坑。等单Agent真的扛不住了再拆不迟。4. 框架选型我为什么没直接用现成的Agent框架4.1 主流Agent框架扫一遍各自的脾气热词里提到的Agent框架不少我基本都试过一轮。这里不点名具体产品只说类型和我的体感。第一类是重编排型框架特点是提供了完整的Agent抽象链、工具、记忆、回调一应俱全。优点是上手快缺点是黑盒多出了问题不好查而且定制化成本高。我试过一个想改一下记忆的压缩策略结果发现要改好几层封装最后放弃了。第二类是轻量工具型框架只提供工具调用和循环控制其他都交给开发者。优点是灵活缺点是啥都要自己写。我早期用这类框架搭了个原型跑通了但状态管理和错误处理写得很痛苦。第三类是平台型方案提供可视化编排和托管运行。优点是省事缺点是绑定深数据和安全不可控。面试场景涉及候选人隐私我不太放心把数据放到第三方平台。框架类型上手速度定制能力调试难度适合场景重编排型快低高快速验证、标准场景轻量工具型中高中需要深度定制平台型很快很低低非敏感、标准化业务4.2 最终选择轻量框架加自研状态层权衡之后我选了轻量工具型框架作为底座自己在上层写状态管理和记忆压缩。这样既享受了工具调用的便利又保留了核心逻辑的可控性。具体来说框架负责“模型调用、工具注册、循环控制”这三件事我负责“状态机、记忆分层、结果摘要、错误兜底”。这个选择的核心逻辑是Agent的差异化价值在业务逻辑不在框架。框架能帮我省掉重复劳动但面试的评分标准、追问策略、状态流转这些才是“码上面试”的护城河必须自己掌控。如果全交给框架做出来的东西和别人的就没区别了。4.3 环境准备里最容易忽略的两个细节搭环境的时候有两个细节我一开始没注意后来吃了亏。第一个是模型输出的结构化约束。Agent的思考结果必须是可解析的所以我强制模型输出JSON格式并在Prompt里给了严格的schema。但模型有时候会“自由发挥”加个注释或者换个字段名。解决办法是在解析层做容错解析失败就重试一次再失败就降级到默认动作。第二个是工具调用的幂等性。有些工具比如代码执行重复调用会产生副作用所以我给每个工具加了幂等标识同一个请求ID重复调用直接返回缓存结果。这个在重试场景下特别重要否则可能把候选人的代码跑两遍。提示环境准备阶段一定要把日志和追踪做好。Agent的行为链路长没有日志基本没法调试。我用的方案是每一步都打结构化日志包含状态、动作、输入、输出、耗时。5. 跑通第一个Demo之后我踩到的三个真坑5.1 坑一上下文爆炸Agent跑到一半“失忆”第一个Demo跑通的时候我挺兴奋但跑到第五六轮就发现Agent开始重复问问题或者忘记之前评过分。排查后发现是上下文管理的问题我把每一轮的完整对话都塞回去token很快逼近上限模型开始“丢信息”。解决办法是分层压缩。最近两轮保留原文第三到第五轮压缩成摘要更早的只保留结构化状态得分、题目ID。这样token占用降了六成稳定性明显提升。这里的关键是摘要要保留决策相关的信息比如“候选人第三题答错原因是没考虑边界条件”而不是笼统的“候选人表现一般”。5.2 坑二工具返回太长把模型“带偏”代码执行工具返回的日志动辄几百行直接塞回去模型会被无关信息干扰甚至开始“评论”日志内容而不是继续面试。我后来加了一层结果摘要只提取关键字段问题就解决了。这个坑的教训是工具返回的内容不是越多越好而是要“刚刚好”。Agent需要的是决策所需的最小信息集多余的都是噪声。现在我的每个工具都有对应的摘要函数返回结果先过摘要再进上下文。5.3 坑三错误处理缺失一个异常整个流程崩早期版本没有错误处理工具调用失败或者模型输出解析失败整个Agent就抛异常终止。这在Demo阶段能忍但没法上线。后来我加了三层兜底工具调用失败重试一次解析失败降级到默认动作连续失败则进入“安全模式”只做简单问答。这里有个经验Agent的错误处理要比普通程序更宽容。因为Agent的行为本身就有不确定性不能指望它每一步都完美。关键是失败后能优雅降级而不是直接崩掉。6. 关于Agent学习路线我的一点个人建议如果你也在学Agent开发我的建议是别从框架开始从循环开始。先手写一个最简单的Agent循环调模型、解析动作、执行动作、把结果塞回去、再调模型。跑通这个循环你就理解了Agent的本质。然后再去看框架你会发现框架帮你省掉的是什么也就知道什么时候该用、什么时候不该用。热词里有“agent学习路线”和“agent for beginner”我觉得初学者的路线应该是先理解LLM的基本调用再手写Agent循环然后加工具调用再加记忆管理最后才是多Agent和编排。每一步都要动手跑通光看文档没用。“码上面试”这个项目我还在继续做后面会记录记忆体系的详细实现、评分Prompt的调优过程、以及怎么用评测集来量化Agent的表现。这一篇先把地基打好下一篇聊记忆和状态的具体代码实现。如果你也在做类似的项目欢迎交流踩过的坑就不用再踩一遍了。
企业数字化 ERP 产品动态
相关推荐
presume、assume、resume、consume 总搞混?词根拆解帮你一次分清 1. 为什么这四个词总被搞混:从词根拆解说起presume、assume、resume、consume 这四个词,长得像四胞胎,前缀不同但词根都是 -sume,意思却差了十万八千里。我带过几批做英文写作和翻译的朋友,几乎每个人都在这个词族上栽… · 2026/11/3 8:18:06
SSE 断线重连:补回 50 条,仍漏 27 条 版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部… · 2026/11/3 8:18:06
Jev接入Claude Code与Codex:让Coding Agent先想清楚再动手 把 Jev 装进 Claude Code 和 Codex,这个想法最初不是为了跑分或者追新模型,而是为了解决一个让我挺头疼的问题:Agent 写代码太快了,快到来不及想清楚就开始改,改到最后和预期完全是两码事。我一度以为是自己 prompt 写… · 2026/11/3 8:17:06
免费模型误读Cron表达式?自养Agent工具链改造实录 早上七点整的同步任务,我的自养 Agent 在日志里白纸黑字写着“每天 7 点到 7 点执行”,看到这句话我先是愣了一秒,然后差点笑出声。这就是我最近在维护“自养 Agent”项目时遇到的最典型、也最危险的坑之一:免费模型可以帮你写代码… · 2026/11/3 8:53:41
Win32 自绘图片按钮:BS_OWNERDRAW、GDI+ 与高 DPI 实战 前段时间被一位朋友拉去看他写的一个小工具,界面里有个“开始扫描”的按钮,他想把按钮做成带图标的样子,结果折腾了一下午:按钮上的图要么不显示,要么显示出来是一团黑,要么点了没反应。他用的就是最朴素的… · 2026/11/3 8:53:41
C语言字符常量到字符串:五种定义方式与内存布局实测 1. 字母在C语言里到底是什么:从字符常量到字符类型很多人学C语言的第一课就是printf("hello");,但真正把C语言中字母的定义讲清楚的人并不多。我见过不少写了半年代码的朋友,仍然说不上来a和"a"到底是什么类型、占几个字… · 2026/11/3 8:53:41
毕业设计企业办公系统三大核心落地实践 简介:这是一套面向计算机专业本科生的毕业设计级企业协同办公系统源码,适用于Java全栈开发入门与课程设计实践,帮助初学者掌握SSM框架整合、前后端交互及典型OA模块开发。资源包含427个文件,主体为48个Java业务类、67个编译后Clas… · 2026/11/3 8:53:41
陀螺仪C语言姿态解算:从IMU误差建模到卡尔曼滤波实现 陀螺仪C语言算法这件事,说难不难,说简单也真不简单。把一颗六轴IMU焊到板子上、通上电、串口一开,数据哗啦啦就出来了,可你要直接把这串角速度积分成角度,用不了半分钟它就能飘到你怀疑人生。真正让姿态解算站得住的&a… · 2026/11/3 8:53:41
MySQL Workbench汉化指南:原理与多平台实操 1. 项目背景与需求解析 作为一名长期使用MySQL Workbench的DBA,我深刻理解英文界面对于部分使用者的障碍。尤其当团队中有非技术背景的成员需要参与数据库操作时,语言门槛会显著降低工作效率。这就是为什么MySQL Workbench汉化这个看似简单的需求&#x… · 2026/11/3 8:52:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46