面灵AI→

16 家 AI 公司面经汇总:8 道高频题与答题要点

轮次
多轮
时间
2026-10
来源
牛客网

《面试题目》

  1. 不用框架,手写一个 Agent 需要哪些模块?
  2. RAG 取不到数据,你怎么排查?
  3. Agent 记忆混乱了,怎么优化?
  4. MCP/Skill 是什么?怎么给 Agent 加工具?
  5. KV Cache 是什么?为什么长文本会爆显存?
  6. MoE 混合专家是什么?路由为什么要加惩罚?
  7. LoRA 原理是什么?rank 怎么选?
  8. Agent 开发和传统前后端开发,最大的区别是什么?

《参考解析》

不用框架手写一个 Agent 需要哪些模块

最小可用的 Agent 只要四个部分:模型调用层(把系统提示、历史消息、工具定义组装成一次请求,处理流式输出与重试)、工具层(每个工具要有名字、参数 schema、描述和执行函数,描述直接决定模型会不会在正确的时机调用它)、循环控制(想 → 调工具 → 把结果回灌成新的观测,再进下一轮)、上下文管理(消息裁剪、长工具结果摘要化、把大对象外置成文件或变量只留引用)。

做到「能用」还得补几块工程件:终止条件必须显式设计,包括模型不再产生工具调用、达到最大步数或 token 预算、连续若干轮没有新信息、工具反复报同一个错;错误处理——工具失败不要把异常直接抛给用户,而是把错误信息作为观测喂回模型让它换路;幂等与去重——同一工具同一参数短时间内重复调用要拦截;可观测性——每一步的输入输出、耗时、token 消耗都要能落盘回放,否则线上出问题只能靠猜。

RAG 取不到数据怎么排查

按「数据有没有 → 切得对不对 → 检索得准不准 → 排序对不对 → 模型用没用」这条链路分段定位,而不是一上来就换 embedding 模型。

先查数据侧:目标文档到底进没进库、解析有没有失败、表格和图片是不是被丢掉了、增量更新是不是漏了一批。再查切分:chunk 是不是太大导致一段里混了好几个主题,或者太小导致半句话被切断、关键上下文被拆到相邻块里——这是最常见的召回不准原因,命中时通常表现为「库里明明有,但召回的都是无关段落」。可以拿一个已知答案的问题,把 query 和全部 chunk 的相似度打出来看排序,判断是「根本没召回到」还是「召回了但排在后面」。

再查检索与排序:纯向量检索对专有名词、数字、缩写不敏感,要补一路 BM25 或关键词检索做混合召回;有 rerank 的话看候选集里有没有正确答案(召回问题)还是 rerank 把正确答案打下去了(排序问题)。最后查生成侧:检索到的内容有没有真的进 prompt、是不是被上下文长度截掉了前面的部分、系统提示有没有让模型「证据不足时不许编」。

Agent 记忆混乱了怎么优化

记忆混乱的本质是上下文里塞了太多信息,注意力被稀释、历史事实互相冲突。常见做法是分层:短期记忆保留最近若干轮原始对话;中期记忆把更早的对话压缩成摘要(摘要要保留数字、人名、结论这类硬信息,别只留流水);长期记忆把稳定事实(用户偏好、项目背景)写进外部存储,需要时按 query 检索召回,而不是每轮都全量带上。

工程上还有几个关键点:写入要过滤——不是所有对话都值得记,重复和低信息量的内容进库只会污染检索;冲突要覆盖——用户改了口径,旧记忆要失效而不是两条并存;召回要限额——检索回来的记忆有数量与 token 上限,并且要给模型标注来源和时效;状态要外置——任务清单、中间结果写成结构化数据(文件、TODO 列表)由程序维护,比让模型从聊天记录里反推可靠得多。

MCP / Skill 是什么,怎么给 Agent 加工具

MCP(Model Context Protocol)解决的是工具接入的标准化问题:把「有哪些工具、参数长什么样、怎么调用」用一个协议描述出来,客户端按协议去连服务端,工具就从「每个应用自己写一遍」变成「一次实现、多处复用」。Skill 更像任务级的知识与流程封装:把一段怎么做事的方法(步骤、注意事项、参考文档、可调用脚本)打包成模型按需加载的资源,模型先决定「要不要用这个技能」,再把正文读进上下文,避免把所有知识常驻在系统提示里。

