跳转至

🎯 大模型应用面试题库

⚠️ 时效性说明:本章涉及前沿模型/价格/榜单等信息,可能随版本快速变化;请以论文原文、官方发布页和 API 文档为准。

自含式LLM应用面试完全手册,覆盖Prompt Engineering、RAG、Agent、微调、推理优化、评估六大方向,每题含面试官追问点和标准答案。


📋 题库总览

方向 题目数 高频指数 考察重点
Prompt Engineering 8题 ⭐⭐⭐⭐⭐ 提示词设计与优化
RAG系统 10题 ⭐⭐⭐⭐⭐ 检索增强生成全链路
Agent 8题 ⭐⭐⭐⭐ 智能体架构与工具调用
微调 8题 ⭐⭐⭐⭐ LoRA/数据/训练策略
推理优化 8题 ⭐⭐⭐⭐⭐ KV-Cache/量化/加速
LLM评估 6题 ⭐⭐⭐ Benchmark/安全/对齐

🪄 一、Prompt Engineering

Q1:Few-shot Prompting的设计原则是什么?

标准答案:

Few-shot通过在Prompt中提供数个示例(exemplar)来引导LLM输出格式和推理模式。

核心原则:

  1. 示例选择:选与目标场景最相似的示例,多样性覆盖不同case
  2. 格式一致:所有示例和目标保持严格一致的输入输出格式
  3. 数量平衡:通常3-5个示例最优,过多会挤占context window
  4. 顺序敏感:最后一个示例对输出影响最大(recency bias)
Python
# Few-shot模板示例
PROMPT = """你是一个情感分析助手。请判断文本的情感倾向。

示例1:
输入: "这家餐厅的菜品真的太好吃了,环境也很棒"
输出: {"sentiment": "positive", "confidence": 0.95}

示例2:
输入: "等了一个小时还没上菜,服务态度极差"
输出: {"sentiment": "negative", "confidence": 0.92}

示例3:
输入: "菜品还行,就是价格偏贵了点"
输出: {"sentiment": "neutral", "confidence": 0.78}

请分析以下文本:
输入: "{user_text}"
输出: """

面试官追问: Few-shot vs Fine-tuning如何选择? - 数据量<100:Few-shot - 100<数据量<10000且任务稳定:参数高效微调(LoRA) - 数据量>10000且高精度要求:全参微调


Q2:Chain-of-Thought (CoT)提示的原理和变体?

标准答案:

CoT通过让模型显式输出中间推理步骤来提升复杂任务的准确率,本质是将隐式推理(在模型内部注意力中完成)转化为显式推理(在token序列中展开)。

三大变体:

变体 方式 优势
Manual CoT 手写推理步骤示例 最可控
Zero-shot CoT 加"Let's think step by step" 最简单
Auto-CoT 自动生成推理链 自动化
Python
# Zero-shot CoT
prompt_zs = f"""
问题:一个商店有45个苹果,卖掉了18个,又进了27个,现在有多少个?
请一步步思考后给出答案。
"""

# Manual CoT (更可靠)
prompt_manual = f"""
问题:小明有12块钱,买了3本书每本2块,还剩多少钱?
思考过程:
1. 3本书的总价 = 3 × 2 = 6块
2. 剩余 = 12 - 6 = 6块
答案:6块

问题:{user_question}
思考过程:
"""

面试官追问: CoT在什么模型上效果好? - 模型参数 >~60B 时CoT效果明显提升(涌现能力) - 小模型可通过CoT蒸馏(用大模型生成的推理链微调小模型)


Q3:Self-Consistency(自一致性)如何提升推理可靠性?

标准答案:

Self-Consistency对同一问题多次采样(高温度),然后对最终答案多数投票

流程: 1. 设置高温度(temperature=0.7-1.0) 2. 对同一问题生成N条不同推理路径(N=5-20) 3. 提取每条路径的最终答案 4. 多数投票选出最终答案

Python
import collections

def self_consistency(client, prompt, n_samples=10, temperature=0.8):
    """自一致性推理"""
    answers = []
    for _ in range(n_samples):
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": prompt}],
            temperature=temperature,
            max_tokens=1024,
        )
        # 提取最终答案(假设格式为 "答案:XXX")
        text = response.choices[0].message.content
        answer = extract_final_answer(text)
        answers.append(answer)

    # 多数投票
    counter = collections.Counter(answers)  # Counter统计每个答案的出现次数
    best_answer, count = counter.most_common(1)[0]  # most_common(1)取最高频的(答案, 次数)元组并解包
    confidence = count / len(answers)

    return {
        "answer": best_answer,
        "confidence": confidence,
        "vote_distribution": dict(counter),
    }

