1. 接口类型
① OpenAI 兼容接口(标准化,支持流式/FC,广泛支持)② LangChain 接口(ChatOpenAI 封装)③ HTTP 原生(httpx/requests)。所有模型可通过 OpenAI 兼容接口统一调用,切换只改 base_url + model。
2. 标准调用流程
构造 Prompt(System+User)→ 消息封装(messages 数组 role+content)→ 参数配置(temperature/max_tokens)→ 发起请求(同步/异步)→ 流式输出(SSE)→ 解析后处理(提取 choices[0].message + 敏感词过滤/JSON 提取)。
3. 采样参数:temperature / top_k / top_p
- Temperature 温度:Softmax 缩放因子,控概率分布平滑度。T→0 尖锐、确定保守(RAG/代码用 0 或小值);T=1 原始分布;T>1 平坦、随机发散(创意 0.7~1.0)。
- Top_k:从概率最高 k 个候选采样(k=50 只看前 50 名)。
- Top_p 核采样:从累积概率达 p 的候选集采样(p=0.9),按分布自信程度动态调整候选范围。
4. 上下文 & 上下文窗口
上下文=模型生成当前回复能"看到"的输入范围。上下文窗口=一次处理最大 Token 数(32k/128k)。本质是 KV Cache 载体——模型无长期记忆,多轮背景、RAG 资料都必须放上下文才能感知。
5. 上下文超长处理
① 文档分块(滑动窗口保连续)② 关键信息提取(TF-IDF/TextRank)③ 摘要压缩 ④ 长窗口模型(Gemini 1.5 Pro 1M)⑤ 滑动窗口只留近 N 轮 + 阶段摘要。
6. 流式输出 SSE
后端用 SSE(Server-Sent Events)。FastAPI 用 StreamingResponse 设 Content-Type: text/event-stream,stream=True 每生成 token 就 yield。前端用原生 EventSource 或 fetch + ReadableStream 接收。封装统一 JSON(含 START/MONITORING/END 状态),结束发 done/END。三层:上游 FastAPI stream=True → 中间件 SSE 长连接包 JSON → 端侧 Android 解析驱动打字机效果压缩 TTFT。
7. SSE vs WebSocket
大模型"一问一答、后端吐字"单向场景选 SSE:基于 HTTP 单向推送,原生断线重连,轻量,防火墙友好,成本低。WebSocket 全双工双向更强但增加握手开销和连接维护成本,本场景性价比不如 SSE。
8. 调用失败/超时/幻觉
失败:指数退避重试(3~10 次应对网络/超时/限流)、备用模型降级(豆包→千问)、输入检查(敏感词)、输出检测(限 token)、流式减超时。
内容错乱:① 换模型 ② 调提示词 ③ JSON 输出 ④ 增加校验模型 ⑤ 重试。
幻觉工程化:① 评估数据集(200+ 用例覆盖单位/数字/格式边界)② 约束生成(JSON mode)③ RAG 增强 ④ 多次采样+投票(高风险调 3 次取多数)⑤ 线上反馈闭环(bad case 回流)。
幻觉成因与分类:
- 两类幻觉:内在(与源内容矛盾)vs 外在(源内容无法验证,可能真但需外部认证)。
- 成因三层:数据层(训练数据虚假/重复致知识 bias)、模型层(弱 backbone / 高随机采样 top-p / 暴露偏差 / 参数知识错误)、推理层(解码随机性)。
- Faithfulness(遵循 input)vs Factualness(符合世界知识):传统任务重前者,开放域重后者。
- 最易幻觉场景:数值/日期、长文本长依赖、上下文与内置知识冲突、错误前提问题(如"氮原子序数为何是 1")。幻觉会传播污染后续生成,故主动检测比事后修复更值。
幻觉检测方法:① SelfCheckGPT(同问题多次采样,真掌握则一致、胡编则发散,无需外部知识库)② logit 低置信度触发检索验证 ③ 事实核心采样(句子后半随机性对事实性伤害大,动态衰减 top-p)④ Reference-free 四类:基于 IE / QA / NLI / 分类器。
9. 成本控制
三维治理:① 短期上下文滑动窗口只带最近 5 轮;② 长文本流式摘要(先低成本模型摘要再高阶推理);③ 长期记忆特征化(只存标签不存原始废话)。其他:记 token/成本表、高频能力查库缓存、语义缓存、Prompt Caching。
9b. 模型评测与选型
为什么静态 benchmark 不够评 LLM:主观性、测试集可能被训练时看过(数据泄露)、开放话题覆盖不到。
主流评测:① 学术基准 MMLU/C-Eval/CMMLU(知识)、GSM8K(数学)、HumanEval(代码)② Chatbot Arena(两两对抗 + 人工打分 + Elo 分,解决主观性和数据泄露)③ LLM-as-judge(GPT-4 当裁判,Vicuna 用)、PandaLM(训打分模型)。
主流模型数据量速记:LLaMA2(2T)/Falcon(1.5T)/Bloom(350B,46 语言)/ChatGLM2(1.4T)/baichuan(1.2T)。国内豆包/DeepSeek/Qwen 中文强、成本低、可私有化;闭源 Claude/GPT 复杂推理和长上下文强。
10. API 健壮性与并发
健壮性五招:① 统一调用封装(一个入口收敛所有模型调用)② 分场景差异化超时 + 指数退避重试 ③ 降级到备用模型(豆包→千问)④ 熔断与限流(下游连续失败跳闸,保护自己和下游)⑤ 非核心任务异步化(丢队列)。
并发性三招:① 模型请求池与业务请求池隔离(模型调用慢,别拖垮业务接口)② 高频结果缓存(含语义缓存)③ 分布式锁避免重复调用(同一 query 并发只算一次)。
❓ 常见追问 · 第三方模型超时怎么处理?→ ① 差异化超时 + 实时反馈提示用户(流式先吐"正在思考")② 缓存兜底保主流程不中断 ③ 非实时任务入队异步重试、结果补发 ④ 监控告警定位 ⑤ 触发轻量限流削峰。核心:超时控制 + 重试 + 降级,必要时熔断器 + 监控大盘。
❓ 常见追问 · 怎么防止重复推理浪费成本? → 幂等 key + 结果按输入 hash 缓存,重试直接命中缓存不再调模型。详见 → 后端-MQ 重复推理优化。
❓ 常见追问 · 熔断/限流/降级的区别? → 详见 后端-服务治理。限流=控入口流量;熔断=下游挂了快速失败给它恢复时间;降级=故障时返回兜底保主链路。
❓ 常见追问 · 多模型路由/备用模型怎么做? → 用路由层(OpenRouter/Neutrino 思路或自建):按成本/能力/可用性把请求分发到最合适的模型,主模型限流/故障时自动切备用;切换只改 base_url+model(OpenAI 兼容接口的好处)。
11. 多模态调用
messages 里 content 数组混排 text 和 image_url:
{"role":"user","content":[
{"type":"text","text":"这是题目和标准答案"},
{"type":"image_url","image_url":{"url": teacher_img}},
{"type":"text","text":"这是学生答题卡"},
{"type":"image_url","image_url":{"url": user_img}}
]}
12. 多模态大模型架构
三段式架构:视觉编码器(ViT 提特征)+ 连接层 + LLM(生成)。BLIP2 的 Q-Former 就是"连接层"——冻结图像模型和 LLM,中间只训 Q-Former,用可学习 query 与图像特征交互。
CLIP:对比学习把图文嵌入同一空间(图文匹配拉近、不匹配推远),是多模态检索/零样本分类基础;DALL·E/Stable Diffusion 是文生图生成模型(扩散去噪)。两者定位不同。
13. 推理性能与 KV Cache
推理两阶段:Prefill(并行处理输入 prompt 所有 token)+ Decoding(自回归逐个吐 token,每步喂回上一个)。
四大指标:TTFT(首 token 时间,实时交互关键,SSE 流式优化它)、TPOT(每 token 时间,决定感知速度)、Latency=TTFT+TPOT×输出长度、Throughput(吞吐量)。启发式:输出长度决定总时延;模型越大越慢但次线性(70B 约 13B 的 2 倍)。
KV Cache:自回归解码时把每个已生成 token 的 K/V 缓存在显存避免重算——所以推理显存涨得多且随序列长度动态变化(LLaMA-13B 单序列达 1.7GB)。传统 KV Cache 因碎片和过度预留浪费 60~80% 显存。
PagedAttention(vLLM 核心):借操作系统虚拟内存分页思想,把 KV Cache 切成固定块存在不连续显存里,块表映射逻辑块→物理块,浪费降到 <4%,能 batch 更多序列提吞吐;还支持相同 prompt 的 KV 块共享(引用计数 + 写时复制)。
深度拆解:容易踩坑的点
维度一:性能优化
⚠️ 你说 SSE 流式能压 TTFT,但流式只是让用户"更早看到已经生成的字",模型真正开始吐第一个 token 之前的时间——排队等 GPU、检索召回、prompt 拼接、System Prompt 里的长 few-shot——这些才是 TTFT 的大头。流式对这部分毫无帮助,你怎么真正降 TTFT?
流式解决的是"体感"问题(把一次性等待拆成渐进反馈),不解决"实际"问题。真正降 TTFT 要在 Prefill 之前和 Prefill 阶段本身下手:① RAG 检索并行化+提前触发(用户输入过程中就预取,而非等提交后才检索)② 精简 System Prompt/few-shot,把静态大块前缀通过 Prompt Caching/KV Cache 复用,避免每次全量 Prefill ③ 请求路由避让排队高峰、模型请求池与业务池隔离防止排队叠加 ④ 小模型先吐"正在处理"这类过渡内容争取时间,本质是体感优化不是消除等待 ⑤ 极限场景用投机采样(Speculative Decoding)用小模型起草、大模型验证降低有效延迟。要跟面试官说清楚:流式优化的是"用户感知延迟",真正的 TTFT 优化在检索、Prefill、调度这几层。
KV Cache 能省重复计算、提速,但它是用显存换时间——命中率低(比如每个用户 query 都不同、prompt 差异大)时,缓存本身反而占着显存不被复用,你怎么处理?
命中率低时 KV Cache 的收益主要不在"跨请求复用",而在"单请求内自回归复用"(这个是必然收益,跟输入是否重复无关)。跨请求复用(Prompt Caching/vLLM 前缀共享)依赖前缀相同,命中率低说明业务场景本身前缀多样,这时候:① 只缓存真正稳定的部分(System Prompt、固定模板、RAG 的公共背景块),把易变部分放后面,人为提高可复用前缀长度 ② 用 PagedAttention 降低碎片和过度预留,即使命中率不高也能减少浪费、腾出显存给更大 batch ③ 命中率低就不要强求缓存收益,转而靠批处理(continuous batching)提吞吐来摊薄单请求成本,不是所有场景都该指望 KV Cache 命中。
维度二:工程实现
⚠️ 上游大模型 API 会超时、限流、偶发 5xx,你说要重试+退避+熔断+降级——但重试本身会不会放大成本和延迟?如果下游本来就在限流边缘,你的重试策略会不会把它压垮,形成雪崩?
会,这正是重试设计最容易踩的坑。要点:① 重试次数要少(3 次量级)且退避要指数级+加抖动(jitter),避免大量请求同一时刻集中重试形成脉冲 ② 区分错误类型:限流(429)应该退避更久甚至直接降级,不该无脑重试;5xx 类瞬时故障才值得快速重试;4xx 参数错误重试没有意义反而浪费成本 ③ 熔断器在下游连续失败达到阈值时直接跳闸、快速失败,不再让重试流量打过去,给下游恢复时间窗口 ④ 重试要配合幂等 key,防止"超时了但其实上游已经处理完"导致的重复计费/重复调用 ⑤ 全链路加限流令牌桶控制并发上限,从源头限制会被重试放大的请求总量。核心认知:重试不是免费的容错手段,它本身是一种额外负载,必须和熔断、限流联动设计,否则会把偶发故障放大成系统性雪崩。
流式输出过程中,如果连接在生成到一半时断了(用户网络抖动、服务重启),已经生成的那部分内容怎么处理?前端怎么"续"上剩下的部分而不是从头再生成一遍?
后端要做到:① 已生成内容按 chunk 落盘/写缓存(比如 Redis 存 session_id → 已生成 token 序列 + 生成状态),不是纯内存态一断就丢 ② 给每次流式会话一个唯一 ID,前端断线重连时带上这个 ID 向后端查询"生成到哪了",而不是重新发起一次完整请求 ③ 如果模型本身还在继续生成(后端和模型的连接没断,只是和前端的连接断了),后端应该继续接收并缓存 token,等前端重连后从断点续传剩余部分;如果模型侧的调用也一起断了,只能选择"从已生成部分之后用原始 prompt+已输出内容当作前缀去续写",但这依赖模型支持,且续写质量不保证严格一致。④ 前端用 EventSource 原生支持重连(但重连是重新发请求,不是断点续传,断点续传要业务层自己实现)。老实说这块很多系统直接选择"断了就整个失败重来",因为断点续传的工程复杂度和收益要权衡,不是所有场景都值得做。
维度三:数据策略
幻觉问题在纯调用层面(不动模型、不做微调)能怎么缓解?温度调低、加约束、事实核查、拒答机制——这些手段里哪些是治标哪些是治本?
纯调用层的手段本质都是治标,因为幻觉的根因在训练数据和模型参数知识层面,调用层无法修正模型"内在知识错误"这一根本问题。分层看:① 治标但见效快:降低 temperature/top_p 减少解码随机性带来的幻觉(只对"推理层"幻觉有效,对"数据层/模型层"幻觉无效);JSON mode/格式约束防止结构性胡编;拒答机制(置信度低就说"不确定")是止损不是纠错。② 部分治本:RAG 把外部权威事实注入上下文,让模型"抄"而不是"编",这是调用层能做的最接近治本的手段,但依赖检索质量,检索错了照样产生幻觉。③ 真正治本的(超出纯调用层):预训练数据清洗去重、RLHF/微调对齐、事实性专项训练——这些都动了模型本身,不属于"纯调用层"。所以回答要点明:调用层的幻觉缓解都是"降低幻觉出现概率"或"幻觉出现后拦截",不是"让模型不产生幻觉",这是能力边界。
维度四:模型选型与迭代
⚠️ 换模型(豆包换千问)或者调整采样参数之后,你怎么保证线上效果不回退?有没有离线评估集加线上 A/B?离线评估通过了,线上却翻车的情况怎么避免?
需要两层保障,且要正视两者天然存在 gap:① 离线:维护一个覆盖核心场景+历史 bad case 的回归评估集(不是随手抽几条,要包含边界 case:数值、格式、长文本、错误前提问题),每次换模型/调参先跑离线评估,用 LLM-as-judge 或规则校验+人工抽检对比新旧版本指标,设定不回退的量化阈值。② 线上:小流量 A/B(1%~5%)观察真实分布下的效果、延迟、成本、用户反馈信号(比如重新生成率、人工介入率),确认无回退再逐步放量,同时保留一键回滚开关。③ 离线线上不一致的根源通常是:离线评估集覆盖不了线上长尾分布、离线用的是历史静态数据而线上是实时多样输入、A/B 桶本身有偏差。缓解办法是让离线评估集持续用线上 bad case 回流更新(形成闭环),而不是一份固定不变的题库,同时线上 A/B 的观察周期要覆盖不同时段/用户群,不能只看短期指标。老实说,离线线上完全一致是不可能的,只能通过持续回流缩小 gap,这是模型迭代的常态而非能一次性解决的问题。
线上 token 消耗/成本突然涨了(成本失控),你怎么归因?是哪个环节在"吃" token,怎么定位到具体原因并治理?
归因要靠可观测性而不是猜:① 先看维度拆分——按接口/场景/用户群/模型版本分别统计 token 消耗,定位是整体涨还是某个场景突增(比如某类 query 触发了异常长的 RAG 召回或死循环重试)② 常见根因:Prompt 模板膨胀(历史对话/few-shot 越堆越多没做滑窗清理)、RAG 召回块数或长度配置被误改、重试没有幂等导致同一请求被算多次、Agent 多步调用链变长(工具调用次数失控,比如死循环反复调用)、拒答/纠错逻辑触发了多次重复请求。③ 定位手段:调用链埋点记录每次请求的 prompt 长度/输出长度/调用模型/是否重试,做成看板按时间对比;对比成本骤增前后的配置变更记录(往往是某次上线改了参数)。④ 治理:滑动窗口/摘要压缩控制上下文长度、缓存去重减少重复调用、给单次调用设置 token 上限熔断、Agent 链路加最大步数限制防止死循环。核心思路:成本失控本质是"某个环节的 token 消耗偏离预期",治理前必须先拆解定位到环节,不能笼统地"降 temperature/减少调用"了事。
评论