AI 方向的前端面试越来越常见。重点不是训练大模型,而是理解 LLM 能力边界,并能把 AI 能力稳定接入产品。

大模型基础

Transformer、Token 与 Attention

知识点讲解

Token 是模型处理文本的基本单位,可能是字、词或词片段。Transformer 通过 Attention 建模上下文关系,让模型判断哪些 token 对当前生成更重要。

面试常问

问:上下文窗口是什么?

答:模型一次能处理的 token 数量上限。超过窗口的内容不能全部被模型直接看到,需要摘要、检索或分段处理。

Embedding

知识点讲解

Embedding 把文本、图片等内容转成向量,让语义相近的内容在向量空间里距离更近。RAG、推荐、聚类、相似搜索都常用 embedding。

面试常问

问:Embedding 和关键词搜索有什么区别?

答:关键词搜索看字面匹配,Embedding 看语义相似。比如“如何提升首屏速度”和“白屏优化方案”字面不同,但语义接近。

Prompt 与模型能力

Prompt 工程

知识点讲解

Prompt 设计要明确角色、目标、输入、输出格式、约束和示例。Few-shot 能通过样例稳定输出风格。复杂任务可以拆成规划、执行、校验多个阶段。

面试常问

问:怎么让模型输出稳定 JSON?

答:明确 schema,要求只输出 JSON,使用结构化输出能力或函数调用,服务端做解析和校验,失败时重试或降级。

Function Calling 与 Tool Calling

知识点讲解

Function Calling 让模型选择调用哪个函数并生成结构化参数。Tool Calling 更强调模型连接外部工具,比如搜索、数据库、业务接口、文件系统。

面试常问

问:为什么不能让模型直接操作数据库?

答:模型输出不可靠,必须经过权限、参数校验、审计和业务层封装。工具调用应该暴露受控能力,而不是裸 SQL 或高权限接口。

RAG 架构

Chunking、向量库与 ReRank

知识点讲解

RAG 流程通常是文档切块、生成 embedding、写入向量库、按用户问题召回相关片段,再把片段交给模型生成答案。ReRank 可以对召回结果重新排序,提高相关性。

面试常问

问:RAG 为什么会答错?

答:可能是切块不合理、召回不准、上下文不足、模型忽略证据、数据过期或提示词约束不清。要从检索和生成两端排查。

前端如何接入 RAG

知识点讲解

前端通常负责文件上传、问题输入、流式展示、引用来源、反馈按钮和错误状态。后端负责文档解析、索引、召回、权限过滤和模型调用。

面试常问

问:回答为什么要展示引用来源?

答:引用能增强可信度,也方便用户验证答案。对企业知识库来说,还能暴露模型答案依据,便于排查错误。

Agent 与协议

Agent、Planning 与 Memory

知识点讲解

Agent 是能基于目标进行规划、调用工具、观察结果并继续行动的系统。Planning 负责拆任务,Memory 负责保存长期或短期上下文,但记忆必须可控、可清理。

面试常问

问:Agent 和普通聊天机器人区别?

答:普通聊天主要生成回答;Agent 会围绕目标规划步骤,调用工具,基于工具结果继续决策,更像一个任务执行系统。

MCP 与 A2A

知识点讲解

MCP 可以理解为模型应用连接工具和数据源的协议化方式,让工具暴露更标准。A2A 更关注 Agent 之间的协作通信。

面试常问

问:MCP 的价值是什么?

答:降低工具接入成本,让不同模型应用用统一方式发现和调用工具,避免每个应用重复写私有集成。

AI 工程化

Streaming 与 SSE

知识点讲解

AI 输出通常较慢,流式返回能让用户更快看到结果。SSE 适合服务端单向推送文本流;WebSocket 适合双向实时通信。

面试常问

问:前端怎么处理流式输出?

答:用 fetch 读取 ReadableStream 或使用 EventSource 接收 SSE,逐块更新 UI,同时处理取消、重试、超时和错误恢复。

Guardrails 与 Observability

知识点讲解

Guardrails 包括输入校验、输出校验、敏感信息过滤、权限控制和人工审核。Observability 包括日志、token、延迟、成本、命中率、错误率和用户反馈。

面试常问

问:AI 应用上线最怕什么?

答:不可控输出、越权访问、成本失控、延迟过高、无法追踪问题。工程上要有权限、审计、监控、降级和人工兜底。

底层追问与代码示例

RAG 的工程链路

知识点讲解

RAG 不是“把文档塞进 prompt”。专业链路至少包含解析、清洗、切块、向量化、索引、召回、重排、上下文拼装、生成、引用和反馈闭环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type Chunk = {
id: string
docId: string
text: string
metadata: {
title: string
page?: number
updatedAt: string
}
}

async function answerQuestion(question: string) {
const queryVector = await embed(question)

const candidates = await vectorStore.search({
vector: queryVector,
topK: 20,
filter: { visibleTo: currentUser.id }
})

const reranked = await rerank(question, candidates)
const contexts = reranked.slice(0, 5)

return generate({
system: '只基于给定资料回答;资料不足就说明不足。',
question,
contexts
})
}

面试常问

问:RAG 如何处理权限?

答:权限不能只在前端做。索引时写入权限 metadata,召回时按用户身份过滤,生成阶段也只传入用户有权访问的片段,并记录审计日志。

Chunking 的取舍

知识点讲解

切块太小会丢上下文,切块太大会降低召回精度并浪费 token。常见策略是按标题层级、段落、语义边界切块,并保留 overlap。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function chunkText(text: string, size = 800, overlap = 120) {
const chunks: string[] = []
let start = 0

while (start < text.length) {
const end = Math.min(start + size, text.length)
chunks.push(text.slice(start, end))
start = end - overlap
if (start < 0) start = 0
if (end === text.length) break
}

return chunks
}

专业回答要补充:真实场景更推荐结构化切块,比如 Markdown 按标题、PDF 按页和段落,代码按函数或类边界。

流式输出前端实现

知识点讲解

前端处理流式输出时要关注增量解码、取消请求、错误恢复和 Markdown 渲染安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async function streamAnswer(question: string, onDelta: (text: string) => void) {
const controller = new AbortController()

const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ question }),
signal: controller.signal,
headers: { 'Content-Type': 'application/json' }
})

if (!response.body) throw new Error('No stream body')

const reader = response.body.getReader()
const decoder = new TextDecoder()

while (true) {
const { value, done } = await reader.read()
if (done) break
onDelta(decoder.decode(value, { stream: true }))
}

return () => controller.abort()
}

面试常问

问:为什么流式输出不能直接 innerHTML?

答:模型输出不可信,直接插入 HTML 有 XSS 风险。应该把内容当文本处理,Markdown 渲染也要做安全过滤。

Tool Calling 的安全边界

知识点讲解

工具调用要把模型限制在“提议调用”,真正执行由业务系统校验。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const tools = {
getOrder: async (args: { orderId: string }, user: User) => {
if (!/^\d+$/.test(args.orderId)) {
throw new Error('invalid order id')
}

const order = await db.order.findUnique({
where: { id: args.orderId }
})

if (!order || order.userId !== user.id) {
throw new Error('forbidden')
}

return order
}
}

面试常问

问:Prompt Injection 怎么防?

答:不要把模型输出当指令直接执行;工具层做权限和参数校验;检索内容和系统指令分离;敏感操作加确认;记录工具调用审计。