面试官追问: Self-Consistency的缺点? - 成本线性增长(N次API调用) - 只适用于有确定答案的任务,开放生成不适合


Q4:Prompt中的角色设定(System Prompt)如何影响输出?

标准答案:

System Prompt设定模型的"人格"和行为边界,影响: 1. 输出风格:专业/口语/学术 2. 安全边界:拒绝什么类型的请求 3. 领域知识:领域专家角色可激活相关知识 4. 输出格式:JSON/Markdown/代码

Python
# 生产级System Prompt模板
SYSTEM_PROMPT = """## 角色
你是一位资深的Python后端开发专家。

## 能力
- 精通Python 3.10+, FastAPI, SQLAlchemy
- 熟悉设计模式和架构原则
- 了解安全最佳实践

## 约束
- 所有代码示例使用Python 3.10+语法
- 遵循PEP 8规范
- 不输出未经验证的安全敏感代码
- 如果不确定,明确说明而非猜测

## 输出格式
- 代码使用```python代码块
- 先给出简要解释,再给代码
- 关键部分添加注释"""

面试官追问: System Prompt会被用户Prompt覆盖吗? - 存在Prompt Injection风险,可通过指令隔离、输入过滤、输出检测缓解


Q5:Structured Output(结构化输出)如何保证?

三层保障策略:

Python
# 方法1: Function Calling (最可靠)
tools = [{
    "type": "function",
    "function": {
        "name": "extract_entities",
        "parameters": {
            "type": "object",
            "properties": {
                "persons": {"type": "array", "items": {"type": "string"}},
                "locations": {"type": "array", "items": {"type": "string"}},
            },
            "required": ["persons", "locations"]
        }
    }
}]

# 方法2: JSON Mode
response = client.chat.completions.create(
    model="gpt-4o-mini",
    response_format={"type": "json_object"},
    messages=[{"role": "user", "content": "以JSON格式提取..."}],
)

# 方法3: Pydantic + Instructor (第三方库)
import instructor
from pydantic import BaseModel

class Sentiment(BaseModel):  # Pydantic BaseModel:自动数据验证和序列化
    label: str
    score: float
    reasoning: str

client = instructor.patch(OpenAI())
result = client.chat.completions.create(
    model="gpt-4o-mini",
    response_model=Sentiment,
    messages=[{"role": "user", "content": "分析情感..."}],
)

Q6:Prompt优化的系统方法?

优化闭环:

  1. 基线建立:用简单Prompt在评测集上跑baseline
  2. 错误分析:分类错误case(格式错误/推理错误/知识缺失)
  3. 针对优化:针对错误类型调整Prompt
  4. A/B测试:对比新旧Prompt在全量评测集上的效果
  5. 迭代循环

常用技巧: - 明确输出格式和约束 - 提供反例("不要输出XXX格式") - 分解复杂任务为多步骤 - 使用XML标签分隔不同部分


🔍 二、RAG系统

Q7:RAG的完整Pipeline是什么?各阶段有什么优化点?

标准答案:

Text Only
文档 → [解析] → [分块] → [向量化] → [索引存储]
用户Query → [Query改写] → [检索] → [重排序] → [生成] → 回答

各阶段优化:

阶段 关键技术 优化方向
解析 PDF/OCR/表格提取 保留结构信息
分块 固定/语义/递归分块 分块大小、重叠比
向量化 BGE/E5/Cohere 领域适配微调
检索 稠密/稀疏/混合 召回率
重排序 Cross-Encoder 精排精度
生成 Prompt设计/引用 忠实度

面试官追问: RAG vs 长上下文窗口(128K+)哪个好? - 长窗口:简单直接,但成本高、存在"中间遗忘"问题 - RAG:可扩展到任意规模知识库,成本可控 - 最佳实践:RAG检索 + 长窗口兜底


Q8:文档分块(Chunking)策略对比?

标准答案:

