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

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

面试题 23:如何开发一个高质量的 Agent Skill?一个好的 SKILL.md 应该包含什么、不应该包含什么?

参考答案

先搞清楚 Skill 的本质——它是写给 Agent 看的操作手册,不是写给人看的文档。

Skill 的载体是一个 SKILL.md 文件加上可选的附带资源。Agent 加载 Skill 后,SKILL.md 的内容会注入到它的上下文中,指导它在特定场景下的行为。所以 Skill 开发的核心问题是:怎么用最少的 token 传递最准确的行为指令。

一个好的 SKILL.md 应该包含:

1. 触发条件——什么时候该激活这个 Skill

这是最关键的部分。Agent 可能同时加载了很多 Skill,它需要知道"当前用户的请求该触发哪个 Skill"。触发条件必须明确且互斥——"当用户要求生成 PDF 文档时使用此 Skill""当用户要求部署到 Vercel 时使用此 Skill"。模糊的触发条件("当用户需要帮助时")会导致 Skill 在不该触发的场景乱入。

2. 执行步骤——具体做什么、按什么顺序

写成清晰的分步指令,每步做一件事。关键是要写得足够具体让 Agent 能直接执行,而不是写抽象的原则。差的写法:"处理好错误情况"。好的写法:"如果 npm install 返回非零退出码,读取错误输出中的包名,检查 package.json 中该包的版本约束是否正确"。

3. 约束和边界——什么不该做

Agent 有过度行为的倾向。明确写出禁止项:"不要修改用户没有明确提到的文件""不要自动执行 git push""不要在未经用户确认的情况下删除文件"。这些负面约束往往比正面指令更重要。

4. 输出格式要求——结果长什么样

如果 Skill 有特定的输出要求(比如必须返回某种格式、必须包含某些字段),在这里明确定义。

不应该包含的:

冗长的背景知识:Skill 不是教程。不要在里面解释"什么是 PDF""为什么要做测试"这种基础概念。Agent 已经懂了,你在浪费上下文窗口。

过于灵活的选项:"你可以选择方案 A 或方案 B,取决于具体情况"——这种写法等于没写。Agent 面对选择时倾向于随机,不如直接指定一个默认方案:"默认使用方案 A。只有当用户明确指定时才使用方案 B"。

大段示例代码:如果必须提供示例,保持最小化。大段代码样本严重挤占上下文空间,而且 Agent 会倾向于逐字照抄示例而不是根据实际情况适配。

追问 Q&A

Q:怎么测试一个 Skill 写得好不好?

A: 两个层面。触发准确率测试:构造一组正面用例(应该触发此 Skill 的请求)和负面用例(不应该触发的请求),跑一遍看触发准确率。如果有误触发或漏触发,调整触发条件描述。执行质量测试:对于正确触发的 case,检查 Agent 的执行是否符合 Skill 定义的流程和约束——有没有跳步骤、有没有违反禁止项、输出格式是否正确。这一步可以用 LLM-as-Judge 做自动评估,但初期建议人工审查,因为 Skill 的问题往往很微妙——不是"完全错了",而是"偏了一点"。

Q:Skill 之间有冲突怎么办?比如两个 Skill 的触发条件有交集。

A: 这是多 Skill 管理的核心问题。解法是显式优先级 + 互斥声明。在 Skill 中声明它和哪些其他 Skill 互斥("如果 Skill A 已经触发,本 Skill 不应触发"),以及它的优先级权重。如果两个 Skill 都想触发,按优先级选一个。更根本的解法是在设计阶段就确保 Skill 的职责边界清晰——每个 Skill 负责一个明确的、不重叠的领域。如果发现两个 Skill 经常冲突,通常说明它们应该被合并成一个。

面试题 24:开发一个 MCP Server 需要考虑哪些关键设计决策?常见的坑有哪些?

参考答案

MCP Server 本质上是把一个外部能力包装成 Agent 可调用的标准化接口。 开发时需要在以下几个维度做决策:

1. 工具粒度——一个 Server 暴露多少个工具、每个工具多"大"

