90%开发者踩坑的大模型调用误区,一次性避完
调过100万次API之后,我整理了这份避坑指南
前言
先交代下背景。过去一年,我带着团队做了个基于大模型的RAG项目,日均API调用量2万+,累计调用超过100万次。从最开始的天天被坑,到现在基本稳定,中间踩过的坑没有八十也有一百。
这些坑里,有些是文档里写了但你不会认真看的,有些是文档里压根不会告诉你的。我把最常遇到的几个拎出来,希望能帮你省点时间,也省点钱。
误区一:System Prompt当摆设,随便写写就完事
这是我见过最多的操作。
很多人拿到模型,第一件事就是往User Prompt里塞任务描述,System Prompt要么留空,要么写一句“You are a helpful assistant”。
实际效果:同样一段任务描述,放在System里和放在User里,出来的结果能差一个档次。System Prompt在模型内部的优先级和权重计算方式跟User不同,它更接近“底层指令”而非“当前问题”。
正确姿势:
text
System:
你是一个专业的代码审查助手。你的输出必须遵循以下规则:
1. 只输出问题列表,不要输出任何多余的问候语
2. 每个问题标注严重程度:P0/P1/P2
3. 如果代码没有明显问题,输出"无问题",不要强行找茬
4. 不要重复用户的代码原文
User:
请审查以下Python代码:
def get_user(id):
return db.query(f"SELECT * FROM users WHERE id={id}")
你看,System管“怎么说话”,User管“当前任务”。各司其职。
误区二:Temperature 调来调去,其实没搞懂它干嘛的
Temperature这玩意儿,文档里写“控制随机性”,但很多人的理解就停在这了。
然后你就会看到这样的操作:要严谨输出就把Temperature调到0,要创意输出就调到0.9,中间档就0.5。看似合理,实际踩坑。
真实机制:Temperature影响的是概率分布的“锐度”。温度越低,高概率token被选中的概率越大,输出越确定;温度越高,低概率token也有机会出头,输出越多样。
关键点:Temperature=0不代表一定没有随机性。GPU浮点运算误差、不同batch的padding差异,都可能导致同样输入产生不同输出。如果你真的需要确定性输出,配合seed参数一起用,或者设置top_p=1。
经验值:
-
代码生成/信息提取:0-0.3
-
常规问答/文本摘要:0.4-0.7
-
创意写作/头脑风暴:0.8-1.2
-
超过1.5基本就开始胡言乱语了
误区三:上下文窗口大了,就拼命往里塞
现在的模型动不动就100K、200K的上下文,很多人就觉得:“反正能装下,我把整本手册都贴进去”。
然后你就遇到了:响应变慢、成本暴涨、而且输出质量反而下降了。
为什么:上下文越长,模型在中间位置的信息遗忘越严重。这不是猜的,论文(Lost in the Middle)已经证明了这点——模型对长文本开头和结尾的内容记忆最好,中间部分基本是“看过就忘”。
还有一种更隐蔽的坑:你以为你塞了10万token进去,但实际上模型的有效注意力是稀疏的。很多框架为了加速推理,会做KV Cache的优化,某些位置的token实际上被“降权”了。你觉得自己给了充分的上下文,模型实际看到的打了个折。
建议:
-
能检索就不要硬塞,先做RAG召回TopK
-
如果必须塞长文本,把关键信息放在开头和结尾
-
每轮对话带上历史摘要,而不是原始对话记录
-
超过50K token的场景,仔细评估是否真的需要
误区四:错误处理只判断HTTP状态码
这是最糙的做法。
python
# 反面教材
response = requests.post(url, json=data)
if response.status_code == 200:
return response.json()
else:
print("出错了")
HTTP 200只代表请求通了,不代表模型正常返回了。模型返回的payload里,error字段才是真正需要检查的东西。
更隐蔽的是——有时候既没有HTTP错误,也没有显式的error字段,但返回内容里藏着"Internal Server Error"或者"I'm sorry, I cannot..."之类的字符串。这种半死不活的状态最坑人,你的下游逻辑一处理就直接炸了。
稍微靠谱点的做法:
python
def call_llm(messages):
response = requests.post(url, json={"messages": messages}, timeout=30)
# 1. 先检查HTTP状态
if response.status_code != 200:
raise APIException(f"HTTP {response.status_code}: {response.text}")
# 2. 再检查响应体是否合法JSON
try:
result = response.json()
except json.JSONDecodeError:
raise APIException(f"Invalid JSON response: {response.text[:200]}")
# 3. 检查业务错误
if "error" in result:
raise APIException(f"API error: {result['error']}")
# 4. 检查返回内容是否为空
content = result.get("choices", [{}])[0].get("message", {}).get("content", "")
if not content or len(content.strip()) < 5:
raise APIException(f"Empty or too short response: {content}")
# 5. 敏感词过滤触发时,内容会被截断或替换,需要额外判断
if "敏感词" in content or "***" in content:
raise APIException("Response was filtered")
return content
超时重试也别偷懒,指数退避写一下花不了几行代码。
误区五:JSON Mode 用了但没完全用
很多模型支持JSON Mode,保证输出是合法的JSON。但你开了JSON Mode之后,如果Prompt里不说清楚要输出什么结构,模型就会自己发挥。
今天给你返回 {"name": "xxx", "result": ...},明天心情好就变成 {"code": 0, "data": {...}}。
你以为开了JSON Mode就稳了,实际上只保了语法合法,没保结构固定。
解法:在System Prompt里明确指定JSON Schema,并且在User Prompt里再强调一次。如果模型支持,把response_format参数带上。
text
System:
你的输出必须严格遵循以下JSON Schema:
{
"type": "object",
"properties": {
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"line": {"type": "integer"},
"message": {"type": "string"},
"severity": {"enum": ["P0", "P1", "P2"]}
}
}
}
},
"required": ["issues"]
}
客户端再加一道校验,不符合Schema就重试或报错,别直接往下传。
误区六:Prompt写一次就不管了
这是最普遍但最不被重视的问题。
很多人上线之后就不管Prompt了,除非出大问题。但模型会升级,业务数据会变,用户提问方式也会变。三个月前好用的Prompt,现在可能已经不是最优的了。
推荐做法:把Prompt当代码一样做版本管理,每次改动记录changelog,上线前做A/B测试。
误区七:把"调Prompt"当成万能药
遇到问题就调Prompt,调不好就换模型,换完继续调Prompt。
循环依赖:质量不行→调Prompt→效果上来了→上线跑了一段时间→又不行了→继续调……
其实很多问题根本不在Prompt层面:
-
知识类问题靠RAG
-
逻辑推理问题靠CoT + 自我一致性
-
格式问题靠约束解码
-
多步骤任务靠Agent拆解
-
重复性劳动靠微调
先诊断问题出在哪个层面,再选工具。拿锤子看什么都是钉子,但你不能啥都当Prompt问题去锤。
避坑清单(直接抄作业)
| 误区 | 一句话解决方案 |
|---|---|
| System Prompt随便写 | System管指令,User管任务,分工明确 |
| Temperature乱调 | 代码/提取类0-0.3,问答类0.4-0.7,创意类0.8-1.2 |
| 长上下文无脑塞 | 关键信息放首尾,用摘要代替原始记录 |
| 错误处理只判200 | 检查JSON解析、业务error、内容有效性、敏感词过滤 |
| JSON Mode只开不管 | 约束Schema + 客户端二次校验 |
| Prompt写完就不管 | 版本管理 + 持续迭代 |
| 啥都靠调Prompt | 先定位问题层级,再选工具 |
最后说一句
这些坑看着都不大,但每一个我都真实踩过,而且不止一次。
大模型应用开发跟传统后端开发最大的区别是:不确定性是内生的。你不能用“输入X必然输出Y”的思维去做,得接受概率性存在,然后用工程手段把不确定性控制在可接受范围内。
说白了,就是别把模型当API,把它当一个不太靠谱但能力很强的实习生。你得给清晰的指令,得校验它的产出,得容忍它偶尔犯错,还得持续带教。
祝各位上线顺利,别在凌晨三点被报警吵醒。
— End —
如果这篇文章帮到了你,点赞收藏转发就是对作者最大的支持。有什么踩过的坑也欢迎评论区补充,大家一起避。
更多推荐
所有评论(0)