聊一聊最近碰到的一些 Agent 面试题(三)

淘天 27 届暑期实习生正在招聘 各方向都有海量 HC 欢迎看我置顶帖子投递

面试题 11:代码生成 Agent 和普通代码补全(Copilot 式)的本质区别是什么?设计一个能完成"跨文件修改"任务的代码 Agent,核心难点在哪?

参考答案

本质区别在于决策粒度。

代码补全是行级决策——光标在哪,就在那个位置生成接下来几行代码。它的上下文是当前文件的局部内容,不需要做规划、不需要选择工具、不需要多步推理。本质上是一个"自动完成"功能,不是 Agent。

代码生成 Agent 是任务级决策——接收一个自然语言描述的需求("给这个项目加一个用户认证功能"),然后自主决定需要读哪些文件来理解现有架构、需要修改哪些文件、每个文件改什么、修改的先后顺序、改完之后怎么验证。它操作的粒度是整个代码仓库,面对的是一个多步规划和执行的问题。

跨文件修改的核心难点:

1. 代码库理解——"看懂"整个项目

Agent 不可能把整个代码仓库塞进上下文窗口。一个中等规模的项目可能有几十万行代码,而窗口只有十几万 token。所以 Agent 必须有一套高效的代码检索策略:先通过目录结构和文件名建立粗粒度的"项目地图",然后根据任务需求有针对性地读取相关文件。这个过程本身就是多轮推理——读了 A 文件发现它依赖 B 模块,再去读 B,发现 B 的接口定义在 C 里。Agent 需要像人类开发者一样"跳转查看引用"。

2. 修改一致性——改了 A 别忘了 B

跨文件修改最大的坑是不完整修改。改了一个函数的签名但没改所有调用方,加了一个新的数据库字段但没改对应的 ORM 模型和 API 序列化层。Agent 需要理解代码之间的依赖关系——函数调用链、类型引用、import 依赖、配置文件关联——才能确保修改的完整性。这比"能不能写对代码"难得多,考验的是 Agent 对代码结构的全局理解。

3. 修改顺序——先改什么后改什么

实际开发中修改顺序很重要。比如你要重命名一个被广泛引用的接口,正确做法通常是先加新接口、再逐步迁移调用方、最后删掉旧接口。如果 Agent 直接一步到位把旧接口改名,中间状态下整个项目是编译不过的。Agent 需要能规划一个每步都保持项目可用的修改序列,而不是一次性输出所有改动。

4. 验证闭环——怎么知道改对了

人类开发者改完代码会跑测试、跑编译、手动验证。Agent 也需要这个闭环:执行修改后,调用构建工具检查编译是否通过,跑现有测试看是否有回归,甚至读一下 lint 输出看是否引入了风格问题。如果验证失败,Agent 需要能分析错误信息、定位到自己哪步改错了、然后修复。这个"写 → 验证 → 修复"的内循环是代码 Agent 可靠性的关键。

追问 Q&A

Q:代码库太大看不完,Agent 怎么高效定位到需要修改的文件?

A: 分层检索。第一层用快速手段建立全局感知——读项目目录结构、读 README 和入口文件、读 package.json 或 build 配置了解项目组织方式。第二层根据任务做针对性搜索——用符号搜索找函数/类定义、用文本搜索找关键词引用、用文件名模式匹配找相关模块。第三层基于已读文件做关联跳转——发现 import 依赖就顺着读过去、发现接口调用就找实现方。整个过程就是 Agent 的多轮推理循环在代码检索这个场景上的具体应用。好的代码 Agent 通常还会维护一个"已读文件摘要"列表,避免重复读取同一个文件。

Q:Agent 生成的代码如何保持和现有项目的风格一致?

A: 风格一致性来自两个方面。隐式学习:Agent 在读取现有文件时,已经在上下文中"看到"了项目的代码风格——命名规范、缩进方式、注释习惯、错误处理模式。只要上下文里有足够的代码样本,LLM 通常能自动模仿。显式约束:把项目的 lint 规则、代码规范说明注入系统提示词,或者在生成后直接跑一遍 linter/formatter 做自动修正。实际中后者更可靠——不要完全依赖 LLM 的模仿能力,用工具做确定性保障。