策略 原理 优点 缺点
固定大小分块 按字符/token数切分 简单 可能切断语义
递归分块 按多级分隔符(段→句→词) 保留段落结构 通用性好
语义分块 Embedding相似度断点 语义完整 计算成本高
文档结构分块 按标题/章节切分 结构清晰 依赖文档格式
父子分块 小块检索,返回父大块 兼顾精度和上下文 实现复杂
Python
# 父子分块 (Parent-Child Chunking)
from langchain_text_splitters import RecursiveCharacterTextSplitter

parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=50)

parent_chunks = parent_splitter.split_documents(docs)
for parent in parent_chunks:
    children = child_splitter.split_documents([parent])
    for child in children:
        child.metadata["parent_id"] = parent.metadata["doc_id"]
        # 检索时匹配child,返回对应parent的完整内容

面试官追问: 最优chunk_size如何确定? - 经验值:256-512 token(对话场景偏小,文档QA偏大) - 最佳方法:在评测集上grid search不同大小,看检索命中率


Q9:向量检索 vs 关键词检索 vs 混合检索?

标准答案:

方法 原理 优势 劣势
稠密检索 Embedding语义匹配 理解同义词/上下位 精确匹配弱
稀疏检索 BM25关键词匹配 精确匹配强 无语义理解
混合检索 两者加权融合 互补优势 权重需调优
Python
# 混合检索实现 (Reciprocal Rank Fusion)
def reciprocal_rank_fusion(results_list, k=60):
    """RRF融合多路检索结果"""
    fused_scores = {}
    for results in results_list:
        for rank, (doc_id, _) in enumerate(results):  # enumerate返回(序号, 元素),(doc_id, _)再解包元素,_丢弃第二项
            if doc_id not in fused_scores:
                fused_scores[doc_id] = 0
            fused_scores[doc_id] += 1 / (k + rank + 1)

    # 按分数降序排列:items()返回(doc_id, score)对,lambda x: x[1]取score作为排序依据
    return sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)  # lambda匿名函数

# 实际使用
dense_results = vector_store.similarity_search(query, k=20)
sparse_results = bm25_retriever.get_relevant_documents(query)[:20]
fused = reciprocal_rank_fusion([
    [(doc.metadata['id'], doc) for doc in dense_results],
    [(doc.metadata['id'], doc) for doc in sparse_results],
])

面试官追问: Embedding模型如何选择? - 中文:BGE-large-zh > M3E > text2vec - 英文:text-embedding-3-large > E5-large > GTE - 领域场景:在领域数据上微调Embedding效果显著


Q10:重排序(Reranking)的原理和必要性?

标准答案:

重排序用Cross-Encoder对query-document对做精细打分,弥补Bi-Encoder检索的精度不足。

为什么需要重排序: - Bi-Encoder(检索阶段):query和doc独立编码,效率高但交互信息少 - Cross-Encoder(重排序阶段):query和doc拼接后联合编码,精度高但速度慢

Python
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-large", max_length=512)

def rerank(query, documents, top_k=5):
    """Cross-Encoder重排序"""
    pairs = [(query, doc.page_content) for doc in documents]
    scores = reranker.predict(pairs)

    ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True)  # zip将文档和分数一一配对,sorted按分数降序
    return [doc for doc, score in ranked[:top_k]]  # 取前K个,解包时用doc保留文档、丢弃score

面试官追问: 重排序增加了多少延迟? - 典型: 检索(~50ms) + 重排序(~100ms for 20 docs) = ~150ms总延迟 - 优化:用更小的reranker模型 / 减少候选数量 / 异步执行


Q11:RAG系统如何评估?

标准答案:

检索质量评估: - Hit Rate@K:Top-K结果中是否包含正确答案 - MRR (Mean Reciprocal Rank):正确答案的平均排名倒数 - NDCG:考虑位置的评分

生成质量评估(RAGAS框架):

指标 含义 计算方式
Faithfulness 回答是否忠于上下文 LLM判断回答中每句话是否有上下文支撑
Answer Relevancy 回答是否切题 从回答反推query,与原始query对比
Context Precision 检索到的是否相关 相关文档在Top-K中的排名
Context Recall 是否遗漏了相关信息 参考答案中的信息是否被检索覆盖

面试官追问: 线上RAG系统如何监控? - 记录每次query+检索结果+回答+用户反馈 - 监控拒答率、用户满意度、检索命中率 - 定期人工评估badcase → 反馈到索引和Prompt优化


Q12:Query改写(Query Rewriting)有哪些技术?

