AI 应用研发工程师一面面经
完整信息
本篇目录
大家好,我是Yuka。
9.14下午面的,9.17官网流程终止。阿里味很重,面试官不开摄像头,开口就是Skill、MCP、Harness、MetaHarness,我像在报菜名,报着报着就卡壳了。
上来没太多寒暄,自我介绍后直接项目拷打。手撕最长有效括号,第二道岛屿数量先DFS再BFS。后面全程场景题,从Agent架构问到缓存一致性,从RAG排查问到线程池配置。
总结下来,我输在Harness和一致性场景上,答得太虚了。这篇文章把28道题全部复盘一遍,每道都附上我现场的回答和事后补的思考。准备阿里Agent岗的朋友,建议收藏。
手撕一:最长有效括号
用栈。栈底放一个-1作为哨兵,遍历字符串,遇到左括号入栈,遇到右括号先弹出,如果栈空就把当前索引入栈作为新的哨兵,否则当前索引减栈顶就是当前有效长度。
时间复杂度O(n),空间O(n)。也可以用动态规划,dp[i]表示以i结尾的最长有效括号长度。现场我写了栈版本,面试官没追问。
手撕二:岛屿数量,先DFS再BFS
DFS:遍历矩阵,遇到'1'就岛屿数加一,然后递归把相连的'1'都标记为'0'。BFS:遇到'1'就入队,然后层序遍历把相连的'1'标记为'0'。
DFS用递归,BFS用队列。两个版本都写了。面试官追问:如果矩阵很大,DFS递归会不会栈溢出?答:会,所以大规模场景用BFS或者迭代式DFS。
自我介绍
常规。我重点讲了CR Agent项目,强调了对Agent架构、工具调用、上下文管理的理解,以及实际踩过的坑。你这个CR Agent具体解决什么问题
CR Agent是代码审查Agent,解决的是人工Code Review效率低、容易漏检的问题。它自动扫描代码变更,检查代码规范、潜在bug、安全漏洞,生成审查报告。
具体流程是:监听Git webhook,拉取diff,解析变更文件,对每个文件做静态分析加LLM审查,最后汇总成报告推送到PR评论区。我负责的是审查策略设计和多Agent协作部分。
踩过的坑:早期全量扫描,大仓库一次要跑半小时。后来改成增量扫描加高风险区域聚焦,降到3分钟。
- 为什么用Agent,不用固定Workflow
固定Workflow适合流程固定的场景,但代码审查的复杂度在于不同类型的代码需要不同的审查策略。比如SQL注入检测需要看数据库操作,XSS检测需要看前端渲染,并发bug需要看锁的使用。这些不是固定步骤能覆盖的。
Agent的优势是动态决策——它能根据代码类型自动选择审查策略,遇到不确定的还能追问或查文档。我实际对比过,固定Workflow的漏检率是Agent的2倍多,因为Workflow只能覆盖预设规则,Agent能发现规则之外的问题。
当然Agent也有代价,延迟更高、成本更贵。所以我的设计是混合:简单规则用Workflow快速过,复杂逻辑用Agent深度审。
- Workflow和自治Agent的区别是什么?什么场景更适合Workflow
Workflow是预设路径,步骤固定,稳定高效可预测。自治Agent是动态决策,灵活但成本高、不可预测。
Workflow更适合:流程标准化程度高、步骤明确、不需要动态推理的场景。比如订单处理、数据ETL、定时报表、CI/CD流水线。这些场景用Agent是浪费,Workflow又快又稳。
自治Agent适合:任务复杂多变、需要动态推理、工具组合不固定的场景。比如代码审查、复杂问题解答、行程规划。
我踩过的坑:早期把定时报表也用Agent做,结果每次跑都要调LLM,成本高还不稳定。后来改回Workflow,成本降了90%。
- ReAct和Plan-and-Execute怎么选
ReAct是边走边看,Think→Act→Observe循环,灵活但效率低,容易死循环。Plan-and-Execute是先规划再执行,效率高但规划可能不准。
选型看任务特征:任务明确、步骤可预测的用Plan-and-Execute。任务模糊、需要动态探索的用ReAct。
我项目里用的是混合模式:Planner先生成粗粒度计划,每个步骤内部用ReAct执行。如果执行不下去,回退到Planner重新规划。这样既有规划的效率,又有ReAct的灵活性。
踩过的坑:纯ReAct在复杂任务上容易路径震荡,反复调同一个工具。后来加了规划层才解决。
- Skill、MCP、Function Calling三者区别是什么
Function Calling是模型输出结构化调用指令,框架解析后执行。它是模型层面的能力,不涉及工具怎么发现、怎么管理。
MCP是标准化协议,定义了工具怎么暴露、怎么发现、怎么调用、怎么传参。它解决的是工具集成的标准化问题——一个MCP Server写一次,所有支持MCP的Agent都能用。
Skill是面向场景的能力封装,一个Skill可能包含多个Tool调用,加上Prompt模板和业务逻辑。比如“查天气”是Tool,“规划行程”是Skill。
三者关系:Function Calling是底层机制,MCP是标准化协议,Skill是业务封装。2026年MCP已经演进到无状态核心,支持云原生水平扩展,Agent Plugins 1.0.0规范用plugin.json标准化了Skill打包。
- 你项目里的Skill怎么设计?输入输出契约是什么
每个Skill是一个独立模块,暴露name、description、inputSchema、execute。inputSchema用JSON Schema定义,明确参数名、类型、是否必填、枚举值。输出统一格式,包含status、data、error、metadata。
契约设计的关键是稳定——一旦发布,参数不能随便改,要加版本号。我踩过坑:Skill参数从query改成search_query,结果所有调用方都挂了。后来加了版本兼容层,旧参数名自动映射到新参数名。
另外,Skill要有超时和重试配置,这些也在契约里定义,调用方不用关心底层实现。
- Skill怎么渐进式加载?工具特别多怎么办
渐进式加载分两步:先加载Skill索引,只包含名称和一句话描述,总token控制在5000以内。模型判断需要哪类Skill后,再加载该类下所有Skill的完整Schema。
工具特别多的时候,用向量检索做筛选。每个Skill的brief做embedding存向量库,用户query进来算相似度,取Top-20加载完整描述。这样1000个Skill也只加载20个,token控制在2000以内。
我项目里Skill多的时候Prompt从8000 token降到1500 token。2026年Agent Plugins规范让Skill可以跨框架复用,不用为每个框架维护独立包装层。
- MCP获取工具列表的完整流程讲一下
MCP Client启动时连接MCP Server,发送initialize请求,Server返回能力声明,包括支持的工具列表。Client收到后缓存工具列表,后续调用时直接引用。
如果Server支持动态工具发现,Client可以发tools/list请求获取最新工具列表。工具调用时,Client发tools/call请求,带上工具名和参数,Server执行后返回结果。
2026年MCP无状态核心设计让Server可以水平扩展,Client通过标准HTTP header路由,不需要深度包检测。负载均衡用标准轮询,比自研路由协议更可靠。
- 如果有100个MCP工具,Agent怎么选?怎么保证稳定性
100个工具不能全塞进Prompt。分层路由:第一层按类别粗筛,第二层在类别内用向量相似度精排,取Top-5加载完整描述。
稳定性保障:工具调用前加参数校验,格式不对直接拦截。工具调用后加结果校验,返回异常就重试或降级。加熔断机制,连续失败就切断该工具,避免拖垮整个Agent。
我踩过坑:100个工具全加载,Prompt爆炸,模型选错工具。后来加了分层路由,准确率从60%提到90%。
- 你怎么理解Harness?Harness和Agent框架的关系是什么
Harness是Agent的运行时框架,负责管理执行循环、工具调用、状态管理、异常处理。它比Agent框架更聚焦在“运行”这一层。
Agent框架更宽泛,可能包括Harness加开发工具加部署工具。Harness是Agent框架的核心组件,但不是全部。
DeepSeek Harness的核心理念是“一切皆插件”,模型适配器、工具注册表、会话管理都是可替换的插件。和LangChain的区别是,LangChain是框架优先,你按它的方式写代码;Harness是组合优先,所有组件都是插件,你可以替换任意模块。
2026年Harness Engineering成为Agent工程化的主流思路,不是从零搭框架,而是在成熟运行时上做插件化扩展。
- 看过DeepSeek Harness吗?和Claude Code有什么区别
看过。DeepSeek Harness是开源的Agent运行时,基于Cordis元框架,所有组件都是插件。Claude Code是Anthropic的闭源Agent产品,聚焦在代码场景。
核心区别:Harness是运行时,Claude Code是应用。Harness提供基础能力,Claude Code提供开箱即用的体验。Harness可以定制,Claude Code不能。
我实际用下来,Harness适合需要深度定制的团队,Claude Code适合快速上手。2026年Harness生态里有个ViNote项目,用SQLite做会话恢复,流式交互串联视频检索、下载、转写和笔记生成,架构很干净。
- Agent上下文超限怎么处理?滑动窗口和摘要压缩各自牺牲了什么
滑动窗口牺牲了早期上下文,保留最近对话。优点是简单快,缺点是会丢失早期的重要信息。摘要压缩牺牲了细节,保留关键结论。优点是不会丢关键信息,缺点是摘要本身可能丢信息,而且有生成开销。
我项目里用的是组合策略:滑动窗口保留最近N轮,超出部分做结构化摘要——实体、事件、结论、待办分开存。实体和结论保留原文,事件和待办用简短描述。检索时按需召回。
踩过的坑:纯摘要压缩,结果关键数字被压缩没了。后来改成结构化摘要,关键信息保留原文。
- 工具调用失败怎么兜底?重试策略怎么设计
三层兜底。第一层:区分可重试和不可重试错误。超时、网络抖动、限流可重试。参数错误、权限错误不可重试。
第二层:重试策略用指数退避,第一次延迟1秒,第二次2秒,第三次4秒,最多3次。
第三层:重试失败后降级。主工具挂了切备用,备用也没有就返回缓存或默认值。
我踩过坑:重试没加去重,结果下单接口重试导致重复下单。后来加了request_id做幂等键才解决。另外,重试要有全局限流,避免重试风暴打垮下游。
- 多Agent写同一个文件怎么避免冲突
用分布式锁或乐观锁。分布式锁用Redis,文件路径做key,获取锁才能写。乐观锁用版本号,写之前检查版本,不匹配就重试。
我项目里用的是乐观锁加重试。因为分布式锁在Agent场景下容易死锁——一个Agent持有锁但挂了,其他Agent一直等。乐观锁没这个问题,版本不匹配就重试,最多重试3次。
更细粒度的是分段锁,不同Agent写不同区域。2026年A2A协议里有任务编排和状态管理,多Agent协作可以通过A2A的任务锁机制避免冲突,比自研锁更标准。
- Agent长任务跑失败,怎么定位是模型、检索还是工具的问题
分段排查。先看日志,每个步骤的输入输出都记下来。如果模型输出的Thought不合理,是模型问题。如果检索结果不相关,是检索问题。如果工具返回错误,是工具问题。
我实际项目里加了一个“决策链路追踪”,每个决策点记录四件事:输入状态、决策内容、备选方案、最终选择。复盘时按trace_id查询,就能看出哪一步出了问题。
踩过的坑:长任务失败,排查半天发现是中间某步工具返回了脏数据,模型基于脏数据做了错误决策。后来加了工具结果校验才解决。
- 长任务从5分钟变成20分钟,怎么分析延迟
分段计时。把任务拆成子步骤,每个步骤记录耗时,找出最慢的步骤。
常见原因:模型调用变慢(上游限流或模型升级)、工具调用变慢(下游服务慢)、检索变慢(向量库索引膨胀)、上下文变长(token多了推理慢)。
我踩过坑:任务变慢,排查发现是上下文越来越长,LLM推理时间线性增长。后来加了上下文压缩,延迟降回5分钟。
工具层面,用Prometheus记录每个步骤的P50/P95/P99,Grafana展示,一眼看出瓶颈在哪。
- 线上高并发场景,Agent服务怎么限流、降级、熔断
限流用令牌桶,每秒生成固定令牌,请求消耗令牌,桶空就拒绝。降级分三级:一级切备用模型,二级从Agent降到Workflow,三级返回友好错误。熔断用Hystrix或Sentinel,连续失败超阈值就切断,过段时间半开试探。
我踩过坑:没做限流,突发流量把模型API打爆,所有请求都超时。后来加了令牌桶,超限请求排队或拒绝,系统稳定多了。
Agent场景的特殊性是单次调用成本高、延迟长,所以限流要更保守,降级要更果断。
- RAG召回高但答案不准,怎么排查
召回高说明相关文档找到了,答案不对,问题在生成或上下文构建。
排查:第一,看Rerank后的Top-K有没有正确答案。第二,看上下文拼接顺序,关键信息是不是在中间,调整到开头结尾。第三,看Prompt模板,指令是否明确。第四,看LLM本身,换模型或调temperature。第五,看召回内容是否有冲突,多文档说法不一致时加冲突检测。
我踩过坑:召回文档有正确答案,但LLM被无关信息干扰答错。后来加了Rerank和上下文压缩才解决。
- 文档切分策略怎么选?Markdown没标题怎么切
切分粒度看文档类型:技术文档512 tokens,法律合同256 tokens,代码按函数切分。重叠窗口10%-15%,保证跨chunk的句子不被截断。
Markdown没标题时,按段落和空行切分。连续两个换行视为段落边界,代码块和表格整体保留不切。如果段落超长,按句子边界切。
踩过的坑:统一用512,结果法律合同条款被切碎,召回效果差。后来按文档类型动态调整才解决。
- BM25和向量检索怎么融合?RRF的k值怎么设
用RRF(倒数排名融合)。每路召回Top-K,按排名算分:score = Σ 1/(k + rank_i)。RRF不需要归一化分数,直接融合排名。
k值通常设60。k越小,排名靠前的权重越大;k越大,排名影响越平滑。我实际用60,效果稳定。融合后再用Reranker做二次精排,取Top-5送LLM。
踩过的坑:k值设太小,头部结果权重过大,长尾好结果被淹没。后来调回60才平衡。
- Java线程池核心参数怎么配?IO密集和CPU密集分别怎么设
核心线程数:IO密集型设2倍CPU核数,CPU密集型设CPU核数+1。最大线程数设核心的2-3倍。队列用有界队列,避免OOM。拒绝策略用CallerRunsPolicy,让提交任务的线程自己执行,起到背压作用。
我调过线程池,核心数设太小任务排队,设太大上下文切换开销高。Agent的工具调用是IO密集型,核心线程数设为CPU核数的2倍。
2026年Java虚拟线程已经正式可用,单线程仅占几百字节内存,支持百万级并发,IO密集型场景用虚拟线程比传统线程池更合适。
- ThreadLocal原理,为什么会内存泄漏
每个Thread内部有ThreadLocalMap,key是ThreadLocal对象(弱引用),value是存储的值(强引用)。线程池里的线程复用,ThreadLocal没remove,key被GC后value还挂在Entry上,导致内存泄漏。
解决:每次用完在finally里remove。我踩过坑:线上OOM,MAT分析发现ThreadLocalMap里堆了大量Session对象,后来在Filter里统一remove才解决。
虚拟线程场景下ThreadLocal的使用要更小心,因为虚拟线程创建成本极低,如果每个虚拟线程都创建独立ThreadLocal不清理,内存压力比传统线程池更大。
- MySQL深分页为什么越往后越慢?怎么优化
LIMIT 100000, 10会先扫描前100000行再取10行,越往后扫描越多,所以越慢。
优化:第一,用游标分页,记录上一页最后一条的ID,下一页用WHERE id > last_id LIMIT 10。第二,用覆盖索引,SELECT id FROM table LIMIT 100000, 10先查ID再回表。第三,业务上限制最大页数,不允许翻太深。
我踩过坑:后台管理列表翻到后面几页直接超时,后来改成游标分页才解决。
- Redis缓存击穿、穿透、雪崩分别怎么解决
穿透:查不存在的数据,缓存和数据库都没有。解决:布隆过滤器拦截,或者空值缓存设短TTL。
击穿:热点key失效瞬间大量请求打到DB。解决:互斥锁,只允许一个线程查DB,其他等待。
雪崩:大量key同时失效或Redis挂了。解决:过期时间加随机偏移,Redis高可用,本地缓存兜底,限流熔断。
我踩过坑:热点key没加互斥锁,失效瞬间DB被打爆。后来加了互斥锁才解决。
- 先更新数据库再删缓存,删缓存失败了怎么办
这是Cache Aside模式的经典问题。删缓存失败会导致缓存里是旧数据,数据库是新数据,不一致。
解决方案:第一,删缓存失败就重试,用消息队列异步重试。第二,用binlog订阅,数据库变更后自动删缓存。第三,设短TTL兜底,即使删失败,过期后也会自动失效。
我踩过坑:删缓存失败没重试,结果缓存和数据库不一致持续了几小时。后来加了消息队列重试才解决。
- 如果消息队列重试删除缓存,但旧值又写回来了,怎么保证一致性
这是并发场景下的经典问题。线程A更新数据库,线程B读数据库旧值,线程B写缓存旧值,线程A删缓存,结果缓存里是旧值。
解决方案:第一,延迟双删,更新数据库后删一次缓存,延迟几百毫秒再删一次。第二,用版本号,缓存里存版本号,写缓存时检查版本,旧版本不写。第三,串行化,同一数据的读写走同一个队列。
我踩过坑:没做延迟双删,高并发下缓存和数据库不一致。后来加了延迟双删才缓解。更彻底的是用binlog订阅,数据库变更后删缓存,保证顺序。
- AI Coding:写一个商品计价系统,优惠策略可以随时更新,你会怎么设计
用策略模式加配置化。每种优惠策略是一个独立类,实现统一接口。策略配置存数据库或配置中心,运行时动态加载。
计价流程:基础价格→应用优惠策略链→计算最终价格。优惠策略可以叠加,也可以互斥,用规则引擎控制。
我踩过坑:早期优惠逻辑硬编码,改一次要发版。后来改成配置化,运营自己就能改,不用开发介入。
2026年AI Coding工具可以辅助生成策略类,但核心的规则引擎和边界条件还是要人工设计。优惠计算涉及金额,必须加校验和测试,不能全靠AI生成。
反问
我问了三个问题:团队主要做商家侧还是用户侧Agent?面试官说都有,商家侧偏工具,用户侧偏交互。技术栈是Java为主吗?答:Java为主,部分Python。这个岗位更偏平台还是业务落地?答:平台和业务都有,看具体项目。
写在最后
阿里淘天一面强度不低,但不像字节那样追着代码细节打,更像在考你有没有真正做过Agent工程。我输在Harness和一致性场景上,答得太虚了。
面试官问的都是“你怎么设计”“出问题了怎么办”,不是背概念能过的。尤其是缓存一致性那几道,问得很深,没有真正踩过坑的人根本答不上来。
祝大家面试顺利,别像我一样凉得这么快 🙏
本篇目录
当前问题0144
- 01
手撕一:最长有效括号
- 02
手撕二:岛屿数量,先DFS再BFS
- 03
如果矩阵很大,DFS递归会不会栈溢出?
- 04
自我介绍
- 05
你这个CR Agent具体解决什么问题
- 06
为什么用Agent,不用固定Workflow
- 07
Workflow和自治Agent的区别是什么?什么场景更适合Workflow
- 08
ReAct和Plan-and-Execute怎么选
- 09
Skill、MCP、Function Calling三者区别是什么
- 10
Skill、MCP、Function Calling三者区别是什么
- 11
你项目里的Skill怎么设计?输入输出契约是什么
- 12
Skill怎么渐进式加载?工具特别多怎么办
- 13
Skill怎么渐进式加载?工具特别多怎么办
- 14
MCP获取工具列表的完整流程讲一下
- 15
如果有100个MCP工具,Agent怎么选?怎么保证稳定性
- 16
你怎么理解Harness?Harness和Agent框架的关系是什么
- 17
看过DeepSeek Harness吗?和Claude Code有什么区别
- 18
Agent上下文超限怎么处理?滑动窗口和摘要压缩各自牺牲了什么
- 19
Agent上下文超限怎么处理?滑动窗口和摘要压缩各自牺牲了什么
- 20
工具调用失败怎么兜底?重试策略怎么设计
- 21
工具调用失败怎么兜底?重试策略怎么设计
- 22
多Agent写同一个文件怎么避免冲突
- 23
Agent长任务跑失败,怎么定位是模型、检索还是工具的问题
- 24
长任务从5分钟变成20分钟,怎么分析延迟
- 25
线上高并发场景,Agent服务怎么限流、降级、熔断
- 26
线上高并发场景,Agent服务怎么限流、降级、熔断
- 27
RAG召回高但答案不准,怎么排查
- 28
文档切分策略怎么选?Markdown没标题怎么切
- 29
文档切分策略怎么选?Markdown没标题怎么切
- 30
BM25和向量检索怎么融合?RRF的k值怎么设
- 31
BM25和向量检索怎么融合?RRF的k值怎么设
- 32
Java线程池核心参数怎么配?IO密集和CPU密集分别怎么设
- 33
ThreadLocal原理,为什么会内存泄漏
- 34
ThreadLocal原理,为什么会内存泄漏
- 35
MySQL深分页为什么越往后越慢?怎么优化
- 36
Redis缓存击穿、穿透、雪崩分别怎么解决
- 37
先更新数据库再删缓存,删缓存失败了怎么办
- 38
先更新数据库再删缓存,删缓存失败了怎么办
- 39
如果消息队列重试删除缓存,但旧值又写回来了,怎么保证一致性
- 40
AI Coding:写一个商品计价系统,优惠策略可以随时更新,你会怎么设计
- 41
AI Coding:写一个商品计价系统,优惠策略可以随时更新,你会怎么设计
- 42
团队主要做商家侧还是用户侧Agent?
- 43
技术栈是Java为主吗?
- 44
这个岗位更偏平台还是业务落地?