面试题 12:代码 Agent 的"写 → 运行 → 修复"循环应该怎么设计?失败修复最多尝试几轮,为什么?

参考答案

循环结构:

代码 Agent 的核心执行循环不是简单的"一次生成",而是一个带反馈的迭代修正过程:生成代码 → 执行验证(编译/测试/lint)→ 分析错误输出 → 修正代码 → 再次验证。这个循环持续直到验证通过或达到重试上限。

每一步的关键设计:

验证手段的选择:不同的验证给 Agent 提供不同质量的反馈信号。类型检查/编译错误是最高质量的反馈——精确到行号、错误类型明确、修复方向清晰。测试失败次之——能知道哪个行为不符合预期,但定位到代码层面需要 Agent 做推理。Lint 警告最弱——通常是风格问题,不影响功能。Agent 应该按编译 → 测试 → lint 的顺序验证,先保证能跑起来,再保证行为正确,最后处理风格。

错误信息的处理:编译器/测试框架的输出往往非常长。直接把完整输出塞进上下文会浪费大量窗口空间。需要做智能截取——提取错误类型、错误位置、关键错误信息,去掉冗余的堆栈和无关的警告。保留足够 Agent 定位问题的信息量,但不塞无用的噪声。

修复时的上下文管理:每轮修复后,之前的错误版本代码还有没有价值?通常第一轮的错误版本值得保留(帮 Agent 理解"什么是错的"),但多轮累积的历史版本就应该压缩了,否则上下文里全是废弃代码。

重试上限的设定:

经验上 3 轮是一个合理的上限,背后的逻辑是:

第一轮修复:通常是修语法错误、缺少 import、类型不匹配这类明确的编译问题。成功率很高,因为错误信息指向性强。

第二轮修复:通常是修逻辑错误——第一轮编译通过了但测试失败。Agent 需要理解测试的预期行为和实际行为的差异,做更深层的推理。成功率明显下降。

第三轮修复:如果前两轮都没修好,说明 Agent 对这个问题的理解可能从根本上就偏了。再多给几轮通常是在同一个错误方向上反复打转。此时更合理的策略是退一步——放弃当前方案、重新审视整体思路、甚至换一种实现方式。

超过 3 轮还在修同一个问题,几乎一定是初始方案选择错误而不是修修补补能修好。此时应该把失败的尝试作为"反面经验"总结,重新规划。

追问 Q&A

Q:Agent 修复代码时经常引入新 bug——改好了 A 又搞坏了 B,怎么解决?

A: 核心问题是 Agent 做局部修复时缺乏全局影响评估。应对方式有两个层面。验证层面:每次修复后不只跑失败的那个测试,而是跑全量测试(或至少跑与修改文件相关的测试集)。这样新引入的回归会被立即发现。策略层面:限制每次修复的范围——修复时只改必要的部分,不做"顺便优化"。修改范围越小,引入新问题的概率越低。如果一次修复需要改很多地方,应该拆成多个小步骤,每步之后都做验证。

Q:测试通过了就代表代码正确吗?代码 Agent 的验证还有什么盲区?

A: 测试通过只能证明"覆盖到的场景是对的",无法证明代码没有问题。几个常见盲区:测试覆盖不足——如果原项目的测试覆盖率低,很多行为根本没有被验证。Agent 改坏了也不会有测试失败。非功能性问题——性能退化、内存泄漏、并发安全问题,这些普通测试很难发现。语义正确但设计不合理——代码能跑、测试通过,但实现方式是一个 hack 而不是正确的设计。自动化手段很难判断这类问题。所以生产级的代码 Agent 通常还需要在自动验证之外加一层人工审核——先由 Agent 自动完成到"测试全通过"的程度,最后由人类开发者做 code review 确认设计合理性。

