小红书AI Agent一面凉经 !!!
面了70分钟,从Agent架构问到JVM类加载,最后扔一道算法题。我人没了。
上周面了小红书的AI Agent岗位。投的时候以为是聊Agent、聊LLM、聊Prompt优化,结果面试官后半程画风一转——Java线程池、MySQL两阶段提交、JVM类加载全给安排上了。直接裂开。
嗯,把还记得的21道题整理出来,答案也一并写了。希望对准备类似岗位的朋友有点帮助。
- 简单介绍一下自己的经历,以及为什么选择AI Agent方向?
这个问题基本是开场必问。别背简历,面试官想看的是你的思考过程。
我的回答思路:把经历串成一条线——之前做后端开发时遇到了哪些自动化难题,当时用传统规则引擎解决,但随着业务复杂度的上升发现规则根本维护不动。后来接触到LLM,发现用自然语言做任务拆解和决策的思路很自然,就转了Agent。
标准答案参考:AI Agent的核心价值在于它赋予了LLM与外部世界交互的能力。传统LLM只是被动回答问题,而Agent能主动调用工具、执行计划、完成复杂任务。选择这个方向是因为我认为下一代应用形态一定是“能做事”的模型,而不是“能聊天”的模型。从技术角度看,Agent涉及规划、记忆、工具调用、多智能体协作等多个维度,每个维度都有足够深的技术挑战。
- 平时开发过程中主要使用哪些AI Coding工具?比如Claude Code这类工具,通常有哪些使用习惯?
问这个是想看你是不是真的在用,还是停留在“听说过”。
我的回答:Claude Code和Cursor都在用。习惯上不会直接让它写完整模块,而是把大任务拆成小函数,逐个让它生成或重构。写之前会给清楚输入输出格式、边界条件,有时候还会故意给个错误示例告诉它“别这样写”。
标准答案参考:AI Coding工具的核心价值在于提升编码效率,但使用方式直接影响效果。比较好的实践包括:① 分而治之,单个Prompt控制在单一函数或类层面;② 提供充足上下文,包括相关代码路径、数据结构定义、已有接口签名;③ 迭代式优化,先让AI生成初版,再通过多轮对话逐步修正;④ 对生成的代码做Code Review,AI也会产生逻辑漏洞,尤其是在并发和异常处理上。
- 如何理解Spec Coding和Harness?你认为Harness为什么能够提升Agent完成复杂任务的能力?
这个问题答得一般,说实话平时更多是在业务里用Agent,对Harness的研究不够深。回来查了不少资料。
Spec Coding:先把任务写成一份结构化的规格说明(Spec),包含输入格式、输出格式、约束条件、验收标准。Agent照着Spec干活,而不是自由发挥。
Harness:可以理解为一个“Agent运行沙箱”。它把Agent的执行环境、工具集、上下文、日志全部封装起来。
Harness提升复杂任务能力的三个原因:
- 约束执行空间:不让Agent乱跑,每一步都在边界内。
- 可观测性:每个中间步骤都被记录,方便定位失败点。
- 反馈闭环:Agent执行完一个子任务后,Harness能自动校验结果是否符合预期,不符合就触发修正。
其实就是把Agent“关进笼子里训练”,容错率反而更高了。
- 如果让你从零开始设计一个Agent系统,你认为需要包含哪些关键模块?
面试官想看的不是背八股,而是你真正设计过系统。
我的回答:四个核心模块——感知模块(接收用户输入、解析意图)、规划模块(把大任务拆成子任务、决定调用哪些工具)、执行模块(实际调用工具/API、处理返回结果)、记忆模块(短期存对话上下文、长期存用户偏好和历史知识)。另外还需要一个监控层,记录每一步的输入输出,方便debug。
标准答案参考:
Agent系统核心模块架构├── 感知层 (Perception)│ ├── 输入解析器:意图识别、实体抽取│ └── 上下文组装器:融合历史记忆和当前输入├── 规划层 (Planning)│ ├── 任务分解器:将复杂任务拆解为子任务DAG│ └── 决策引擎:基于当前状态选择下一步动作├── 执行层 (Execution)│ ├── 工具调用器:统一接口调用外部API│ └── 结果处理器:解析并标准化返回结果├── 记忆层 (Memory)│ ├── 短期记忆:对话上下文、当前任务状态│ └── 长期记忆:向量数据库、知识图谱└── 监控层 (Observability) ├── 链路追踪:记录每一步的输入输出 └── 异常告警:超时、重试、失败率监控- Agent在执行任务时,如果调用外部工具或API出现超时、异常等情况,一般应该如何设计容错机制?
我的回答:说到了超时重试、指数退避、熔断器模式,还提到了需要区分“可重试异常”(如网络抖动)和“不可重试异常”(如认证失败)。
标准答案参考:
容错机制设计可以从这几个层次入手:
- 超时控制:为每次API调用设置合理的超时时间,不同接口超时阈值不同。
- 重试机制:采用指数退避重试,避免雪崩。一般重试3次,间隔 2^i 递增。
- 降级策略:主API不可用时切换备用方案,如主模型超时则换小模型快速响应。
- 熔断器:错误率达到阈值后直接熔断,快速失败返回兜底话术。
- 异常分类:区分临时性错误(网络超时、限流)和永久性错误(参数错误、认证失败),只有临时性错误才重试。
# 简易重试逻辑def call_with_retry(func, max_retries=3): for i in range(max_retries): try: return func() except TimeoutError: wait = 2 ** i # 指数退避 time.sleep(wait) except AuthError: raise# 不重试 raise Exception("Max retries exceeded")- 是否考虑过让大模型参与错误分析和自动恢复?这种方案有什么优缺点?
我的回答:考虑过,但生产环境不太敢用。优点是灵活,大模型能理解各种奇怪的错误信息并给出修复建议;缺点是稳定性差,模型可能误判,最坏情况是把一个本可简单恢复的错误搞得更复杂。
标准答案参考:
优点:
- 错误信息是非结构化的,传统规则很难覆盖所有情况,大模型的理解能力强。
- 能提供修复建议,而不只是报错。
缺点:
- 大模型自身的幻觉问题,可能给出错误的分析结论。
- 自动恢复操作有风险,比如误删数据或错误地重试了非幂等操作。
- 额外调用大模型会增加成本和延迟。
折中方案:让大模型做错误分析和建议,但最终决策由人工或预设规则执行。或者只在低风险场景(如对话体验优化)中启用自动恢复,高风险操作(如数据库写入)必须人工确认。
- Agent中的短期记忆和长期记忆分别有什么作用?通常会如何实现?
我的回答:短期记忆存当前会话的上下文,保证多轮对话的连贯性;长期记忆存用户画像、历史行为、知识库。短期用Redis或内存缓存,长期用向量数据库加Embedding检索。
标准答案参考:
短期记忆:
- 作用:维持当前任务的状态,记录已经完成哪些步骤、下一步要做什么。
- 实现:会话窗口(Sliding Window),保留最近N轮对话;或者用Redis缓存当前会话的完整上下文。
长期记忆:
- 作用:跨会话的知识沉淀,比如用户的偏好设置、之前解决过的问题。
- 实现:向量数据库(如Pinecone、Milvus)存储Embedding,配合语义检索召回相关内容。也可以结合传统数据库存储结构化信息。
两者配合的关键在于检索时机——不是每次对话都查长期记忆,而是先由Agent判断“这个任务是否需要历史知识”,再做检索,节省Token。
- 在Agent开发过程中,上下文为什么需要进行压缩?压缩后可能导致信息缺失,应该如何解决?
我的回答:主要原因是大模型的上下文窗口有限,长对话或复杂任务容易爆窗口。压缩的常见方法有摘要和剪枝。
标准答案参考:
为什么需要压缩:
- 成本:Token越多,调用成本越高。
- 速度:输入越长,推理延迟越大。
- 窗口限制:虽然现在模型上下文已经很大(如200K),但超长上下文的推理效果会下降。
压缩方法:
- 摘要压缩:用LLM对历史对话生成简短摘要。
- 剪枝:去除冗余信息,比如重复的中间步骤。
- 向量检索替代:不把全部历史塞进上下文,而是按需检索相关内容。
信息缺失的解决:
- 分层记忆:保留完整的原始日志,压缩的只是传入LLM的部分。如果发现信息不足,可以回溯原始日志。
- 重要性评分:对每条信息打分,压缩时优先保留高分信息。
- 渐进式披露:先给模型一个摘要,如果模型判断需要细节,再通过工具调用获取完整内容。
压缩前:[完整对话 50轮 + 工具调用记录 + 中间推理步骤] → 超长压缩后:[摘要:用户想订机票,已选好航班,等待支付] → 短信息缺失风险:支付方式偏好、用户特殊要求等细节可能丢失解决方案:关键信息用结构化字段单独提取,不与摘要混在一起- Prompt优化除了添加规则约束之外,还有哪些常见的方法?你在实际使用中有哪些经验?
我的回答:Few-shot示例、结构化输出约束(JSON Schema)、思维链、角色设定、动态Prompt拼接。实际中最管用的是Few-shot,给两个高质量示例比写一堆规则效果好得多。
标准答案参考:
- Few-shot / In-context Learning:给2-3个高质量示例,比写规则更有效。示例要覆盖边界情况。
- Chain-of-Thought(CoT):引导模型一步步推理,而不是直接给答案。
- 结构化输出约束:指定输出格式(JSON Schema、XML标签),方便后续解析。
- 角色设定(System Prompt):限定Agent的人格和知识边界,比如“你是一个MySQL专家,只回答数据库相关问题”。
- 动态Prompt:根据任务类型动态拼接不同的Prompt片段,避免单一Prompt太臃肿。
- 自我纠错指令:在Prompt里要求模型在不确定时主动说明,而不是瞎编。
实际经验:规则写太多反而让模型畏手畏脚,容易拒绝正常请求。通常保留3-5条核心约束,剩下的用示例来暗示效果更好。
- 当模型出现幻觉问题时,一般有哪些解决思路?
我的回答:幻觉的本质是模型在“猜”答案而不是“查”答案。解决思路分两条线——一是限制模型自由发挥,强制它引用外部知识源;二是在后置环节做校验,对明显不合理的输出进行拦截。
标准答案参考:
- RAG(检索增强生成):让模型基于检索到的外部文档回答,不要依赖参数化知识。关键是检索质量要高。
- 约束解码:用JSON Schema或正则表达式约束输出格式,减少自由文本生成中的幻觉。
- 自我一致性:多次采样,对多次生成结果取交集或投票。
- 事实校验:对模型输出的关键事实,用外部工具(如搜索引擎、数据库查询)交叉验证。
- 不确定性表达:要求模型在低置信度时明确说出“我不确定”,而不是强行回答。
- 如果Token消耗突然增加,你会如何定位原因并进行优化?
我的回答:先看是单次调用Token变大(Prompt太长或输出太长),还是调用次数变多(任务变复杂、有循环)。用日志分析工具统计Token分布,定位到具体环节后再针对性优化。
标准答案参考:
定位步骤:
- 分维度统计:按任务类型、时间段、用户、Agent版本等维度拆分Token消耗。
- 检查Prompt长度:是不是某个场景下拼接了过长的上下文或知识库内容。
- 检查输出长度:模型是不是在生成冗余信息(如重复解释)。
- 检查调用次数:是不是进入了死循环或过度规划。
优化手段:
- Prompt压缩:去除冗余指令,合并重复约束。
- 输出长度限制:用max_tokens参数强制限制。
- 缓存机制:对相同或相似的Query,缓存之前的回答。
- 模型降级:简单任务用小模型,复杂任务才用大模型。
- 工具调用精简:减少不必要的工具调用,合并多个操作为一个调用。
- 你有没有设计过Agent Skill?一个Skill从设计到上线通常需要考虑哪些因素?如何判断效果好坏?
我的回答:实际项目中设计过类似插件。关键考虑因素包括Skill的职责边界、输入输出Schema、错误处理、调用频率限制。
标准答案参考:
设计阶段考虑:
- 职责单一:一个Skill只做一件事,不要大而全。
- 输入输出Schema:明确定义参数类型、必填/可选、格式约束。
- 异常处理:Skill内部异常要优雅降级,不能拖垮整个Agent。
- 幂等性:同一个请求多次调用结果一致,尤其是涉及写操作的Skill。
- 超时设置:不同Skill的超时阈值不同,查询类可长一点,写操作类要短。
上线考虑:
- 版本管理:Skill升级要兼容旧版调用方式。
- 灰度发布:先小流量验证,再全量。
- 监控告警:成功率、延迟、调用量三个核心指标。
效果判断:
- 客观指标:调用成功率、平均响应时间、Token消耗。
- 主观指标:用户反馈、任务完成率。
- 对比测试:有Skill和无Skill的完成质量差异。
- 介绍一下之前做过的相关项目,这个项目是完全自主开发,还是基于已有开源方案进行改造?
如实回答就好,关键是要说清楚哪些是自研、哪些是借鉴、自己的贡献是什么。
我的回答:项目是基于开源框架(LangChain)做的二次开发,但核心的调度逻辑和多Agent协作协议是自研的,因为开源方案在任务编排上不够灵活。
面试官关注点:不是考你“能不能造轮子”,而是看你有没有技术判断力——什么场景该自研、什么场景该复用。如果每个项目都从零开始写,反而是减分项。
- 在项目过程中遇到过哪些比较困难的问题?你主要负责哪些部分?最后取得了什么结果?
又是老生常谈的“项目难点”问题,但Agent项目确实有些特殊的坑可以讲。
我的回答:最头疼的是多Agent协作时的死锁问题——Agent A等Agent B的结果,Agent B又在等Agent A。解法是引入超时机制和优先级调度,超时未返回的Agent直接跳过,由主Agent做兜底决策。
标准回答框架:问题是什么 → 当时怎么想的 → 尝试了什么方案 → 最终怎么解决的 → 量化结果。
- Java线程池的核心参数有哪些?线程提交任务后的执行流程是怎样的?
从这里开始画风突变,从AI Agent直接跳到Java基础。
我的回答:七个核心参数——corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。提交任务后的流程是:核心线程数未满则新建线程执行,满了则入队,队列满了则新建非核心线程,线程数达到最大值则触发拒绝策略。
标准答案参考:
// Java线程池核心构造参数public ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 空闲线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 任务队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略)执行流程:
- 如果让你重新设计一个线程池,你会重点考虑哪些问题?
我的回答:这个问题考察的是对线程池本质的理解,而不是背参数。核心问题是“线程数设多少”。IO密集型和CPU密集型的线程数配置差异很大。
标准答案参考:
- 线程数动态调整:根据系统负载自动调整线程数,而不是固定值。可以基于CPU利用率、队列深度等指标动态扩缩。
- 任务分类隔离:不同类型的任务(IO密集型 vs CPU密集型)使用不同的线程池,避免互相影响。
- 队列策略选择:有界队列防OOM,但无界队列可能堆积任务,需要根据场景权衡。
- 优雅关闭:shutdown()和shutdownNow()的合理使用,确保任务能安全终止。
- 可观测性:线程池的活跃线程数、队列大小、完成任务数等指标需要暴露出来。
线程数配置公式:
- CPU密集型:
线程数 = CPU核数 + 1 - IO密集型:
线程数 = CPU核数 * (1 + 等待时间/计算时间)
- JVM加载一个class文件的完整过程是什么?
我的回答:加载 → 验证 → 准备 → 解析 → 初始化,五个阶段。面试官追问了“准备阶段做了什么”,回答是给类变量分配内存并设置初始值(不是赋值)。
标准答案参考:
加载:通过全限定名查找并加载class文件,生成Class对象。
验证:确保class文件的字节流符合JVM规范,防止恶意代码。
准备:为类变量(static变量)分配内存,并设置默认初始值(int为0,引用为null)。注意不是赋值阶段,赋值在初始化阶段。
解析:将常量池中的符号引用替换为直接引用(内存地址)。
初始化:执行类构造器<clinit>方法,初始化静态变量和静态代码块。
- MySQL中的undo log、redo log和binlog分别解决什么问题?它们之间有什么区别?
我的回答:undo log做事务回滚和多版本并发控制(MVCC),redo log做崩溃恢复(保证事务持久性),binlog做主从复制和数据恢复。
标准答案参考:
| undo log | redo log | binlog | |
|---|---|---|---|
| 层次 | InnoDB存储引擎层 | InnoDB存储引擎层 | MySQL Server层 |
| 作用 | 事务回滚、MVCC(多版本并发控制) | 崩溃恢复(保证持久性) | 主从复制、数据恢复 |
| 内容 | 逻辑日志,记录数据变更前的旧值 | 物理日志,记录数据页的物理修改 | 逻辑日志,记录SQL语句或行变更 |
| 写入时机 | 事务执行过程中写入 | 事务执行过程中写入(WAL机制) | 事务提交时写入 |
| 循环/追加 | 循环写入 | 循环写入 | 追加写入 |
- 什么是MySQL两阶段提交?为什么需要这个机制?
我的回答:两阶段提交是保证redo log和binlog数据一致性的机制,分Prepare阶段和Commit阶段。如果不做两阶段提交,数据库崩溃恢复后可能出现主从数据不一致。
标准答案参考:
两阶段提交(2PC)发生在事务提交时:
为什么需要2PC:因为redo log和binlog是两个独立的日志,写入时机不同。如果只写redo log不写binlog,主从同步会丢数据;如果只写binlog不写redo log,数据库崩溃后事务无法恢复。两阶段提交确保要么两个日志都写成功,要么都不算成功。
- 算法题:合并两个有序数组
LeetCode 88题,经典双指针。面试时写出来了,但因为在前面Java和MySQL花了太多精力,写的时候思路有点卡。
标准答案:
public void merge(int[] nums1, int m, int[] nums2, int n) { int p1 = m - 1; int p2 = n - 1; int p = m + n - 1; while (p1 >= 0 && p2 >= 0) { if (nums1[p1] > nums2[p2]) { nums1[p] = nums1[p1]; p1--; } else { nums1[p] = nums2[p2]; p2--; } p--; } // nums2剩余元素直接copy while (p2 >= 0) { nums1[p] = nums2[p2]; p2--; p--; }}- 反问环节
问了一个问题:Agent方向的工程落地和前沿研究,这个岗位更侧重哪个方向?
面试官说两者都涉及,但当前阶段更关注工程落地能力——能稳定、高效地把Agent系统部署到生产环境,比单纯追求SOTA模型更重要。
这个回答其实也解释了他为什么后半程全在问Java和MySQL——Agent系统的稳定性严重依赖后端基础设施。
学AI大模型的正确顺序,千万不要搞错了
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋
📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~