给 Agent 加工具时,真正影响效果的是工具描述的写法:名字要能自解释,描述里写清「什么时候该用它、什么时候不该用、返回什么」,参数用 schema 严格约束并给出示例;工具粒度不要太细(模型要串十步)也不要太粗(一个工具干十件事,参数描述不清);有副作用的工具要标出来并做幂等与确认。加完必须用真实任务回归——包括「不该调用时是否克制」和「调用失败后是否能自己换路」两类用例。

KV Cache 与长文本显存

自回归生成时,每个新的 token 都要对所有历史 token 做注意力计算,如果不缓存,历史的 K、V 每步都要重算一遍。KV Cache 就是把每层每个头的 Key 和 Value 存下来复用,把单步计算从「随序列长度平方增长」压到线性,代价是显存占用。

显存占用大致正比于:层数 × 2(K 和 V)× 注意力头数 × 头维度 × 序列长度 × batch × 精度字节数。可以看到它对 seq_len 是线性的、对 batch 也是线性的,所以长文本 + 大并发时,KV Cache 会迅速超过模型权重本身成为显存主要占用——这就是「长文本爆显存」的原因。缓解手段包括:GQA/MQA 减少 KV 头数、PagedAttention 之类的分页管理减少碎片、量化 KV(INT8/FP8)、滑动窗口或 StreamingLLM 只保留近期与少量「注意力锚点」、prefix caching 复用公共前缀,以及从系统层面限制单请求最大长度与并发数。

MoE 与路由惩罚

MoE 把原本一个大 FFN 拆成多个专家(expert),每个 token 经过路由网络只激活其中 Top-K 个。好处是总参数量可以做得很大,但每个 token 的实际计算量只跟激活的专家数相关,所以在同等算力下换到更大的模型容量,推理速度接近小模型。

训练时通常会给路由加**负载均衡损失(auxiliary loss)**并做容量限制,原因是:路由是「模型自己学出来的」,很容易出现赢家通吃——少数几个专家被反复选中、其余专家几乎不更新参数,结果是有效容量退化、那几张卡成为吞吐瓶颈,还有一些 token 因为专家容量满了被丢弃(token dropping)。惩罚项的作用是让专家被选中的概率分布更均匀,配合 capacity factor、专家并行下的 all-to-all 通信优化一起用。追问时常会延伸到:既然推理只激活部分专家,为什么显存还是吃满(权重仍要全部装下、要专家并行切分)、以及为什么 MoE 对 batch 和序列长度更敏感。

LoRA 与 rank 选择

LoRA 的思路是冻结原权重,只训练一个低秩增量:原来一个 D×D 的权重矩阵,改成旁边挂两个小矩阵 D×r 和 r×D,前向时输出为 Wx + BAx(B 是 D×r、A 是 r×D,通常把 A 随机初始化、B 置零,保证训练开始时增量为零)。可训练参数量从 D² 降到 2Dr,当 r 远小于 D 时能省好几个数量级,显存和存储都跟着降下来;推理时可以把 BA 合并回 W,不增加额外延迟。

rank 的选法没有万能值,取决于任务与原模型差距:越接近原模型已有能力的任务(风格、格式、领域术语)用越小的 r 就够,常见从 8 起试;要让模型学会全新能力或做较复杂的指令跟随,r 需要放大(32、64 甚至更高),并配合调 alpha(一般取 r 的 1~2 倍)与 dropout。实操上先固定其余超参做 r 的扫描,看验证集是否还在涨、以及过拟合出现的位置;同时要清楚 LoRA 的局限——它主要影响注意力与 FFN 的线性层,对需要大范围改变模型行为、或者要扩充词表/长上下文外推的场景,效果不如全参微调。

Agent 开发与传统前后端开发最大的区别

传统后端是确定性系统:同样的输入必然得到同样的输出,出问题可以复现、可以断点、可以写单测断言。Agent 是概率性系统:同一个提示词两次运行走的工具链、给出的答案都可能不同,很多「问题」根本没有唯一正确答案,因此传统那套「复现 → 定位 → 修掉」的闭环经常失效。

工程上的应对是换一套方法:把不确定性收敛到可控范围——用结构化输出与 schema 校验约束模型的返回,用显式状态机或工作流固定关键步骤的顺序,把「判断」留给模型、把「确定性的事」交给代码;用评测集代替单测——建一批带标准答案或评分标准的真实任务,改一次提示词或换个模型就跑一遍回归,看通过率和成本的变化;把每一层都做成可观测的——完整的调用轨迹、token 与耗时、失败分类,因为线上问题是概率性出现的,没有轨迹就没法归因;最后是兜底设计——超时、重试、降级、人工接管这些在传统后端是边缘逻辑,在 Agent 里是主链路。