这是最容易犯错的地方。粒度太粗——一个工具做太多事("database_operation" 既能查询又能写入又能建表),Agent 很难精确使用。粒度太细——几十个工具每个只做一件小事("create_table""add_column""drop_column"...),Agent 面对太多选项容易选错,而且每个工具描述都要占上下文空间。

经验法则是以用户意图为粒度。用户会说"查一下这个用户的订单"而不是"先连接数据库再执行 SELECT 语句再解析结果集"。所以工具应该是 "query_user_orders" 而不是 "execute_sql"。每个工具对应用户层面一个完整的操作意图。

2. 参数设计——让 LLM 容易传对参数

参数名必须自解释。"q" 不如 "search_query","n" 不如 "max_results"。参数描述中给出格式要求和示例值。用枚举类型而不是自由字符串来约束有限选项——"status" 参数如果只有 "active/inactive/pending" 三个合法值,就定义为 enum,不要让 LLM 自由发挥。

3. 返回值设计——给 Agent 有用的信息而不是原始数据

MCP Server 的返回值会成为 Agent 上下文的一部分。返回原始的数据库查询结果(几百行 JSON)会浪费大量上下文空间。应该在 Server 端做预处理——汇总、截取、格式化——返回 Agent 真正需要的信息。比如"找到 47 条订单记录,最近 5 条是:..."比返回完整的 47 条记录有用得多。

4. 错误信息设计——让 Agent 能自己修正

工具失败时返回的错误信息必须对 Agent 有可操作性。差的错误信息:"Error 500"。好的错误信息:"查询失败:参数 date_from 格式应为 YYYY-MM-DD,实际收到 '2024/03/15'"。后者让 Agent 能自己修正参数重试。

常见的坑:

认证状态不持久:MCP Server 是独立进程,和 Agent 的生命周期不一定一致。如果 Server 重启了但 Agent 还在用之前的 session,需要有重新认证的机制。

超时处理不当:有些操作天然就慢(大数据查询、文件上传)。如果 MCP Server 的默认超时太短,Agent 会频繁收到超时错误。需要根据操作类型设置合理的超时阈值,并且在可能超时的工具描述中提前说明("此操作可能需要 10-30 秒")。

并发安全:多个 Agent 可能同时调用同一个 MCP Server。如果 Server 内部有共享状态(比如数据库连接池、文件锁),需要处理好并发问题。

追问 Q&A

Q:MCP Server 的工具描述应该由谁来写——开发 Server 的工程师还是使用 Agent 的 prompt 工程师?

A: 理想情况下是两者协作,但最终决策权在 prompt 工程师手里。开发工程师了解工具的技术细节和约束,prompt 工程师了解 Agent 的行为模式和 LLM 对描述的理解方式。实践中常见的问题是开发工程师按照"写 API 文档"的思路写工具描述,过于技术化和精确但不符合 LLM 的"理解习惯"。比如开发者会写"接受 ISO 8601 格式的时间戳",但对 LLM 来说写"日期格式示例:2024-03-15T10:30:00Z"更容易理解和遵循。工具描述需要持续根据 Agent 的实际调用表现迭代优化,这本质上是一种 prompt 工程。

Q:一个 MCP Server 应该包含多少个工具?有上限吗?

A: 没有硬性上限,但有实际瓶颈。所有工具描述加起来的 token 总量不能超过上下文预算中分配给工具描述的额度。更重要的是认知层面的限制——给 LLM 的选项越多,选对的概率越低。实测中,单个 Server 7-15 个工具是比较舒适的范围。超过 20 个就需要考虑拆分成多个 Server,或者用前面说的"动态加载"策略——根据任务类型只注册相关的工具子集。

面试题 25:Rules 文件(.cursorrules / CLAUDE.md / AGENTS.md)的配置策略有什么讲究?怎么写才能真正有效?

参考答案

这些文件的共同本质是"持久化的系统提示词"——每次 AI 交互都会自动注入。

不同工具用不同的文件名,但作用相同。Cursor 用 .cursorrules,Claude Code 用 CLAUDE.md,Codex/多种工具识别 AGENTS.md。它们让你不用每次对话都重复交代项目规范,AI 自动就知道。