面试题 13:代码 Agent 在处理存量代码时,怎么避免"破坏性重构"?什么是最小化修改原则?

参考答案

问题的根源:

LLM 生成代码时有一个固有倾向——它倾向于按照自己"认为最好"的方式重写代码,而不是在现有代码的基础上做最小改动。当你让 Agent "修复函数 A 的一个 bug"时,它可能把整个函数重写了,顺便改了变量命名、调整了代码结构、加了它认为有用的注释。表面上看代码"更好了",但实际带来几个严重问题:

diff 不可审查:人类 reviewer 看到一个函数被整个替换,根本无法快速判断哪些改动是修 bug 的、哪些是"顺手重构"的。审查成本急剧上升。

引入隐性回归:重写的代码可能改变了原始代码的某些隐含行为——边界条件处理、错误码返回、副作用顺序——这些可能不在测试覆盖范围内。

git blame 污染:大面积重写后,整个函数的 git blame 都指向 Agent 的那次提交,历史归因信息丢失。

最小化修改原则:

核心思想是只改必须改的,不碰不需要碰的

在系统提示词中明确约束 Agent 的行为——"你的修改应该尽可能小,只改变实现需求或修复 bug 所必需的代码。不要重命名现有变量,不要调整代码格式,不要添加额外的注释,不要重构你没有被要求重构的代码"。

关键实现策略:

精确定位修改点:Agent 在做修改前,先明确列出"需要改动的具体位置和改动内容",形成一个修改计划。这个计划本身就可以作为 review 的依据——改 5 处比重写整个文件更容易审查。

使用 diff 而不是全文替换:Agent 的输出格式应该是"在第 X 行,把旧内容改成新内容",而不是"这是整个文件的新版本"。这在技术上约束了 Agent 只能做局部修改,从机制上防止了大面积重写。

修改后自动对比:Agent 完成修改后,自动生成 diff 并检查——修改的行数是否合理?有没有碰到不应该碰的文件或函数?如果 diff 范围明显超出任务需要,触发自查或人工确认。

追问 Q&A

Q:有时候修复一个 bug 确实需要重构一部分代码,怎么判断这个重构是"必要的"还是"过度的"?

A: 判断标准是能不能在不重构的情况下完成任务。如果 bug 的根因是某个数据结构设计不合理,不改结构就没法修——这就是必要的重构。如果 bug 只是一个条件判断写错了,但 Agent 顺便把整个函数的控制流都重新组织了——这就是过度的。实践中可以让 Agent 做两步决策:先尝试最小修改方案,如果发现做不到或者做出来明显是 hack,再提出重构方案并说明为什么。关键是让重构成为一个有意识的决策而不是无意识的习惯。而且当需要重构时,应该把重构和功能修改分成两个独立的步骤——先重构(保持行为不变)、跑测试确认没有回归,再做功能修改。不要混在一起。

面试题 14:代码 Agent 需要理解多少项目上下文才"够用"?如何设计代码库的索引策略?

参考答案

够用的标准不是"读了多少",而是"理解了相关的依赖链"。

一个需求可能只涉及改一个文件,但要改对它,Agent 可能需要理解这个文件的上下游——它被谁调用(影响面评估)、它依赖了什么(接口约束)、相关的类型定义(参数和返回值)、对应的测试文件(验证方式)。这条依赖链就是"够用"的上下文。

索引策略的分层设计:

第零层:项目骨架

不读具体代码,只看结构——目录树、入口文件、package.json/go.mod/pyproject.toml 等配置文件。目的是让 Agent 快速建立"这个项目的大概组织方式"的认知:是前后端分离还是单体?用了什么框架?模块怎么划分的?这一层的信息量很小但价值极高,几乎每次任务都需要。

第一层:符号索引

对代码库做静态分析,提取函数名、类名、接口定义、导出符号,构建一个轻量的符号表。Agent 做任务时先在符号表中搜索相关名称,快速定位到文件和行号,然后再有针对性地读具体代码。这比让 Agent 盲目遍历文件高效得多。

第二层:依赖图

