LLM 应用开发面试题 & 参考答案
面试官:严察
日期:2026-06-02
面试阶段:基础知识 → 工程实战 → 开放场景
目录
阶段一:基础知识与核心概念
问题一:System Prompt 要素与指令遵循优化
题目: 一个好的 System Prompt 应该具备哪些要素?如果模型不按照你的指令执行,你会从哪些方向去排查和优化?
参考回答
优质 System Prompt 的六大要素
| 要素 | 说明 |
|---|---|
| 角色定位 | 明确身份、领域与职责 |
| 任务目标 | 写明核心工作与使用场景 |
| 约束边界 | 划定能做 / 禁止事项 |
| 输出规范 | 限定格式、语种、篇幅 |
| 示例参考 | 内置少量样例(Few-shot) |
| 异常处理 | 信息缺失 / 超范围时的应答规则 |
模型不遵指令的排查优化方向
- 提示词本身: 关键规则前置、细化量化、精简长度、补充样例
- 上下文污染: 清空历史、防范用户输入覆盖系统指令(最容易被忽视)
- 推理参数: 降低
temperature、合理设置top_p/max_tokens - 模型选型: 能力不足则换大模型或领域微调模型
- 工程拆分: 复杂任务分多轮调用,降低单次指令的认知负荷
深挖点 Q&A
Q:Role Prompt 为什么有效?
本质上是为模型预设了输出的概率分布先验,压缩了解空间。当模型被赋予一个具体角色时,它在高维空间中的输出路径会被约束在与该角色相关的语义区域,减少了随机漂移。
Q:Few-shot 放 System Prompt 与放 User Message 有何不同?
放在 System Prompt 中权重更高,占据上下文头部位置(attention bias 偏好开头),但也占用宝贵的系统指令预算。放在 User Message 中更灵活,适合动态切换示例,但在长上下文中容易被中间内容淹没(Lost in the Middle)。
问题二:Embedding 模型选型与 Top-K 噪声处理
题目: 为知识库问答系统选择 Embedding 模型,你会考虑哪些关键指标?如果检索回的 Top-K 中混入大量不相关内容,怎么处理?
参考回答
Embedding 模型选型指标
- 向量维度: 高维度(1536/3072)表达力强但成本高;低维度(384/768)速度快,适合实时场景
- 评估指标: MTEB / BEIR 等公开 benchmark 得分
- 成本: API 调用费用 vs 本地部署成本
- 支持的 token 长度: 长文档需要大窗口模型
- 领域适配性: 通用模型 vs 领域微调模型
- 语言支持: 是否覆盖目标语种
Top-K 噪声处理方案
- Reranker(重排序): 对检索结果做二次精排,大幅提升精度,是最直接有效的手段
- Hybrid Search(混合检索): 关键词(BM25)+ 向量检索互补,覆盖语义和字面匹配的盲区
- Chunk 调优: 根据文档类型实验最优切分粒度(大块噪声多,小块语义断)
- Query 重写(Rewrite): 用户短查询表达模糊,先让 LLM 扩展 / 改写后再检索
深挖点 Q&A
Q:维度与召回率的关系是什么?
高维度(1536/3072)能捕获更细粒度的语义差异,精度理论上更高,但带来了更高的存储和计算成本,且在数据量不足时容易过拟合。低维度(384/768)适合对延迟敏感、数据量大的场景。选型需在精度、成本、延迟之间做 trade-off。
Q:Hybrid Search 中 BM25 和向量检索的权重如何配比?
没有通用最优值。实践中通常从 RRF(Reciprocal Rank Fusion)的默认 k=60 开始,或者用 0.5:0.5 等权,然后通过线上 A/B 测试或离线评测调整。推荐用 Auto-weight 方式:在检索结果上训练一个轻量级权重模型,让数据决定配比。
问题三:RAG 幻觉的检索侧与生成侧缓解策略
题目: RAG 系统中产生幻觉的主要原因有哪些?在检索侧和生成侧分别如何缓解?
参考回答
幻觉本质: 检索内容与模型生成之间的对齐失败。
检索侧缓解方案
| 方案 | 说明 |
|---|---|
| 混合检索 | BM25 + 向量检索,互补盲区 |
| 重排序 | Reranker 二次精排 Top-K |
| 阈值过滤 | 设置相似度阈值,低于阈值的宁可不要 |
| Chunk 调优 | 合适的粒度 + 重叠切片 |
生成侧缓解方案
| 方案 | 说明 |
|---|---|
| 强制引用 | 要求模型逐句标注来源 Chunk ID |
| 自检 | 生成内容后模型自我验证 |
| 低置信拒绝 | 置信度低于阈值时拒答 |
| LLM-as-Judge | 引入评判器做二次验证 |
核心原则: 宁可承认不知道,也不输出未经检索支撑的"合理编造"。
强制引用的落地方式: 在 Prompt 中要求模型逐句标注来源 chunk ID,后处理脚本检查引用对应关系。若某句无引用或引用并非来自检索内容,直接截断或打回重写。
深挖点 Q&A
Q:怎么用代码实现"强制引用"的后处理?
大致流程:解析 LLM 输出中 [来源: chunk-xxx] 格式的标注 → 提取所有 chunk ID → 与本轮检索返回的 chunk ID 集合取交集 → 未匹配到的句子打标删除,或在返回给用户前触发重新生成。
Q:LLM-as-Judge 的 prompt 怎么写才不偏?
关键原则:评判器需使用与生成器不同的 Prompt 模板,且评判标准要量化(打分制 + 具体扣分项),避免模糊的"是否符合事实"。实践中可以让评判器只看检索片段和生成的对应句子,不看完整对话,减少位置偏差。
阶段二:工程实战与架构设计
问题四:多轮对话 Agent 架构拆解
题目: 设计一个能自主调用外部工具的 Agent,核心模块有哪些?各模块的职责是什么?
参考回答
| 核心模块 | 职责 |
|---|---|
| 模型适配器 | 对接不同 LLM 提供商,统一调用接口,处理 token 限流和重试 |
| 推理 / 规划模块 | 决策引擎 — 选择 ReAct、Plan-and-Execute 或混合策略 |
| 上下文管理 | 维护对话窗口,管理截断策略,防止上下文溢出 |
| 记忆管理 | 短期(对话窗口)vs 长期(持久化存储),筛选关键信息写回 |
| 工具管理与执行 | 工具注册、参数注入、结果解析、异常处理 |
| 感知层 | 解析用户意图,识别关键实体和约束条件 |
深挖点 Q&A
Q:长期记忆怎么写回?写哪些?
筛选标准:涉及用户偏好、已完成的跨轮任务状态、明确的决策结果。实现常用方案是每次对话结束时让 LLM 对当前对话做摘要,提取该记住的信息,然后写入向量库或 KV 存储。核心原则是不要全盘存,只存摘要和关键事实。
Q:上下文窗口满了怎么办?
常见策略:
- 滑动窗口: 保留最近的 N 轮对话
- 摘要压缩: 将历史对话压缩为摘要,放回窗口顶部
- 分层检索: 窗口内仅保留当前轮强相关的历史消息,其余放入外部记忆
问题五:ReAct vs Plan-and-Execute 策略选择
题目: 面对复杂任务,ReAct(边想边做)和 Plan-and-Execute(先计划再执行)如何选择?
参考回答
| 对比维度 | ReAct | Plan-and-Execute |
|---|---|---|
| 流程 | 循环:思考→行动→观察→再思考 | 先规划出 DAG,再依次/并行执行 |
| 灵活性 | 高,每步都能根据环境反馈临时转向 | 低,计划一旦定下来不易中途切换 |
| LLM 调用量 | 多(每步都要调) | 少(规划一次,后续按图执行) |
| 适合场景 | 开放探索型、信息不确定的任务 | 流程固定、依赖明确的管道式任务 |
| 容错/可恢复 | 天然支持:观察报错→调整策略 | 需额外编排重试/回滚逻辑 |
| 举例 | 「帮我规划周末杭州两日游」 | 「查 Q1 数据→画图→发邮件」 |
决策原则:
- 任务结构已知 → Plan-and-Execute
- 结果不确定、需要探索 → ReAct
- 两者不互斥 → 外层 Plan 搭骨架,内层每个子任务用 ReAct
生产最佳实践(混搭策略): 先用 Plan 编排 DAG,每个子节点内部用 ReAct 做局部决策。这样既有全局的确定性,又有局部的灵活性。
深挖点 Q&A
Q:混搭策略中,Plan 的执行器怎么感知子任务的中间状态?
常见方案是维护一个全局上下文对象(Shared Context / Blackboard),每个子节点执行后将中间结果写入,后续节点按需读取。Plan 编排器负责 DAG 的状态流转(待执行 → 执行中 → 成功 / 失败),失败时可触发重试或重新规划。
问题六:LangChain vs LlamaIndex 框架选型
题目: 从开发效率、可调试性、Agent 支持、生产维护成本出发,LangChain 和 LlamaIndex 怎么选?
参考回答
| 对比维度 | LangChain | LlamaIndex |
|---|---|---|
| 强项 | Agent / Chain / 工具编排 | RAG / 数据索引 / 检索 |
| 生态丰富度 | 高,集成最多 | 中,聚焦检索场景 |
| 开发效率 | 初期上手慢(抽象层多),熟悉后强大 | 初期上手快,开箱即用 |
| 可调试性 | LCEL 回调机制完善,但问题定位需要经验 | 链路清晰,调试相对简单 |
| Agent 支持 | ✅ 最强,Tool/Function Calling 原生支持 | 🔶 支持但不如 LangChain 成熟 |
| 生产维护 | 版本迭代快,API 变动频繁,需锁版本 | 版本稳定,维护量小 |
| 选型建议 | 系统复杂、Agent 多、需深度定制 | 以 RAG 为核心、检索链路重的场景 |
一句话原则: 做 Agent 选 LangChain,做 RAG 选 LlamaIndex,两者也可以混用。
深挖点 Q&A
Q:LangChain 版本迭代快导致生产维护难,具体怎么应对?
- 锁大版本: 用
poetry或pip freeze锁定到具体小版本,不随意升级 - 封装抽象层: 对 LangChain 的调用做一层薄封装(如
LLMService、ToolExecutor),业务代码不直接依赖 LangChain 内部类 - 跟踪 Deprecation 通知: 关注官方 changelog,有计划地批量升级
- 关键模块自己实现: 如回调链路、记忆管理等对稳定性要求高的模块,可以考虑自己写
阶段三:开放场景题与故障排查
问题七:RAG 客服系统答案不一致排查
题目: RAG 客服问答系统上线一周后,用户满意度下降 15%,发现同一问题答案不一致、有时对有时错。排查路径和修复方案?
参考回答
Step 1 — 快速止血(P0)
| 动作 | 说明 |
|---|---|
| 黄金答案缓存 | 将该高频问题的标准答案通过缓存/规则直接返回,绕过 RAG 流程 |
| 临时人工兜底 | 关键业务问题暂时转人工 |
Step 2 — 链路排查
① 检索层:召回结果是否稳定?
- 取该 query 连续调用检索接口 20-30 次
- 记录每次返回的 Top-K 文档 ID 和排序
- 计算 Jaccard 相似度,若波动 > 10%,检索层是主因
| 可能根因 | 修复方案 |
|---|---|
| 向量索引正在重建或实时更新,分片数据不一致 | 确保全量重建时新旧索引切换是原子的 |
| 多副本间数据未完全同步 | 对检索层做 sticky session 绑定,或统一数据版本 |
| Embedding 模型版本不一致(新旧混用) | 统一模型版本 |
| 检索策略含随机性 | 去掉随机采样,固定随机种子 |
| — | 短期内对该高频问题做查询结果缓存 |
② 知识库层:是否存在矛盾或过时内容?
- 拉出多次召回的文档集合,人工审查
- 检查是否有相互矛盾的文档共存
| 可能根因 | 修复方案 |
|---|---|
| 旧文档未下架或未标记失效 | 建立文档生效/失效时间标记,检索时过滤过期内容 |
| 切片更新遗漏 | 切片与源文档建立强关联,文档更新时原子性重切 |
| 多数据源信息冲突 | 增加知识审核流程,冲突内容告警 |
③ Prompt 拼接层:上下文是否一致?
- 记录线上完整 Prompt,对比同一问题的多次请求
- 检查是否有随机元素 / 时间戳 / 动态系统指令
| 可能根因 | 修复方案 |
|---|---|
| Prompt 中注入了当前时间、轮次等动态变量 | 该高频问题使用固定 Prompt 模板,去除动态变量 |
| 历史截断策略不稳定 | 统一上下文窗口截断逻辑 |
| Prompt A/B 测试 | 该问题不参与实验 |
④ LLM 生成层:模型本身是否稳定?
- 用相同 Prompt 调用模型 10 次,观察输出
- 检查
temperature、top_p设置
| 可能根因 | 修复方案 |
|---|---|
| temperature > 0.3 导致随机性强 | 对该请求设 temperature=0 |
| 模型灰度升级,新旧并存 | 确保同一场景打到同一模型版本 |
| 不同 endpoint 行为差异 | 统一 endpoint |
Step 3 — 系统性修复(防复发)
| 措施 | 说明 |
|---|---|
| FAQ 黄金答案 | 高频问题走意图识别直接返回标准答案 |
| 全链路缓存 | Query 归一化后查缓存,知识库更新时主动失效 |
| 一致性监控 | 定期对标杆 Query 做探测,检测答案分布的熵值,异常告警 |
| 知识库治理 | 文档标注生效时间、来源;更新走灰度→全量流程,切原子化 |
排查优先级矩阵
| 优先级 | 排查层 | 核心问题 | 动作 |
|---|---|---|---|
| P0 | 止血 | 用户体验持续受损 | 缓存标准答案 / 转人工 |
| P1 | 检索层 | 召回结果波动 | 对比多次召回结果 |
| P1 | LLM 层 | temperature/模型版本 | 检查生成参数 |
| P2 | 知识库 | 矛盾内容共存 | 审查召回文档集 |
| P2 | Prompt | 动态变量干扰 | 检查拼接后完整 Prompt |
深挖点 Q&A
Q:怎么在线上拿到每次请求的召回文档 ID 和完整 Prompt?没有日志怎么办?
这是考察可观测性建设。如果线上没有日志,排查难度极大。标准做法:
- 用 OpenTelemetry 做全链路 tracing,每个请求带一个
trace_id,贯穿 query→检索→rerank→生成→输出 - Agent 框架层暴露中间结果回调(LangChain 的
CallbackHandler或 LlamaIndex 的EventHandler) - 如果没有 tracing 设施,现场加日志重新上线是唯一选择。这也说明了一个关键教训:可观测性是 RAG 系统的第一基础设施,不是可选功能
Q:temperature=0 仍不一致,还能是什么原因?
这是一个进阶追问。可能原因:
- GPU 计算精度: float16 vs float32、不同 GPU 架构的微小差异
- vLLM prefix caching: 缓存命中状态不同导致推理路径不同
- 批次内 padding: batch 内其他请求的 padding 长度影响计算图
- 模型提供商的负载均衡: 不同后端节点的模型权重微小差异
问题八:第三方 API 不稳定下的容错与降级策略
题目: Agent 调用第三方天气 API 经常超时或 5xx,不能换提供商。设计 Function Calling 的容错与降级策略。
参考回答
1. 超时策略(双层异步超时)
| 层级 | 配置 | 说明 |
|---|---|---|
| IO 层(Socket) | 连接超时 3s,读取超时 5s | 防止 socket 挂起 |
| Agent 调度层 | 工具调用整体超时 8s | 独立上下文,超时后主线程快速失败,不被阻塞 |
关键点:超时链路必须对齐。 Agent 框架超时 > HTTP 超时。如果 Agent 超时设 10s 但 HTTP 读超时设 15s,HTTP 永远走不完但 Agent 先超时了,中间线程一直悬空。
2. 重试机制
- 库选型: Tenacity(Python),带随机抖动的指数退避(1s → 2s),最多 3 次
- 重试条件: 仅对 5xx、429 及网络级错误(ConnectionError、Timeout)
- 不重试: 4xx 客户端错误(业务拒绝)
- 安全阀: 引入重试预算(Retry Budget),每分钟最多 N 次重试,超出后直接降级,防止重试风暴击穿服务
- 熔断器: 与重试分层 — 先查熔断器状态,已熔断则直接降级;未熔断才进重试
3. 降级方案(多级缓存 + 结构化 Fallback)
第一级降级 — 缓存数据(Redis):
TTL=5min 的缓存
返回数据 + header: X-Cache: HIT
附标注:"数据来自 12:34 缓存,非实时"
第二级降级 — 无缓存可用:
返回结构化 JSON:
{
"status": "fallback",
"message": "天气服务暂时不可用",
"recommendation": "请稍后再试或选择其他日期"
}
核心原则:降级输出的 schema 与正常输出保持一致,下游解析逻辑无需特殊处理。
严禁行为: 不允许 LLM 说"根据最新数据"而实际返回的是缓存。降级时通过 is_fallback: true 标记让 LLM 调整措辞。
4. 用户反馈
| 端 | 策略 |
|---|---|
| 前端 | 定时器在等待期流式展示"查询中 / 响应慢"等状态文案 |
| 后端 | 降级状态作为 ToolMessage 传给 LLM,配合 System Prompt 约束模型输出透明提示 |
| 监控 | Prometheus 埋点:weather_api_latency_seconds{status="success|timeout|fallback"} 三个标签,分别设置告警阈值 |
深挖点 Q&A
Q:Redis 缓存失效策略怎么选?如果用户查的城市都不同,缓存命中率低怎么办?
- 选型: Cache-Aside(旁路缓存),TTL 过期自动失效。热门城市预缓存(手动预热 Top 100 城市)。
- 低命中率应对: 如果查询分布极度离散,缓存收益有限,应倒过来优化 API 本身的稳定性(如增加 provider 冗余),而不是在缓存上继续加码。
Q:熔断器打开期间有用户一定要查天气,怎么办?
区分场景:
- 非强实时场景: 返回陈旧缓存 + 告知数据时间
- 强实时场景(如航班调度): 保留手动刷新入口,后台真正触发请求时绕过熔断器(用单独的 bypass 通道)
Q:怎么保证 LLM 在降级时不自己编数据?有没有翻车经验?
一个典型翻车案例:降级时返回的 JSON 被 LLM 忽略,LLM 自行编造了"25°C,晴"的回答。修复方案:
- 在 ToolMessage 中加入
"override_user_message": true标记,System Prompt 中要求如果看到此标记,直接输出recommendation字段内容,不自行生成 - 或者在 Agent 层面做规则拦截:如果输出包含天气数据但工具返回是 fallback,拒绝输出并返回预设文案
问题九:长 System Prompt 的代码质量与重构
题目: 初级工程师在 System Prompt 中硬编码 2000 字业务规则,要求 LLM 严格遵循。有什么问题?怎么重构?
参考回答
三个核心问题
| 问题 | 解释 |
|---|---|
| Lost in the Middle | LLM 对长文本中间段的注意力最弱。2000 字规则,中间部分几乎等于没写 |
| Token 成本浪费 | 日均万次调用 × 1500 token × 30 天,仅规则部分烧掉 ~4500 万 token,按常见定价约数百到上千元 |
| 改规则 = 改代码 | 业务更新频繁,每次改规则要走 CI/CD 上线,迭代周期长、风险高 |
重构方案
Step 1 — 规则分类
| 类别 | 内容 | 存放位置 |
|---|---|---|
| A | 角色身份 + 行为边界 | 保留在 System Prompt(≤ 200 字) |
| B | 具体业务规则(条目化) | 搬进知识库 / 向量库,RAG 按需检索 |
| C | 条件判断逻辑(if-else) | 搬进 Function Calling / 代码逻辑 |
Step 2 — System Prompt 精简后的样子
你是一个客服助手。回答时必须依据知识库中的最新规则。
如果规则未覆盖,回答"我暂时没有相关信息"。
Step 3 — 运行效果对比
修改前:
System Prompt: 2000 字规则 + 角色 + 格式
每次请求: 2000 token 固定开销
改规则: 走 CI/CD 上线流程
修改后:
System Prompt: 150 字(角色 + 约束)
每次请求: 按需检索注入 ~200-300 token
改规则: 更新知识库,无需上线
核心理念: Prompt 是胶水,不是数据库。
深挖点 Q&A
Q:RAG 按需注入规则,怎么保证每次能召到对的规则?如果规则有优先级(新政策覆盖旧政策),相似度检索能处理好吗?
相似度检索本身没有优先级概念,它只衡量语义相近程度。要处理规则优先级,需要:
- 元数据过滤: 每条规则带
effective_start、effective_end、priority字段。检索时先过滤生效时间范围内的规则,再按优先级排序 - 检索 + 规则引擎: RAG 只做粗筛,具体的优先级冲突由后置规则引擎(如简单的 if-else 链或决策表)解决
- 显式版本标记: 在规则内容中标记版本号,Prompt 中要求 LLM 如发现同一问题的多个版本,取版本号最高的
Q:如果规则总长度超过上下文窗口的 60%,怎么处理?
- 分层检索: 先检索规则摘要(summary index),再根据摘要命中结果检索详细规则
- 滑窗策略: 一次只注入当前轮任务相关的规则子集,不一次性全放
- 摘要压缩: 对规则做 LLM 摘要,压缩到关键要点的 bullet list
Q:规则版本管理怎么做?线上两套规则同时生效(灰度实验),RAG 怎么区分?
- 规则数据带实验标签: 每条规则携带
experiment_group: "control" | "treatment"字段 - 用户分桶 ID 传入检索层: 检索时根据用户 ID 的 hash 值决定过滤哪个实验组的规则
- 版本历史不可变: 规则更新不走修改,走新增 + 标记版本号,旧版本只标记过期不下架,保证可追溯
面试总结
评分矩阵
| 维度 | 评价 |
|---|---|
| 基础理论 | 🟢 扎实,Prompt 原理、Embedding 选型、RAG 链路认知清晰 |
| 架构设计 | 🟢 有系统思维,模块拆解、缓存策略、容错降级都落到了具体方案 |
| 工程实战 | 🟢 明显有生产经验,线上排查路径完整,有止血意识 |
| 带队能力 | 🟢 有导师意识,懂得让新人自己发现问题 |
| 表达结构 | 🟢 结构化表达好,擅先用框架再填充细节 |
可加强的方向
- 可观测性落地: 排查时"如何拿到数据"有时比"拿什么数据"更难,建议加强对全链路 Tracing 和日志体系的认知
- 成本量化意识: 已有 token 成本感知,可以强化单位换算和 ROI 表达(如"日均万次调用 × 每请求节省 X token = 每月省 Y 元")
- 混搭策略的边界判断: ReAct vs Plan-and-Execute 的选型如果能给出量化阈值(如"子任务数 > 5 且依赖明确 → Plan"),会更可信
一句话总结
Senior 级别。有实战深度,有架构视野,有带队经验。
评论区