核心配置策略:

1. 分层配置——全局 vs 项目 vs 目录

多数工具支持多级 Rules 文件。比如 CLAUDE.md 可以放在项目根目录(全局规范),也可以放在子目录(该模块的特定规范)。合理的分层是:

  • 根目录:项目级的通用约束——技术栈声明、代码风格规范、构建和测试命令、Git 工作流规范
  • 子目录:模块级的特定规则——"此目录下是 React 组件,使用函数组件 + hooks,不要用 class 组件""此目录是 API 层,所有接口必须做入参校验"

子目录的规则会叠加到根目录规则上,形成层级化的约束体系。这样既保持了全局一致性,又能对不同模块做差异化指导。

2. 内容组织——写什么、怎么写

技术栈和架构声明(高优先级):告诉 AI 项目用什么语言、什么框架、什么版本。"本项目使用 TypeScript 5.x + React 18 + Next.js 14 App Router"。这一句话能防止 AI 生成 Pages Router 的代码、用 JavaScript 而不是 TypeScript、或者引入项目没有的依赖。

代码风格强约束(高优先级):只写 AI 最容易犯错的规范。不需要复述整个 ESLint 配置——那些 lint 工具会自动检查。重点写 lint 检查不到的约定:"组件文件用 PascalCase 命名""hooks 放在 src/hooks 目录""API 请求统一用 src/lib/api 中的封装方法,不要直接用 fetch"。

关键命令(高优先级):构建、测试、lint 的具体命令。"运行测试:pnpm test""类型检查:pnpm typecheck""启动开发服务器:pnpm dev"。AI 需要知道怎么验证自己的修改,如果不告诉它具体命令,它会猜——猜错就浪费一轮循环。

禁止项(中优先级):明确写出不希望 AI 做的事。"不要使用 any 类型""不要引入新的第三方依赖除非经过讨论""不要修改 prisma schema 除非被明确要求"。

架构边界(中优先级):如果项目有明确的分层架构,声明层间依赖规则。"src/services 不能直接 import src/components 中的模块""数据库操作只能在 src/repositories 中进行"。

3. 不要写什么

不要写教程内容:"React 是一个用于构建用户界面的 JavaScript 库..."——AI 知道这些,你在浪费 token。

不要写过长的示例代码:如果需要示例,给一个最小化的片段就够。50 行的示例代码意味着每次交互都少了 50 行放实际代码的空间。

不要写模棱两可的建议:"尽量保持代码简洁"——这种话对 AI 没有约束力。要么给出具体标准("单个函数不超过 40 行"),要么不写。

不要写会频繁变化的内容:如果某个规则下周就要改,不如不写进 Rules,在对话中临时交代。Rules 文件适合放稳定的、长期有效的约束。

追问 Q&A

Q:Rules 文件的内容和在对话中说的指令冲突了,AI 会听谁的?

A: 大部分工具的设计是对话中的指令优先级高于 Rules 文件。逻辑是 Rules 是默认规范,而对话中的指令代表用户当前的明确意图。比如 Rules 里写了"使用函数组件",但用户在对话中说"这个用 class 组件实现",AI 应该听用户的。但这个优先级不是硬性保证——LLM 在极端情况下可能被 Rules 中的强措辞影响而忽略对话指令。所以 Rules 中避免用过于绝对的措辞("你绝对不能在任何情况下..."),给对话指令留出覆盖空间。

Q:团队多人协作时,Rules 文件怎么管理?要不要提交到 Git?

A: 要提交到 Git,这是核心观点。Rules 文件本质上是"项目编码规范的机器可读版本",和 .eslintrc、.prettierrc 一样应该是项目配置的一部分,跟着代码走。好处是团队所有人的 AI 助手遵循相同的规范,不会出现"A 的 AI 用 tabs 缩进、B 的 AI 用 spaces 缩进"的混乱。更新 Rules 应该像更新 lint 规则一样走 Code Review 流程——因为它直接影响 AI 对全团队生成的代码质量。唯一不应该提交的是个人偏好类配置("我喜欢 AI 用中文回复"),这类放在工具的用户级配置中。