基于 import/require/include 关系构建文件间的依赖图。Agent 确定了核心修改文件后,可以沿着依赖图向上(调用方)和向下(依赖方)扩展,自动找出所有可能受影响的文件。这一层解决了"改了 A 还要改什么"的问题。

第三层:语义索引

对代码块做向量嵌入,支持自然语言检索。当 Agent 需要找"处理用户认证的逻辑"但不知道具体函数名时,可以用语义搜索。这一层的精度不如符号搜索,但覆盖面更广,适合模糊搜索。

实际执行中的组合使用:

Agent 接到任务后,先用第零层了解项目结构,再用第一层或第三层定位到核心文件,读完核心文件后用第二层扩展出影响范围,最后有针对性地读取所有相关文件。整个过程在 Agent 的多轮推理循环中动态进行,而不是一开始就试图读完所有东西。

追问 Q&A

Q:索引需要多频繁更新?Agent 自己的修改会让索引过时吗?

A: 这是一个真实的工程问题。Agent 在一次任务中可能修改了多个文件,此时符号索引和依赖图就过时了。短期的解法是任务内增量感知——Agent 自己维护一个"本次修改的文件清单和改动摘要",在后续推理中参考这个清单而不是过时的索引。长期的解法是索引系统支持增量更新——文件修改后只重新索引变化的文件及其直接依赖,而不是全量重建。在实践中,精确的实时增量索引成本很高。常见的折中方案是:任务开始时做一次全量快照,任务过程中靠 Agent 的工作记忆跟踪变化,任务结束后触发增量索引更新。

面试题 15:如何评估一个代码生成 Agent 的实际能力?有哪些维度和基准?

参考答案

不能只看"能不能生成正确代码",要看完整的开发循环。

代码生成的正确率只是冰山一角。真实开发场景中,Agent 的价值体现在从理解需求到交付可用代码的完整链条上。

评估维度:

维度一:任务完成率

给定一组明确的编程任务(实现功能、修复 bug、重构代码),Agent 能成功完成多少比例。这里"成功"的定义是——生成的代码能编译通过、测试全部通过、满足需求描述。这是最基础的指标。业界常用的 benchmark 有 SWE-bench(从真实 GitHub issue 中提取的 bug 修复任务)和 HumanEval(函数级代码生成)。

维度二:修改精准度

Agent 完成任务时实际修改了多少代码?改动是否精准?和人类开发者完成同一个任务的 diff 相比,Agent 的 diff 是否有大量多余改动?改动越精准,说明 Agent 对代码库的理解越好。可以用"多余修改率"——Agent 的 diff 行数与最优 diff 行数之比——来量化。

维度三:自主程度

Agent 完成任务过程中需要多少次人工干预?完全自主完成的比例是多少?需要人工提示、纠正方向、指出遗漏的比例分别是多少?自主程度越高,Agent 在实际开发流程中的价值越大。

维度四:效率

完成一个任务需要几轮 LLM 调用?总 token 消耗是多少?端到端延迟是多少?两个 Agent 都能完成同一个任务,但一个用了 5 轮、另一个用了 25 轮,成本和体验差异巨大。

维度五:安全性

Agent 生成的代码有没有引入安全漏洞?SQL 注入、XSS、硬编码密钥、不安全的依赖——这些都需要自动扫描检查。一个功能正确但有安全漏洞的代码,在生产中是不可接受的。

追问 Q&A

Q:SWE-bench 跑分高就代表真实场景好用吗?

A: 不一定。SWE-bench 的价值在于提供了一个可量化、可复现的横向对比基准,但它和真实开发场景有几个显著差距。任务颗粒度:SWE-bench 的任务是"修复一个具体 issue",而真实开发中很多任务是模糊的——"这个页面加载太慢了""用户反馈说导出功能有问题",Agent 需要自己做问题定位。代码库复杂度:SWE-bench 选取的项目虽然是真实开源项目,但 Agent 面对的上下文通常已经被预处理过(问题描述比较清晰、定位范围相对明确)。真实场景中 Agent 面对的是完全陌生的、文档可能不完善的私有代码库。评估维度单一:SWE-bench 只看"测试是否通过",不评估代码质量、修改精准度、安全性。所以跑分要看,但不能只看跑分。更有价值的评估方式是在自己团队的真实项目上做 A/B 测试——让 Agent 处理一批真实任务,对比有 Agent 和没有 Agent 时开发者的效率差异。