标准答案:

  1. HyDE (Hypothetical Document Embedding):让LLM先生成假设性答案,用答案的embedding去检索
  2. Multi-Query:LLM将原始query改写为多个角度的子query,分别检索后合并
  3. Step-back Prompting:将具体问题抽象为更一般的问题
  4. Query Decomposition:将复杂问题拆解为多个子问题
Python
# HyDE实现
def hyde_retrieval(query, llm, retriever):
    """HyDE: 先生成假设答案,用答案做检索"""
    # Step 1: 生成假设答案
    hypothetical_answer = llm.invoke(
        f"请直接回答以下问题(不需要确认准确性): {query}"
    ).content

    # Step 2: 用假设答案的embedding检索
    docs = retriever.get_relevant_documents(hypothetical_answer)
    return docs

# Multi-Query实现
def multi_query_retrieval(query, llm, retriever, n_queries=3):
    """多角度Query改写"""
    expanded_queries = llm.invoke(
        f"请将以下问题从{n_queries}个不同角度改写:\n{query}\n只输出改写后的问题,每行一个"
    ).content.strip().split('\n')  # 链式调用:strip去除空白

    all_docs = []
    seen_ids = set()
    for q in [query] + expanded_queries:
        for doc in retriever.get_relevant_documents(q):
            doc_id = doc.metadata.get('doc_id')
            if doc_id not in seen_ids:
                all_docs.append(doc)
                seen_ids.add(doc_id)
    return all_docs

Q13:如何处理RAG中的多跳推理(Multi-hop Reasoning)?

标准答案:

多跳问题需要结合多个文档片段推理。

方案: 1. Iterative RAG:检索 → 部分回答 → 生成子问题 → 再检索 → 完善答案 2. Graph RAG:用知识图谱连接实体,沿图谱路径检索 3. Agentic RAG:让Agent自主决定检索策略和次数

Python
# Iterative RAG简化实现
def iterative_rag(query, retriever, llm, max_steps=3):
    context = ""
    for step in range(max_steps):
        docs = retriever.get_relevant_documents(query if step == 0 else sub_query)
        context += "\n".join([d.page_content for d in docs])

        response = llm.invoke(f"""
        基于已有信息回答问题,如果信息不够,输出"需要更多信息:<子问题>"。
        已有信息:{context}
        问题:{query}
        """).content

        if "需要更多信息" not in response:
            return response
        sub_query = response.split("需要更多信息:")[1].strip()

    return response

🤖 三、Agent

Q14:ReAct框架的原理是什么?

标准答案:

ReAct = Reasoning + Acting,让LLM交替执行推理(思考)和行动(调用工具),形成"思考→行动→观察"的循环。

核心流程:

Text Only
Thought: 我需要查询今天北京的天气
Action: search_weather(city="北京")
Observation: 北京今天晴,最高温度25°C
Thought: 用户还问了穿什么衣服,25度适合穿...
Action: 返回最终答案
Answer: 北京今天晴朗,最高25°C,建议穿长袖薄外套...
Python
# ReAct Agent简化实现
class ReActAgent:
    def __init__(self, llm, tools, max_steps=5):
        self.llm = llm
        self.tools = {t.name: t for t in tools}
        self.max_steps = max_steps

    def run(self, query):
        prompt = self._build_prompt(query)
        history = []

        for step in range(self.max_steps):
            response = self.llm.invoke(prompt + "\n".join(history))

            if "Answer:" in response.content:
                return response.content.split("Answer:")[1].strip()

            # 解析Action
            action, action_input = self._parse_action(response.content)

            if action in self.tools:
                observation = self.tools[action].invoke(action_input)
                history.append(f"Thought: {response.content}")
                history.append(f"Observation: {observation}")
            else:
                history.append(f"Observation: 工具 {action} 不存在")

        return "达到最大步数,无法完成任务"

面试官追问: ReAct vs Plan-and-Execute的区别? - ReAct:边想边做,灵活但可能走弯路 - Plan-and-Execute:先制定计划再逐步执行,适合复杂任务


Q15:Function Calling / Tool Use的实现原理?

标准答案:

LLM通过特殊的训练学会在需要时输出结构化的函数调用请求,而非自然语言。

流程: 1. 在System Prompt中提供工具的schema定义 2. LLM判断是否需要调用工具 3. 输出JSON格式的函数名+参数 4. 应用层执行函数,将结果返回给LLM 5. LLM基于结果生成最终回答