面试题 26:Agent 输出不符合预期时怎么调试?和调试传统代码有什么区别?

参考答案

核心区别:传统代码的 bug 是确定性的——同样的输入必然复现。Agent 的问题是概率性的——同样的输入可能偶尔出、偶尔不出。

这使得传统的"复现 → 定位 → 修复 → 验证"调试流程需要适配。

Agent 调试的核心方法——Trace 分析:

Agent 的每一步(推理内容、工具选择、参数、工具返回结果)都应该有完整的 Trace 记录。出问题时第一步不是去改代码,而是看 Trace——Agent 在哪一步开始偏离预期?

偏离通常发生在三个地方:

推理偏差:Agent 的 Thought 内容表明它对问题的理解就是错的。比如用户问"删除这个用户",Agent 理解成了"删除这个用户的所有数据"。这类问题的根因通常是系统提示词不够明确、或者上下文中有误导性的信息。修复方向是优化 prompt 和上下文。

工具选择错误:推理方向对了,但选错了工具。比如该用精确查询的工具却用了模糊搜索。根因通常是工具描述不够清晰、或者多个工具的描述有歧义重叠。修复方向是优化工具描述。

参数提取错误:工具选对了,但参数值提取错了。比如日期格式不对、ID 字段搞混了。根因通常是参数描述缺少示例和格式要求。修复方向是优化参数定义。

和传统调试的关键差异:

不能打断点:Agent 的推理过程发生在 LLM 内部,你没办法在"第三步推理和第四步推理之间"设置断点查看中间状态。只能靠 Trace 事后分析。

修复方式不同:传统 bug 修复是改代码。Agent 的问题修复可能是改 prompt、改工具描述、调整上下文注入策略、甚至换一个模型。这些都是"软"的调整,效果不像改代码那样确定。

验证需要多次:修复后不能只跑一次验证。因为问题可能是概率性出现的,需要在同一个场景上跑多次确认修复有效、且没有引入其他场景的回归。

追问 Q&A

Q:有没有一些快速诊断 Agent 问题的经验法则?

A: 几个常见模式对应的诊断方向:

Agent 反复调用同一个工具→ 大概率是工具返回的结果不包含 Agent 需要的信息,它不知道怎么推进。看看工具的返回值是否足够有用。

Agent 做了很多步但最终答案很浅→ 大概率是上下文被中间步骤填满了,后期推理时模型已经"忘了"最初的问题和早期的关键发现。检查上下文管理策略。

Agent 的第一步就选错了方向→ 大概率是任务描述或系统提示词有问题,模型从一开始就误解了任务。检查初始 prompt。

Agent 表现时好时坏、不稳定→ 大概率是处于模型能力的边界区域。可以尝试更强的模型,或者通过增加 few-shot 示例、细化指令来降低任务难度。

面试题 27:什么是 Prompt 缓存?它对 Agent 系统的成本和性能影响有多大?

参考答案

Prompt 缓存的原理:

Agent 的每次 LLM 调用,prompt 中有大量内容是重复的——系统指令、工具描述、Rules 文件、项目规范。这些内容在一次任务的多轮循环中几乎不变。Prompt 缓存的思路是:首次调用时这些内容被处理并缓存(在 API 提供商的服务端),后续调用如果 prompt 的前缀部分和缓存匹配,就可以跳过这部分的处理,直接复用。

对成本的影响:

主流的 API 提供商(Anthropic、OpenAI)对缓存命中的 token 按显著低于原价的费率计费。比如 Anthropic 的 prompt 缓存命中部分只收正常输入 token 价格的 10%。Agent 的单次任务可能包含 10-20 轮 LLM 调用,每轮的系统指令 + 工具描述可能有 3000-5000 token。如果这部分全部缓存命中,相当于每轮节省了这几千 token 90% 的费用。累积下来,一次复杂任务的成本可能降低 40-60%。

对性能的影响:

缓存命中意味着这部分 token 不需要重新做前向计算,直接加载已经计算好的 KV Cache。这对首 token 延迟(TTFT, Time To First Token)的改善非常明显——缓存的 token 越多,TTFT 越低。对于 Agent 这种多轮调用的场景,每轮节省几百毫秒,累积下来端到端延迟能减少好几秒。

