AI 踩坑记录
G AI 域的踩坑与排查。每条固定四段:症状 → 原因 → 解法 → 预防。 系统学习见 AI 域,成本相关见 13 · 成本与模型路由。
429 / 限流:请求被拒
症状
HTTP 429 或错误:rate limit exceeded / 429 too many requests,
偶发在并发请求或批量任务中,重试后恢复。原因 超出供应商的 RPM/TPM(每分钟请求数/Token 数)配额。常见触发:循环里同步请求、并发没控制、消息变长后 TPM 先到顶。
解法
# 控制并发 + 退避重试
import asyncio, random
async def call_with_retry(func, *, max_retries=3):
for i in range(max_retries):
try:
return await func()
except RateLimitError:
await asyncio.sleep(2 ** i + random.random()) # 指数退避
raise RuntimeError("重试后仍限流")预防 并发打满前先看配额;批量任务用固定速率(semaphore + 间隔);超长输入先算 token 数再决定是否截断。
token 超限:输入太长被截断/报错
症状
报错 max context length exceeded / context_length_exceeded,
或响应看起来"忘记"了对话开头的内容。原因 请求总 token(输入 + 输出预留)超过模型上下文窗口。对话越长越容易触发;有些 SDK 静默截断最早的轮次导致"失忆"。
解法
# 请求前估算并裁剪,预留输出空间
max_context = 128_000 # 按模型配置
reserve = 4_000 # 给输出留的预算
while estimate_tokens(messages) + reserve > max_context:
messages.pop(0) # 丢最旧的一轮,再裁剪预防 长对话要做摘要/分层裁剪(见 12 · 上下文工程);固定输出预算,别让用户消息无限撑爆。
流式响应中断 / 解析错位
症状
SSE 流式输出到一半断开,或 JSON 被切成两半、`JSON.parse` 抛错;
前端拿到的是拼接错位的碎片。原因 三处都可能:网络/网关超时中断流;输出超过 max_tokens 被截断(JSON 不完整);前端按"整块"解析而不是按流累积。
解法
// 正确姿势:累积整个流,流结束时再一次性解析
let text = ''
const reader = res.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
text += new TextDecoder().decode(value)
}
const data = JSON.parse(text) // 流结束后再 parse预防 流式场景不要对半成品做 JSON.parse;需要"边出边用"就要求模型输出稳定结构(如每行一条 JSON);max_tokens 留足余量。
embedding 维度不一致:向量入库/查询报错
症状
向量维度 mismatch:dimension 1536 vs 3072 / column "embedding" is of type vector(1536)原因 入库和查询用了不同模型(如先 text-embedding-3-small=1536,后 text-embedding-3-large=3072),或表结构写死了维度。pgvector 要求列维度固定且一致。
解法
-- 统一模型后,要么重建列,要么迁移数据
ALTER TABLE documents DROP COLUMN embedding;
ALTER TABLE documents ADD COLUMN embedding vector(3072);
-- 全量重算 embedding 再入库预防 embedding 模型定死一个,写入元数据记录 model + dims;升级模型要走"双写 + 校验 + 迁移"流程。
检索质量差:召回一堆无关内容
症状
RAG 回答答非所问,明明库里有答案却检索不到,或召回结果与问题无关。原因 常见三类:分块太大把关键句淹没、相似度阈值设置错误(太高漏检/太低误检)、混合检索里某一路静默降级(如关键词路挂了没发现)。
解法
# 诊断:对比"问题"与"召回片段"的相似度分布
# 健康值参考:关键词 30% / 向量 30% / 重排 40% 左右的贡献比
# 先看单路召回有没有问题,再谈融合预防 分块策略按内容类型设计(表格/长文不同);阈值用真实问题集校准;混合检索要监控每路贡献率(详见 GP08)。
模型"自信地胡说":幻觉难发现
症状
回答流畅、语气笃定,但事实是错的;特别是引用"不存在的文献/链接/API"时。原因 LLM 是"预测下一个词",不是数据库。开放域生成没有可靠来源时也会编;检索质量差时会基于错误片段放大。
解法
1. 要求引用来源并做可溯源校验(RAG 场景强制)
2. 高风险场景用工具/函数调用拿事实,不靠模型记忆
3. 对输出做二次校验(正则/白名单/独立模型交叉)预防 明确"哪里必须用工具、哪里允许生成"的边界;上线前用评测集跑回归,量化幻觉率(见 GP05)。
成本失控:账单超预算
症状
月底账单暴涨,排查发现某条链路 token 消耗异常:重复调用、缓存没生效、日志里误记录。原因 常见:每次请求都带超长上下文、prompt 没缓存、循环里重复调用同一模型、流式/重试放大了次数、把调试输出也走了计费调用。
解法
1. 请求前算 token,超预算直接拒绝/降级
2. 相同前缀用 prompt 缓存(cache hit 便宜一个数量级)
3. 模型路由:简单任务用小模型,复杂任务才用大模型
4. 全链路记 usage,按天出报表对比预防 上线前设预算上限与告警;对每类请求预估单次成本并压测峰值;定期看 usage 报表找异常链路(详见 13 · 成本与模型路由)。
API Key 泄露:被陌生人调用扣费
症状
账单出现陌生来源调用,或第三方扫描工具报"key 明文出现在前端代码/公开仓库"。原因 Key 写进前端代码、提交进 Git 仓库、环境变量被打印到日志/构建产物。前端代码任何人可见,放进去等于公开。
解法
1. 立即撤销泄露的 key 并换新
2. 前端只调自己的后端,由后端持有 key(见 C19)
3. 清理 Git 历史中的明文(rewrite + 通知泄漏渠道)预防 Key 只放后端环境变量/密钥服务;用 .gitignore 排除 .env;监控平台开用量告警,异常调用自动停。