Python
# OpenAI Function Calling
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "获取股票当前价格",
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {"type": "string", "description": "股票代码,如AAPL"},
                },
                "required": ["symbol"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "苹果公司现在股价多少?"}],
    tools=tools,
    tool_choice="auto",
)

# 处理tool call
if response.choices[0].message.tool_calls:
    tool_call = response.choices[0].message.tool_calls[0]
    func_name = tool_call.function.name
    func_args = json.loads(tool_call.function.arguments)  # json.loads将JSON字符串→Python对象

    # 执行工具
    result = execute_tool(func_name, func_args)

    # 将结果返回给LLM
    messages.append(response.choices[0].message)
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": json.dumps(result)  # json.dumps将Python对象→JSON字符串
    })
    final_response = client.chat.completions.create(model="gpt-4o", messages=messages)

面试官追问: Function Calling如何训练的? - 在SFT阶段加入工具调用的示例数据 - 输出格式通常是特殊token包裹的JSON


Q16:多Agent协作的架构模式?

标准答案:

模式 描述 适用场景
顺序链式 A→B→C,每个处理一步 Pipeline任务
主从模式 Orchestrator分派子Agent 复杂任务分解
辩论模式 多Agent讨论达成共识 需要多角度分析
群聊模式 多Agent自由对话 头脑风暴
Python
# 主从模式示例(简化)
class OrchestratorAgent:
    def __init__(self, planner_llm, worker_agents):
        self.planner = planner_llm
        self.workers = worker_agents  # {"researcher": ..., "coder": ..., "reviewer": ...}

    def run(self, task):
        # 1. 规划子任务
        plan = self.planner.invoke(f"将以下任务分解为子任务,指定负责的Agent:\n{task}")
        subtasks = self._parse_plan(plan)

        # 2. 分派执行
        results = {}
        for subtask in subtasks:
            agent_name = subtask["agent"]
            result = self.workers[agent_name].run(subtask["description"])
            results[subtask["id"]] = result

        # 3. 汇总
        summary = self.planner.invoke(f"汇总以下子任务结果:\n{results}")
        return summary

面试官追问: 多Agent系统最大的挑战? - 状态同步:Agent之间的信息共享和上下文传递 - 错误传播:一个Agent错误会影响下游 - 成本控制:多次LLM调用的token消耗


Q17:MCP(Model Context Protocol)是什么?

标准答案:

MCP是Anthropic提出的开放协议,标准化了LLM与外部工具/数据源的通信方式,类似于"AI的USB接口"。

核心概念: - MCP Server:提供工具/资源的服务端 - MCP Client:LLM应用(如Claude Desktop, VS Code) - Transport:通信方式(stdio/SSE/HTTP)

与Function Calling的区别: - Function Calling: 工具定义和执行都在应用代码中 - MCP: 工具以独立服务存在,可跨应用复用


Q18:Agent的记忆(Memory)系统如何设计?

标准答案:

记忆类型 实现方式 生命周期
短期记忆 对话历史窗口 单次会话
长期记忆 向量数据库存储 跨会话
工作记忆 Scratchpad/变量 单次任务
实体记忆 结构化KV存储 持久化
Python
# 带记忆的Agent简化实现
class MemoryAgent:
    def __init__(self, llm, vector_store, max_history=20):
        self.llm = llm
        self.long_term = vector_store  # 长期记忆
        self.short_term = []            # 短期记忆(对话历史)
        self.max_history = max_history

    def chat(self, user_message):
        # 1. 从长期记忆检索相关信息
        relevant_memories = self.long_term.similarity_search(user_message, k=3)
        memory_context = "\n".join([m.page_content for m in relevant_memories])

        # 2. 构建Prompt
        messages = [
            {"role": "system", "content": f"相关记忆:\n{memory_context}"},
            *self.short_term[-self.max_history:],
            {"role": "user", "content": user_message}
        ]

        # 3. 生成回复
        response = self.llm.invoke(messages).content

        # 4. 更新记忆
        self.short_term.append({"role": "user", "content": user_message})
        self.short_term.append({"role": "assistant", "content": response})

        # 5. 重要信息存入长期记忆
        if self._is_important(user_message, response):
            self.long_term.add_texts([f"用户: {user_message}\n助手: {response}"])

        return response

🔧 四、微调(Fine-tuning)

Q19:LoRA的原理是什么?为什么有效?