利用 Prompt 缓存的工程技巧:

前缀稳定性:缓存匹配是前缀匹配——prompt 从开头到第一个不同字符的位置,这之前的部分才能被缓存复用。所以关键是把不变的内容放在 prompt 最前面、会变化的内容放在最后面。系统指令 → 工具描述 → Rules → 长期记忆 → 对话历史 → 当前问题。越往前越稳定,缓存命中率就越高。

避免不必要的变化:如果系统指令中嵌入了时间戳或随机 ID,每次调用都不一样,缓存就永远命中不了。动态内容尽量往 prompt 的后部放。

追问 Q&A

Q:Prompt 缓存和 RAG 的关系是什么?会不会冲突?

A: 不冲突,但需要配合。RAG 检索到的文档每次可能不同,这部分内容破坏了前缀稳定性。所以 RAG 结果应该放在 prompt 的后部(在稳定的系统指令和工具描述之后),这样前面的稳定前缀仍然能被缓存。如果 RAG 结果放在前面,每次检索结果不同就导致整个 prompt 的缓存失效,完全享受不到缓存红利。这是上下文排列顺序影响实际成本的一个具体例子。

面试题 28:Agent 场景下如何做灰度发布和 A/B 测试?和传统软件的灰度有什么区别?

参考答案

传统灰度发布的对象是代码,Agent 灰度的对象更多。

传统软件灰度比较简单——新版代码在小部分流量上验证,没问题再全量。Agent 系统中可以"发布"的东西包括:prompt 版本、工具描述版本、模型版本、上下文策略版本、Rules 文件版本。这些变更的影响链路比代码改动更模糊,因为 LLM 的行为是概率性的。

Agent A/B 测试的关键差异:

样本量需要更大:传统 A/B 测试中,同一用户点同一个按钮,效果是确定的——要么展示 A 版本要么展示 B 版本,结果可复现。Agent 场景中,同一用户问同一个问题,A/B 两组的输出都有随机性。需要更大的样本量才能在统计上区分"A 组真的比 B 组好"还是"只是随机波动"。

评估指标更复杂:传统 A/B 看点击率、转化率这种明确指标。Agent 的评估需要多维度——任务完成率、回答质量评分(可能需要 LLM-as-Judge)、用户满意度、平均调用轮数、Token 成本。可能出现 A 方案完成率高但成本也高的情况,需要综合权衡。

变量隔离更难:如果你同时换了 prompt 和模型,效果变了但不知道是谁的贡献。Agent 的 A/B 测试必须严格控制变量——每次只改一个因素。这意味着迭代周期更长,但结论更可靠。

灰度策略建议:

分阶段发布:先在内部测试账号上跑(冒烟测试),通过后开 5% 真实流量,观察 24 小时的自动化指标和人工抽检结果,没问题再逐步放量到 20% → 50% → 100%。

自动回滚条件:定义明确的回滚触发条件——任务完成率下降超过 X%、平均 token 消耗上升超过 Y%、或者出现任何安全相关的异常行为。这些条件必须是自动化监控的,不能靠人盯着。

追问 Q&A

Q:改了 prompt 后效果变好了,怎么确认不是巧合?

A: 必须做统计显著性检验。最直接的方法是让 A/B 两组在相同的测试集上各跑 N 次(N 要足够大,通常 50-100 个 case 以上),对比两组的指标分布。用配对检验(同一个 case 在两组上的表现对比)比独立检验更有效力,因为消除了 case 本身难度差异的干扰。如果 p 值低于显著性阈值才接受"真的变好了"的结论。实操中一个常见错误是跑了 5 个 case 发现"好像好了"就直接发布——5 个 case 的随机波动完全可能造成这种假象。

#面试___岗的必刷题单##面试##面试问题记录##面试官最爱问的 AI 问题是......##AI求职记录#
全部评论

相关推荐

gravedigge...:手撕有几题嘞
查看15道真题和解析
点赞 评论 收藏
分享
评论
2
5
分享

创作者周榜

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