# AI 大模型与 Agent 面试题汇总
这份题库是给正在或准备做 AI 方向的前端 / 全栈工程师准备的,重点放在真实面试常考、能直接用上工程的题目,而不是 ChatGPT 拽词汇说一遍就完事的概念题。
几条原则:
- 每道题都标了「考察点」,知道面试官真正想确认什么,比记标准答案更值钱。
- 答案尽量按面试节奏写:先用一两句话把结论说清,再补关键细节,再补一个能让对方点头的延伸或例子。
- 实在通用的概念题不会写得太啰嗦,真正决定差异化的,是工程实战那几节(Agent 架构、RAG、MCP、LangChain/LangGraph、前端集成、AI 提效)。
题量按主题排布,越往后越偏工程实操:
- 一、大模型基础(先把"是什么"打通)
- 二、Prompt 工程(最该练的硬功夫)
- 三、AI Agent 架构(高频且能拉开差距)
- 四、RAG 检索增强生成(ToB 项目几乎必问)
- 五、Function Calling 与 MCP(新一年最火的实战题)
- 六、Memory 与上下文管理(Agent 真正难的部分)
- 七、LangChain / LangGraph 框架(开源生态主战场)
- 八、模型微调 / 私有化部署 / ToB 落地(资深岗常问)
- 九、前端 AI 集成与工程化(前端的主场)
- 十、AI 提效篇(怎么用 AI 反过来帮自己干活)
- 十一、综合追问 & 场景题(拉差距的部分)
# 一、AI 与大模型基础
这一节别背太多概念,面试官真正想确认的是:你有没有过手感。每个点能说出一个自己见过的现象,胜过把维基百科背一遍。
# 1. 什么是大语言模型(LLM)?它和过去的 NLP 模型本质区别是什么?
考察点:能否用一句话讲清,并知道它不是「智能」而是「概率」。
LLM 本质上是一个只会做一件事的概率模型:给一段上文,预测下一个 token 最可能是什么。把这个动作循环执行,就能输出一句话、一段代码、一篇文章。
它和过去 NLP 的区别有两点最关键:
- 不再针对单一任务训练。过去要做分类训分类,做翻译训翻译;现在一个模型靠 prompt 切换几十种任务。
- 规模带来质变。参数量到一定规模后,会涌现出推理、代码、跨语言能力,这是小模型里不存在的。
一句话总结:本质是「自回归概率分布」+「大力出奇迹」,不要把它当成会思考的人。
# 2. GPT、Claude、Gemini、LLaMA、DeepSeek、通义、Kimi 这些怎么选?
面试时别背版本号,记住选型口径:
| 选型角度 | 倾向哪家 |
|---|---|
| Agent / 工具调用 / 长任务稳定 | Claude(Anthropic) |
| 通用 + 生态最广 + 多模态 | GPT / OpenAI |
| 超长上下文 / 多模态 | Gemini |
| 开源 + 微调研究的事实标准 | LLaMA(Meta) |
| 开源 + 推理 / 代码 / 数学 | DeepSeek |
| 中文场景 / 国内私有化 | Qwen(阿里)、GLM(智谱) |
| 中文长文档 / 阅读理解 | Kimi(Moonshot) |
| 轻量 / 边缘 / 端侧部署 | Mistral / Phi / Gemma |
被追问"为什么这么选"时一定要说业务场景:
- 我们做企业内部 Agent,链路 10 步以上,所以选 Claude,工具调用更稳;
- 我们做 RAG + 长文档,所以选 Kimi / Gemini,长上下文成本比切片好控;
- 我们做合规私有化,所以选 Qwen / DeepSeek 自部署;
- 我们要做学术微调实验对比开源底座,所以选 LLaMA 系;
- 我们要把模型塞进 IoT / 浏览器端,所以选 Phi / Gemma 这种 1B-4B 的小模型。
# 3. Token 是什么?为什么按 token 计费而不是字符?
Token 是模型实际处理的最小单元,由 tokenizer 把文本切成一串整数 id。模型从头到尾看到的都是 token id,不是字符。
按 token 计费的真正原因:模型的算力消耗和 token 数线性相关,和字符数不是。比如同一句话英文 4 token、中文可能 8 token,按字符算就不公平了。
常用换算(够你在面试里给个数):
- 英文:1 token ≈ 4 字符 ≈ 0.75 个单词
- 中文:1 token ≈ 1.5 个汉字(不同模型差别不小)
- 代码:和英文接近,但符号多的语言会更碎
实战经验:估成本时给 1.3 倍 buffer,因为输入和输出都会算,且 system prompt 在多轮里会反复带。
# 4. 上下文窗口(Context Window)是什么?越大越好吗?
窗口 = 模型一次能塞进去的 token 总额 = system + 历史对话 + 当前输入 + 留给输出的预算。超过就要截断、报错或者换策略。
不是越大越好,几个反常识的点:
- 大窗口 ≠ 注意力均匀。模型对开头和结尾的内容关注更高,中间段容易被忽略,叫「Lost in the Middle」。
- 成本和延迟一起涨。1M token 上下文每次调用都极贵,而且首 token 时间会肉眼可见地变慢。
- 大窗口不能完全替代 RAG。把 50 篇文档全塞进去,效果通常不如 RAG 检索出最相关的 5 段塞进去。
工程上反而要主动控制:滑动窗口、摘要压缩、向量检索拼接才是常态。
# 5. Temperature、top_p、top_k、seed 这几个参数怎么调?
记住一句话:调一个就够,别全都调。最常用的是 temperature。
| 参数 | 控制什么 | 代码 / 抽取场景 | 创意 / 闲聊 |
|---|---|---|---|
| temperature | 整体随机性 | 0 - 0.3 | 0.7 - 1.0 |
| top_p | 截断到累计概率 p | 默认 0.9 不动 | 同上 |
| top_k | 截断到前 k 个候选 | 一般不调 | 一般不调 |
| seed | 复现性(部分模型支持) | 固定 seed + temperature=0 | — |
要让结果完全可复现:固定 seed + temperature=0 + top_p=1,且不要打开 streaming(部分 SDK streaming 有微差)。
# 6. Embedding 是什么?和 LLM 的关系?
Embedding 模型是专门把一段文本压成一个固定长度向量(比如 1024 / 1536 / 3072 维)的模型,向量距离反映语义相似度。
它和 LLM 是两个独立模型:
- LLM:处理理解 + 生成
- Embedding 模型:只做表示,不生成
典型用途:语义搜索、RAG 检索、聚类、推荐、查重、相似工单合并。
面试常被追问的细节:
- 维度越高 ≠ 效果越好,主流 1024 / 1536 已经够用,维度高会让向量库存储和检索都变贵;
- 同一份语料要用同一个 embedding 模型,换模型必须全量重建索引;
- 中文场景优先选支持中文的模型(bge-m3、Qwen-embedding、jina-zh),用英文 embedding 在中文上效果会折损。
# 7. 余弦相似度 vs 欧氏距离怎么选?
向量检索里 99% 用余弦相似度:只看方向不看长度,对文本归一化更友好。
欧氏距离会受向量模长影响,多用在「位置 / 物理量 / 图像特征」这种长度本身有意义的场景。
实战记一句话:embedding 都归一化之后,余弦相似度和欧氏距离结果基本等价(差一个常数变换),所以选哪个看库支持。
# 8. 模型「幻觉」(Hallucination)的根因是什么?
不是 bug,是架构决定的特性。
LLM 在做"下一个 token 概率最大化",并不会去查事实。当训练里没见过对应内容,它会按统计相关性继续编——表达通顺、事实瞎说。
减少幻觉是组合拳,没有单点药方:
- 接 RAG,让答案有据可查(这是最有效的一招);
- 在 system prompt 显式要求 "不知道就说不知道,不要编",并给一个示范;
- 强约束输出格式,比如必须 JSON + 必须带引用片段编号;
- 用代码或第二个 LLM 做后置校验(金额、日期、URL 这类容易瞎编的字段重点查);
temperature拉到 0 - 0.3;- 实在不行才上微调(成本最高)。
# 9. 自回归(Decoder-only)和 Encoder-Decoder 区别?
自回归:从左到右一个 token 一个 token 生成,代表 GPT / Claude / Llama / Qwen,现在主流 LLM 都是这个架构。
Encoder-Decoder:先把整个输入编码成中间表示,再解码出来,代表 T5 / BART,输入输出有明确对应的任务(翻译、摘要、纠错)历史上效果好。
为什么现在都偏向 Decoder-only?工程上更简单:一个模型搞定所有任务,只看 prompt。
# 10. KV Cache 是什么?为什么能加速生成?
自回归生成时,每个新 token 都依赖前面所有 token 的 Key/Value。如果每生成一个 token 都重算一遍前面的 KV,复杂度 O(n²) 极慢。
KV Cache 的本质:把已经算过的 K、V 存下来,新 token 只追加计算,复杂度降到接近 O(n)。
附带几个延伸:
- Prompt Caching(Anthropic / OpenAI 都支持)就是把不变的 system prompt 部分 KV 复用,对长 system + 多轮对话的场景能省很多钱;
- KV Cache 占显存,所以推理服务的并发上限就被显存卡住。
# 11. 什么是 Streaming(流式输出)?
模型每生成一个 token 就推到客户端,不等整段生成完。体感上和 ChatGPT 一样:边生成边显示。
为什么必须做?
- 首 token 出现快(TTFT < 1s),用户感知到"它在响应";
- 长回答(几千 token)总时长好几秒,等完再显示体验灾难。
前端三种实现:
- SSE(Server-Sent Events):HTTP 单向流,最简单也最普遍;
- HTTP Chunked:底层和 SSE 类似,自己拼协议;
- WebSocket:双向场景(比如可以中途打断 / 多用户协作)。
前端读 SSE 的标准模板:
const res = await fetch('/api/chat', { method: 'POST', body, signal })
const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ''
while (true) {
const { value, done } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true })
// 按 \n\n 分包,解析 data: 字段
let idx
while ((idx = buffer.indexOf('\n\n')) !== -1) {
const chunk = buffer.slice(0, idx)
buffer = buffer.slice(idx + 2)
onDelta(JSON.parse(chunk.replace(/^data: /, '')))
}
}
# 12. System Prompt 是干什么的?应该放些什么?
System Prompt 是整段对话的"底色",模型每轮回答前都会先读它。
四要素,最好按顺序写:
- 角色定位:你是谁、你的专业是什么;
- 任务边界:能做什么、不能做什么;
- 风格 / 格式:语气、长度、是否带代码、是否带引用;
- 兜底规则:不知道就说不知道、敏感问题怎么处理、什么时候让用户兜底。
实战经验:
- 把"重要约束"放在 system 的开头和结尾,中间放细节,因为中间最容易被模型忽略;
- 不要在 system 里塞知识,那是 RAG 的工作;
- system 不变的部分尽量复用,触发 Prompt Caching。
# 13. 多模态模型是什么?前端怎么用?
多模态 = 能处理文本之外的东西。常见组合:
- 文本 + 图(GPT-4o、Claude 4 Vision、Gemini、Qwen-VL)
- 文本 + 音频(Whisper STT、Realtime API)
- 文本 + 视频(Gemini、Sora 类的生成)
前端场景:
- 上传截图问"这块 UI 该用什么组件"
- 把设计稿喂给模型生成 HTML / Tailwind
- 录音转文字、做语音输入
- 把后端长报表截图扔上去做摘要
注意 token 计费:一张图常常等于 1k - 2k token,比文本贵很多,要做大小压缩和 base64 vs URL 的取舍。
# 14. 模型的「知识截止时间」(Knowledge Cutoff)是什么?
模型训练数据冻结的日期。过了这个日期发生的事它全不知道(昨天发布的 Vue 新版本、上周的政策、今天的股价)。
工程上三种应对:
- RAG / 联网检索补最新信息;
- system prompt 显式告诉它今天是几月几号,避免它瞎猜;
- 让它不确定就说不确定,不要装懂。
# 15. RLHF、DPO、Constitutional AI 三个是什么?
都是对齐(Alignment)的方法,让预训练完只会"猜 token"的模型变得"会听人话"。
- RLHF:让人给模型多个回答打分,训一个奖励模型,再用 PPO 强化学习。流程长、训练贵;
- DPO / ORPO:跳过奖励模型,直接用「选中 / 拒绝」对来做监督学习。简单、稳定,现在主流团队偏好 DPO;
- Constitutional AI(Anthropic 提的):用一组人写的「宪法原则」让模型自己批改自己的输出,再用改后的数据再训一遍,减少人工标注。
# 16. 推理(Inference)和训练(Training)的成本结构差异?
- 训练:一次性、超贵。GPT 级模型一次训练上千万到上亿美元;
- 推理:单次便宜,累计巨贵。生产环境跑半年,推理成本会远远超过训练。
前端调 API 付的是推理成本,所以省 token 才是日常的钱:Prompt Caching、压缩历史、控制 max_tokens、用小模型分流、复用 Embedding 索引。
# 17. 涌现能力(Emergent Ability)是真的吗?
是真的,但也被一部分论文质疑过(说是因为评估指标不连续造成的错觉)。
工程上重要的不是争论它真假,而是记住一个直觉:当某个任务在 7B 上做不了,先想想 70B 能不能做了再说,不要立刻去微调。
# 18. MoE(专家混合)和稠密模型的区别?
稠密模型:每次推理所有参数都激活。
MoE:模型里有 N 个「专家」子网络,每个 token 只路由到 K 个专家(比如 8 选 2),参数总量大但激活量小,所以 700B 的 MoE 推理速度可以接近 70B 稠密模型。
代表:Mixtral、DeepSeek-V3、GPT-4 据传也是。
前端做接入时一般感知不到差异,主要影响私有化部署时的显存和路由策略。
# 19. 模型的"温度墙"为什么 temperature=0 也不稳定?
temperature=0 表示总是取概率最高的 token,理论上应该完全确定。但实际还是会有微小差异,原因:
- 浮点运算非结合律,多卡 / batch 内顺序变化导致最大值的并列 token 被选中的方式不一样;
- 服务端可能有并行调度带来的非确定;
- 某些 SDK 默认
top_p < 1,需要显式设置。
要求严格可复现:固定 seed + temperature=0 + top_p=1 + 单条请求 + 关 streaming,而且不同服务商之间不能跨着复现。
# 20. 国产模型和海外模型在工程上最大的差异是什么?
不是"中文好不好"那种泛泛回答,要给点真实落地痕迹:
- 网关稳定性 / 限流策略不一样,国产更宽松、海外更严格;
- 合规要求不一样,国内要求大模型生成内容备案 + 关键词过滤;
- 私有化部署能力国产更普遍(Qwen、DeepSeek、ChatGLM 都有完整开源生态);
- 价格曲线国产明显更便宜,DeepSeek-V3 等价位经常打到 GPT-4 的 1/10;
- 工具调用 / 多模态成熟度整体还是 Claude / GPT 领先,国产追得最快的是 Qwen。
# 二、Prompt 工程
别小看 Prompt 工程。90% 让人惊艳的 AI 项目,本质上都是 prompt 调得好。 微调是没办法的最后手段。
# 21. Prompt 工程到底是什么?为什么花时间在它上面值得?
朴素一句话:用结构化、可复用的输入文本,引导模型给出可控、稳定的输出。
为什么值得:
- 同一个模型,一个写糟的 prompt 和一个写好的 prompt,效果可能差 5 倍以上;
- Prompt 是最便宜的优化手段,比微调快 1000 倍,比换模型省几十倍钱;
- Prompt 出问题最常见的不是"模型不行",而是"指令没写清"。
# 22. Zero-shot / One-shot / Few-shot 的区别和适用边界?
- Zero-shot:直接问,不给例子。模型已经擅长的任务(翻译、改写、总结)够用;
- One-shot:给一个范例。让模型知道"输出长这样";
- Few-shot:给 2-5 个范例。对输出格式特殊 / 业务规则复杂的场景特别有效。
经验值:
- 简单任务 0-1 例;
- 复杂格式 3-5 例就够,超过 5 个收益快速衰减还涨 token;
- 例子要覆盖边界,比如带空值、异常输入的例子各放一个;
- 例子顺序有影响,和真实输入相近的放最后。
# 23. CoT(Chain of Thought)是什么?什么时候要 / 不要?
让模型先想再答,把推理过程显式写出来,再给结论。
最简单的触发:在 prompt 末尾加一句 Let's think step by step.,或者用 Claude 风格的 <thinking>...</thinking>。
适合:数学、多步推理、规则复杂的判定题(合规审查、合同抽取)。
不适合:
- 简单任务(翻译、改写、抽取一个字段),CoT 反而拖慢且无收益;
- 追求最低延迟的场景,CoT 让输出变长 5-10 倍;
- 现在很多新模型(Claude / o1 / DeepSeek-R1)内部已经做了隐式推理,再手动加 CoT 收益不大反而干扰。
# 24. ReAct 是什么?和 CoT 的区别?
ReAct = Reason + Act:让模型按 思考 → 行动 → 观察 → 再思考 的循环走,是 Agent 的基础范式。
CoT 只有「想」,ReAct 多了「想完之后调工具,把工具结果带回来继续想」这一步。
简化的输出格式:
Thought: 我需要查今天天气
Action: get_weather
Action Input: {"city": "北京"}
Observation: 26°C 晴
Thought: 已经拿到,可以回答了
Final Answer: 北京今天 26 度,晴
实际工程里很少手写 ReAct,LangChain / Agent SDK / 大模型自带的 Tool Calling 就是 ReAct 的工程化封装。
# 25. 怎么让模型严格输出 JSON?
按可靠性从低到高:
- Prompt 描述格式:最弱,模型经常多说一句话或把 JSON 包在 Markdown 里;
- JSON Mode:大多数 SDK 支持
response_format: { type: 'json_object' },强制输出合法 JSON; - Function Calling / Tool:把你要的字段定义成函数参数 schema,模型必须按 schema 填。最稳,强烈推荐;
- Structured Output(OpenAI / Anthropic 都有):在 Tool Calling 基础上加 JSON Schema 强约束;
- 约束解码:在推理引擎层面卡 token,只允许输出符合语法的 token,私有部署常用(outlines、jsonformer)。
兜底策略:解析失败时,把错误信息 + 原始输出一起塞回模型让它修,或者用 jsonrepair / partial-json 这种容错解析库。
# 26. Prompt 写长了为什么效果反而变差?
三个根因,按重要性排序:
- Lost in the Middle:长上下文中间段的信息被忽略;
- 指令冲突:写多了容易自相矛盾,比如前面说"简短"后面又写"详细";
- 稀释效应:核心指令在大量背景文字里被淹没。
优化:
- 关键指令放开头和结尾两次(甚至复述);
- 用 XML 标签或分隔符显式分块:
<context>...</context>、<task>...</task>、<output>...</output>; - 把静态背景知识挪到 RAG,prompt 里只留当前任务。
# 27. 怎么写一个高质量的 Prompt?给你一个能直接套的骨架。
# 角色
你是一名 [具体角色,越具体越好]。
# 任务
[要做什么,一句话讲清楚]
# 输入
{{user_input}}
# 步骤(可选,复杂任务必加)
1. ...
2. ...
3. ...
# 输出格式
[JSON schema / Markdown 模板 / 自由文本]
# 约束
- 必须 ...
- 不能 ...
- 当 [边界情况] 时,[怎么做]
# 示例(可选,复杂任务必加)
输入:...
输出:...
把这个骨架记下来,95% 业务 prompt 都能套出来。
# 28. 为什么"不要做某件事"经常没效果?
这是模型的特性:它对正向指令敏感得多。否定指令需要"想完该做什么,再否定它",路径更长。
错误写法:不要使用复杂的词。
更好的写法:使用日常生活中的简单词,每句话不超过 15 个字,避免行业术语。
经验上能用「做什么」就别写「不要做什么」。
# 29. Prompt 注入(Prompt Injection)和越狱(Jailbreak)的区别?
- Prompt Injection:用户输入里夹带恶意指令,让模型偏离 system prompt。攻击的是"信任边界";
- Jailbreak:突破模型自身的对齐和安全限制,让它输出本不该输出的内容。攻击的是"对齐策略"。
两者经常组合:先注入再越狱。
前端要做的防御:
- 结构化分隔:用 XML / 特殊 token 把用户输入和系统指令分开;
- 输入审核:先用一个轻量模型判断输入是否包含可疑指令;
- 输出审核:敏感关键词过滤、PII 检测;
- 限制权限:哪怕被越狱,工具调用、数据访问也要有独立的鉴权层;
- 不要把密钥 / 内部链接放进 prompt。
# 30. 模型不听话怎么排查?
按顺序排查,命中一个就停:
- 指令是否冲突?system 和 user 互相矛盾时模型会随机挑一个听;
- few-shot 例子是不是带错?例子比指令权重高,例子错了就跟着错;
- 格式约束是否过严?比如要求 JSON 还要求 Markdown,模型会放弃;
- temperature 是否太高?业务任务 0-0.3 就好;
- 能不能换模型试试?有些任务 Claude 强、有些 GPT 强、有些 Qwen 反而稳;
- 是不是 prompt 太长了?关键指令被埋在中间。
# 31. 怎么调试 / 评估一个 Prompt?
不要靠"我自己点几下感觉还行"。最少要做:
- 写一组测试用例(10-30 条),每条包含输入、期望输出、判定方式;
- 用脚本跑全量,统计通过率、token 消耗、平均耗时;
- 改完 prompt 重新跑,对比指标,优化前后看趋势;
- 可视化错误样本:失败的 case 单独看,找模式;
- 上 LangSmith / Helicone / Phoenix 一类的可观测平台,把线上请求都记下来,回放调优。
# 32. Few-shot 例子放几个最合适?放哪里?
- 简单任务:0-2 个;
- 复杂格式:3-5 个;
- 涉及边界情况:每种边界 1 个例子。
放在哪里?system prompt 后、user input 前。如果在多轮对话里,例子要保持稳定,别让用户输入混在里面。
# 33. 什么是 Prompt 模板?怎么管理?
把变量从 prompt 里抽出来:
const tpl = `请把下面的中文翻译成 {{lang}}:
<text>
{{text}}
</text>`
const prompt = tpl
.replaceAll('{{lang}}', 'English')
.replaceAll('{{text}}', '你好')
工程上别自己拼字符串:
- LangChain
PromptTemplate:最常见; - Anthropic / OpenAI 自带的模板能力;
- Mustache / Handlebars:纯文本场景;
- Prompt 库 / Prompt 平台(LangSmith Hub、PromptLayer):团队级版本控制 + A/B + 灰度。
不要把 prompt 写死在代码里,把它当成代码一样版本化,A/B 测试、回滚、灰度都靠它。
# 34. Prompt Caching 是什么?为什么能省钱?
Anthropic / OpenAI / Gemini 都支持。原理:把 prompt 的**前缀(不变的部分,比如长 system + 工具描述 + few-shot)**对应的 KV Cache 缓存下来,下次同样前缀直接命中。
收益:
- 命中部分 token 计费 打折到 1/10 - 1/2;
- TTFT(首 token 时间)大幅下降。
工程上怎么用好:
- system prompt 不要每次拼新内容,把变量放在末尾;
- few-shot 例子放在 system 末尾、用户输入前;
- 监控命中率,命中率低就反推哪里在变。
# 35. Persona 是什么?什么时候要慎用?
Persona = 给模型设定的人格。比如「你是一个温柔耐心的客服小可,自称『小可』」。
好处:风格一致、用户体验稳定。
慎用的场景:
- 涉及专业判断的(医疗、法律),人格化会让用户错误信任;
- 容易被用于 越狱(DAN 那类);
- 多语言场景容易翻车(人格可能只在中文里起作用)。
# 36. 怎么压缩太长的 Prompt?
四个维度,按优先级:
- 历史消息摘要:旧轮次用一段总结代替;
- RAG 化静态背景:把"产品介绍 / 政策条款"这类放向量库,只在需要时拼回来;
- 缩写约定:在 system 里告诉模型「PR = Pull Request、SOP = 操作规程」,正文用缩写;
- Prompt Caching:不动 prompt 内容,让重复的部分免费。
不要靠"删表情符号、删空行"这种节省,省下的 token 杯水车薪。
# 37. 什么时候不调 Prompt,直接微调?
判断口径:
| 场景 | Prompt | 微调 |
|---|---|---|
| 输出格式固定且复杂 | 不行 | 行 |
| 内化大量企业内部知识 | 不行(也可 RAG) | 行 |
| 高频调用想压缩 prompt 省钱 | — | 行 |
| 业务规则会频繁变 | 行 | 不行(要频繁重训) |
| 数据少(< 200 条) | 行 | 不行(不够) |
一句话:业务规则变得快、数据少 → Prompt + RAG;业务规则稳定 + 数据多 + 调用量大 → 微调。
# 38. Self-Consistency 和 Tree of Thoughts 是什么?
- Self-Consistency:CoT 跑多次(temperature 拉高一点),看多数投票。复杂数学 / 推理题准确率能提 5-10%。
- Tree of Thoughts:让模型生成多个推理分支,每个分支再展开,树状探索最终选一条最好的。
代价都是 token 倍增,工程上很少跑全量,多用在评估、复杂决策点。
# 39. Prompt 工程会不会被淘汰?
不会,但会演化。
- 简单任务的 prompt 越来越不需要精雕细琢(模型变聪明了);
- 复杂工作流的 prompt 编排(system / 工具描述 / few-shot / 输出约束的组合)反而变重;
- "Prompt 工程师"作为单一岗位会被合并到 AI Engineer 里,但写好 prompt 是 AI 工程师的基本功。
# 40. 给一个真实场景:让模型把用户聊天记录里的退款诉求抽取成结构化 JSON。
# 角色
你是一名客服质检员。
# 任务
从用户和客服的对话中,抽取**退款相关的关键信息**,输出 JSON。
对话可能包含和退款无关的闲聊,请忽略。
# 输入
<conversation>
{{conversation}}
</conversation>
# 输出格式
```json
{
"has_refund_request": true | false,
"order_id": "string | null",
"refund_reason": "string | null",
"refund_amount": number | null,
"agreed_by_agent": true | false | null,
"evidence_quotes": ["原文片段1", "原文片段2"]
}
```
# 约束
- 不在对话里出现的字段一律返回 null,不要编。
- evidence_quotes 必须是对话原文,不要改写。
- 只输出 JSON,前后不要任何说明文字。
# 示例
输入:
<conversation>
用户:我之前买的耳机想退,订单是 A100,没什么问题就是不想要了
客服:可以的,明天处理
</conversation>
输出:
{"has_refund_request": true, "order_id": "A100", "refund_reason": "不想要了", "refund_amount": null, "agreed_by_agent": true, "evidence_quotes": ["想退,订单是 A100", "可以的,明天处理"]}
面试常被追问的两点:
- 为什么用
evidence_quotes?—— 强迫模型在原文中找证据,减少幻觉; - 为什么字段类型写在注释里?—— 实战里建议升级到 JSON Schema + Tool Calling,注释只是 fallback。
# 三、AI Agent 架构与设计模式
这一节是面试最能拉差距的部分。能讲清"为什么需要 Agent"和"Agent loop 的常见坑",比背 LangChain API 强一百倍。
# 41. 什么是 AI Agent?和普通 LLM 调用的区别?
一句话:Agent = LLM + 工具 + 记忆 + 规划,能自己做决策、自己跑工具、自己修正错误。
和普通 LLM 调用的区别用表格更清楚:
| 普通调用 | Agent | |
|---|---|---|
| 控制流 | 单次问答 | 循环(直到任务完成) |
| 工具 | 无 | 有,且能自己选 |
| 状态 | 无 | 有上下文 / 记忆 |
| 错误处理 | 失败就退出 | 自己重试 / 换路 |
| 适合任务 | 翻译、改写、抽取 | 写代码、跑命令、查数据、写报告 |
经典例子:你让普通模型"创建一个 React + Vite 项目",它只会告诉你命令;Cursor / Claude Code 这种 Agent 会自己写文件、跑命令、看报错再改——这才叫 Agent。
# 42. ReAct Agent 怎么实现的?给个最小可运行骨架。
def run_agent(user_input, tools, max_steps=10):
history = [{"role": "system", "content": SYSTEM_PROMPT}]
history.append({"role": "user", "content": user_input})
for step in range(max_steps):
resp = llm.chat(messages=history, tools=tools)
msg = resp.choices[0].message
history.append(msg)
if not msg.tool_calls:
return msg.content # 最终回答
for call in msg.tool_calls:
result = tool_registry[call.name](**call.arguments)
history.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(result)
})
raise RuntimeError("达到最大步数仍未完成")
关键点:
- LLM 决定调工具还是直接给答案;
- 每次调工具的结果都要塞回 history;
- 必须有 max_steps,否则可能无限循环;
- 工具的 schema 是模型理解工具的唯一信息来源,描述要写好。
# 43. Plan-and-Execute Agent 和 ReAct 的区别?
- ReAct:边想边做。优点灵活,缺点中间一旦判断错容易跑偏;
- Plan-and-Execute:先一次性规划出所有步骤,再按计划执行,必要时回头改计划。优点路径稳定,缺点对长程任务一次规划容易遗漏。
工程上常用混合:先 plan 出粗粒度大步骤,每个大步骤内部跑 ReAct 小循环。
# 44. Agent Loop 在工程里有哪些常见坑?
跑过的人都被坑过:
- 死循环 / 振荡:模型反复调同一工具或在两个工具之间来回横跳;
- Token 烧得飞快:每轮都把全量上下文带过去,几轮翻好几倍;
- 错误放大:第一步观察就理解错了,后面跟着错的方向越走越远;
- 越权 / 安全风险:没限制的话模型会调危险工具(删库、发邮件、
rm -rf); - 不会停:自我反思没有终止条件,永远在"再确认一下"。
兜底动作(必做):
- 设硬上限:max_steps、max_tokens、max_duration;
- 重复检测:同一工具同一参数连续 N 次直接停;
- 工具白名单 + 危险操作二次确认;
- 全链路日志:每步 prompt / tool_call / result 都落盘,事后能回放;
- 上下文压缩:旧轮次定期摘要。
# 45. Agent 怎么自己判断"任务完成了"?
几种常见判定,按工程靠谱程度:
- 显式工具返回
final_answer:模型主动调"完成"工具; - 没有 tool_calls 的回答:模型直接给文本输出(最常见);
- 触发停止词 / 标签:比如输出
<done>后中断; - 外部判定:跑一个评测 LLM 判断"够不够";
- 轮次上限:兜底,不能省。
不要只靠"模型自己判断"。
# 46. 单 Agent vs 多 Agent 怎么选?
复杂 Agent 产品基本是多 Agent 架构。原因:
- 决策准确率更高:每个子 Agent 只看自己需要的 prompt,没有无关信息干扰;
- Token 更省:不是每次都把所有工具描述塞进去,调用变多但单次更便宜;
- 可并行:主 Agent 派活,子 Agent 并发处理;
- 多角色互相纠错:A 写代码 B 评审 C 验证,比单 Agent 自反思靠谱。
什么时候不要多 Agent?
- 任务简单、步骤少、用户期待秒级响应;
- 团队还没把单 Agent 跑稳就上多 Agent,反而更难调试。
拿 Cursor / Claude Code 类比:早期是单 Agent,现在内部分了 plan、edit、verify、search 多个角色。
# 47. Reflexion / Self-Reflection 是什么?
让 Agent 跑完一轮后自己评估这次结果好不好,如果不好就调整策略再跑一遍。
简化流程:
1. 跑一遍任务 → 拿到 result_v1
2. 让 LLM 评估 result_v1 哪些地方不对 → 拿到 critique
3. 把 critique 注入 prompt → 再跑 → result_v2
适合复杂推理 / 代码生成场景,对延迟敏感的不适合。
# 48. Agent 怎么处理"用户中途打断"?
前端这边几个动作必须做:
- 给请求加 AbortController,能取消正在跑的 fetch;
- 服务端识别到客户端断连,立刻停止 LLM 调用 / 工具执行(OpenAI / Anthropic SDK 都支持中断);
- 已经写入的状态(数据库、文件)要有回滚或标记为中断的机制;
- 重新拉对话时,把"被打断的轮次"作为状态显示给用户,让他决定继续还是重做。
# 49. Anthropic Agent SDK / Claude Code 这种 Agent 框架做了什么?
把"Agent 工程的脏活"封装成开箱即用:
- Tool Calling 标准协议:统一的 schema / 错误处理;
- 多步骤循环:自动跑直到任务完成;
- 工具集合:内置 Read / Write / Edit / Bash / Search / WebFetch;
- 可观测:每步日志、回放、调试;
- 权限模型:哪些工具可以无确认跑、哪些必须用户点确认;
- 子 Agent / 多角色:内置 dispatch 能力。
前端工程师拿来即用,重点研究它的 system prompt 和工具 schema,比写自己的 Agent 框架更值。
# 50. LangChain、LangGraph、CrewAI、AutoGen、Vercel AI SDK 选哪个?
按需选:
| 场景 | 推荐 |
|---|---|
| 前端 / Next.js 项目快速做 Chat / 流式 | Vercel AI SDK |
| 后端做 Agent 工作流、链式调用 | LangChain |
| 多 Agent + 图编排 | LangGraph |
| 多角色协作(CEO / Eng / QA)模拟 | CrewAI / AutoGen |
| 企业内部用应用、可视化拖拽 | Dify / Coze / FastGPT |
别问"哪个最好",问你的用户是谁、任务多复杂、要不要私有化。
# 51. Agent 工具描述写不好会怎样?
模型理解工具靠的就是描述。描述写不好直接表现为:
- 模型该调没调(不知道这个工具能解决);
- 调错工具(两个工具描述太像);
- 传错参数(schema 字段名 / 必填项 / 枚举值没写清);
- 传冗余参数(描述太长,模型脑补出不存在的字段)。
工具描述模板(亲测好用):
name: search_user_orders
description: 根据用户 ID 查询该用户最近 30 天的订单列表,
返回订单 ID、状态、金额。**仅用于查询,不能创建或修改订单**。
parameters:
user_id (string, required): 用户的唯一 ID,类似 'U-12345'。
limit (number, optional, default=10): 返回数量,最大 50。
经验:
- 明确"能做什么"和"不能做什么";
- 给一个典型用法例子(用 # example 字段);
- 字段写取值范围、单位、格式;
- 工具数量超过 15 个就要分组 / 分层加载,否则模型选错率飙升。
# 52. Agent 怎么调试?看哪些指标?
最少四件套:
- 每步 prompt + tool_call + result 日志(落盘 + 可搜索);
- 步数分布:均值、p95、超过 N 步的 trace;
- Token 消耗分布:哪些工具调用 token 异常高;
- 失败模式聚合:把失败 trace 按错误类型聚类,看是 prompt 问题 / 工具问题 / 模型问题。
工具推荐:LangSmith(最常见)、Helicone、Phoenix、Langfuse。
# 53. Human-in-the-loop(HIL)是什么?什么时候必加?
让用户在 Agent 关键步骤介入决策。
必加的场景:
- 不可逆操作:发邮件、付款、删数据;
- 金额超阈值:比如退款 > 500;
- 跨权限操作:访问别的部门数据;
- 法律 / 合规风险点。
实现方式:Agent 跑到关键节点时,返回一个 pending 状态给前端,前端展示"是否继续"按钮,用户确认后再继续。状态保存到 DB,断线能恢复。
# 54. Agent 的成本怎么优化?
一套组合拳:
- 小模型分流:简单分类 / 路由用 7B 小模型,复杂任务才给大模型;
- Prompt Caching:长 system + 工具描述全部缓存;
- 工具结果裁剪:返回前砍掉不必要字段,别让模型读完整 SQL 输出;
- 历史摘要:旧轮次定期压成几句话;
- 并行 vs 串行:能并行的工具调用一定要并行(多数 SDK 支持);
- 缓存层:常见问答先查缓存 / 向量库再决定要不要调模型。
# 55. LLM-as-Judge 是什么?
用一个 LLM 评估另一个 LLM 的输出。
典型场景:
- 跑 prompt 改进 A/B,让"裁判模型"对比两个回答打分;
- Agent 跑完后,让裁判模型判断"是否完成任务";
- 给数据集打偏好标签,省人工。
注意:
- 裁判模型要比被评估模型更强(GPT-4 当 Claude 4 的裁判没问题,反过来不行);
- 明确评估维度(准确性 / 相关性 / 格式 / 礼貌),别让它笼统打个分;
- 跑多个裁判取平均,减少裁判模型本身的偏差。
# 56. Agent 的延迟(Latency)怎么优化?
最影响体感的几个动作:
- streaming:首 token 时间从几秒降到 1 秒内;
- 并行工具调用:多个工具同时跑而不是串;
- 小模型预筛 + 大模型精排;
- 预热 / Keep-alive:减少连接建立开销;
- Prompt Caching 命中率;
- 边缘部署 / CDN:让首跳 RTT 更短。
# 57. Agent 怎么测?写得了单元测试吗?
写得了,但要换思路:
- 确定性部分:工具函数、parser、router 当普通函数测;
- LLM 调用部分:mock 掉,或者用录制 / 回放(vcr 模式);
- 整体端到端:写一组业务测试用例,跑全量,用 LLM-as-Judge 判通过,统计通过率作为回归指标。
不要追求 100% 通过,AI 系统天然有不确定性,关注趋势:每次改完通过率涨还是跌。
# 58. AutoGPT、BabyAGI、Devin 这类"全自主 Agent"为什么不实用?
理论很美,工程上一堆问题:
- 目标偏移:开放性任务模型容易越走越远;
- token 爆炸:跑几小时一两千美元下去了;
- 错误传播:早期错误后期放大;
- 没有 HIL 节点,跑错也没人能拦;
- 可观测差:跑完不知道为啥成 / 为啥败。
教训:生产用的 Agent 都是"半自主 + 有边界 + 有 HIL",不是完全放飞。
# 59. 怎么把现有产品改造成 Agent?
务实步骤:
- 找一个高价值的 workflow(比如客服处理退款),不要一上来全产品 Agent 化;
- 梳理这个 workflow 的所有手动步骤:每一步用了哪个内部接口;
- 把这些接口包成 Tool(写好 schema + 描述);
- 写一个严格的 system prompt,限制 Agent 只能在这个 workflow 内做事;
- HIL 卡关键节点(涉及钱、涉及不可逆);
- 小流量灰度(5% → 20% → 50% → 100%),看转化和投诉。
不要"先做个 Agent 框架再说"。
# 60. 一个 Agent 的"思考预算"应该怎么设?
三个维度:
- 最大步数(max_steps):8 - 20 是常见范围,超过基本是死循环;
- 最大 token(max_total_tokens):按业务任务复杂度估,比如 50k;
- 最大耗时(max_duration):用户能忍受的上限,通常 60-120 秒。
任何一个达到上限就优雅终止:返回部分结果 + 说明"任务未完成",不要让用户等永远。
# 61. Computer Use Agent 是什么?
Anthropic 在 Claude 上开放的能力:模型直接看屏幕截图、移动鼠标、敲键盘,跨任意 GUI 应用操作。
工作流:
- 客户端截屏给模型;
- 模型返回
screenshot/mouse_move/mouse_click/key/type等动作; - 客户端执行动作,再截屏;
- 循环直到任务完成。
适合:
- 没有 API 的老软件操作;
- 跨多个软件协作的流程;
- 浏览器自动化(替代 Selenium)。
风险:
- 慢(每步都要看截图);
- 贵(每次截图都是几千 token);
- 安全(模型实际在你电脑上操作)。
生产 Agent 优先选 API / MCP,Computer Use 是兜底。
# 62. Agent 评测有哪些常用 benchmark?
| benchmark | 测什么 |
|---|---|
| SWE-bench | 真实 GitHub issue 修复,软件工程能力 |
| GAIA | 多步真实世界任务(搜索、计算、推理) |
| AgentBench | 多种工具调用场景 |
| WebArena | 浏览器操作能力 |
| OSWorld | 桌面 GUI 操作能力 |
| τ-bench | 客服 / 业务流程 Agent |
| HumanEval / MBPP | 单函数代码生成(偏基础) |
工程上常见:不直接跑 benchmark,而是自己造业务 case 集 + 用 LLM-as-Judge 跑回归。
# 63. Agent 的 Context Engineering 是什么?
2026 年新词,本质是「精心构造 Agent 每一轮的输入」,被认为是比 Prompt Engineering 更高维的工作。
包括:
- System Prompt 设计:角色、能力边界、风格;
- 工具描述精炼:哪些工具该加进来、怎么排序;
- 历史压缩 / 摘要:哪些保留、哪些丢;
- 检索结果拼接:RAG 召回片段放哪儿、怎么排版;
- 思考预算控制:CoT、reasoning 用不用;
- 格式约束:JSON Schema、XML 标签;
- 示例选择:动态 few-shot 检索最相关样例。
Claude Code、Cursor 这类工具内部最复杂的不是模型,而是 Context Engineering。
# 64. Background Agent 和 Foreground Agent 区别?
- Foreground:用户直接对话的 Agent,重 TTFT、重交互、重打断;
- Background:跑在后台的 Agent,时长可能几分钟到几小时(爬数据、跑测试、生成报告、监控告警)。
工程差异:
| 维度 | Foreground | Background |
|---|---|---|
| 延迟 | 关键 | 不关键 |
| 状态 | 内存 / Redis | 必须持久化(DB / Checkpoint) |
| 中断恢复 | 不需要 | 必须支持 |
| 失败重试 | 用户重发 | 自动重试 |
| 可观测 | 用户能看 | 必须有 dashboard |
| 成本上限 | 较低 | 容易跑爆 |
Background Agent 必须有预算守门员:超步数 / 超 token / 超耗时自动停。
# 65. Agent 的 Tool Selection 怎么优化?
工具一多模型选错率飙升。优化套路:
- 静态分组:按业务域分组,先路由再加载;
- 动态加载:用轻量分类器先选 top 5 工具再喂主 Agent;
- MCP Resources / Skills:把工具按粒度分层;
- 工具描述加例子:模型容易抓「example 里的关键词」;
- 工具名加前缀:
order_*、user_*、payment_*,命名上分组; - 历史命中加权:用户上下文里最近用过的工具优先级提高。
# 66. Agent 出错后怎么定位?看 trace 看什么?
trace 是 Agent 的「飞行记录仪」,按步骤回放:
- 每步的 prompt(system + history + tools) ;
- 模型输出(tool_calls 或 final);
- 工具执行入参 / 出参 / 耗时;
- 上下文 token 用量。
常见排错路径:
- 第一步就跑偏 → system prompt / 工具描述问题;
- 某步工具选错 → 工具描述太相似 / 排序错;
- 工具调对了但执行错 → 业务接口 bug;
- 跑到死循环 → 工具结果格式让模型困惑,反复确认;
- 过早 final → 终止条件太宽松。
工具:LangSmith / Langfuse 看 trace 是基本功。
# 67. Agent 怎么做 retry / fallback?
不是简单的 try-catch。分层处理:
- 工具调用失败:把 error 信息塞回 messages,让模型自己决定;
- 模型超时 / 限流:客户端重试(指数退避),切到备用模型;
- 整段步数耗尽:保存进度,返回"任务未完成 + 已完成的部分";
- 格式解析失败:把错误塞回去让模型修;
- 检测到死循环:强制中断 + 报警 + 人工兜底。
不要让 Agent 静默失败。所有失败都要落日志 + 告警。
# 四、RAG 检索增强生成
ToB 项目几乎必问 RAG。能讲清"为什么 RAG 比微调更常用"和"切片 / Embedding / 检索 / 重排"四个环节的优化,就拉开差距了。
# 68. 什么是 RAG?为什么要发明它?
RAG = Retrieval-Augmented Generation:用户提问 → 先去知识库检索相关片段 → 把片段塞进 prompt 增强上下文 → 模型基于这些生成回答。
为什么需要它:
- 模型不知道你公司的内部文档;
- 模型有知识截止日期,最新政策 / 数据它不知道;
- 模型会幻觉,没有依据时会瞎编;
- 微调成本高且对频繁更新的知识不友好。
RAG 用最便宜的方式,让模型"外挂"了知识库。
# 69. RAG 标准流程拆解?
离线(建索引):
- 加载(Loader):读 PDF / Word / Markdown / Notion / 数据库;
- 切片(Splitter):按 token / 段落 / 语义切成小块;
- Embedding:每块算向量;
- 入库:向量 + 元数据进向量库。
在线(查询):
- Query 预处理:改写、拆解、补全;
- 检索:向量召回 + 关键词召回(Hybrid Search);
- 重排(Rerank):用 Cross-Encoder 重新打分排序;
- 拼接:把 top-N 片段填入 prompt;
- 生成:LLM 输出回答(带引用)。
每一步都有调优空间,90% 的 RAG 问题出在切片和检索。
# 70. 文档怎么切片(Chunking)?什么大小合适?
切片是 RAG 里最容易出问题的环节。常见策略:
| 策略 | 说明 | 适合 |
|---|---|---|
| 固定 token | 比如每 500 token 切一块 | 简单粗暴,通用 |
| 按段落 / 标题 | 按 \n\n 或 # 切 | Markdown / 结构化文档 |
| 递归切分 | 大→小,多级 fallback | LangChain 默认 |
| 语义切分 | 按句子向量相似度切 | 长文、效果好但慢 |
| Late Chunking | 先 embedding 整段再切 | 新方法,召回更好 |
切片大小:
- 太小(< 100 token):每块语义不完整,检索召回散;
- 太大(> 1000 token):召回准了但塞进 prompt 浪费 token;
- 常用:300 - 600 token + 50 - 100 overlap。
实战建议:先用默认 500/50 跑通,根据召回质量再调。
# 71. Embedding 模型怎么选?
按场景:
- 中文场景:bge-m3、Qwen-embedding、jina-zh;
- 英文 / 多语言:text-embedding-3-large、bge-large-en;
- 私有化:bge / m3e(开源、自己部署);
- 资源紧 / 维度敏感:bge-small(384 维)。
几个易错点:
- 一份索引必须绑定一个 embedding 模型,换模型必须全量重建;
- 维度越高存储和检索越贵,1024 / 1536 是甜点;
- query 和 document 用同一个 embedding 模型,且 query 端经常需要前缀(
Query: ...)。
# 72. 向量数据库怎么选?
| 选型 | 推荐 |
|---|---|
| 已有 PostgreSQL,量不大 | pgvector |
| 中量、需要快速上手 | Chroma(本地 / 内存) |
| 中大型 + 多语言 + 高性能 | Qdrant、Weaviate |
| 大型 + 企业级 / 国内开源 | Milvus(生态最全) |
| Serverless 托管 | Pinecone、Vercel Vector |
| 不想引入新组件 | Elasticsearch dense_vector |
记住:别一上来就上 Milvus,量小时 pgvector 完全够用,运维成本低一个数量级。
# 73. 检索召回准不准?怎么改进?
如果用户问 X 但召回的都是 Y,检查顺序:
- 切片是否合理(最常见根因):太碎 / 太大都会出问题;
- Embedding 模型是否适合中文 / 业务领域;
- Query 改写:把用户口语化的 query 改成更标准的检索 query;
- 加入 BM25 / 关键词召回做 Hybrid:向量召回擅长语义、BM25 擅长精确词,结合更稳;
- Reranker 重排:召回 50 条 → 重排 top 5 → 塞 prompt;
- 元数据过滤:按部门 / 时间 / 文档类型先过滤再向量检索;
- 检查文档本身:很多时候是文档质量太差,不是 RAG 不行。
# 74. 什么是 Hybrid Search(混合检索)?
向量检索 + 关键词检索(BM25 / Elasticsearch)两路同时召回,再合并打分。
为什么有效?
- 向量召回擅长语义相似但用词不同("忘记密码" ↔ "登录不上");
- BM25 擅长精确匹配(产品编号、报错代码、专有名词);
- 合并起来覆盖更全。
合并算法常用 RRF(Reciprocal Rank Fusion),简单稳定。
# 75. Reranker 是什么?为什么向量召回还不够?
向量召回用的是 bi-encoder:query 和 doc 各自编码后比相似度,速度快但精度有限。
Reranker 是 cross-encoder:把 query 和 doc 拼起来一起进模型,输出一个相关性分数。精度高,但每对都要算一次,慢。
工程标准做法:
- 用向量召回召出 30-100 条候选;
- 用 reranker 重排选 top 5-10;
- 把 top 拼进 prompt。
常用模型:bge-reranker、Cohere Rerank、Jina Reranker。
# 76. 什么是 GraphRAG / Agentic RAG?
进阶 RAG 思路:
- GraphRAG:把文档抽成「实体 + 关系」的知识图谱,回答时不仅检索片段,还检索实体关系。适合"涉及人物 / 公司 / 关系网络"的复杂问答。微软研究院推得多。
- Agentic RAG:用 Agent 来跑 RAG,模型自己决定:要不要查、查几次、查完够不够、要不要再查。适合多跳推理(A → 找 B → 再查 C)。LangGraph 的图编排能直接干这事。
普通 RAG 一问一答,Agentic RAG 可以反复检索。
# 77. RAG 怎么评估效果?
最少四个指标:
- 召回率(Recall):理论上应该被检索到的片段,实际有多少被检索到;
- 精确率(Precision):检索到的片段里有多少真的相关;
- 回答正确率:用 LLM-as-Judge 判断回答是否准确(需要 ground-truth 集合);
- 引用准确率:回答里引的片段是不是真的支持这个回答。
工具:RAGAS(最常见)、TruLens、DeepEval。
# 78. RAG 中怎么减少幻觉?
不是 RAG 自动就不幻觉,工程上要做:
- 强制要求引用:
回答中每个事实必须用 [片段编号] 注明出处; - 拒答提示:
如果检索片段中没有相关内容,必须回答"不知道"; - 后置校验:用第二个 LLM 检查引用片段是否真的支持回答;
- 检索阈值:相似度低于 X 的片段不参与生成;
- Self-RAG / 反思 RAG:模型先判断需不需要检索、再判断结果够不够。
# 79. 长文档怎么处理?
长文档(论文、合同、手册)的几个套路:
- 层次摘要:每章 / 每节先做摘要存起来,问答时先用摘要定位章节,再下钻到具体片段;
- 结构化目录:把目录抽出来当索引,用户问题先定位章节再精检索;
- 多粒度索引:句子级 + 段落级 + 章节级都建索引,按问题类型选;
- 元数据驱动:用文档类型 / 章节 / 日期等元数据缩小检索范围;
- 超长上下文模型补刀:定位到某一章后,把整章塞进 200k 上下文一次性问。
# 80. RAG 的 prompt 模板长什么样?
你是一名 [角色],根据以下检索到的资料回答用户问题。
# 规则
1. 仅基于下面的资料回答,资料里没有的内容请回答"我不确定"。
2. 每个事实都要标注引用编号,如 [1]、[2]。
3. 如果资料之间有冲突,请同时列出并说明。
# 资料
[1] {{chunk_1}}
[2] {{chunk_2}}
[3] {{chunk_3}}
# 用户问题
{{question}}
# 输出格式
回答:...
引用:[1], [2]
记住三点:强约束、强引用、强拒答。
# 81. 长上下文模型出来后 RAG 还需要吗?
需要,原因:
- 成本:1M 上下文一次几美元,RAG 一次几分;
- 延迟:长上下文 TTFT 慢得多;
- 效果:Lost in the Middle,关键信息不一定能用上;
- 可解释性:RAG 能告诉用户"答案出自哪个文档",长上下文做不到;
- 数据范围:企业知识动辄 GB / TB 级,根本塞不进任何上下文。
长上下文是 RAG 的互补,不是替代。
# 82. RAG 的离线评估和在线评估区别?
- 离线:准备一组标注好的 query + 期望答案,每次迭代跑全量,看指标趋势。便宜、可重复;
- 在线:用真实用户流量看转化率、点踩率、停留时间、问完是否追问。贵但真实。
工程上的标准做法:离线主导迭代 + 在线小流量验证 + 用户反馈回灌。
# 83. Contextual Retrieval 是什么?
Anthropic 2024 年推的检索增强技巧。核心:切片之前,先用 LLM 给每个 chunk 加一段「上下文说明」,把它在原文里的位置 / 关系交代清楚。
例子:
- 原 chunk:
"上一财年净利润同比下降 3.4%。" - 加上下文:
"以下内容来自 ABC 公司 2025 年 Q4 财报中关于经营业绩的章节:上一财年净利润同比下降 3.4%。"
效果:
- 检索召回率显著上升(论文 +35%-50%);
- 重排 + 上下文检索叠加效果更好;
- 代价是预处理多调一遍 LLM,靠 Prompt Caching 把成本压住。
适合碎片化文档 / 简短切片的场景。
# 84. 父子切片(Parent-Child Chunking)是什么?
矛盾:切片太小召回不准、切片太大占 token。
父子切片的做法:
- 小 chunk 用于检索(200 token,语义精确);
- 大 chunk 用于喂模型(800 token,上下文完整);
- 每个 small chunk 有 parent_id 指向 large chunk。
流程:用 query 召回 small chunks → 找它们的 parent → 用 parent 内容喂模型。
效果:召回更准、上下文更全,生产 RAG 常用套路。
# 85. 多向量检索(Multi-Vector Retrieval)是什么?
一个 chunk 不止存一个向量,而是存多个:
- 原文向量;
- 用 LLM 抽取的"假设问题" 向量;
- 摘要向量;
- 关键词向量。
检索时这些向量都参与召回,最后合并去重。
好处:
- 用户问题和文档表述不一致时,"假设问题"能命中;
- 长文档对应的多个角度都能召回。
代价是存储多倍 + 入库慢,适合关键文档。
# 86. ColBERT 和 Dense Retrieval 区别?
- Dense Retrieval(普通向量检索):query 和 doc 各压成 1 个向量,比相似度;
- ColBERT:query 和 doc 都保留每个 token 的向量,检索时 token-级别匹配(MaxSim)。
ColBERT 优势:
- 召回精度更高(token 级匹配能抓细节);
- 比 cross-encoder 重排快很多。
劣势:
- 存储成本几十倍上升;
- 索引复杂;
- 工程实现少(生产用得不多)。
记一句话:精度 > 速度 → cross-encoder rerank;速度 + 中精度 → ColBERT;速度 + 低成本 → Dense。
# 87. RAG 的"幻觉引用"怎么处理?
模型答出来的内容里引用了根本不在召回片段里的事。两步处理:
- 结构化输出强约束引用:每个事实必须带
[N]编号; - 后置校验:用代码 / 第二个 LLM 检查引用编号对应的 chunk 是否真的支持这条事实。
校验失败两种处理:
- 软:标红显示"此条未找到出处";
- 硬:直接删掉无引用的句子。
不要相信"我已经在 prompt 里要求带引用",模型还是会编。
# 88. RAG 的索引更新策略?
文档会改、会删、会加。常见策略:
| 策略 | 说明 | 适合 |
|---|---|---|
| 全量重建 | 定期(每天 / 每周)完全重新算 | 文档变化不频繁 |
| 增量更新 | 监听 webhook,文档改了就单独更新对应 chunk | 文档变化快 |
| 软删除 | 标记 deleted,检索过滤 | 频繁删除 |
| 版本化 | 每篇文档保留多个版本,按时间查 | 法规 / 历史溯源 |
工程上要点:
- chunk 必须有 doc_id 元数据,便于按文档操作;
- 删除 / 更新走异步队列,不阻塞业务写;
- 检索时按
valid=true过滤; - 大量更新后跑回归测试,召回质量可能波动。
# 89. RAG 的"冷启动"问题怎么解?
新业务、文档少、用户问的常常超出知识库范围,回答质量差。
解法:
- 承认局限:拒答 + 转人工,比瞎答好;
- FAQ 补齐:让运营手写常见问题 + 答案,直接进知识库;
- 从客服日志 / 历史工单蒸馏:把已答问答对入库;
- 联网检索兜底:库里没有的允许走搜索 API;
- 缩小用户期望:UI 文案明确"我能回答 XX 类问题"。
# 90. RAG 的"重排"什么时候必须做?
下面情况几乎必加 Reranker:
- 召回 top-k 中相关度参差不齐;
- 业务专有名词多(产品编号、报错码);
- 多语言混合;
- 文档质量不均;
- 用户问题口语化严重。
跳过 Reranker 的成本:召回的 chunk 顺序差 → LLM 看 prompt 时把"无关 chunk"也当成事实 → 幻觉。多花 200ms 一次重排,省一堆幻觉。
# 五、Function Calling / 工具调用 / MCP
这一年面试问得最多的实战题之一。能讲清"Function Calling 怎么走完一轮"和"MCP 解决了什么问题",就证明你真的写过 Agent。
# 91. Function Calling 是什么?背后的机制?
模型不会直接执行任何函数,它做的事是:
- 收到 prompt 和工具列表(包含 name / description / parameters schema);
- 模型判断该调用哪个工具、参数是什么,以 JSON 形式吐出来;
- 你的代码读到这个 JSON → 实际执行函数 → 把返回值拼成 ToolMessage 喂回模型;
- 模型基于新结果继续决策。
本质上 Function Calling = 模型负责"决策 + 参数生成",你的代码负责"执行 + 反馈"。
# 92. Function Calling 一次完整流程?
tools = [{
"name": "get_weather",
"description": "查询某城市当前天气,返回温度和天气状况。",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,如'北京'"}
},
"required": ["city"]
}
}]
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
# 第一次调用:模型决定调工具
resp = llm.chat(messages, tools=tools)
if resp.tool_calls:
for call in resp.tool_calls:
result = TOOLS[call.name](**call.arguments)
messages.append(resp.message)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(result)
})
# 第二次调用:模型基于工具结果继续
final = llm.chat(messages)
print(final.content) # 北京今天 26 度,晴
要点:
- 同一次回答可能返回多个 tool_calls(并行执行更快);
- tool_call_id 要对得上,否则模型会蒙;
- 工具执行失败也要把错误塞回去,让模型自己决定怎么办(重试 / 换工具 / 报错)。
# 93. 工具描述写得好不好直接决定调用准不准?
模型理解工具只靠你写的 description + parameters schema。写得不好会出三类问题:
- 该调没调:描述模糊,模型没意识到这个工具能解决;
- 调错工具:两个工具描述相似,模型抓阄;
- 参数错:字段名 / 必填 / 枚举值 / 单位没说清。
实战经验:
- 描述写"能做什么"+ "不能做什么" + "典型用法";
- 参数字段加 取值范围、单位、格式、示例;
- 必填的字段 description 里再强调一遍 "Required";
- 工具数量超过 15 个就分组加载,不要全部塞 system。
# 94. Function Calling 和 JSON Mode 有什么区别?
| JSON Mode | Function Calling | |
|---|---|---|
| 目的 | 让输出是合法 JSON | 让输出符合特定函数 schema |
| 用法 | 一个布尔开关 | 定义 tools 列表 |
| 严格度 | 只保证合法 JSON | 保证字段 / 类型 / 必填 |
| 适合 | 自由 schema 输出 | 精确控制结构 |
| 是否触发调用流程 | 不会 | 会进入 tool_calls 循环 |
需要结构化输出但不需要后续调函数:用 Structured Output / JSON Schema 即可,不用走完整 Tool Calling 循环。
# 95. 多个工具同时调用怎么管?
现代模型(GPT-4o / Claude / DeepSeek-V3)一次回答可以返回多个 tool_calls。
工程上:
- 检查是否可并行:纯读 / 无依赖的工具直接
Promise.all并发; - 有依赖的串行:比如"先查订单再退款",必须等订单查完;
- 合并结果:所有结果都加进 messages 后再调下一轮 LLM;
- 失败处理:单个工具失败不要影响其他,把失败信息也塞回去让模型决定。
# 96. 工具调用失败怎么处理?
不要直接 throw 给 Agent 框架。统一格式塞回去:
try:
result = tools[call.name](**call.arguments)
content = json.dumps({"success": True, "data": result})
except ValidationError as e:
content = json.dumps({"success": False, "error": "invalid_params", "msg": str(e)})
except TimeoutError:
content = json.dumps({"success": False, "error": "timeout"})
except Exception as e:
content = json.dumps({"success": False, "error": "internal", "msg": str(e)})
让模型看到错误后自己决定:
- 重试(参数错的话改参数再试);
- 换工具;
- 跟用户解释。
# 97. 工具结果太大怎么办?
工具返回 50k token 直接塞回 LLM 就炸了。常见做法:
- 裁剪:只取前 N 行 / 关键字段;
- 摘要:用小模型把结果摘成 1k token 以内;
- 分页:让模型自己决定要不要看后面几页;
- 存档 + 引用:完整结果存对象存储,工具返回一个引用 ID,需要详情时再单独取;
- 结构化裁剪:根据请求里的字段筛选返回内容。
# 98. 工具调用的"幂等性"为什么重要?
Agent 有时会重试 / 重复调同一个工具。如果不是幂等的:
- 重复扣款;
- 重复发短信;
- 重复创建订单。
要做的事:
- 写操作必须支持 idempotency_key(前端生成 UUID 传给工具);
- 服务端用这个 key 做去重;
- 危险操作(删除 / 转账)走 HIL,让用户确认。
# 99. MCP 是什么?为什么需要它?
MCP = Model Context Protocol(模型上下文协议,Anthropic 提出,OpenAI / Google 等厂商陆续支持)。
要解决的问题:Function Calling 没有跨厂商 / 跨进程 / 跨语言的标准协议。
每个厂商自己定义 Tool Calling 的格式,工具是用 Python 写的还是 Node 写的都得重新接一遍。MCP 把这件事协议化:
- 工具方实现 MCP Server(用什么语言无所谓,按协议跑就行);
- 客户端(Claude Code / Cursor / 自研 Agent)通过 MCP 协议连这些 Server;
- 协议规定了 list_tools、call_tool、list_resources、list_prompts 等标准接口(底层基于 JSON-RPC)。
效果:写一次工具,所有支持 MCP 的客户端都能用。
# 100. MCP 的三层核心结构(Server / Client / Bridge)
很多面试官会追问 MCP 的结构,按三角色记:
- Server(工具服务端):提供一组可用的工具 / 资源 / Prompt(如文件读写、数据库、HTTP 请求、图像生成);
- Client(模型 / IDE / Agent):通过协议访问 Server,把工具能力暴露给 LLM;
- Bridge(中间层):负责协议转发、权限校验、上下文同步、日志审计。Claude Code / Cursor 自身就充当 Bridge 角色。
调用链路:
LLM → Function Calling → MCP Client → (Bridge) → MCP Server → 真实外部资源
工程上:Server 由工具方独立维护,Client 由 Agent 框架实现,Bridge 决定了"哪些工具能被哪个用户哪个会话调用",是企业级权限和审计的关键点。
# 101. MCP 和 Function Calling 是替代关系吗?
不是。
- Function Calling 是模型理解工具的方式(schema → JSON 调用);
- MCP 是工具进程间通信的协议(stdio / HTTP / SSE)。
模型还是用 Function Calling 调工具,只是工具的实现可以放在另一个 MCP Server 里,跨语言、跨进程、跨机器。
类比 HTTP 和 RESTful:HTTP 是协议,RESTful 是风格,MCP 让"工具的封装"也变得跨生态可复用。
# 102. Function Calling vs MCP 全维度对比
| 维度 | Function Calling | MCP |
|---|---|---|
| 定义者 | OpenAI(2023) | Anthropic(2024,事实标准) |
| 核心目标 | 模型调用外部函数 | 模型与外部环境标准化交互 |
| 注册方式 | 静态注册(请求时塞 tools 列表) | 动态发现 / 热加载 |
| 协议层 | SDK 私有格式 | JSON-RPC(任意语言) |
| 工具描述 | 每次请求都拼进 system,token 暴涨 | Client 启动时拉一次,可复用 |
| 安全机制 | 完全靠开发者自管 | 协议内建权限 + Bridge 兜底 |
| 跨语言 / 跨进程 | 受 SDK 限制 | 任意语言 + 跨进程(stdio / SSE / HTTP) |
| 工具结果中转 | 必须人工塞回 messages | 协议直接返回 |
| 适合场景 | 单 Agent 单语言、简单工具 | 多 Agent 协作 / IDE 集成 / 系统级控制 |
一句话:Function Calling 是模型协议,MCP 是生态协议。前者解决"模型怎么调函数",后者解决"函数怎么跨边界提供给模型"。
# 103. MCP Server 一般怎么实现?
最小 MCP Server(TypeScript):
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
const server = new Server({ name: 'demo', version: '0.0.1' }, { capabilities: { tools: {} } })
server.setRequestHandler({ method: 'tools/list' }, async () => ({
tools: [{
name: 'echo',
description: '把输入原样返回',
inputSchema: {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text']
}
}]
}))
server.setRequestHandler({ method: 'tools/call' }, async ({ params }) => {
if (params.name === 'echo') {
return { content: [{ type: 'text', text: params.arguments.text }] }
}
throw new Error('unknown tool')
})
const transport = new StdioServerTransport()
await server.connect(transport)
跑起来 + 在 Claude Code / Cursor 的配置里注册 → 模型就能调你的工具。
# 104. MCP 三种传输方式(stdio / HTTP / SSE)怎么选?
- stdio:通过子进程的标准输入输出通信。简单可靠、本地 / Claude Code / Cursor 默认;
- HTTP:远程服务的常规调用,无状态;
- SSE:HTTP + 服务端推送,支持长连接 / 流式工具。
工程上 90% 选 stdio。需要远程共享 / 跨机器才上 HTTP / SSE。
# 105. MCP 和 LangChain Tool 怎么共存?
实战做法:
- 团队内部工具用 MCP Server 写,跨多个 Agent 客户端复用;
- LangChain 项目里可以装
@langchain/mcp或类似适配器,把 MCP Server 自动转换成 LangChain Tool; - 反向也成立:LangChain Tool 也可以包成 MCP Server 暴露给外部客户端。
整体趋势:MCP 在成为事实协议,LangChain 不会消失但会从"封装一切"变成"和 MCP 互通"。
# 106. 工具调用的 token 怎么算?
容易被忽略:
- 工具描述本身计费:所有工具的 description + parameters 都拼进 system,每次调用都计费;
- tool_call 输出:模型吐的 JSON 算 output;
- tool_result 输入:你回填的结果算 input;
- 多轮调用:每轮所有历史都重新计费(除非命中 Prompt Caching)。
优化:工具描述精炼、结果裁剪、用 Prompt Caching、按需加载工具。
# 107. 工具权限 / 越权怎么控制?
模型本身没有权限概念,全靠你的代码兜底。
至少做这几层:
- 工具白名单:当前会话 / 当前用户能看到哪些工具;
- 参数校验:执行前用 zod / JSON Schema 校验,类型不对直接拒;
- 数据范围隔离:工具内部根据
user_id限定能查 / 写的数据范围; - 危险操作 HIL:删除、转账、对外发消息都走人工确认;
- 审计日志:每次工具调用记录 who / when / what。
不要相信"模型不会调危险工具"。要假设它一定会调。
# 108. 工具集合怎么管理(工具一多模型选错)?
工具数量超过 10-15 个时模型选错率明显上升。常见策略:
- 分组:按业务域分组(订单组、商品组、用户组),用户问题先路由到组;
- 动态加载:根据用户问题用一个轻量分类器选出 top 3-5 个工具,再传给主 Agent;
- 多 Agent 分工:每个子 Agent 只看自己负责的工具;
- MCP Resources / Prompts:MCP 不只能注册 tools,还能注册 resources / prompts,把工具按粒度分层。
# 109. Skills 和 Function Calling 是什么关系?
Anthropic 提出的 Skills(技能)是更高一层的封装:
- 一个 Skill 包含:一组工具 + 配套 prompt + 示例 + 触发条件;
- 模型按用户意图自动加载对应的 Skill;
- 让 Agent 能力可以像插件一样发布、共享、复用。
可以理解为:Function Calling 是单工具,Skill 是工具 + Prompt 的组合包。
# 110. 工具调用的"自描述"为什么重要?
工具的 schema 是模型理解工具的唯一信息源。模型看不到你的代码,只看 description + parameters。
自描述好 = 描述清楚 + 字段有约束 + 示例齐全。
不自描述(比如 description: "do thing")= 模型只能瞎调。
# 111. 一个常被问的场景:让 Agent 自动写代码并跑测试,应该怎么设计工具集?
最小工具集:
- list_directory(path): 看目录结构
- read_file(path): 读文件
- write_file(path, content): 写文件
- edit_file(path, old, new): 局部修改
- run_command(cmd): 执行命令
- search_code(pattern): 搜代码
关键设计:
- edit_file 比 write_file 更安全,全量重写容易丢东西;
- run_command 必须做白名单,禁止
rm -rf、sudo等; - 写文件必须先 read 再 write,避免误覆盖;
- 每次工具调用都打日志,便于回放。
这就是 Cursor / Claude Code 内部的最小工具集形态。
# 112. 同一个 LLM 既给前端又给 Agent 用,工具怎么设计?
抽两层:
- 底层业务接口:纯后端,保持原样不要污染;
- AI 工具层:在业务接口外面套一层封装,做参数转换、权限收敛、错误格式化、结果裁剪。
不要直接把后端接口暴露给 Agent,否则:
- 权限漏;
- 错误信息泄露内部细节;
- 返回数据太大;
- 参数命名前后端不一致让模型困惑。
# 113. Anthropic Skills 是什么?和 MCP 什么关系?
Skills 是 Anthropic 提的 Agent 能力封装单元,比 MCP Tool 高一层。
一个 Skill 包含:
- 能力描述(什么时候用我);
- 一组工具(怎么做);
- prompt 模板 / 示例(具体怎么调);
- 触发条件(什么场景自动加载)。
类比:MCP Tool 是函数,Skill 是「函数 + 调用手册 + 触发器」打包。
Claude Code 的 .claude/skills/ 目录就是 Skills 的物理形态,每个 Skill 一个 markdown + 配套脚本。
# 114. MCP 的 Resources、Tools、Prompts 三种能力区别?
MCP Server 能暴露三类东西:
| 类型 | 是什么 | 例子 |
|---|---|---|
| Tools | 模型主动调的函数 | read_file、run_sql |
| Resources | 模型可以读的"资料" | 一个 README、一份 schema、一份配置 |
| Prompts | 预设的 prompt 模板 | "用 X 风格生成 Y" |
工程区别:
- Tools 由模型决定何时调,Resources 由 Client 决定何时读;
- Resources 不消耗工具调用预算,但占 context;
- Prompts 让用户能"选择 prompt 模板"而不是手敲。
实战 90% 用 Tools,Resources / Prompts 用得少但很有用。
# 115. MCP 有哪些常见的安全风险?
工具被模型自动调,安全模型必须有:
- 凭据泄露:MCP Server 持有 API key / DB 密码,被 prompt injection 套出来;
- 越权:Server 给所有 client 看同样工具,租户隔离没做好;
- 数据泄露:Resources 暴露了不该看的文件;
- 危险操作:模型自动
rm -rf、删数据库; - 供应链攻击:第三方 MCP Server 里有恶意代码。
防御:
- Bridge 层做权限:哪些用户能调哪些工具;
- 白名单 + 危险操作 HIL;
- 审计日志:每次调用记录 who / when / what;
- 第三方 Server 必须 review,不要随便装。
# 116. 常用的 MCP Server 有哪些?
2026 年生态已经丰富,按用途:
| 类别 | 代表 Server |
|---|---|
| 文件 / Shell | filesystem、shell、git |
| 数据库 | postgres、mysql、sqlite、mongodb |
| 浏览器 | puppeteer、playwright、chrome-devtools |
| 搜索 | brave、google、tavily |
| GitHub / GitLab | github、gitlab |
| 协作 | slack、notion、linear、jira |
| 设计 | figma |
| 监控 | sentry、datadog |
| 云服务 | aws、gcp、azure |
实战流程:能用现成的就用现成的,自研只在内部业务工具。
# 117. Computer Use 和 MCP 是什么关系?
不是替代,是互补:
- MCP:通过协议调函数,精确、快、成本低;
- Computer Use:模型直接操作屏幕,通用但慢且贵。
工程上的策略:
- 优先用 MCP(接 API / SDK 的场景);
- 没有 API 的老软件、跨多软件的复杂流程 → Computer Use 兜底;
- 混用:让 MCP 做主流程,Computer Use 处理零星 GUI 操作。
# 118. 怎么用 Python 写一个 MCP Server?
最小可运行(基于 mcp SDK):
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""两数相加。"""
return a + b
@mcp.tool()
def search_user(name: str) -> dict:
"""按用户名查询用户信息。"""
return {"name": name, "email": f"{name}@example.com"}
if __name__ == "__main__":
mcp.run()
Claude Code 配置:
{
"mcpServers": {
"demo": {
"command": "python",
"args": ["server.py"]
}
}
}
启动 Claude Code → 工具自动出现 → 模型能直接调用。
# 119. Function Calling 在 Agent 框架里的位置?
容易混淆:Function Calling、Tool、Agent 是不同层。
Agent ← 整个跑循环的框架(决定顺序、错误处理、终止)
└─ Tool(业务函数封装)
└─ Function Calling(模型调用 Tool 的协议)
└─ Model(LLM 本体)
实战:你写代码时直接写 Tools(业务函数),Agent 框架(LangChain / Agent SDK)负责处理 Function Calling 协议和循环。Function Calling 你基本不直接接触。
# 六、Memory 与上下文管理
大模型本质是无状态的。所谓"它记得我之前说过什么",其实都是你做的 Memory 管理。这一节决定 Agent 能不能跑长。
# 120. 大模型本身是无状态的,为什么 ChatGPT 能记住上文?
因为客户端 / 服务端帮它把历史 messages 拼回去了。每次请求都把整段对话历史塞进 prompt。
模型本身永远在做"看这次输入 → 产生这次输出"。你看到的"记忆"全是外部状态管理。
这也解释了为什么对话长了会慢、会贵:每轮都重新带全量历史。
# 121. Memory 管理的核心矛盾是什么?
上下文窗口是有限的,但对话可能无限长。
直接往 messages 里 push 早晚撞墙。所以要做有损压缩:
- 保留近期上下文(精确);
- 把远期上下文压缩成摘要(粗糙);
- 把"事实性内容"抽取出来存进结构化记忆 / 向量库(可检索)。
# 122. 短期记忆有哪几种实现?各自适合什么?
- 全量 messages:最简单,对话一两轮够用;
- 滑动窗口:只保留最近 N 轮,超过的丢掉。简单粗暴;
- 滑动窗口 + 摘要:丢掉前先摘要,最常用;
- Token 上限驱动:按 token 数(不是轮数)滚动;
- 关键消息标注:用户标记的"重要消息"始终保留,其他可丢。
# 123. 长期记忆怎么做?
短期记忆只活在当前会话,长期记忆要跨会话。
常见实现:
- 结构化记忆:抽取出"用户偏好 / 历史事件 / 关键事实"存数据库(user_id → JSON);
- 向量记忆:把每段重要对话 embedding 入向量库,下次提问时检索相关历史拼回 prompt;
- 图谱记忆:实体 + 关系存图数据库(Neo4j),适合"人物关系 / 项目关系";
- 文件 / 文档:让 Agent 把"我学到的东西"写成 markdown 文件,下次开会话先 read。
Claude Code 的 memory 系统就是文件型 + 索引型混合。
# 124. 滑动窗口的 N 怎么定?
经验值:
- 简短闲聊:保留最近 8-12 轮;
- 任务对话:保留最近 5-8 轮;
- 长任务 / 编程:按 token,保留最近 10k-20k token。
要紧的不是 N,而是:
- 超过 N 时先摘要再丢,别直接扔;
- 关键消息(用户确认过的、Agent 写过文件的)独立保留。
# 125. 摘要压缩什么时机做?
不要"对话长了再说",否则用户会卡顿。常见两种时机:
- 定时:每 5 轮 / 每 N 个 token 就摘要一次(异步);
- 触发式:上下文剩余 token 不足 X 时强制摘要;
- 结束时:会话结束写一份"长期记忆"入库。
异步做摘要的好处是不阻塞主线程,用户感知不到。
# 126. 摘要丢关键信息怎么办?
工程上几条经验:
- 抽取式摘要 + 关键事实清单双轨:摘要负责"语义连贯",事实清单负责"不丢细节";
- 强约束 prompt:明确告诉摘要 LLM "用户确认过的事情、订单号、金额、时间等必须保留";
- 多级摘要:粗摘要 + 细摘要,按需取;
- 关键消息独立保留:不进摘要,永远在 messages 末尾。
# 127. 多用户怎么隔离记忆?
最起码三层:
- 会话级:session_id 隔离,每个会话独立 messages;
- 用户级:user_id 隔离,跨会话的长期记忆只能本人访问;
- 租户级(ToB):tenant_id 隔离,企业之间数据完全不可见。
实现上要点:
- 向量库的查询必须带 metadata 过滤
user_id == 当前用户; - 缓存层别误共享:模型缓存 / 工具缓存如果按 prompt key 命中,可能跨用户串数据;
- 审计:所有记忆写入都记录 who + when + what。
# 128. 用户改主意了,记忆怎么处理?
例子:用户先说"我要订北京的酒店",几分钟后改成"算了改去上海"。
工程上:
- 覆盖式更新:用户最近一次表述优先,旧的标记为 outdated;
- 冲突检测:定期让 LLM 扫描记忆,发现冲突时提醒用户确认;
- 版本化:所有记忆带版本号 + 时间戳,回溯也方便;
- 不要悄悄"合并":合并意图容易出错,明确"以新为准"。
# 129. Agent 的"工作记忆"(Working Memory)是什么?
工作记忆 = 当前任务正在用的临时变量,区别于:
- 短期记忆(对话历史);
- 长期记忆(用户偏好 / 历史事件)。
例子:Agent 正在处理一个退款流程,工作记忆里临时存"订单号 = A100、退款金额 = 200、客户已同意 = true"。任务结束就丢。
实现上常见:
- 用一个 dict / Redis 存当前 task_id → state;
- 把工作记忆显式注入 prompt,让模型每步都能看到。
# 130. Memory 系统设计有哪几条铁律?
工程上踩过坑总结:
- 不要把所有 messages 都送给大模型:超贵且效果反而差;
- 可读性 > 完整性:摘要是为了让模型理解,不是给人看的;
- 写入读取分离:写入异步、读取同步;
- 可观测:能查每段记忆是怎么产生的、用过几次;
- 可撤销:用户能"清除我的记忆",符合 GDPR / 个保法。
# 131. 怎么让 Agent 记住"用户偏好"?
最常见两种:
- 显式存储:用户说"我以后回答都用中文",Agent 把这条写入 user_preferences 表,每次 system prompt 拼回去;
- 隐式学习:定期扫描历史对话,让 LLM 抽取偏好("用户喜欢简短回答"、"用户喜欢代码带注释"),更新偏好库。
不要靠"模型自己记住",模型不持久化任何东西。
# 132. 记忆系统的隐私和合规怎么做?
涉及 PII(个人身份信息)的:
- 采集前告知 + 同意;
- 敏感字段加密存储(身份证、手机号、邮箱);
- **支持"删除我的所有数据"**接口;
- 导出我的数据接口;
- 审计日志:谁访问了我的记忆;
- 跨境传输合规:用海外模型时要考虑数据出境问题。
# 133. Memory 演进路线(从 demo 到生产)?
四步:
- 全量 messages:能跑就行;
- 滑动窗口 + 异步摘要:能跑长任务;
- 向量长期记忆:能跨会话;
- 图谱 / 结构化记忆 + 多层级:企业级 Agent。
不要一上来上第 4 步,对中小项目就是过度设计。
# 134. Claude Code 的 memory 系统怎么实现的?
Claude Code 的 memory 是「文件型 + 索引型混合」:
- 每个会话 / 项目可以有
memory/目录; - 子目录按类型分:
user.md(用户偏好)、feedback.md(修改习惯)、project.md(项目状态)、reference.md(外部资源); - 一份
MEMORY.md索引每个 entry 的 title + 1-2 句话; - 模型按需
Read索引或具体文件。
设计精髓:
- 可读性强(人能看 / 改 / 删);
- 可版本化(git 跟踪);
- 可选读(不像全量 messages 那样必须带);
- 支持显式编辑(用户能精准纠错)。
这种"显式可控的 memory"是 LLM 时代 memory 系统的主流思路。
# 135. Episodic Memory vs Semantic Memory 区别?
借自认知科学:
- Episodic(情景)记忆:记得"具体发生过什么事"。例子:用户上次说想退款;
- Semantic(语义)记忆:抽象出来的知识 / 偏好。例子:用户喜欢简短回答。
Agent 系统里这两种都要:
- Episodic 适合当前任务推理("我和你之前说过 X");
- Semantic 适合个性化定制(用户偏好、风格、规则)。
实现上:Episodic 用对话历史 + 向量库,Semantic 用结构化 key-value。
# 136. 多 Agent 共享 memory 怎么设计?
多个子 Agent 协作时,信息怎么传递:
- 共享 state(LangGraph 做法):所有 Agent 都能读写一个 state 字典;
- Message Passing:子 Agent 之间发消息,主 Agent 协调;
- 共享存储 + 锁:Redis / DB 加分布式锁;
- 写一份事件流(Event Log):所有 Agent 看同一份事件流,各取所需。
最佳实践:
- 别让所有 Agent 都看全量 memory,按角色过滤;
- 写入要有"是谁写的"标签,方便追责;
- 多 Agent 并发写要序列化或加锁。
# 137. Memory 的访问控制(哪些 Agent 能读 / 能写)?
不同 Agent 信任级别不一样。常见做法:
- 角色 = 权限:QA Agent 只读,Edit Agent 可写,Auditor Agent 全只读;
- 白名单:每个工具 / memory 字段都列出允许的 Agent;
- 审计:所有写入记录 actor + reason;
- 回滚:保留写入历史,能 undo。
ToB 场景这是合规硬要求。
# 138. 用户偏好 Memory 怎么实战?
最常用方案:
// 结构化偏好表
interface UserPrefs {
user_id: string
language: 'zh' | 'en' | 'auto'
response_style: 'concise' | 'detailed'
preferred_models: string[]
custom_instructions: string // 用户自己写的"对我说话要..."
topics_of_interest: string[]
}
注入方式:
- 每次 system prompt 拼一段
## 用户偏好\n{prefs}; - 模型回答前能感知;
- 用户能在 UI 上显式编辑这份偏好。
不要让模型"自己猜偏好",给用户编辑入口才合理。
# 139. 怎么判断一段记忆该不该写?
不是所有对话都值得长期记忆。判定规则:
- 用户明确说"记住这个":必写;
- 用户偏好性表达("我以后都用中文回答"):必写;
- 关键事实(订单号、地址、ID):必写;
- 闲聊 / 重复确认:不写;
- 会过期的状态("我现在很忙"):不写或加 TTL。
简单粗暴的"全写"会把记忆库污染。让一个轻量 LLM 做记忆筛选是常见做法。
# 七、LangChain / LangGraph 框架
不是所有团队都用 LangChain,但面试官几乎都会问。能讲清"LangChain 解决了什么"和"什么时候用 LangGraph",比背 API 强。
# 140. LangChain 是什么?它真正帮你做了什么?
LangChain 把"LLM 应用开发的常见动作"封装成可组合的组件:
- Models:统一调多家 LLM 的接口;
- Prompts:模板、变量、few-shot 管理;
- Output Parsers:把模型输出解析成结构化数据;
- Tools / Toolkits:工具定义 + Function Calling 流程;
- Memory:对话历史 / 长期记忆封装;
- Retrievers:向量库 / RAG 检索抽象;
- Chains / LCEL:把上面这些链式拼起来;
- Agents:常见 Agent 模式(ReAct、Plan-and-Execute 等)。
简单说:它让你不用从零写 prompt 拼接、工具调度、错误重试这些脏活。
# 141. LCEL(LangChain Expression Language)是什么?
LangChain 的管道语法,用 | 把组件串起来:
const chain = promptTemplate
.pipe(model)
.pipe(outputParser)
const result = await chain.invoke({ topic: 'AI' })
好处:
- 写起来像 Unix pipeline,直观;
- 自动支持 batch / stream / async;
- 容易换组件(换模型只改
.pipe(model))。
LCEL 适合线性流程,分叉 / 循环 / 条件就该上 LangGraph。
# 142. LangGraph 是什么?为什么有了 LangChain 还要它?
LangChain 的 chain 是线性管道,无法表达:
- 条件分支(这步成功才走下一步);
- 循环(不达标就回头);
- 多 Agent 并行 / 协作;
- 显式状态管理。
LangGraph 是图编排引擎,节点 = 一个动作(LLM 调用 / 工具调用 / 自定义函数),边 = 转移规则。
适合:
- 多 Agent 协作;
- Agentic RAG(要不要再查一次);
- 复杂工作流(审批、订单、客服路径);
- 显式可视化整个 Agent 流程。
# 143. 用 LangGraph 写一个最小图怎么写?
import { StateGraph, END } from '@langchain/langgraph'
const graph = new StateGraph<{ input: string; output?: string }>({
channels: { input: null, output: null }
})
graph.addNode('plan', async (state) => ({ output: `planned: ${state.input}` }))
graph.addNode('execute', async (state) => ({ output: `done: ${state.output}` }))
graph.addEdge('plan', 'execute')
graph.addEdge('execute', END)
graph.setEntryPoint('plan')
const app = graph.compile()
const result = await app.invoke({ input: 'hello' })
关键概念:
- State:所有节点共享的状态(合并而非覆盖);
- Node:一个动作;
- Edge:节点间转移;
- Conditional Edge:根据 state 决定走哪条边;
- Checkpoint:每步状态可以存到 DB,支持中断 + 恢复(HIL 神器)。
# 144. Runnable 是什么?为什么所有组件都是 Runnable?
LangChain 给所有组件定义了一个统一接口 Runnable:
interface Runnable<I, O> {
invoke(input: I): Promise<O>
stream(input: I): AsyncIterable<O>
batch(inputs: I[]): Promise<O[]>
}
任何组件(Prompt、Model、Parser、Tool、Chain)都实现这个接口,所以才能用 | 串起来。
类比 React 的 component:只要符合接口,就能复用 / 组合。
# 145. Output Parser 和 Tool Calling 怎么选?
- Output Parser:模型输出文本,你写正则 / JSON 解析。适合输出格式相对自由 + 不需要严格 schema 的场景;
- Tool Calling / Structured Output:模型按 schema 输出。适合严格 JSON / 字段必填 / 类型检查。
经验:
- 简单解析(提取一段总结、抽几个关键词)→ Output Parser;
- 复杂结构化(多字段、嵌套、必填)→ Tool Calling;
- 流式场景:Output Parser 支持流式增量解析,Tool Calling 通常等完整 JSON。
# 146. Prompt Template 和写字符串拼接的区别?
字符串拼接看起来够用,但写多了会有:
- 变量散在各处难追踪;
- 多语言 / 模板复用难;
- 没法自动绑定 few-shot;
- 没法集成版本管理 / 灰度。
PromptTemplate 把 prompt 当一等公民:变量声明清晰、可继承、可序列化、可版本化。
# 147. LangChain 全部 Splitter,挑哪个用?
90% 场景用一个就够:RecursiveCharacterTextSplitter。
它会按 \n\n → \n → " " → "" 递归切分,尽量保持段落完整。
其他特殊场景:
- 代码:
Language.PYTHON / JS / ...专用 splitter; - Markdown:
MarkdownHeaderTextSplitter,按标题层级切; - HTML:
HTMLHeaderTextSplitter; - 语义:
SemanticChunker(嵌入模型驱动,慢但效果好)。
# 148. 怎么把 LangChain 的链接到 Nest / Next API?
Nest 后端最小骨架:
@Controller('chat')
class ChatController {
@Post('stream')
async stream(@Body() body: { input: string }, @Res() res: Response) {
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
const chain = prompt.pipe(model).pipe(parser)
const stream = await chain.stream({ input: body.input })
for await (const chunk of stream) {
res.write(`data: ${JSON.stringify(chunk)}\n\n`)
}
res.end()
}
}
前端用前面给的 SSE 模板读就行。
# 149. LangSmith 是什么?为什么所有 LangChain 项目都建议接?
LangSmith = LangChain 的可观测平台。
接入只要加三个环境变量:
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=...
LANGCHAIN_PROJECT=my-project
跑起来后所有 Chain / Agent 调用都自动上报,可以看:
- 每一步的 prompt、输入、输出;
- 每步 token、耗时、cost;
- Agent 的完整调用树;
- 失败 trace 一键回放;
- 历史调用打 dataset,跑评估。
工程上没有可观测 = 没法调优 = 没法上线。强烈建议从第一天就接。
# 150. LangGraph 的 Checkpoint 怎么用?
Checkpoint 是 LangGraph 的杀手锏:每步状态都能保存到 DB,所以可以:
- 中断后恢复(用户离开几小时后接着跑);
- HIL(跑到关键节点暂停,等用户确认);
- 时间旅行(回到之前某一步重新执行);
- 多用户并行运行不同 thread。
最简单 sqlite checkpoint:
import { SqliteSaver } from '@langchain/langgraph-checkpoint-sqlite'
const checkpointer = SqliteSaver.fromConnString('./checkpoints.db')
const app = graph.compile({ checkpointer })
const config = { configurable: { thread_id: 'user-123' } }
await app.invoke({ input: 'hello' }, config)
// 后面任何时候用同一个 thread_id 都能从上次断点继续
# 151. LangChain vs LlamaIndex 怎么选?
| 维度 | LangChain | LlamaIndex |
|---|---|---|
| 定位 | 通用 LLM 应用框架 | RAG 专精 |
| 强项 | Agent、工具调用、链编排 | 文档加载、索引、检索 |
| 学习曲线 | 偏陡 | 相对简单 |
| 文档生态 | 庞大 | 聚焦 |
| 适合 | 复杂 Agent / 多步骤工作流 | 纯 RAG 场景 |
实战常见组合:LlamaIndex 做索引 + LangChain 做 Agent。两者也都能独立做完所有事。
# 152. LangChain 内置的 Agent 类型有哪些?怎么选?
| Agent 类型 | 工作方式 | 适合 |
|---|---|---|
| ReAct Agent | 边想边调工具 | 通用 |
| OpenAI Functions Agent | 用 Function Calling 标准 | OpenAI / Claude 系列 |
| Plan-and-Execute | 先规划再执行 | 长程任务 |
| Self-Ask | 自问自答分解问题 | 推理 / 多跳问答 |
| Structured Chat | 多工具结构化输出 | 工具数量多 |
2026 年趋势:直接用 Tool Calling Agent(基于模型自带 Function Calling),不用旧的 ReAct prompt-based Agent。
# 153. LangGraph 怎么做 Human-in-the-loop?
LangGraph 用 interrupt + Checkpoint 实现 HIL:
graph.addNode('confirm_payment', async (state) => {
// 等待用户确认
return await interrupt({ amount: state.amount, action: 'approve_or_reject' })
})
graph.addConditionalEdges('confirm_payment', (state) => {
return state.approval === 'yes' ? 'execute' : 'cancel'
})
效果:跑到 confirm_payment 节点时保存当前状态 + 暂停,前端拿到状态展示给用户确认 → 用户决定 → 用 app.invoke({...}, { resume: 'yes' }) 继续。
适合所有"需要二次确认"的场景(付款、删除、对外发消息)。
# 154. LangGraph 的多 Agent 模式有哪些?
| 模式 | 拓扑 | 适合 |
|---|---|---|
| Supervisor | 主 Agent 派活,子 Agent 干完汇报 | 任务可拆解 |
| Network | 多 Agent 互相调用 | 复杂协作 |
| Hierarchical | 多层 supervisor | 超大规模 |
| Swarm | Agent 之间 handoff | 客服路由 |
Supervisor 是最常用的。Swarm(基于 OpenAI Swarm)适合"客户被不同专家接力服务"的场景。
# 155. LangChain 的 Memory 类型对比?
| Memory | 怎么用 | 适合 |
|---|---|---|
| ConversationBufferMemory | 全部带 | demo |
| BufferWindowMemory | 最近 N 轮 | 简单对话 |
| SummaryMemory | 用 LLM 摘要 | 长对话 |
| SummaryBufferMemory | 摘要 + 窗口混合 | 实战首选 |
| VectorStoreMemory | 向量检索历史 | 长期记忆 |
| EntityMemory | 抽取实体 + 关系 | 用户画像 |
生产用 SummaryBufferMemory 或者干脆自己写(LangChain Memory 抽象偶尔不够灵活)。
# 156. Vercel AI SDK 和 LangChain 是什么关系?
- Vercel AI SDK:前端 / Edge / Node 全栈 SDK,主打流式 UI(
useChat、useCompletion)、模型抽象(generateText/streamText)、Tool Calling 简化。前端友好,复杂 Agent 弱; - LangChain:后端 Agent 框架,长链 / 多 Agent / 复杂工作流强。
实战常见组合:
- 前端(Next.js)用 Vercel AI SDK 处理 UI / 流式 / 简单工具;
- 复杂业务后端跑 LangChain / LangGraph Agent,通过 SSE 给前端推结果。
两个其实是不同层,不冲突。
# 157. LCEL Streaming 怎么实现?
LangChain 所有 Runnable 都自带 .stream():
const chain = prompt.pipe(model).pipe(new StringOutputParser())
for await (const chunk of await chain.stream({ input: 'hi' })) {
process.stdout.write(chunk)
}
后端给前端流式(Next.js Route Handler):
export async function POST(req: Request) {
const { input } = await req.json()
const stream = await chain.stream({ input })
return new Response(stream.pipeThrough(new TextEncoderStream()), {
headers: { 'Content-Type': 'text/plain' }
})
}
或者用 Vercel AI SDK 的 LangChainAdapter.toDataStreamResponse(stream) 适配。
# 158. LangChain 怎么写一个完整 RAG chain?
最小骨架:
import { createRetrievalChain } from 'langchain/chains/retrieval'
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents'
const ragPrompt = ChatPromptTemplate.fromTemplate(`
基于以下检索资料回答问题:
{context}
问题:{input}
`)
const docChain = await createStuffDocumentsChain({ llm: model, prompt: ragPrompt })
const ragChain = await createRetrievalChain({ retriever, combineDocsChain: docChain })
const result = await ragChain.invoke({ input: '什么是 RAG?' })
console.log(result.answer)
复杂场景(重排、Hybrid、HyDE)用 LCEL 拼,或者直接上 LangGraph 写图。
# 八、模型微调 / 私有化部署 / ToB 落地
资深岗 / ToB 岗常问。前端工程师不一定要会训练,但必须知道什么时候要微调、什么时候不要。
# 159. 大模型在 ToB 业务里落地有哪些核心难点?
直接拿通用模型给企业用会撞上这些坑:
- 不懂业务:训练语料是公网通用知识,对企业内部规章、产品文档一无所知;
- 幻觉风险:不知道时不会闭嘴,会"看着像那么回事"地编;
- 数据合规:员工 / 客户敏感信息不能直接送外部 API;
- 响应慢、单价高:交互密集业务直接调外部模型不友好;
- 可控性差:用户问答风格不符合公司话术。
主流解法:
- RAG:把企业知识向量化,给模型外挂记忆;
- 私有化部署:选开源模型(Qwen / DeepSeek / LLaMA)在自己机器上跑;
- 微调:把客服话术、产品规则训进模型;
- 工作流编排:Dify / Coze / FastGPT 把 Prompt + RAG + 工具串起来。
# 160. 模型幻觉的深层原因(再追问版)?
不只是"瞎说",拆开看:
- 概率模型的天然倾向:在"算最可能的下一个 token",不是"查事实";
- 训练语料噪声:互联网真假混杂;
- 没有事实校验:出结果时不会回头验证;
- 上下文断裂:检索片段不全时会自动"补缝";
- 任务边界模糊:开放性问题模型倾向于"展开发挥"。
减少幻觉是组合拳:RAG + 引用 + 二次校验 + 低温 + 拒答指令。
# 161. 微调(Fine-tuning)核心是什么?什么时候才该用?
在已经预训练好的模型上用领域数据继续训练,把权重调整到对该领域更敏感。理解成"再上岗培训",不是"重新培养"。
适合:
- 输出格式 / 风格特别固定(客服话术、报告模板);
- 行业术语 / 知识体系密集(医疗、法律、金融);
- prompt 膨胀到不可控,希望把规则"内化"省 token;
- 闭源场景下本地化部署。
不适合:
- 业务规则会频繁变(每次都重训性价比低);
- 数据少(< 200 条);
- 短期内 RAG / Prompt 还能优化。
# 162. 全参微调 vs PEFT(LoRA / QLoRA)区别?
| Full Fine-tuning | PEFT | |
|---|---|---|
| 训练对象 | 全部权重 | 一小部分(增量矩阵) |
| 显存 | 极高(70B 几百 G) | 单卡 24G 也能玩 |
| 训练速度 | 慢 | 快几倍到十几倍 |
| 效果上限 | 最好 | 略弱,95% 场景够用 |
| 过拟合 / 灾难性遗忘 | 容易 | 影响小 |
| 适合 | 大厂底座 | 中小团队业务定制 |
99% 应用层用 PEFT 就够,LoRA / QLoRA 是甜点。
# 163. LoRA 为什么能省显存?
核心思想:别动原矩阵,旁边加两个小矩阵。
数学上:原权重 W 冻结,新增低秩矩阵 A、B(rank 通常 8 - 64),让 W' = W + A·B。训练只更新 A、B(参数量小一两个数量级),推理时把 A·B 合并回去。
收益:
- 显存占用大幅下降;
- 训练速度快几倍;
- 训完只存 A、B(几十 MB),换底座或叠加多个 LoRA 都方便;
- QLoRA 进一步把基座量化到 4bit,单卡能玩 70B。
# 164. 微调要准备什么数据?格式怎么定?
数据类型:
| 类型 | 形态 | 适合 |
|---|---|---|
| 指令数据 | {instruction, input, output} | 让模型听特定指令 |
| 对话数据 | messages: [{role, content}] | Chat 类模型 |
| 知识 QA | 上下文 + 问答对 | 强化领域问答 |
| 偏好数据 | {prompt, chosen, rejected} | DPO / RLHF 对齐 |
质量比数量重要:
- 1000 条干净 > 10 万条杂乱;
- 去重、去矛盾、去低质;
- 风格 / 长度 / 格式统一(模型很会学风格);
- 留 5-10% 做验证集;
- token 长度尽量贴近实际推理分布。
# 165. 私有化部署有哪些选项?
按规模:
| 规模 | 推荐 |
|---|---|
| 单机 / 玩具 | Ollama、LM Studio、llama.cpp(CPU/Metal) |
| 单卡生产 | vLLM + 14B-32B 量化模型 |
| 多卡 / 高并发 | vLLM / SGLang + 70B 模型 |
| 集群 | TGI / Triton + K8s |
| 企业一体机 | 阿里 / 腾讯 / 火山 / 智谱的私有化解决方案 |
vLLM 是事实标准,PagedAttention 让吞吐高出传统几倍。
# 166. Dify / Coze / FastGPT 这类平台怎么选?
| 维度 | Dify | Coze | FastGPT | LangFlow |
|---|---|---|---|---|
| 开源 | 是 | 否(字节托管) | 是 | 是 |
| 私有部署 | 是 | 否 | 是 | 是 |
| 国内合规 | 看部署 | 友好 | 友好 | 看部署 |
| 工作流可视化 | 是 | 是 | 是 | 是(LangChain 底) |
| Agent / 多 Agent | 中 | 强 | 中 | 灵活但要写 |
| 模型支持 | 全 | 主要豆包 / GPT | 全 | 全 |
| 适合 | 通用快速搭建 | 字节生态 / 抖音渠道 | 知识库为主 | 已用 LangChain |
选型小结:
- 想完全自控 + 私有化:Dify / FastGPT;
- 抖音 / 飞书 / 公众号:Coze;
- 重 RAG 知识库:FastGPT 起步快;
- 已用 LangChain + 想可视化:LangFlow。
# 167. 自己搭 LLM 应用平台 vs 用 Dify?
| 自己搭 | 用 Dify | |
|---|---|---|
| 上手 | 慢 | 快 |
| 定制 | 自由 | 受抽象限制 |
| 维护 | 全自己 | 跟社区版本 |
| 性能 | 可极致优化 | 中规中矩 |
| 适合 | 超大流量 / 强定制 | 中小项目 / 内部工具 / MVP |
务实结论:MVP / 内部工具用 Dify 先跑通,核心业务自研,混合最常见。
# 168. Function Calling 的优缺点?为什么很多团队转 MCP?
优点:上手快、几乎所有 SDK 都支持、模型生态成熟。
缺点:
- 没有跨厂商标准;
- 工具描述全靠塞 prompt,工具多了 token 暴涨;
- 没内建权限模型;
- 跨语言 / 跨进程不友好;
- 工具发现 / 热加载难。
这些短板正是 MCP 想解的,所以 2026 年明显朝 MCP 倾斜。
# 169. Agent Loop 在工程里有哪些坑?
跑过 Agent 的人都被这些坑过:
- 死循环 / 振荡;
- Token 烧得飞快;
- 错误被放大;
- 越权风险;
- 不会停。
兜底必做:
- 设硬上限(步数 / token / 时间);
- 重复检测;
- 工具白名单 + 危险操作二次确认;
- 全链路日志;
- 上下文压缩。
# 170. ElasticSearch / 倒排索引在 AI 场景的作用?
向量检索擅长语义,倒排索引擅长精确匹配 / 关键词 / 字段过滤。
在 RAG 场景下,最佳实践是 ElasticSearch + 向量库混合检索:
- ES 做 BM25 召回 + 字段过滤(按部门、时间、标签);
- 向量库做语义召回;
- RRF 合并结果。
如果团队已经有 ES 集群,可以直接用 ES 的 dense_vector + KNN,少引入一个组件。
# 171. Neo4j / 知识图谱在 AI 场景的作用?
把"实体 + 关系"显式建模成图:
- 节点:人、公司、产品、订单;
- 边:归属、关联、引用、合作。
适合:
- 多跳推理("客户 A 的关联公司在哪些行业有业务?");
- 反洗钱 / 合规审查(关系穿透);
- 个性化推荐(基于关系)。
GraphRAG 就是基于知识图谱的 RAG,适合关系复杂、单文档语义不够的场景。
# 172. Docker Compose 在 AI 开发提效里能做什么?
本地一键起依赖(向量库 + Redis + Postgres + 监控):
services:
milvus:
image: milvusdb/milvus
ports: ['19530:19530']
redis:
image: redis:7-alpine
postgres:
image: pgvector/pgvector:pg16
langfuse:
image: langfuse/langfuse
docker compose up -d 一秒起完,免去手动安装。
生产场景一般会上 K8s,但 dev / 测试 / 小型企业一直用 Compose 也合理。
# 173. LangSmith / Helicone / Langfuse 选哪个?
| LangSmith | Helicone | Langfuse | |
|---|---|---|---|
| 开源 | 否 | 否 | 是 |
| 自部署 | 否 | 部分 | 是 |
| 和 LangChain 集成 | 原生 | 通用 | 原生 |
| 数据集 / 评估 | 强 | 弱 | 中 |
| 价格 | 中 | 低 | 自部署免费 |
中小项目 / 合规要求高 → Langfuse 自部署;已用 LangChain + 不在意合规 → LangSmith。
# 174. vLLM 为什么吞吐高?
vLLM 推理引擎的两个核心创新:
- PagedAttention:把 KV Cache 按页存(类似操作系统虚拟内存),消除显存碎片,能塞更多并发;
- Continuous Batching:新请求随时插入批次,不等慢的请求。传统 batching 一个慢拖一片。
效果:单卡吞吐比 transformers + naive batching 高 5-10 倍。
竞品:SGLang(更激进的优化)、TGI(HuggingFace 出品)、TensorRT-LLM(NVIDIA 官方,最快但配置复杂)。
# 175. 模型量化(INT8 / INT4 / AWQ / GPTQ)是什么?
模型权重从 FP16 / BF16 压缩到更低精度,显存和延迟下降,精度有少量损失。
| 类型 | 精度 | 显存压缩 | 典型损失 |
|---|---|---|---|
| FP16 / BF16 | 原始 | 1× | — |
| INT8 | 8 位整数 | 2× | < 1% |
| INT4 | 4 位整数 | 4× | 2-5% |
| AWQ | 4 位,关键权重保护 | 4× | < 2% |
| GPTQ | 4 位,基于梯度优化 | 4× | < 2% |
实战:
- 推理优先 AWQ(性能稳定、社区生态好);
- 端侧 / 极端资源紧用 INT4 / GGUF;
- 训练阶段一般不量化(影响梯度)。
# 176. 模型蒸馏(Distillation)是什么?
用大模型(Teacher)"教"小模型(Student):
- 让 Teacher 生成大量高质量样本(包含 logits / token 概率);
- 训练 Student 模仿 Teacher 的输出分布。
效果:
- Student 参数量 1/10,但效果接近 Teacher;
- 推理速度快好几倍;
- 经典案例:DistilBERT、DeepSeek-V3 蒸馏出来的小模型。
适合:业务场景固定、追求极致延迟 / 成本的生产环境。
# 177. 私有化部署 GPU 选什么?
| 卡 | 显存 | 适合 |
|---|---|---|
| RTX 4090 | 24G | 个人 / 试验,14B 模型量化版 |
| A10 / A30 | 24G | 中小生产,32B 量化版 |
| L40S | 48G | 70B 模型量化版 |
| A100 80G | 80G | 70B 全精度、训练 |
| H100 | 80G | 主流大模型推理 / 训练 |
| H200 / B200 | 141G+ | 旗舰生产,175B+ |
国内合规:A100/H100 受出口管制,替代方案为 A800/H800(被砍 NVLink 带宽)或华为 910B。
# 178. 模型评测常见 benchmark?
| benchmark | 测什么 |
|---|---|
| MMLU | 57 学科多选题,知识广度 |
| GSM8K | 小学数学题,多步推理 |
| MATH | 高难度数学 |
| HumanEval / MBPP | Python 代码生成 |
| SWE-bench | 真实软件工程 |
| MT-Bench / AlpacaEval | 多轮对话质量 |
| C-Eval / CMMLU | 中文综合能力 |
| GAIA / AgentBench | Agent 能力 |
注意:benchmark 分数和实际业务效果不一定一致,最终还是要拿业务数据测。
# 179. 私有化模型怎么更新?
不像调 API 那样无感升级。常见策略:
- 灰度切换:新模型挂上来,按流量比例分流,对比指标;
- 双跑评估:旧 / 新模型同时跑,离线对比答案差异;
- 回归测试集:维护一组业务测试 case,新版必须通过;
- 可快速回滚:模型版本管理 + 一键切回旧版本;
- 保留旧版本一段时间:用户反馈"上次回答更好"时能回查。
不要"周末偷偷换新模型"。
# 180. ToB 项目灰度发布有什么特殊?
ToC 灰度按用户 ID hash,ToB 不行:
- 一个客户的几百用户必须同时升级(避免同公司内体验割裂);
- 必须支持按客户灰度(先小客户 / 试点客户 / 大客户);
- 部分客户合同里写明"不要给我用新版",要尊重;
- 告知机制:升级前邮件 + 站内信通知,让客户管理员有准备;
- 回滚要在合同 SLA 内。
# 181. ToB 项目的成本怎么算给客户看?
客户最关心的不是技术,是钱。展示口径:
- 按 token 计费透明:每次调用 input/output token 给出;
- 月度账单:按租户 / 按用户 / 按使用场景;
- 预算告警:超过 X% 自动通知;
- 模型分级:便宜模型默认、贵模型按需开;
- 缓存命中率告诉客户"省了多少钱"。
成本可见性是 ToB 续费的关键。
# 九、前端 AI 集成与工程化
前端的主场。AI 应用最终都要落到一个 UI 上,怎么把流式输出做丝滑、怎么管理多会话状态、怎么处理用户中断,这些是前端真正能拉差距的部分。
# 182. 前端调 LLM API 怎么做流式输出?
不要用 axios,用 fetch + ReadableStream。
async function streamChat(input: string, onDelta: (text: string) => void) {
const controller = new AbortController()
const res = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ input }),
headers: { 'Content-Type': 'application/json' },
signal: controller.signal
})
if (!res.body) throw new Error('no body')
const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true })
let idx
while ((idx = buffer.indexOf('\n\n')) !== -1) {
const block = buffer.slice(0, idx)
buffer = buffer.slice(idx + 2)
if (block.startsWith('data: ')) {
const data = block.slice(6)
if (data === '[DONE]') return
const { delta } = JSON.parse(data)
onDelta(delta)
}
}
}
return controller
}
记得:
- 返回 controller 给上层做中断;
- 错误要单独处理(一段 chunk 解析失败别拉垮整个流);
- TextDecoder 必须用
{ stream: true },否则中文截断会乱码。
# 183. 为什么不能在前端直接调 OpenAI / Claude?
理论上能,实际上不能:
- API key 暴露:放前端等于公开发钱;
- 没法做权限 / 速率限制:被人薅羊毛;
- 没法统计 / 计费:哪个用户花了多少钱;
- 没法注入 system prompt:用户能改请求;
- CORS / 跨域:很多家不支持浏览器直连;
- 没法做合规过滤。
必须走自己的后端 BFF / API 网关代理。
# 184. 流式输出在 React 里怎么处理?
最简单:
function Chat() {
const [text, setText] = useState('')
const controllerRef = useRef<AbortController>()
const send = async (input: string) => {
setText('')
controllerRef.current = new AbortController()
await streamChat(input, (delta) => {
setText((prev) => prev + delta)
}, controllerRef.current.signal)
}
const stop = () => controllerRef.current?.abort()
return (...)
}
注意:
- 每个 token 都 setState 会卡,用 useReducer 或 ref 缓冲再批量 flush 在 60fps 内更新;
- 长文章场景上 react-window 虚拟列表;
- 别每个字都触发 layout / scroll 计算。
# 185. 大段文字流式渲染卡顿怎么办?
罪魁祸首通常是 Markdown 增量解析。优化:
- 节流渲染:每 30-50ms flush 一次缓冲区,不要每 token 重渲染;
- Markdown 流式解析:用
react-markdown+ memo,或专门的 streaming-markdown 库; - 代码高亮异步化:shiki / Prism 跑在 Web Worker;
- 避免大组件树重渲染:消息列表只追加,最新一条单独组件;
- 滚动跟随节流:scrollToBottom 防抖。
# 186. SSE 和 WebSocket 哪个适合 LLM 流式?
| SSE | WebSocket | |
|---|---|---|
| 方向 | 单向(服务端 → 客户端) | 双向 |
| 协议 | HTTP,简单 | 升级握手,复杂 |
| 自动重连 | 原生支持 | 自己写 |
| 代理 / CDN 友好 | 友好 | 一般 |
| 适合 | 流式输出(LLM 99% 场景) | 多人协作 / 双向打断 |
LLM 默认上 SSE,**有"实时打断 / 多端协同 / 服务端主动推送"**才上 WS。
# 187. 怎么取消正在流式的请求?
前端用 AbortController,后端要识别到客户端断开立即停止 LLM 调用:
- OpenAI / Anthropic SDK 都支持传 AbortSignal;
- Node http 监听
req.on('close')触发 cleanup; - 已经调过的工具结果要做事务处理或标记中断。
不要让用户点了"停止"还在烧钱。
# 188. Token 预算怎么在前端做提示?
实战经验:
- 输入框旁边显示估算 token 数(前端用 tiktoken-js / cl100k_base 估);
- 长度临近上限时变红 + 提示"内容过长,可能截断";
- 上传文件 / 长 prompt 时显示预估成本(按用户套餐计算)。
库选:gpt-tokenizer、tiktoken-js、@anthropic-ai/tokenizer。
# 189. 错误怎么向用户展示?
LLM 错误分几类,UI 表达要区分:
| 错误 | 用户感知 | 建议表达 |
|---|---|---|
| 速率限制 (429) | 服务忙 | "请求过于频繁,请稍后重试" |
| 配额耗尽 | 额度问题 | "今日额度已用完,明日恢复 / 升级套餐" |
| 上下文超长 | 内容过长 | "对话过长,建议开新会话" |
| 服务异常 | 后端问题 | "服务暂时不可用" + 自动重试 |
| 模型拒答 | 触发安全 | "无法回答此类问题" |
| 网络中断 | 本地问题 | "网络异常" + 自动重连 |
每种都要有重试按钮 + 错误码便于排查。
# 190. ChatGPT 那种"消息列表"怎么实现?
数据结构:
type Message = {
id: string
role: 'user' | 'assistant' | 'system' | 'tool'
content: string
reasoning?: string // 思考过程(CoT 显示)
toolCalls?: ToolCall[]
attachments?: File[]
createdAt: number
status: 'pending' | 'streaming' | 'done' | 'error'
}
UI 关键:
- 流式追加:最后一条 message 是 streaming 状态时不断更新 content;
- 虚拟列表:消息多了用 react-window;
- 滚动控制:用户手动滚动后停止自动滚到底;
- 重新生成 / 编辑:编辑某条 user 消息后,从这条开始的所有后续 message 清空 再重新跑。
# 191. 怎么管理多个会话状态?
类似 ChatGPT 的左侧会话列表:
- 会话表
conversations(id, title, created_at, user_id) - 消息表
messages(id, conversation_id, role, content, ...) - 前端状态:当前 conversation_id + 当前 messages 数组
- 路由
/c/[conversationId]反映在 URL 上,方便分享 / 刷新
进阶:
- 会话标题用 LLM 自动从第一条对话生成;
- 软删除(标记 deleted_at)+ 30 天后真删;
- 大对话支持分页加载;
- 多端同步用 WebSocket / 长轮询。
# 192. AI 对话用 Edge Runtime 还是 Node?
| 场景 | Edge | Node |
|---|---|---|
| 纯流式代理 | 推荐 | 也行 |
| 复杂业务 / 数据库重 | 不行 | 推荐 |
| 全球低延迟 | Edge 完胜 | 受机房限制 |
| 大依赖 / 二进制包 | Node 才能跑 | 灵活 |
Vercel / Cloudflare 上的 LLM 代理大多 Edge,复杂 Agent 后端用 Node(要操作数据库、调多工具、跑长任务)。
# 193. 怎么实现"图片 + 文字"混合输入?
数据格式(OpenAI / Anthropic / Qwen-VL 类似):
{
"role": "user",
"content": [
{ "type": "text", "text": "这张设计稿对应哪些组件?" },
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,..." } }
]
}
前端:
- 支持粘贴 / 拖拽 / 文件选择多种方式;
- 图片前端压缩到 1MB 以内再传(base64 太大很贵);
- 上传到对象存储拿 URL 比 base64 便宜(前提是模型能访问到);
- 显示缩略图 + 移除按钮让用户可以删;
- 多图按顺序排列。
# 194. Markdown 增量渲染怎么处理?
直接每次都 re-parse 整段会卡。三个套路:
- Streaming Markdown:用支持流式的 parser(marked / micromark + 增量插件),只 parse 新增片段;
- 代码块缓存:代码高亮的输出按内容 hash 缓存,重复不重 parse;
- DOM diff 友好:用 React key 让 DOM 复用而不重建。
记得:未闭合的代码块要做容错(用户还没输入 ``` 结尾),不要让一半的代码把后面渲染全搞乱。
# 195. AI 应用的埋点要监控什么?
不只是 PV / UV,还要 AI 特有的:
- TTFT(First Token Time):用户感知响应速度的关键;
- 完成耗时:整个回答从发出到结束;
- Token 消耗:每用户 / 每会话 / 每模型;
- 成本:折算成钱;
- 中断率:用户主动停的比例;
- 重试率 / 重新生成率:暗示回答质量;
- 拒答率:触发了安全过滤;
- 错误码分布;
- 多轮深度:用户问到第几轮;
- 点赞 / 点踩:用户反馈最直接信号。
# 196. AI 应用的"灰度发布"怎么做?
新 prompt / 新模型 / 新 RAG 配置上线要灰度:
- 配置中心驱动:prompt、模型、RAG 参数从配置中心动态加载,不发版;
- 用户分组:按 user_id hash 取模,5% → 20% → 50% → 100%;
- AB 对照:旧版 vs 新版同时跑,对比关键指标(满意度、token 成本、TTFT);
- 影子流量:新版本只跑不返回,只是为了拿数据;
- 快速回滚:发现问题 5 分钟内切回旧版本。
# 197. AI 应用的成本怎么算和优化?
公式:成本 = Σ(每次调用的 input_tokens × in_price + output_tokens × out_price)
优化思路:
- 更便宜的模型分流(简单任务用小模型);
- Prompt Caching(命中率打 1-5 折);
- 缩短 prompt + 工具描述;
- 结果裁剪 / 摘要;
- 多轮压缩(旧轮次摘要);
- 业务侧缓存(同问题先查 KV);
- 限流 + 套餐(防止个别用户跑爆)。
# 198. AI 应用的"国际化"(i18n)有什么特别?
不只是把文案翻译:
- system prompt 多语言:每种语言一份;
- 输出语言:用户的浏览器语言 / 用户偏好;
- 不要混用语言:在 prompt 里告诉模型"全程用同一种语言";
- 错误信息 i18n:拒答信息、错误码都要翻;
- 数字 / 日期 / 货币格式按 locale;
- RTL 语言(阿拉伯语)UI 也要 RTL。
# 199. AI 应用的"乐观更新"怎么做?
用户发送消息后立刻显示在列表里,不等服务端确认:
const send = (input: string) => {
const tempMsg = { id: nanoid(), role: 'user', content: input, status: 'pending' }
appendMessage(tempMsg)
// 异步调用 API
api.chat(input).then((real) => replaceMessage(tempMsg.id, real))
.catch(() => markFailed(tempMsg.id))
}
注意:
- 失败时用红色 + 重试按钮;
- 不要让"乐观"骗用户:服务端真失败要明确告知;
- 多端同步时小心冲突。
# 200. AI 自动补全代码(类似 Copilot)怎么实现?
前端流程:
- 编辑器 cursor 位置 + 上下文(前后 200 行 / token)通过 debounce(300-500ms)发给后端;
- 后端 FIM(Fill-in-the-Middle)prompt 调模型;
- 流式返回,前端 ghost text 渲染;
- Tab 接受 / Esc 拒绝 / 编辑中放弃。
要点:
- 用 FIM 友好的模型(DeepSeek-Coder、Qwen-Coder、StarCoder 等);
- AbortController 让新一次输入立刻取消上一次;
- 接受率 / 拒绝率打点优化模型;
- 长函数不要一次全补,让用户分阶段确认。
# 201. AI 应用要不要 PWA / 离线支持?
实战经验:
- 离线 LLM 一般不支持(模型太大,浏览器跑不动);
- 历史会话可以做离线只读:IndexedDB 存历史,无网时也能看;
- 草稿离线写,回到在线再发送;
- 不要让 ServiceWorker 缓存 LLM API 接口,必须 NetworkOnly;
- 静态资源走标准 PWA 缓存就好。
# 202. Vercel AI SDK 的 useChat 怎么用?
最简化的 Next.js 集成:
'use client'
import { useChat } from 'ai/react'
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat({
api: '/api/chat'
})
return (
<>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={isLoading} />
<button type="submit">发送</button>
{isLoading && <button type="button" onClick={stop}>停止</button>}
</form>
</>
)
}
后端:
import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'
export async function POST(req: Request) {
const { messages } = await req.json()
const result = await streamText({ model: openai('gpt-4o'), messages })
return result.toDataStreamResponse()
}
省去了流式协议处理、状态管理、停止逻辑的大量样板。
# 203. 消息编辑 / 重新生成怎么实现?
设计要点:
- 编辑 user 消息:编辑后,从这条开始的所有后续消息全清空,从这条重新跑;
- 重新生成 assistant 消息:保留 user 消息,重新调用模型生成新回答,前一次答案要么覆盖、要么作为历史版本保留;
- 历史版本切换:UI 上
< 1/3 >形式让用户在版本间切换; - 状态机:消息有
editing | streaming | done | error几种状态,UI 分别处理。
数据库 schema:
message {
id, conversation_id, role, content,
parent_id, // 编辑后的新分支
version, // 同一节点的多版本
is_active // 当前显示的版本
}
# 204. 对话分支 / Fork 怎么做?
ChatGPT / Claude 都支持"从某条消息分叉重问"。
实现:
- 数据结构从"线性 list"改成"树":每条 message 有
parent_id; - UI 在分叉点展示版本切换;
- 默认只显示一条线性路径(最新分支);
- URL 带
?branch=xxx让分享和回访能恢复对应分支。
收益:用户能探索不同问法,避免反复开新会话浪费上下文。
# 205. 语音输入 / TTS 怎么集成?
输入侧(STT,语音转文字):
- 浏览器原生
webkitSpeechRecognition(兼容性一般); - 接 Whisper API / 阿里云 NLS / 讯飞,自己录音 + 上传;
- 实时流式 STT 用 WebSocket 推送音频流。
输出侧(TTS,文字转语音):
- 浏览器原生
speechSynthesis(音色差); - 接 OpenAI TTS / Azure Speech / 火山 / 阿里 TTS;
- 流式 TTS:边生成边播(豆包同款)。
工程要点:
- 录音前先申请权限,UI 提示;
- 静音检测自动结束录音;
- 实时 STT 用 SSE / WebSocket 流式更新 UI;
- TTS 队列管理:一句一句播,能跳过 / 暂停。
# 206. 文件上传 + 处理流怎么做?
复杂场景常见:
- 前端:File API 读文件 → 压缩 / 切片 → 上传到对象存储;
- 后端:拿到文件 URL → 用 Loader 解析(PDF / Word / Excel) → 切片 + embedding → 入向量库;
- 会话注入:把文件 ID 写入当前 conversation 的 metadata;
- 检索:用户提问时,先检索该 conversation 关联的文件;
- UI:上传时显示进度,处理中显示 loading,处理完显示文件卡片。
注意:
- 大文件分片上传(避免超时);
- 异步处理(不阻塞对话);
- 处理失败时给清晰错误(PDF 加密 / 编码异常等);
- 单用户的存储配额必须控制。
# 207. Markdown 渲染中的 XSS 安全?
LLM 输出会被渲染成 Markdown / HTML,潜在 XSS 风险:
- 用户问"输出
<script>标签" → 模型照写 → 直接渲染就执行了; - 第三方 RAG 文档里夹带恶意脚本。
防御:
- 用 DOMPurify 等库过滤 HTML;
- Markdown 渲染器关闭 raw HTML(
marked设sanitize、react-markdown默认安全); - 代码块单独渲染(用
<pre><code>包裹,不解析); - iframe 嵌入要警惕;
- 用户输入也要消毒,不能让用户在自己问题里塞攻击。
# 208. 移动端 AI 应用有什么特殊问题?
不是把 Web 缩小那么简单:
- 键盘弹起:消息列表要重新计算 viewport 高度;
- 流式更新滚动:要避免每个 token 都触发滚动;
- 后台切换:iOS / Android 切到后台后流式可能断,要做重连;
- 网络抖动:弱网下 SSE 易断,要支持断点续传 / 重试;
- 输入法预测:避免误触发发送;
- 语音输入:移动端用户期望更高;
- 流量提示:长文 / 图片传输前提示用户;
- 省电:长时间流式 + 不间断渲染会发热掉电。
# 209. 怎么实现"AI 自动补全代码"(Copilot 同款)?
前端流程:
- 监听 cursor 位置 + 上下文(前后 200 行);
- debounce 300-500ms 后请求后端;
- 后端用 FIM(Fill-in-the-Middle)prompt 调模型;
- 流式返回,前端 ghost text 渲染;
- Tab 接受 / Esc 拒绝 / 编辑中放弃。
关键点:
- FIM-friendly 的模型才合用(DeepSeek-Coder、Qwen-Coder、StarCoder);
AbortController让新一次输入立刻取消上一次;- 接受率 / 拒绝率打点持续优化;
- 长函数分阶段补,让用户分阶段确认。
# 210. 怎么把 AI 集成到富文本编辑器(TipTap / Lexical / Slate)?
主流交互模式:
- 斜杠菜单(/):输入
/ai弹出操作面板(总结 / 改写 / 翻译 / 续写); - 选中改写:选一段文字 → 右键 / 浮动按钮 → "用 AI 改写";
- 行内补全:cursor 后显示 ghost text,Tab 接受;
- 侧边栏 AI 助手:独立面板,可与文档双向同步。
工程要点:
- AI 改写要走事务:原文 → 模型流式输出 → 替换;用户能撤销;
- 多人协作时要走 CRDT,AI 写入算特殊作者;
- 长文档别全量喂模型,只喂选中片段 + 必要上下文。
# 十、AI 提效篇(怎么用 AI 反过来帮你干活)
这一节是 2026 年面试新增的高频区。所有公司都在问"你日常用什么 AI 工具",能讲出真实工作流 + 踩过的坑,比"我用 ChatGPT 写代码"具体一百倍。
# 211. 你日常用哪些 AI 工具?典型的工作流是什么?
参考答案要素:
- 写代码主战场:Cursor / Claude Code / Codex / Copilot 选 1-2 个;
- 写文档 / 写脚本 / 调研:ChatGPT / Claude / 通义;
- 画图 / 生图:Figma AI / Midjourney / 国内即梦;
- 会议 / 笔记:飞书妙记 / Notion AI / 通义听悟。
工作流示例(可参考改写):
我用 Claude Code 做主力编码:早上接到需求 → 让 Claude Code 先读相关文件给出初步实现思路 → 我确认方案 → 让它写出来 + 跑测试 → 我 review + 局部修 → commit。一些零散的研究 / 文档我用 ChatGPT。每周复盘的时候让模型帮我总结这周的 commit。
讲得越具体越能加分。
# 212. Cursor / Claude Code / Copilot 这些 AI 编程工具的本质区别?
| Copilot | Cursor | Claude Code | |
|---|---|---|---|
| 主战场 | 编辑器补全 | IDE 整合 | 命令行 / Agent |
| 单次粒度 | 单行 / 单函数 | 多文件编辑 | 跨任务 Agent |
| 主力模型 | OpenAI Codex / GPT-4 | 多家可选 | Claude 系列 |
| 上下文 | 当前文件 | Workspace 全局 | 工作目录 + 工具调用 |
| 强项 | 行内补全 | 改造代码 | 完成完整任务 |
| 适合 | 加速打字 | 改造重构 | 端到端开发 |
工程上常组合:Copilot 行内补全 + Cursor / Claude Code 端到端任务。
# 213. AI 写代码最容易翻车的几种情况?
实战踩坑:
- 依赖虚构 API:模型编不存在的库函数 / 方法名;
- 版本不匹配:写的是旧版 API,你用的是新版(或反过来);
- 静默改了无关代码:让它改 A,它顺手"优化"了 B、C、D;
- 删测试 / 删错误处理凑通过:测试跑不过它就改测试;
- 不读现有约定:项目里用 antd 它写 element-ui;
- 改完不验证:声称"已修复"但其实没跑。
面试讲出来这些细节就能加分。
# 214. 怎么写一个高质量的 AI 编程指令?
不要扔一句"帮我写个登录页"。结构化指令:
背景:项目用 React 18 + Vite + antd 6 + zustand。
任务:实现一个用户列表页,要求支持搜索、分页、删除。
接口:GET /api/users?q=&page=&size= ,返回 { list, total }。
约束:
- 只改 src/pages/UserList/,别动其他文件。
- 用 antd ProTable,不要重新造轮子。
- 删除要二次确认。
- 我已经有 useAuth、useApi hook,直接复用。
完成标准:
- 列表能渲染。
- 搜索和分页能联动。
- 删除有 message 反馈。
- 写一个最小的 vitest 测试。
要点:背景 + 任务 + 边界 + 约束 + 完成标准,模型不会跑偏。
# 215. AI 写完代码你怎么 review?
一定要 review,不要直接 commit。最少这几步:
- 读 diff:每一行都过一遍,看有没有"惊喜改动";
- 跑测试 / 跑应用:能在本地跑通 + 关键路径过一遍;
- typecheck + lint;
- 看依赖:有没有新增包,是不是必要;
- 看 commit message 是否准确:别让 AI 写 "fix everything"。
AI 写的代码 ≠ 你不用读。它写得快,但你署名。
# 216. AI 帮调 bug 应该怎么用?
无效用法:把报错堆栈丢过去问"怎么修"。
更有效的用法:
- 先描述上下文:项目结构、当前任务、最近改了什么;
- 完整堆栈 + 最小复现:错误信息 + 触发步骤;
- 告诉它你试过什么、排除了什么;
- 让它先给出几个假设,而不是直接给修复方案;
- 挨个验证假设,找到根因再修。
不要让 AI 替你思考根因,让它辅助你思考。
# 217. AI 写单元测试该怎么用?
容易踩的坑:
- AI 写的测试只覆盖 happy path,没覆盖边界;
- 测试和实现耦合太紧,重构就挂;
- mock 写错,测试根本没在测;
- 看起来通过,实际没 assert 关键逻辑。
更好的用法:
- 先告诉 AI 输入输出契约,让它写"测试用例描述";
- 你 review 测试用例够不够,再让它生成代码;
- 故意改坏实现,跑测试看能不能测出来(mutation testing 思路);
- 测试要简单到一眼看懂,复杂测试反而藏 bug。
# 218. AI 帮 code review 怎么用?
让 AI 做"第一道筛"是合理的:
- 自动跑 lint / type check 看不到的问题;
- 命名 / 复杂度 / 副作用之类的"软指标";
- 安全 / 性能的一般性建议。
但不能替代人 review:
- AI 看不到业务上下文;
- AI 容易给出"安全的废话"建议(什么都建议加 try/catch);
- 关键决策(API 设计、架构)还是要人拍。
# 219. AI 帮写文档 / commit message / PR 描述?
完全可以,但有讲究:
- commit message:让 AI 看 diff 写一句话总结,你最后审一眼。我用过
aicommit类工具,命中率 80% 但还是要改; - PR 描述:让 AI 看所有 commit 写 changelog 草稿,然后你补"为什么这么做";
- API 文档 / TSDoc:让 AI 看代码生成初稿,你必须 review 准确性;
- README:自己写比让 AI 写更靠谱,README 是给人看的,要有"人味"。
# 220. AI 帮设计 API / 数据结构靠谱吗?
不靠谱当主笔,靠谱当评审。
- 让 AI 给 3 个方案比让它给 1 个方案有用;
- 让 AI 找出某个方案的潜在问题;
- 让 AI 模拟"如果未来要加 X 字段,这个设计能不能扛"。
API 设计最关键的是业务理解,AI 不知道你的业务,所以决策权永远在你。
# 221. AI 改造遗留代码(legacy code)的正确姿势?
遗留代码最危险,常见错误:让 AI 一次性"重构这个文件"。
更安全的方式:
- 先让 AI 解释这段代码做了什么(让它先理解);
- 写测试覆盖现有行为(用 AI 写测试);
- 小步重构:一次只改一个函数 / 一个职责;
- 每次重构后跑测试;
- 保留原 commit,新建分支 / PR 做对比。
不要把"重构一万行代码"当成一个 prompt。
# 222. AI 帮选技术栈 / 框架对比靠谱吗?
部分靠谱:
- 客观对比(性能、生态、上手成本)AI 给的信息 80% 准确;
- 结合业务的推荐不可信,因为它不了解你的业务;
- 最新信息(半年内的新框架、新版本)容易过时,必须查官网。
最佳用法:让 AI 列对比维度,然后你按维度自己拉数据。
# 223. 怎么避免对 AI 过度依赖?
实战感受:
- 重要决策不让 AI 拍(架构、API 设计、技术栈选型);
- 手感不能丢:定期写一段不用 AI 的代码,保持思维;
- review 不外包:AI 写的也是你的代码,你要懂;
- 不要"我让 AI 写过了所以肯定对":AI 错误率高于直觉;
- 写 prompt 比写代码更难:能说清需求才能让 AI 帮你,逻辑思考还是要练。
# 224. AI 帮做需求分析 / PRD 解析?
实战用法:
- 把 PRD 丢给 AI,让它抽取需求点(功能、约束、验收标准);
- 让它指出含糊的地方(这里没说限制条件、这里和前面冲突);
- 让它列出实现要点(要建几张表、要改几个接口、要考虑哪些边界);
- 你拿着这份草稿去和产品对齐。
把 AI 当一个"会做笔记的实习生",它善于结构化整理。
# 225. 怎么让 AI 帮你"读代码 / 接手老项目"?
接手陌生项目时最高效用法:
- 让 AI 读项目根目录 +
package.json+README→ 总结技术栈; - 让 AI 看 src 目录结构 → 推断架构分层;
- 让 AI 挑一条核心链路(比如"用户登录")走读 → 解释主流程;
- 你拿着这份"地图"去看代码,事半功倍。
Claude Code / Cursor / Codex 类工具特别擅长这件事。
# 226. AI 写脚本(一次性 ops 脚本)的正确姿势?
很多时候不值得自己写:迁移数据、清洗 log、跑 cron 任务。
实战经验:
- 明确输入输出:数据格式、文件路径、预期效果;
- 跑前先 dry-run:让 AI 加
--dry-run模式打印不执行; - 加日志 + 进度条:长时间脚本要能看进度;
- 可中断 + 可重入:跑一半挂了能从中间继续;
- 小数据集先跑一遍:再跑全量。
# 227. 让 AI 帮"写英文 / 改邮件 / 翻译" 的注意点?
- 写英文邮件:明确风格(正式 / 友好 / 简短),明确收件人;
- 翻译:来回翻译看是否丢信息;
- 技术翻译:术语先 review,AI 容易把专业术语翻成日常词;
- 多语言文档:让 AI 翻一遍 + 找一个母语同事过一眼。
# 228. AI 帮"画架构图 / 时序图" 怎么用?
实战流程:
- 让 AI 输出 Mermaid 代码:
graph LR / sequenceDiagram / classDiagram; - 在 VSCode / Typora / Mermaid Live 里渲染看效果;
- 不满意继续让 AI 改 mermaid;
- 满意后导出 SVG / PNG 用到 PR / 文档里。
不要让 AI 直接画图(多模态生成图片可控性差),让它写代码。
# 229. AI 帮"查文档 / 学新框架" 怎么用?
- 官方文档先用 AI 摘要:但要 verify 关键代码,AI 容易把版本搞混;
- 新框架快速 onboarding:让 AI 给"5 个最常用的 API 示例";
- 不要全信:新版 API 是 AI 训练后才出的,比如 React 19 / Next 16 的新特性 AI 容易写错;
- 代码示例必须自己跑:别信"我刚刚帮你写好"。
# 230. AI 帮"看性能 profile / 看 source map" 靠谱吗?
部分靠谱:
- 看 profile:让 AI 看 Chrome Performance / Lighthouse 报告总结瓶颈,靠谱;
- 看 minified 代码:AI 能读 source map 反映射后的代码,定位 bug;
- 优化建议:AI 给的是"通用建议",你的项目特定优化它不懂。
更好的用法:你自己定位到瓶颈点 → 把那段代码喂给 AI 让它给优化方案。
# 231. AI 工具的 cost 怎么控制?
公司给的 AI 工具有预算,超了要被关怀。控制思路:
- 选小模型:日常 80% 任务用 Haiku / GPT-4o-mini / DeepSeek 这种便宜模型;
- 大模型只在难任务上用:架构设计、复杂 debug;
- 避免重复对话:复杂任务一次问清楚,不要来回试探;
- 缓存常用 prompt:开发模板存起来;
- 关掉自动续传 / Background Agent:跑着不知道,就是烧钱。
# 232. AI 工具的"安全 / 数据合规"风险?
工作中要警惕:
- 不能把公司源代码 / 客户数据传给个人 ChatGPT 账户;
- 走公司统一网关 / 企业版(数据不进训练集);
- 敏感字段(密钥、客户信息)脱敏后再问;
- 生成的代码也是代码,要走 code review,不要直接合。
面试里被问"你怎么保证用 AI 不泄密",答出这几点就稳了。
# 233. AI 工具帮做技术调研 / 写技术分享的工作流?
- 第一步:明确要分享的主题 + 受众(前端组 / 全公司);
- 第二步:让 AI 列大纲(10 - 15 个点);
- 第三步:每个点让 AI 写 200 字初稿;
- 第四步:你补自己的例子 / 项目截图 / 失败经验——这部分 AI 写不出来;
- 第五步:让 AI 生成 PPT 用 Mermaid / Marp 大纲;
- 第六步:本地 review 修改,配图。
AI 帮你处理体力活,判断力和真实经验你自己出。
# 234. 怎么用 AI 帮你"晋升 / 写自评"?
不开玩笑,很多人这么用。但要小心:
- AI 不知道你做了什么:你得先列出来;
- AI 容易写得"假大空":让它优化"具体到指标 / 影响范围 / 协作角色";
- 避免明显 AI 味:成段排比、抽象动词(赋能、闭环、抓手)多半要改;
- 最后自己读一遍:能不能复述出来。如果不能,说明写虚了。
# 235. 长期看,AI 对前端工程师意味着什么?
实诚答法(面试这种题不要装高调):
- 门槛上升:以前写组件、调样式就能干活,现在这部分 AI 半秒做完;
- 架构 / 业务 / 系统设计 的权重上升:决策能力比写代码更值钱;
- 学习曲线变陡:跟不上 AI 工具的人会落后;
- 不是替代,是升级:会用 AI 的前端 > 不会用 AI 的前端;
- 健康的心态:把 AI 当协作伙伴,不当奴隶也不当神。
# 236. 怎么用 AI 复盘一周 / 一月的 commit?
实用工作流:
git log --since="1 week ago" --pretty=format:"%h %s%n%b" --no-merges拿到所有 commit;- 把列表喂给 AI,让它按主题分类(feature / bugfix / refactor / chore);
- 让它写两份:对内技术周报(细节) + 对外业务周报(成果);
- 你补"为什么这么做" + "踩过什么坑"。
提示词模板:
帮我整理这一周的工作,按"完成的功能 / 解决的 bug / 重构 / 文档"四个分类。
每项写 1 句话,强调对业务的影响和量化指标。
风格简洁、可读、面向非技术 leader。
# 237. AI 帮处理 Excel / CSV / JSON 数据怎么用?
实战路径:
- 结构化整理:把"乱格式"的数据用 AI 转成规范 schema;
- 批量改写:让 AI 写 Python / Node 脚本,跑 dry-run 看输出再批量;
- 数据清洗:让 AI 列出"可能的脏数据模式",再写规则过滤;
- Excel 公式:让 AI 写复杂公式(VLOOKUP 嵌套、数组公式),可读性差但能跑;
- 直接 ChatGPT Data Analysis:上传文件让它跑代码(适合一次性分析,不要长期依赖)。
提示词模板:
我有一份 CSV,字段是 [...],目标是 [...]。
请写一个 Node.js 脚本,要求:
1. 支持 --dry-run 模式
2. 异常数据写到 error.log
3. 输出每一步进度
# 238. AI 帮做产品 / 设计 brainstorm?
不是让 AI 拍板,是让 AI 当反弹墙:
- 让它列当前方案的潜在问题(10 个);
- 让它扮演典型用户 / 竞品给你提反馈;
- 让它给3 个不同的解决方向让你选;
- 让它模拟 5 年后这个产品会被怎么颠覆。
不要问"你觉得 XX 怎么样"(它一定说"很好"),要问"找 5 个理由说为什么不该做 XX"。
# 239. AI 帮写周报 / 月报 / 述职报告?
提示词技巧:
- 先输入事实:列出"做了什么、改了什么文件、解了什么 bug";
- 指定风格:简洁 / 详细 / 数据驱动 / 故事化;
- 限制字数;
- 指定结构:成果 / 难点 / 协作 / 改进;
- 要求量化:每点尽量带数字(前后对比、用户量、性能提升)。
最后一定自己读一遍:能不能口头复述出来?不能的话就是写虚了。
# 240. AI 提效的"反模式"有哪些?
工作中容易踩的坑:
- 凡事先问 AI:简单事情靠 AI 反而慢;
- AI 给的答案不验证:当成事实直接用;
- 代码 review 外包给 AI:自己不读就 commit;
- AI 写的注释 / 文档不改:充满"如上所述、综上所述";
- 越聊越长不止:来回十几轮还没解决,直接看文档 / 看源码更快;
- 过度依赖单一工具:AI 不可用时啥都不会做;
- 不积累自己的方法论:每次都重新问 AI,没有沉淀。
健康的工作流:先想 → 上 AI 加速 → review → 沉淀到 own playbook。
# 241. AI 帮你"学新框架 / 新工具"的最快路径?
参考流程:
- 让 AI 给你一份 30 分钟入门路径(核心概念 + 最小 demo);
- 让它对比你已会的框架("React 开发者怎么理解 Svelte");
- 跟着写一个最小可运行项目;
- 让 AI 帮你列 5 个最常见踩坑 + 解决方案;
- 实际项目尝试 → 出问题再回头问;
- 一周后写一份自己的小结(强迫输出加深记忆)。
关键:别只看,要写。AI 让"看懂"变得容易,但只有"写出来"才真懂。
# 242. AI 帮你做技术博客 / 知识沉淀?
实战做法:
- 大纲:让 AI 从你的笔记 / commits / 问答记录里抽取"值得写的话题";
- 初稿:你列要点,AI 扩展段落;
- 改写:AI 给的初稿"AI 味"重,用"删形容词、加例子、加自己的话"三招过一遍;
- 配图:让 AI 生成 Mermaid 流程图 / 表格;
- 校对:让 AI 当 reviewer,从读者角度提"哪里不清楚"。
写完后:自己讲一遍能不能讲明白,是检验质量的硬指标。
# 243. AI 帮你做 OKR / 目标拆解?
公司层级 OKR 落到个人时,让 AI 帮你:
- 把模糊目标翻译成可衡量动作;
- 让它列出潜在阻塞 / 依赖;
- 让它模拟季度末复盘,提前看到"哪些指标会卡住";
- 给一份周维度的拆分计划。
记住:AI 给的是模板,真正的目标取舍只能你自己拍板。
# 244. 怎么用 AI 提升英文 / 跨国协作?
- 写英文邮件 / 文档:先中文起草,让 AI 翻译 + 优化语气;
- 接收英文长邮件 / PR review:让 AI 总结要点 + 列出"必须回应的问题";
- 会议:飞书妙记 + Notion AI 自动转录 + 摘要;
- 跨时区沟通:让 AI 帮你写"非阻塞式回复"模板(明确说清楚下一步、避免无谓 ping)。
提示:英文表达从"语法对"到"地道"中间还有一大段,让 AI 多给几个候选自己挑。
# 245. 用 AI 学竞品 / 做技术调研的工作流?
参考流程:
- 收集竞品的公开资料(官网、文档、博客、PR);
- 让 AI 抽取"它解决了什么问题、用了什么技术、有什么独特性";
- 让 AI 对比"我们家做法 vs 竞品做法";
- 让 AI 帮你列问竞品的好问题(如果以后能聊到他们工程师);
- 自己亲测竞品,形成第一手感受——这个 AI 替代不了。
# 246. Claude Code 的架构是什么样的?
理解 Claude Code 别只把它当成"命令行版 Cursor"。它本质是 Agent Loop + 多层治理:
- 核心 Loop:标准 Agent Loop(思考 → 工具调用 → 观察 → 再思考),但循环里能调几十种内置工具;
- 工具层(Tools):Read / Write / Edit / Bash / Grep / WebFetch / Agent / TodoWrite 等几十个,每个都有完整 schema;
- MCP 层:通过 MCP 协议把外部能力(数据库 / Figma / 浏览器 / 自研工具)接进来;
- Skills 层:可复用的"能力包",包含 prompt + 工具组合 + 触发条件(如
dev-guide/brainstorming); - Memory 层:
CLAUDE.md(项目级)+~/.claude/CLAUDE.md(全局)+memory/目录(结构化记忆); - Hooks 层:用户可配置的脚本,能在工具调用前后插入校验 / 自动化动作;
- Permissions 层:哪些工具自动允许、哪些每次问、哪些禁止。
记一句话:Claude Code 真正强的不是模型,是治理(governance)——这套分层让 AI 编程从"放飞"变成"可控"。
# 247. Claude Code 的"治理"具体怎么做?
四件套从粗到细:
- CLAUDE.md:项目级指令文件,约定技术栈、命令、不要做的事、不要碰的文件。每次会话自动加载;
- Skills:把"对这个项目怎么干活"封装成可调用的能力。比如
dev-guideskill 列出本仓库所有命令 + 部署流程,模型按需读; - Hooks:在
pre-commit、tool-call-before/after这些事件点跑用户脚本,能做格式化、敏感词过滤、危险命令拦截; - Permissions:
settings.json里精确控制哪些工具 / 哪些参数模式可以自动跑,哪些必须用户点确认。
实战收益:
- 团队新人接手项目,AI 自动遵守约定(避免反复教);
- 危险操作(
rm -rf、force-push)必须人工二次确认; - 跨项目复用 Skills,省掉重复教模型。
# 248. 什么是 Spec-Driven Development(SDD)?为什么 AI 时代需要它?
SDD = 先写规范再写代码,本身不是新概念,但 AI 编程让它复活。
为什么 AI 时代必须:
- AI 理解需求不靠谱:你说"加个登录",它可能给你 Session 也可能 JWT,结果跑偏;
- AI 写的代码缺决策上下文:关掉聊天窗口决策就没了,后来人看不懂为啥这么做;
- AI 生成速度太快,review 跟不上:缺一层"先达成共识再让 AI 写"的过滤。
SDD 的核心动作:在让 AI 写代码前,先用文档把**「为什么 / 做什么 / 怎么做」**写清楚,模型按文档执行,结果可追溯、可对齐、可审计。
# 249. OpenSpec 是什么?解决了什么问题?
OpenSpec 是把 SDD 工程化的工具,主要解决 AI 编程的三个痛点:
| 痛点 | OpenSpec 解法 |
|---|---|
| 需求偏差(AI 不懂你真要什么) | 用 proposal.md 把"为什么 / 不做会怎样"写下来 |
| 设计漂移(AI 一会儿用方案 A 一会儿用方案 B) | 用 design.md 锁定架构决策、接口、数据流 |
| 实施失控(AI 顺手改一堆无关代码) | 用 tasks.md 列出可验证的具体任务 |
| 决策遗失(下次会话又重头讨论) | 用 changes/ 目录归档每次变更的完整提案 |
工程上 OpenSpec 把"和 AI 聊天"变成"和 AI 共同维护一份蓝图"。
# 250. OpenSpec 的核心三件套:proposal / design / tasks 各写什么?
proposal.md:为什么要做。背景、业务痛点、不做的代价、成功标准。一两屏长度,不写技术;design.md:技术怎么实现。架构决策、接口定义、数据流、依赖、风险点、备选方案对比。这是 AI 写代码时的事实来源;tasks.md:具体要做哪些动作。可执行清单,每项粒度小到能被一次executing-plans跑完。
附加:
specs/<capability>/spec.md:当前系统的稳定能力规范(事实记录,不是变更);changes/<change-id>/:每次变更的完整目录;changes/archive/<date>-<id>/:完成后归档。
# 251. OpenSpec 的双文件夹模型(specs vs changes)是什么意思?
OpenSpec 区分两类内容:
specs/:当前系统已稳定的事实规范。"系统现在长这样";changes/:每次变更的完整提案。"这次要把系统改成怎样"。
工作流:
1. /opsx:propose → 在 changes/<id>/ 下生成 proposal + design + tasks
2. 人工 review design.md
3. 执行 tasks.md(交给 Superpowers / Claude Code)
4. 完工后 /opsx:archive → 改动反向更新 specs/,change 归档到 changes/archive/
精髓:变更和事实分离。下一次会话来,看 specs/ 知道系统现状,看 changes/archive/ 知道历史决策。AI 不会重头讨论已经决定过的事。
# 252. Superpowers 是什么?提供了哪些核心能力?
Superpowers 是把"工程纪律"封装成 Skills 包。核心能力:
| Skill | 干什么 |
|---|---|
brainstorming | 创造性工作前先发散,避免 AI 跑偏 |
writing-plans | 把目标拆成可执行的实施计划(带文件、命令、验证步骤) |
executing-plans | 严格按计划执行,跑完一步勾一步 |
test-driven-development | 强制先写测试再写实现("会删掉测试之前写的代码"——硬约束) |
systematic-debugging | 调 bug 的系统方法:复现、隔离、根因、修复、验证 |
code-reviewer | 独立 review pass,不和实现混在一起 |
verification-before-completion | 完成前必须跑过验证(测试 / 构建 / 真访问) |
worktrees | git worktree 隔离开发,避免污染主分支 |
简单说:OpenSpec 管"要做什么",Superpowers 管"怎么做得专业"。
# 253. Claude Code + OpenSpec + Superpowers 三件套是过度工程吗?
被面试官追问最容易翻车的题,记住一个观点:按项目规模分档,不是非黑即白。
| 项目规模 / 类型 | 推荐配置 |
|---|---|
| 30 分钟脚本 / 一次性任务 | 只用 Claude Code,跑完丢 |
| < 2h 探索性原型 | Claude Code + 必要时 brainstorming |
| 2-8h 个人项目 / 小功能 | Claude Code + Superpowers(保质量) |
| 4-16h 团队项目 / 跨人协作 | 全套(OpenSpec 留决策痕迹 + Superpowers 守纪律) |
| 长期维护 / ToB 交付 | 全套 + 严格 archive 流程 |
不分场景上全套 = 过度工程;不分场景拒绝全套 = 野路子。务实地按场景挑。
面试答法:
我会按"任务可逆性 + 跨人协作度 + 长期维护可能性"三个维度判断。一次性脚本直接 Claude Code,团队级功能必上 OpenSpec 留决策痕迹。
# 254. OpenSpec 的常见踩坑有哪些?
实际用过的人会踩到这些:
- 完成后忘了 archive:下一次会话以为是新需求,重复实现已有功能;
- 把 spec 写成伪代码:太具体反而限制 AI 实现空间,应该停留在"接口 / 数据流 / 决策"层;
- 跳过 brainstorming 直接 propose:技术选型偏差,AI 写到一半才发现方向不对;
- proposal 和 design 混写:proposal 只讲"为什么",design 才讲"怎么做";
- tasks 颗粒度太大:一项
tasks跑两小时,AI 中途跑飞; - OpenSpec 和 Superpowers 没有串联:用了 propose 但执行时没走 TDD / review,等于半套。
避免方式:在 CLAUDE.md 明确写"propose 之后 tasks 必须走 Superpowers 的 TDD + verification + code-review 链路"。
# 255. "你日常怎么用 AI 提效"被问到,怎么答得让人记住?
把流程讲具体、有例子、有反思。参考模板:
我们团队最近上 AI First 工作流,分三层:
1. **决策层**:用 OpenSpec 先写 proposal + design 锁定方向。
解决的痛是:以前一句话需求让 AI 干,常常跑偏 + 决策没留痕。
2. **执行层**:Claude Code 跑 Agent + Superpowers 守纪律。
关键约束:跑功能必须先写测试(TDD skill 强制),完成前必须 verify。
实战收益:上线后回归率明显下降,且改完代码自带 review pass。
3. **沉淀层**:每个变更跑完 archive 到 changes/archive/,
下次有人接手能直接读历史决策,省掉一遍口头同步。
踩过的坑:
- 早期 OpenSpec 写得太详细,反而限制实现 → 后来 design 只写决策不写代码;
- Superpowers 全开太重 → 现在按任务规模分档,一次性脚本不用全套。
我自己最大的体感:AI 写代码的速度上限不是模型决定的,是"治理"决定的。
有治理 = AI 是高级实习生;没治理 = AI 是熊孩子。
要点:有架构、有指标、有反思,是讲故事不是背概念。
# 十一、综合追问 & 场景题
这一节是把前面所有知识揉到具体场景,面试官最爱问。能讲出真实方案就赢。
# 256. 场景题:公司想做一个"内部知识库问答机器人",让你设计技术方案。
参考答案(30 秒能讲完的版本):
- 数据层:把 Confluence / 内部 Wiki / 飞书 / Git 文档汇总,做 ETL 进入统一存储;
- 切片 + Embedding:递归切分(500/50 overlap),用 bge-m3 入 Milvus / pgvector;
- 检索:Hybrid Search(ES BM25 + 向量),用 bge-reranker 重排 top 5;
- 生成:Claude / Qwen,prompt 强制带引用 + 拒答;
- 接入层:Next.js BFF + SSE 流式,Slack / 飞书机器人 + 网页 UI 双入口;
- 可观测:Langfuse 自部署,监控 TTFT / 召回 / 满意度;
- 合规:私有化部署 / 数据不出网 / 审计日志;
- 运营闭环:用户点踩的样本进入"待整理"队列,由文档负责人补充 / 更新。
面试官追问:
- "为什么不直接用 ChatGPT?" → 数据合规 + 内部知识;
- "为什么 Hybrid 不只向量?" → 产品编号 / 错误码 / 专有名词;
- "怎么评估效果?" → 准备 100 条 ground truth + RAGAS 跑回归。
# 257. 场景题:让你做一个"代码评审 Agent",怎么设计?
最小可行:
- 触发:GitHub Actions / GitLab Webhook,PR 创建时拉 diff;
- 预处理:识别变更文件类型、过滤 vendor / lock / generated;
- Tool 集合:read_file、search_code、run_linter、run_tests;
- Agent 流程:
- 读 diff → 理解改了什么;
- 看 related files 拿上下文;
- 跑 lint / type check 看明显问题;
- 用 LLM 评审 → 输出结构化建议;
- 输出:行级 comment + 总体评分 + 必须修 / 建议修两档;
- HIL:高严重度自动 request changes,其他只提建议;
- 反馈闭环:开发者标记"无效建议",反过来调 Agent。
要点:让 Agent 跑工具拿事实,不要让它凭"读 diff"瞎评。
# 258. 场景题:公司 ToB 客户要私有化 LLM,从硬件到部署你怎么选?
阶段化:
- POC:单卡 A10/A100,跑 Qwen-14B AWQ 量化版,Ollama / vLLM 起来快;
- 试运行:2-4 卡 H800 / 4090 部署,跑 32B / 70B AWQ,vLLM + nginx 反代;
- 生产:8 卡 H100 集群 + K8s + vLLM serverless 模式 + Prometheus + Grafana;
- 监控:tokens/s、并发、显存、温度、错误率;
- 备份模型:主模型挂时自动切到备模型。
要点:别一上来上 70B,先证明小模型 + RAG 业务跑得通,再扩。
# 259. 场景题:让你优化一个"AI 回答平均要 30 秒"的产品,怎么排查?
按"用户感知"维度拆:
| 维度 | 排查 | 优化 |
|---|---|---|
| TTFT | streaming 是否开 / 网关是否缓冲 | 上 SSE / 关闭 buffer |
| 首跳网络 | 是否走 CDN / 边缘 | Edge Runtime / CDN |
| Prompt 长度 | system + 历史是否过长 | 压缩 + Prompt Caching |
| 工具调用 | 串行 vs 并行 | 改并行 |
| RAG 检索 | 单次召回耗时 | 加索引 / Reranker 异步 |
| 模型 | 是否用了 o1 / DeepSeek-R1 这种慢模型 | 切到 Haiku / GPT-4o-mini |
| 后端处理 | 是否在 LLM 调用前同步等了一堆数据 | 提前并行加载 |
不要只看一个数字,画成瀑布图才知道时间花在哪。
# 260. 场景题:让你做一个"AI 客服",怎么保证不乱说话?
防护多层:
- 意图分类:先用小模型分类用户意图,只有白名单内意图才走 AI 回答;
- 强 system prompt:明确回答范围 + 拒答规则;
- RAG 限定知识源:只用公司知识库,不让模型用通用知识;
- 关键事实校验:金额、订单状态、政策类回答用代码二次确认;
- 敏感词过滤:输出前过一层;
- HIL 兜底:遇到投诉 / 复杂诉求 → 转人工;
- 审计 + 回溯:所有对话保存,方便事后排查;
- 持续学习:用户点踩样本 → 改 prompt / 加 FAQ。
宁可"我不知道"也不能"瞎说"。
# 261. 场景题:把 ChatGPT 类的对话产品迁移到你们的国产替代方案,应该注意什么?
不只是改 SDK:
- Tokenizer 不同:上下文 token 估算要重新校准;
- system / user / assistant 行为差异:有些国产模型对 system 不那么"听话",要在 user 里补强;
- 工具调用格式:每家略有差异,封一层适配器;
- 流式协议:不一定都标准 SSE,写 fallback;
- 速率限制 / 重试:不同家限流策略不一样;
- 多模态接口:图片 base64 / URL 支持度不同;
- 价格 / token 模式:算成本要重新做。
测试一定要跑端到端真实场景而不是单元测试。
# 262. 场景题:用户对 AI 输出不满意怎么办?
产品 / 工程都要联动:
- 用户视角:点踩 / 重试 / 编辑 / 切模型;
- 数据视角:点踩样本进入标注队列,每周一次回顾改进 prompt / 知识库;
- 指标视角:监控点赞率 / 点踩率 / 重试率 / 满意度;
- 闭环视角:改进上线后 A/B 看指标是否上升。
不要只在用户体验上做"满意度评分",要落到可改进的样本。
# 263. 场景题:模型出现"复读机"现象怎么处理?
复读 = 同一句话不断重复,原因可能:
- temperature 太低 + presence_penalty 太低;
- 模型陷入局部最优;
- 部分量化模型常出。
处理:
- 适度提高 temperature(0.5-0.7);
- 设置 presence_penalty / frequency_penalty;
- 用更大的模型;
- streaming 时前端检测连续 N 个 token 重复 → 中断;
- 后端检测连续 N 句重复 → 中止并重试。
# 264. 场景题:怎么做"AI 应用的灾备 / 降级"?
模型挂了你的产品不能挂:
- 多模型互备:主模型超时 → 自动切到备模型;
- 降级回答:模型完全不可用时返回 FAQ / 文档链接;
- 缓存兜底:常见问题预生成答案,挂了也能答;
- 熔断:错误率高于阈值时自动熔断,不要持续重试拖垮系统;
- 状态保留:用户的会话别因为模型挂了就丢,能继续接着用。
# 265. 自我介绍:怎么把"我做过 AI 项目"讲得让面试官眼前一亮?
模板:
我在 [项目名] 里做了一个 [一句话功能],
解决的核心问题是 [业务痛点]。
技术上用了 [前端栈] + [LLM + 工具] + [RAG / Agent / 工作流],
关键决策点是 [选型 + 为什么]。
上线后 [一两个指标] 提升了 [X%],
我自己负责 [模块 / 端到端],
踩过的最深的坑是 [真实事故],最后用 [方案] 解决。
要点:有数字 + 有决策 + 有踩坑,三件套缺一不可。
# 266. 场景题:让你设计一个 Cursor 同款 AI 编辑器,怎么做?
参考方案:
- 编辑器内核:Monaco / CodeMirror 起步,复用社区基础;
- AI 集成方式:
- 行内补全(ghost text + FIM);
- 选中改写(command palette / 浮动菜单);
- 侧边栏对话(项目级问答);
- 端到端任务(Agent 跑工具改文件);
- 上下文管理:当前文件 + workspace 索引(用向量库);
- 工具集:read_file / write_file / edit_file / run_command / search_code;
- Agent 模式:plan + execute + diff 三阶段;
- diff 预览:AI 改动以 diff 形式预览,用户 Accept/Reject;
- 历史回滚:每次 AI 改动一个 commit;
- 多模型支持:用户可切 Claude / GPT / 本地模型;
- 隐私模式:可选不把代码上传给云模型。
被追问要点:
- 为什么 Cursor 比 Copilot 好?→ workspace 级上下文 + 多文件编辑;
- diff 预览为什么必须?→ 用户对 AI 改动可控;
- 本地模型有什么用?→ 合规 / 离线 / 省钱。
# 267. 场景题:AI 监控告警归并系统怎么做?
业务背景:监控系统一天发几千条告警,人工看不过来。
方案:
- 采集:从 Prometheus / Grafana / Sentry / 日志系统 webhook 接告警;
- 归一化:把不同来源的告警转成统一 schema(service / severity / message / time);
- 聚类:用 embedding 做向量聚类,相似告警归一组;
- AI 总结:每组让 LLM 生成"根因猜测 + 影响范围 + 建议动作";
- 优先级:用 LLM 评分 P0-P3,根据评分推不同通道(电话 / IM / 邮件);
- 关联历史:检索过去类似告警的解决记录,附在新告警旁边;
- HIL:高严重度自动推 + 人工确认才能 ack;
- 闭环:值班人员标"误报 / 已解决"反向训练系统。
收益:值班人从看 1000 条到看 20 组,注意力聚焦。
# 268. 场景题:智能客服路由(什么时候转人工)?
不能让 AI 永远兜底。分流策略:
| 场景 | 处理 |
|---|---|
| 简单查询 / FAQ | AI 直接答 |
| 涉及金额 / 退款 / 投诉 | 直接转人工 |
| 用户连续点踩 N 次 | 转人工 |
| AI 检索后置信度低(无相关文档) | 转人工 |
| 用户明确说"转人工" | 立即转 |
| 涉及合规 / 法务 | 转人工 |
| 情绪检测:用户情绪激动 | 转人工 |
| 关键词触发("投诉 12315") | 转人工 + 飞书报警 |
转人工时带上对话摘要,人工不用从头看。
# 269. 场景题:让 AI 把设计稿自动转代码?
务实方案(注意:完全自动不可行,辅助才靠谱):
- 输入:Figma URL 或截图;
- 解析:调 Figma API 拿出结构化设计描述(不是裸图);
- 组件匹配:和项目已有组件库(antd / shadcn)做 mapping;
- 代码生成:让 AI 输出用项目组件实现的代码,不是从零写;
- 样式提取:颜色、字号、间距从 design token 取;
- 响应式:要求 AI 输出多个 breakpoint;
- 人工 review:开发者 review + 微调,不能 100% 替代。
避免误区:让 AI"看图写代码"会得到一堆 inline 样式的烂代码,结合设计系统的代码生成才有产品价值。
# 270. 场景题:AI 应用的 SLA 怎么保证?
外部模型不可控,SLA 必须做兜底:
- 多模型互备:主模型挂自动切;
- 本地小模型兜底:基本能答简单问题;
- 熔断 + 降级:错误率高于阈值就熔断,UI 降级为"暂不可用";
- 缓存预热:常见问题预生成答案;
- 告警:错误率 / 延迟 / token 用量异常立刻报警;
- SLA 透明化:状态页 + 月度报告;
- 限流 + 公平队列:避免少数用户拖垮所有人。
ToB 客户要看 SLA 数字,说不准就别承诺。
# 271. 场景题:多端 AI 助手(Web + iOS + Android + 桌面)怎么统一?
架构:
- 核心 API 后端:唯一事实来源,所有端都调它;
- 会话存储:服务端为主,端侧只缓存;
- 流式协议:SSE 或 WebSocket,端侧统一适配;
- 同步:端侧 push 新消息到服务端 + 拉取其他端的更新(WebSocket 推送);
- 离线:端侧支持只读历史 + 草稿;
- 能力差异:端侧能力不一致(如桌面端能跑本地模型、移动端只能调云),后端按 capability 协商;
- 共享 prompt / 配置:通过 globalConfig 接口下发。
不要每端各写一套核心逻辑,重 BFF 或 SDK。
# 272. 场景题:AI 应用全链路可观测性怎么做?
至少四层:
| 层 | 工具 | 看什么 |
|---|---|---|
| 前端 | Sentry / Web Vitals | 客户端错误、TTFB、流式卡顿 |
| 接入层 | Nginx / API Gateway | 请求量、错误码、限流 |
| LLM 调用层 | LangSmith / Langfuse | 每次调用的 prompt、token、cost、耗时 |
| Agent / RAG | 自定义 trace | 每步 plan / tool / retrieval / output |
聚合:
- 全链路 trace_id 串起来;
- 每个请求能从前端点击 → 后端 → LLM → 工具调用 → 回包,一条线追完;
- 关键指标进 Grafana 看实时;
- 错误归类 + alerting。
没有可观测 = 没法调优 = 没法上线。
# 273. 场景题:AI 应用合规风险有哪些?怎么处理?
不只是技术问题,是法务问题:
- 数据出境:海外模型涉及,国内业务要走合规审批;
- PII 保护:身份证 / 手机号 / 地址不能明文进 prompt;
- 未成年人保护:可能触发实名 + 内容过滤;
- 大模型生成内容备案(国内):明确告知用户"内容由 AI 生成";
- 版权:生成内容的归属、训练数据的合法性;
- 审计:所有对话保留 N 天,监管要求随时调取;
- 拒答场景:政治、暴力、医疗 / 法律建议要做明显约束。
合规上线前一定有法务过一遍。
# 274. 场景题:把团队"AI First"推进开发流程,怎么做?
不是发几个 ChatGPT 账号就行:
- 统一工具链:选一两个核心工具(Claude Code / Cursor / Copilot),统一付费 / 培训;
- 统一 prompt 库:把团队验证过的高质量 prompt 共享出来;
- 统一 MCP / Skills:把内部工具封装成可复用能力;
- 代码规范同步给 AI:CLAUDE.md / .cursorrules 写好;
- 培训 + 分享:每周一次 AI 用法分享,沉淀 best practices;
- 指标驱动:跟踪 AI 工具使用率 / commit 中 AI 参与比例 / 节省工时;
- 底线规则:什么不能让 AI 做(提交不读、改生产、写测试不审);
- 合规护栏:源代码 / 客户数据不进个人账号。
记住:工具好不好用,看团队;不是发完账号就万事大吉。
# 275. 终极开放题:如果让你三年内深耕一个 AI 方向,你会选哪个?
参考思路(不要背,要按自己情况答):
- AI Agent 工程:架构 + 工具 + 落地,需求量最大;
- Context Engineering / Prompt Engineering:基础设施型岗位;
- RAG / 知识工程:ToB 长青;
- AI 基础设施:网关 / 推理 / 评估,技术门槛高;
- 多模态 / 端侧:手机 / 车机 / 机器人,硬件结合;
- AI 安全 / 对齐:研究偏多,国内还没大规模商业化;
- AI 产品:把模型能力翻译成用户价值,需求量上升。
要点:
- 选自己有兴趣 + 公司有资源的方向;
- 不要追最热(红海早进的人吃肉,晚进的人吃灰);
- 每个方向都需要工程能力 + 业务理解,纯算法岗在缩。
# 附录:常用速查表(背版)
# AI 名词速查(面试官最爱当快问快答)
| 名词 | 一句话 |
|---|---|
| Prompt | 给大模型的输入指令,控制行为 / 风格 / 思路 |
| LLM | Large Language Model,大语言模型 |
| Token | 模型实际处理的最小单元,影响计费和上下文 |
| Context Window | 一次能看到的最大 token 数 |
| Embedding | 把文本压成高维向量,反映语义相似度 |
| RAG | 检索增强生成,给模型外挂知识库 |
| Fine-tuning | 用领域数据在预训练模型上继续训练 |
| PEFT / LoRA / QLoRA | 轻量微调,省显存的代表方案 |
| Agent | LLM + 工具 + 记忆 + 规划,能自主完成任务 |
| Tool | Agent 能调用的外部功能(接口、文件、命令) |
| Function Calling | 模型按 schema 输出 JSON 决定调哪个函数 |
| MCP | Model Context Protocol,跨语言跨进程工具协议 |
| CoT | Chain of Thought,让模型先想再答 |
| ReAct | Reason + Act,Agent 的基础范式 |
| Memory | 模型的"记忆",分短期 / 长期 / 工作记忆 |
| Hallucination | 模型幻觉,听起来合理但事实错误 |
| Prompt Injection | 用户输入夹带恶意指令攻击 system prompt |
| Jailbreak | 突破模型自身安全限制 |
| Streaming | 一边生成一边推到客户端 |
| TTFT | First Token Time,首 token 出现时间 |
| Prompt Caching | 复用 KV Cache 给重复 prompt 打折计费 |
# 主流模型(2026 年)
| 厂商 | 主力 | 特点 | 适合 |
|---|---|---|---|
| Anthropic | Claude Opus 4.7 / Sonnet 4.6 / Haiku 4.5 | Agent、长文本、代码 | 复杂 Agent / 编程 |
| OpenAI | GPT-4.1 / GPT-5 / GPT-4o / o1 | 通用、工具生态 | 通用业务、多模态 |
| Gemini 2 Pro / Flash | 多模态、超长上下文 | 长文档、视频 | |
| Meta | LLaMA 系列 | 开源标杆、微调研究事实底座 | 学术研究 / 私有定制 |
| DeepSeek | V3 / R1 | 开源、推理 / 代码 / 数学强 | 私有化、降本、推理任务 |
| 阿里 | Qwen Max / Plus / Qwen-VL | 中文、私有化生态 | ToB / 多模态 |
| Moonshot | Kimi K1 | 长文本、中文阅读 | 长文档问答 |
| 智谱 | GLM-4 | 国内私有化好 | 国企 / 政企 |
| 字节 | 豆包 / Doubao | 抖音生态打通 | 字节渠道 |
| Mistral / Phi / Gemma | 1B - 14B 轻量模型 | 边缘部署、端侧推理 | IoT / 浏览器 / 端侧 Agent |
# 主流框架 / SDK
| 类别 | 推荐 |
|---|---|
| 前端 SDK | Vercel AI SDK |
| 后端 Agent | LangChain / LangGraph |
| 多 Agent | CrewAI / AutoGen / LangGraph |
| RAG | LlamaIndex / LangChain |
| 向量库 | pgvector / Milvus / Qdrant / Chroma |
| 评估 | RAGAS / DeepEval / TruLens |
| 可观测 | LangSmith / Langfuse / Helicone |
| 私有化推理 | vLLM / Ollama / SGLang |
# Prompt 万能骨架
# 角色
# 任务
# 输入
# 步骤(复杂任务必加)
# 输出格式
# 约束
# 示例(复杂任务必加)
# Agent 公式
Agent = LLM + 工具 + 记忆 + 规划
用户输入
↓
规划(拆任务)
↓
循环:思考 → 工具调用 → 观察 → 再思考
↓
输出 + 写记忆
# RAG 公式
切片 → embedding → 入库
查询 → 改写 → 向量召回 + BM25 召回 → 重排 → top-k
材料 + 问题 → LLM → 回答(带引用)
# MCP 公式
LLM ↔ Function Calling ↔ Client ↔ MCP Protocol ↔ Server ↔ Real Tools
# Memory 公式
全量 messages → 滑动窗口 → 滑动窗口 + 摘要 → 向量长期记忆 → 图谱 / 结构化记忆
第一版整理到这里。每年都会补 30-50 道新题,建议只看问题不看答案先自己讲一遍,能讲清的跳过、卡壳的再看答案。
真正能拉差距的不是题目多寡,而是有没有真的写过 Agent、调过 RAG、踩过 Memory 的坑。面试前找一个你正在用的产品想想能怎么加 AI,自己做一个最小 demo 上线让真实用户用一周,胜过刷十遍题。