标准答案:

LoRA (Low-Rank Adaptation) 冻结原始权重,在旁路中训练低秩矩阵。

数学原理:

\[ h = W_0 x + \Delta W x = W_0 x + BAx \]

其中 \(W_0 \in \mathbb{R}^{d \times k}\) 冻结,\(B \in \mathbb{R}^{d \times r}\)\(A \in \mathbb{R}^{r \times k}\)\(r \ll \min(d, k)\)

为什么有效: 1. 预训练权重已有很强的通用能力,微调时的变化量 \(\Delta W\) 本身就是低秩的 2. 实验表明 \(r=8\)\(r=16\) 就能达到全参微调95%+的效果

方法 可训练参数 以7B模型为例
全参微调 100% ~7B
LoRA (r=16) ~0.1% ~8M
QLoRA (4bit+LoRA) ~0.1%+4bit量化 ~8M (显存从28GB→6GB)
Python
from peft import LoraConfig, get_peft_model, TaskType

lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                      # 秩
    lora_alpha=32,             # 缩放因子 (alpha/r 为实际缩放)
    lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],  # 作用模块
    bias="none",
)

model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters()
# trainable params: 8,388,608 || all params: 6,746,804,224 || trainable%: 0.124%

面试官追问: LoRA的rank如何选择? - 简单任务(分类): r=4-8 - 复杂任务(对话/指令跟随): r=16-64 - 经验法则: 先用r=16,在验证集上对比r=8和r=32


Q20:微调数据如何准备?质量如何保证?

标准答案:

数据格式(指令微调):

JSON
{
    "instruction": "将以下英文翻译成中文",
    "input": "Machine learning is a subset of AI.",
    "output": "机器学习是人工智能的一个子集。"
}

数据质量保障:

维度 检查方法 工具
格式正确性 JSON Schema验证 jsonschema
答案准确性 LLM评分+人工抽检 GPT-4 as judge
多样性 去重+分布分析 MinHash/Embedding聚类
长度分布 统计token长度 tiktoken
安全性 毒性/偏见检测 Perspective API
Python
# 数据质量检查Pipeline
def validate_training_data(data):
    """验证微调数据质量"""
    issues = []

    for i, item in enumerate(data):  # enumerate同时获取索引和元素
        # 1. 格式检查
        if not all(k in item for k in ['instruction', 'output']):  # all()全部为True才返回True
            issues.append(f"[{i}] 缺少必要字段")
            continue

        # 2. 长度检查
        total_tokens = count_tokens(item['instruction'] + item.get('input','') + item['output'])  # get('input',''):若该键不存在则返回空字符串,避免KeyError
        if total_tokens > 2048:
            issues.append(f"[{i}] 超长: {total_tokens} tokens")
        if len(item['output'].strip()) < 10:
            issues.append(f"[{i}] 回答过短")

        # 3. 重复检查
        # ... MinHash去重

    print(f"共 {len(data)} 条, {len(issues)} 个问题")
    return issues

面试官追问: 微调数据量多少合适? - 领域适配: 1000-5000条高质量数据 - 对话能力: 10000-50000条 - 关键是质量 > 数量,1000条精标数据 > 10000条低质量数据


Q21:全参微调 vs LoRA vs QLoRA如何选择?

标准答案:

维度 全参微调 LoRA QLoRA
显存 (7B) ~56GB ~28GB ~6GB
训练速度 基准 ~1.2x慢 ~1.5x慢
效果上限 最高 接近全参 略低
适用场景 充足资源+大量数据 主流选择 消费级显卡
灾难遗忘 较严重 较轻 较轻

决策树:

Text Only
显存 < 16GB → QLoRA
16GB < 显存 < 48GB → LoRA
显存 > 48GB + 数据 > 10K → 全参微调


Q22:SFT(监督微调)和RLHF/DPO的区别?

标准答案:

阶段 方法 数据格式 目标
SFT 监督学习 (prompt, response) 学会指令跟随
RLHF PPO强化学习 (prompt, chosen, rejected) 对齐人类偏好
DPO 直接偏好优化 (prompt, chosen, rejected) 简化RLHF

DPO损失函数:

\[ \mathcal{L}_{DPO} = -\log \sigma\left(\beta \log\frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \log\frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)}\right) \]

面试官追问: 为什么DPO正在替代RLHF? - RLHF需要训练奖励模型+PPO,流程复杂 - DPO直接用偏好数据优化,效果相当但训练更稳定


