聊一聊最近碰到的一些 Agent 面试题(四)
淘天 27 届暑期实习生正在招聘 各方向都有海量 HC 欢迎看我置顶帖子投递
面试题 17:Cursor 和传统 IDE + Copilot 插件的本质区别是什么?为什么"AI Native IDE"比"IDE + AI 插件"体验好很多?
参考答案
表面区别是功能多少,本质区别是信息流架构。
传统模式是 IDE 和 AI 各管各的。Copilot 作为插件,能拿到的信息非常有限——基本就是当前文件的内容和光标位置。它和 IDE 的关系是"寄居"的——IDE 不会为了 AI 调整自己的数据流,AI 也没办法深度访问 IDE 的内部状态。
Cursor 的做法是反过来——围绕 AI 的需求重新设计 IDE 的信息架构。AI 不再是一个插件,而是整个编辑器的一等公民。这带来了几个根本性的差异:
1. 上下文获取能力完全不同
Copilot 只能看到当前文件的局部内容。Cursor 可以主动索引整个代码库,在用户提问时自动检索相关文件、相关函数定义、相关类型声明,把这些信息组装成高质量的上下文传给 LLM。用户说"帮我改一下登录逻辑",Cursor 能自动找到认证模块、路由配置、用户模型等相关文件,而不是只盯着当前打开的那一个文件。
2. 编辑操作的粒度不同
Copilot 的输出是"在光标位置插入代码"。Cursor 的 Agent 模式可以输出跨文件的编辑操作——同时修改三个文件、创建一个新文件、删除一段旧代码。IDE 原生支持这种"多文件 diff 预览和一键应用"的交互,用户可以在应用前逐个审查每处改动。这种交互在插件模式下几乎不可能做好,因为插件没有权限重新设计 IDE 的编辑流程。
3. 反馈闭环的深度不同
Cursor 可以在 AI 生成代码后自动触发类型检查、lint 检查,把错误直接反馈给 AI 让它自动修正——整个循环在 IDE 内部闭环完成。插件模式下,AI 生成完代码就结束了,用户得自己看错误、自己复制粘贴错误信息再去问 AI。
一句话总结:插件模式下 AI 是 IDE 的附属品,AI Native 模式下 IDE 是 AI 的执行环境。
追问 Q&A
Q:Cursor 的代码库索引是怎么工作的?它的 @codebase 功能底层做了什么?
A: 核心流程是:对整个项目的代码做分块(按函数、类、文件等粒度)→ 每个块生成向量嵌入存入本地索引 → 用户提问时把问题也向量化 → 做相似性检索拿到最相关的代码块 → 作为上下文注入 prompt。这本质上就是 RAG 在代码场景的应用。但光有语义检索不够,Cursor 还会结合 IDE 本身的结构信息——LSP(Language Server Protocol)提供的符号定义、类型关系、引用关系——来补充纯语义检索可能漏掉的结构性依赖。比如语义检索可能找到了一个相关函数,但没找到它的返回类型定义——LSP 可以直接"跳转到定义"把类型信息补上。
Q:这种 AI Native IDE 的模式有没有天然劣势?
A: 有。最大的劣势是绑定性。Cursor 的核心体验和它自己的编辑器深度耦合,你没办法把这套体验完整迁移到 VS Code 或 JetBrains 上。如果你的团队对 IDE 有强制要求(比如必须用 IntelliJ),Cursor 就用不了。而 Copilot 的插件模式虽然体验弱一些,但几乎所有主流 IDE 都能装。此外,AI Native IDE 承担了更大的维护成本——每次 VS Code 上游更新,Cursor 都要做合并适配。如果上游做了大的架构变更,Cursor 的适配成本会很高。
面试题 18:Claude Code 这类终端 Agent 的交互模式和 Cursor 有什么区别?各自适合什么场景?
参考答案
核心区别在于执行环境和交互范式。
Cursor 运行在 GUI IDE 中,交互模式是可视化编辑——用户看到代码、看到 diff 高亮、用鼠标点击接受或拒绝改动。整个体验围绕"看到变化并确认"设计。
Claude Code 运行在终端里,交互模式是对话式指令——用户用自然语言描述任务,Agent 在后台自主执行一系列操作(读文件、搜索代码、编辑文件、运行命令),最后把结果报告给用户。用户不需要实时盯着每一步,更像是"委托一个开发者去做事"。
这带来了几个本质差异:
自主性程度:Cursor 的 Tab 补全和 inline edit 是人机协作模式——人类主导、AI 辅助。Claude Code 的 Agent 模式更接近全自主——用户给任务、Agent 完整执行。适合的任务粒度完全不同:写一个函数的实现用 Cursor 更顺手,做一个跨文件的功能改造用 Claude Code 效率更高。
上下文获取方式:Cursor 通过索引整个项目来构建上下文。Claude Code 是在运行时动态获取——Agent 用 grep、find、cat 等命令实时探索代码库,根据任务需要决定读哪些文件。前者更快(提前索引好了),后者更灵活(不受索引更新延迟影响,且能用任何系统命令获取信息)。
工具链集成:Claude Code 跑在终端里,天然能调用所有命令行工具——git、npm、docker、curl、数据库 CLI 等。Cursor 的 terminal 集成虽然也在进步,但核心体验还是围绕编辑器内的操作。如果一个任务的链路是"改代码 → 跑测试 → 看日志 → 改配置 → 重启服务 → 验证",终端 Agent 做这种端到端的操作链更自然。
审查体验:Cursor 的 diff 预览让你在应用前逐行审查。Claude Code 做完一堆改动后,你通常需要用 git diff 整体审查。前者适合你希望对每处改动有细粒度控制的场景,后者适合你信任 Agent、只关心最终结果的场景。
各自适合的场景:
写新函数、补全代码片段 | Cursor(实时补全更快) |
跨多文件的功能开发或重构 | Claude Code(自主性强) |
不熟悉的代码库探索和理解 | Claude Code(可以自由搜索和提问) |
精细的局部代码修改 | Cursor(diff 预览更直观) |
涉及运维操作的开发任务 | Claude Code(终端原生环境) |
追问 Q&A
Q:这两种模式未来会融合吗?
A: 已经在融合了。Cursor 加入了 Agent 模式,可以自主执行多步操作和运行终端命令。Claude Code 也可以配合编辑器扩展使用。趋势是根据任务粒度自动切换交互模式——简单补全用 inline 模式、复杂任务切 Agent 模式。用户不应该需要主动选择"用哪种工具",而是在同一个环境里自然地在两种模式间流动。最终竞争的不是"IDE 模式好还是终端模式好",而是谁的上下文理解更准、工具链集成更深、执行可靠性更高。
面试题 19:这些工具为什么让你"感觉很懂你的代码"?背后的上下文工程做了哪些事?
参考答案
"懂你的代码"不是模型更聪明了,而是喂给模型的上下文更好了。
同一个基座模型,在 Cursor 里用感觉比在裸 API 里用聪明很多。区别不在模型本身,而在于这些工具在调用模型之前做了大量的上下文工程——决定把什么信息、以什么格式、放在 prompt 的什么位置传给模型。
上下文工程的几个关键层面:
1. 自动收集相关代码
用户说"帮我修这个函数",工具不只把这个函数传给模型,还会自动附带:这个函数的调用方(理解影响面)、这个函数依赖的类型定义(理解参数和返回值)、这个文件的 import 列表(理解可用的依赖)、相关的测试文件(理解预期行为)。这些信息的获取组合了多种手段——LSP 提供的"跳转到定义/查找引用"、代码库向量索引的语义检索、基于 import 的静态依赖分析。
2. 最近编辑感知
你过去几分钟刚改了哪些文件、正在看哪些文件,这些信息暗示了你当前的工作上下文。工具会把最近编辑/浏览的文件内容作为高优先级的上下文传给模型。这就是为什么你刚改完 A 文件再去改 B 文件时,AI 好像"知道"你之前在 A 里做了什么——因为 A 的内容已经在上下文里了。
3. 项目规范注入
好的工具会读取项目中的配置文件——.cursorrules、AGENTS.md、CLAUDE.md 这类文件——将项目特定的编码规范、架构约束、风格要求注入到系统提示词中。这让模型生成的代码自动符合项目约定,而不是用通用的"最佳实践"。
4. 上下文窗口的精细管理
窗口空间有限,不可能把所有信息都放进去。工具需要做优先级排序——当前文件 > 直接依赖文件 > 最近编辑文件 > 语义相关文件。每类信息分配多少 token 也需要动态调整——如果当前文件本身就很长,留给其他上下文的空间就少了,需要对其他文件做更激进的截取。这个分配策略直接决定了模型表现的上限。
5. prompt 结构设计
同样的信息,放在 prompt 不同位置效果不同(Lost in the Middle 问题)。通常把最重要的信息放在最前面(系统指令和当前任务)和最后面(当前文件和用户指令),中间放参考上下文。这种结构利用了模型对首尾位置关注度更高的特点。
追问 Q&A
Q:.cursorrules / CLAUDE.md / AGENTS.md 这些项目配置文件有什么设计上的讲究?
A: 核心原则是写给模型看,不是写给人看。人类文档讲究完整性和可读性,但模型配置文件需要讲究信息密度和可操作性。
几个实践要点:具体优于抽象——写"函数名使用 camelCase,文件名使用 kebab-case"而不是"请遵循项目命名规范"。模型没法查阅你的规范文档,必须把规则直接写清楚。约束优于建议——写"不要使用 any 类型"而不是"尽量避免使用 any 类型"。"尽量"这种弹性表述对模型约束力很弱。短优于长——这些内容每次调用都要占上下文窗口。写 500 行规则意味着每次调用少了 500 行放代码的空间。只写最关键的、模型最容易犯错的规则。结构化呈现——用清晰的分类和列表,不要写大段散文。模型对结构化信息的解析和遵循度更高。
Q:用户没有显式 @mention 文件时,工具怎么决定自动带哪些上下文?
A: 这是这些工具的核心竞争力所在,决策逻辑通常是多信号融合。编辑器状态信号:当前打开的文件、光标位置、最近的编辑历史、当前选中的文本。语言服务信号:LSP 提供的当前符号的定义位置、类型信息、引用列表。检索信号:根据用户的问题文本做语义检索,从代码库索引中拉取相关代码块。启发式规则:同目录下的测试文件、同名的类型定义文件、配置文件等。这些信号按优先级加权排序,在窗口预算内尽可能多地填充。做好这一步的工具让用户感觉"它什么都知道",做不好的工具让用户反复手动 @mention 文件——体验天差地别。
面试题 20:Cursor 的 Tab 补全为什么感觉比 Copilot 更"准"?可能的技术原因有哪些?
参考答案
"更准"的感觉来自多个技术层面的差异叠加。
1. 模型选择策略
代码补全对延迟极其敏感——用户打字流中每一次补全建议都必须在几百毫秒内返回。这意味着不能用大型推理模型,必须用专门优化过的小型快速模型。Cursor 在这一层的关键决策是为补全场景专门训练或选择模型,这个模型不需要能做复杂推理、不需要能写长文章,只需要在"根据上下文预测下几行代码"这一件事上做到极致。而 Copilot 早期主要基于 Codex 系列,后续迭代中模型选择策略也在变化,但两家在模型层面的投入侧重点可能不同。
2. 更丰富的编辑上下文
前面讨论过,AI Native IDE 能给模型喂更多上下文。补全场景中,除了当前文件内容,Cursor 还可以带上最近编辑过的其他文件片段、当前文件的 import 解析出的依赖类型定义等。信息越多,预测越准。
3. 预测范围更灵活
传统补全通常是"从光标位置往后插入"。Cursor 的补全可以做到更复杂的编辑预测——不只是插入,还包括修改光标附近已有的代码。比如你刚写了一个函数调用但参数写错了,Cursor 可能直接建议修改已有的参数而不是在后面追加代码。这种"编辑预测"比"插入预测"更贴合实际编码场景,但技术实现更复杂——需要把补全问题建模为"当前代码到目标代码的 diff 预测"而不是简单的"续写"。
4. 投机采样(Speculative Decoding)和缓存
为了解决延迟问题,可以用技术手段加速推理。投机采样的思路是用一个极小的模型快速生成候选,再用大模型验证,减少大模型的推理步数。此外,如果用户的编辑模式有重复性(比如在多处做类似修改),之前的推理结果可以部分缓存复用。
5. 用户行为数据的飞轮
用户接受或拒绝补全建议是一个天然的标注信号。大量用户的接受/拒绝行为构成了一个持续的反馈数据集,可以用来微调模型、优化排序策略。用户量越大,这个飞轮转得越快。
追问 Q&A
Q:补全和 Agent 模式用的是同一个模型吗?为什么?
A: 通常不是。两个场景对模型的要求几乎相反。补全需要低延迟、高吞吐、短输出——在几百毫秒内返回几行代码。Agent 模式需要强推理、长上下文、复杂输出——可以花几十秒完成一个多步任务。前者适合小型、快速、专门化的模型;后者适合大型、通用、推理能力强的模型。Cursor 在不同场景使用不同模型,并让用户自己选择 Agent 模式的基座模型(Claude、GPT、等),补全模型则由 Cursor 自己控制不让用户选。这种分层模型策略是成本和体验之间的精细权衡。
面试题 21:为什么这些工具都强调 apply 模型 / diff 模式?直接让 LLM 输出完整文件不好吗?
参考答案
直接输出完整文件有三个致命问题。
Token 浪费极其严重
一个 500 行的文件,你只需要改其中 3 行。如果让 LLM 输出完整文件,它需要生成 500 行 token(包括 497 行原封不动的内容),你为这些没有任何价值的"复制粘贴"付出了大量的 token 成本和等待时间。用 diff 模式只需要输出修改的 3 行及其少量上下文,效率差一两个数量级。
输出过程中容易出错
LLM 在输出长文本时,到后半段的质量通常会下降。让它逐字"抄写"几百行没有改动的代码,它可能在抄写过程中引入微小的变化——少了一个空格、多了一个换行、微调了一个变量名。这些"无意识的修改"混在真正的改动中,极难发现极难排查。
审查体验很差
输出完整文件后,用户需要自己对比新旧版本才能知道到底改了什么。输出 diff/edit 指令的话,用户直接看到的就是"在第 42 行,把 X 改成 Y"——审查效率高一个量级。
Apply 模型是怎么工作的:
这是工程上一个很精巧的设计。LLM 生成的输出通常是"自然语言混杂代码片段"——比如"把 fetchUser 函数中的错误处理改成这样:..."。Apply 模型的作用是把这种自然语言描述的修改意图转化为精确的文件编辑操作——定位到具体文件的具体行,执行精确的文本替换。
这里有两种技术路径。一种是让 LLM 直接输出结构化的编辑指令(比如 search-and-replace 格式),然后工具端做精确的字符串匹配和替换。另一种是用一个专门的小模型(Apply Model)做"中间翻译"——大模型输出意图,小模型把意图转化为精确的 diff。后者更鲁棒,因为大模型不需要精确到每一个空格和缩进,容错空间更大。
追问 Q&A
Q:diff 模式下 LLM 的输出精确度不够怎么办——比如搜索串匹配不上原文?
A: 这是实际工程中的高频问题。LLM 输出的"旧代码片段"可能和文件中的实际内容有细微差异——多了一个空格、缩进用了 tab 而不是 space、少了一个分号。纯字符串精确匹配就会失败。
解法分几层。模糊匹配:不做精确字符串匹配,而是用编辑距离或相似度算法找到文件中最接近的片段,在相似度超过阈值时视为匹配成功。行号辅助:让 LLM 同时输出大致行号范围,缩小搜索范围后再做匹配,减少误匹配。专用 Apply 模型:让一个专门训练过的小模型来完成"意图 → 精确编辑"的转化,它看到完整的原文件和 LLM 的修改意图,直接输出可以精确应用的 diff。这比让大模型自己精确到每个字符更可靠,也是 Cursor 等工具实际采用的方案。
面试题 22:如何理解 "Context Engineering > Prompt Engineering" 这个说法?在实际工具中怎么体现?
参考答案
Prompt Engineering 只关心"怎么问",Context Engineering 关心"带着什么信息去问"。
早期大家觉得 LLM 表现不好是因为 prompt 写得不好——换个措辞、加个 "Let's think step by step"、用 few-shot 示例就能大幅提升。这在简单任务上确实有效。但在 Agent 和代码工具这类复杂场景中,模型表现的上限不取决于你怎么问,而取决于你给模型看了什么。
一个完美的 prompt 搭配错误的上下文(比如给了不相关的代码文件),输出一定是差的。一个普通的 prompt 搭配精准的上下文(给了正确的依赖文件、类型定义、测试用例),输出大概率是好的。上下文质量对结果的影响远大于 prompt 措辞。
Context Engineering 在工具中的具体体现:
检索系统就是上下文工程的核心——怎么从百万行代码中找到和当前任务最相关的 20 个代码片段。前面讨论的分层索引、混合检索、重排序都属于这个范畴。
上下文预算分配也是——系统指令占多少、工具描述占多少、代码上下文占多少、历史对话占多少。这个分配比例直接影响模型在不同维度上的表现。
信息格式化同样关键——同一段代码,带不带文件路径前缀、带不带行号标注、带不带类型注解、函数是展示完整实现还是只展示签名,这些格式差异影响模型的理解效率。
动态上下文组装——同一个模型,处理不同类型的任务时应该带不同的上下文。写测试时优先带相关的实现代码和已有测试;修 bug 时优先带错误日志和相关调用链;做重构时优先带依赖图和调用方信息。好的工具会根据任务类型动态调整上下文策略。
一句话:Prompt Engineering 是调节发问者的语言技巧,Context Engineering 是构建回答者的知识基础。后者的天花板更高、工程量更大、对结果的影响也更大。
追问 Q&A
Q:Context Engineering 做得好不好怎么衡量?
A: 最直接的指标是上下文命中率——模型实际使用了注入上下文中多大比例的信息。如果塞了 10 个代码块进去,模型只引用了 2 个,说明有 80% 的上下文是浪费的。反过来,如果模型的回答中引用了上下文之外的信息(幻觉),说明该给的上下文没给到。理想状态是高命中率 + 低幻觉率。
间接指标是同模型不同上下文策略的效果对比。固定使用同一个模型,只改变上下文组装策略,对比任务完成率的变化。如果换了上下文策略后完成率从 60% 涨到 85%,这 25% 的提升全部归功于 Context Engineering——这也说明了为什么它比换一个更贵的模型更值得投入。
#Agent##面试___岗的必刷题单##面试##AI求职记录##面试官最爱问的 AI 问题是......#
查看24道真题和解析
MiniMax成长空间 42人发布