面试题 16:设计一个能处理"模糊需求"的代码 Agent——用户只说"这个页面太慢了",Agent 该怎么做?

参考答案

这道题考察的是 Agent 从"模糊问题"到"具体行动"的推理链路设计。

"太慢了"不是一个可执行的指令。Agent 必须先把它转化为具体的、可度量的问题,然后才能开始修复。整个过程分为几个阶段:

阶段一:问题定义——"慢"是什么意思?

Agent 需要先收集信息来定义问题的边界。首先确认是哪个页面、什么操作慢(首次加载?交互响应?数据请求?)。如果用户没说清楚,Agent 应该主动提问而不是猜测——"你说的慢是首次打开页面的加载速度,还是页面内某个操作的响应速度?"一个能主动提问澄清需求的 Agent,比一个闷头做事做错的 Agent 有用得多。

阶段二:问题定位——慢在哪?

确认了"什么慢"之后,Agent 需要用工具做诊断而不是凭直觉猜。读取相关页面组件的代码 → 找到数据请求逻辑 → 检查是否有明显的性能反模式(在渲染循环中发请求、没有做缓存、加载了过大的依赖、无意义的重复渲染等)。如果能跑 profiling 工具就更好——用 bundle 分析工具看包大小、查看 API 响应时间日志。关键是用数据定位瓶颈,而不是凭经验猜测

阶段三:方案选择——怎么解决?

定位到瓶颈后,可能有多种修复方案。比如数据请求慢:加缓存?做懒加载?优化查询?Agent 应该给出几个方案和各自的取舍,让用户选择,或者在无法询问的场景下选择最安全(侵入性最小)的方案。性能优化领域有一个原则——先摘低垂果实,不到万不得已不做架构级改造。

阶段四:执行与验证

做出修改后,必须量化验证——不是"我觉得快了",而是"修改前 API 响应时间 800ms,修改后 200ms"或者"包体积从 2.1MB 降到 1.3MB"。有数据支撑的优化结论才有说服力。

这道题的评估重点不是性能优化知识本身,而是 Agent 面对模糊输入时的处理策略——会不会主动澄清需求、会不会用工具做诊断而不是猜测、方案选择是否有理有据。

追问 Q&A

Q:如果 Agent 的诊断方向错了——花了很多轮在排查前端渲染问题,但实际瓶颈在后端接口,怎么办?

A: 这是多步推理中典型的"方向性错误"问题。应对机制有两个。事前:在诊断阶段不要过早收窄范围。Agent 应该先用轻量手段对所有可能的瓶颈做一次快速排查(网络请求耗时、包大小、渲染次数各看一眼),而不是一上来就钻进某一个方向。事中:设置诊断轮数阈值。如果在某个方向上探索了 N 轮还没找到明确瓶颈,Agent 应该自动退出当前方向,总结"在前端渲染层面没发现明显问题",转向下一个可能性。关键是让 Agent 有"我可能搞错方向了"的自我觉察能力,而不是沿着错误方向一路走到底。这可以通过在系统提示词中明确引导:"如果连续 3 步没有取得实质性进展,请暂停并重新评估问题方向。"

#Agent##面试问题记录##面试##AI求职记录##面试官最爱问的 AI 问题是......#
全部评论

相关推荐

03-15 10:59
已编辑
美团_后端开发(实习员工)
爱写代码的菜code...:哎,自己当时拿到字节offer的时候也在感叹终于拿到了,自己当时最想去的企业就是字节,结果还是阴差阳错去了鹅厂。祝uu一切顺利!!!
点赞 评论 收藏
分享
评论
2
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务