⚡ 五、推理优化

Q23:KV-Cache的原理是什么?

标准答案:

自回归生成时,每个token的生成都需要对前面所有token做注意力计算。KV-Cache缓存已计算的Key和Value向量,避免重复计算。

数学理解:

  • 无Cache:生成第 \(t\) 个token需计算 \(t\) 个K和V → 总计算量 \(O(n^2)\)
  • 有Cache:只计算新token的Q,与缓存的K和V做注意力 → 增量计算 \(O(n)\)

显存占用:

\[ \text{KV-Cache Size} = 2 \times n_{layers} \times n_{heads} \times d_{head} \times \text{seq\_len} \times \text{batch\_size} \times \text{bytes} \]

以Llama-2-7B为例(32层, 32头, d=128, FP16): - seq_len=2048, batch=1: \(2 \times 32 \times 32 \times 128 \times 2048 \times 2 = 1.07\text{GB}\)

面试官追问: KV-Cache占用太大怎么办? - GQA (Grouped Query Attention): 多个Q头共享K/V头,如Llama-2用GQA将KV头从32减到8 - MQA (Multi-Query Attention): 所有Q头共享一组KV - 滑动窗口注意力 (Mistral): 限制attention范围


Q24:PagedAttention(vLLM)的核心创新?

标准答案:

传统KV-Cache为每个请求预分配最大长度的连续显存,导致大量浪费。

PagedAttention借鉴操作系统虚拟内存的分页思想: 1. 将KV-Cache分成固定大小的block(类似内存页) 2. 用page table映射逻辑位置→物理block 3. 按需分配,不需要连续内存 4. 支持block共享(beam search/prefix caching)

效果: - 显存利用率从50%→95%+ - 相同显存下吞吐量提升2-4倍

Python
# vLLM使用示例
from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Llama-2-7b-chat-hf",
    tensor_parallel_size=1,
    gpu_memory_utilization=0.90,
    max_num_seqs=256,          # 最大并发
    max_model_len=4096,
)

sampling_params = SamplingParams(
    temperature=0.7,
    top_p=0.9,
    max_tokens=512,
)

outputs = llm.generate(["你好,请介绍一下自己"], sampling_params)

面试官追问: vLLM vs TGI vs TensorRT-LLM如何选? - vLLM:通用性好,易用,社区活跃 - TGI:HuggingFace生态,部署简单 - TensorRT-LLM:性能最优,但配置复杂


Q25:模型量化的方法对比?

标准答案:

方法 精度 速度 质量损失 特点
FP16 16bit 基准 训练/推理标准
INT8 (LLM.int8()) 8bit 1.2-1.5x 极小 混合精度分解
GPTQ 4bit 1.5-2x 训练后量化,需校准数据
AWQ 4bit 1.5-2x 保护重要权重通道
GGUF (llama.cpp) 2-8bit 1-3x 可变 CPU友好

面试官追问: 4bit量化真的能保持效果吗? - 7B模型4bit量化后,MMLU下降通常<1% - 越大的模型对量化越鲁棒 - 关键:保护attention层中少数重要通道


Q26:投机解码(Speculative Decoding)原理?

标准答案:

用小模型(Draft Model)快速生成多个候选token,大模型(Target Model)并行验证,接受概率匹配的token。

流程: 1. Draft Model自回归生成 \(\gamma\) 个token(如5个) 2. Target Model一次前向传播并行验证这5个token 3. 按照rejection sampling: 如果小模型置信度≤大模型,直接接受 4. 否则以一定概率接受/拒绝,从拒绝位置重新采样

加速比: 通常 1.5-3x,取决于Draft Model与Target Model的一致率

Text Only
Draft Model: "今天 天气 真 不错 想 出去"  (6个token, 很快生成)
Target Model: ✅ ✅ ✅ ✅ ❌ (验证前4个ok, 第5个拒绝)
-> 接受 "今天 天气 真 不错", 从第5个位置用Target采样

面试官追问: 投机解码的输出分布与原始Target Model一致吗? - 是的,通过rejection sampling数学保证输出分布完全一致


Q27:Continuous Batching(持续批处理)原理?

标准答案:

传统Static Batching等所有请求都完成才处理下一批,导致短请求等长请求。

Continuous Batching在iteration级别动态调度: - 每个iteration后,检查是否有请求完成(EOS) - 已完成的请求立即移出,新请求立即插入 - 显存利用率大幅提升

效果: 吞吐量可提升10-20x(高并发场景)


Q28:Prefill和Decode阶段的计算特性区别?

标准答案:

阶段 计算模式 瓶颈 特点
Prefill 并行处理所有输入token Compute-bound 一次前向,批处理高效
Decode 逐token自回归生成 Memory-bound 每次只生成1个token

优化策略: - Prefill: Tensor并行、FlashAttention - Decode: KV-Cache、投机解码、量化

面试官追问: 什么是TTFT和TPS? - TTFT (Time To First Token): Prefill延迟,用户感知的等待时间 - TPS (Tokens Per Second): Decode速度,流式输出的速度


📊 六、LLM评估

Q29:主流LLM Benchmark有哪些?各评估什么能力?

标准答案:

Benchmark 评估能力 方式
MMLU 学科知识(57科) 多选题
HumanEval / MBPP 代码生成 Pass@k
GSM8K / MATH 数学推理 精确匹配
MT-Bench 多轮对话 GPT-4打分
AlpacaEval 指令跟随 GPT-4对比评分
TruthfulQA 真实性 多选+生成
BBH 复杂推理 CoT

面试官追问: Benchmark的局限性? - 数据污染:模型可能在训练时见过测试题 - 刷榜优化:针对Benchmark优化,不代表真实能力 - 静态评估:无法覆盖开放式生成的质量


Q30:LLM-as-Judge评估方法的原理和问题?

标准答案:

用强LLM(如GPT-4)评判其他模型的回答质量。

Python
JUDGE_PROMPT = """请评估以下AI回答的质量。

用户问题: {question}
AI回答: {answer}
参考答案: {reference}

请从以下维度打分(1-5分):
1. 准确性: 信息是否正确
2. 完整性: 是否覆盖关键点
3. 清晰度: 表述是否清楚
4. 有用性: 对用户的帮助程度

输出JSON: {"accuracy": x, "completeness": x, "clarity": x, "helpfulness": x, "overall": x}
"""

已知问题: - 位置偏见:倾向于给第一个出现的回答更高分 → 解决:交换位置取平均 - 长度偏见:更长的回答更容易获高分 → 解决:控制回答长度范围 - 自我偏好:GPT-4可能偏好GPT-4生成的内容 → 解决:多个judge交叉评估


Q31:人类对齐(Alignment)的目标和方法?

标准答案:

对齐三原则(HHH): - Helpful: 有用、准确、完整 - Harmless: 无害、安全、不歧视 - Honest: 诚实、承认不确定

技术路线: 1. RLHF: 人类标注偏好 → 训练奖励模型 → PPO优化 2. DPO: 直接使用偏好数据优化 3. Constitutional AI: LLM自我评判+修改 4. RLAIF: AI生成反馈替代人类


Q32:LLM安全性评估包括哪些方面?

标准答案:

维度 评估内容 测试方法
毒性 生成有害/攻击性内容 毒性分类器评分
偏见 性别/种族/年龄偏见 偏见基准测试
幻觉 生成不存在的事实 事实核查
泄露 输出训练数据 成员推断攻击
越狱 Prompt注入/越狱 红队测试
隐私 输出个人信息 PII检测

红队测试要点: - 直接要求 → 角色扮演诱导 → 编码绕过 → 多步骤攻击 - 持续更新攻击策略,防御是动态过程


📝 面试备考清单

高频必会

  • Few-shot / CoT / Self-Consistency原理和代码
  • RAG全链路(分块→检索→重排→生成)
  • LoRA原理和参数选择
  • KV-Cache / PagedAttention原理
  • 量化方法对比(GPTQ/AWQ/GGUF)

进阶加分

  • ReAct / Function Calling实现
  • 多Agent协作架构
  • DPO vs RLHF对比
  • 投机解码 / Continuous Batching
  • RAG评估(RAGAS框架)

系统设计题准备

  • 设计一个企业RAG系统
  • 设计一个多模态对话系统
  • 设计一个LLM推理服务(高并发)
  • 设计一个Agent开发平台

💡 高频出题公司参考:字节跳动(豆包/推理优化)、腾讯(混元/Agent)、阿里(通义/RAG)、百度(文心/微调)、月之暗面(Kimi/长文本)、智谱(GLM/评估)