你的第一次 LLM API 调用
从零到跑通第一个请求,外加路上一定会撞上的四个报错。
各家厂商的 API 形状都一样。学会一家,剩下的都是变体。
一个请求的解剖
永远都是四个部分:
端点和认证。 一个 HTTPS URL,加上放在请求头里的 API key。
模型标识。 用哪个模型,写成一个字符串。
消息列表。 一串带角色的消息——先是 system,然后 user 和 assistant 交替出现。
参数。 温度(temperature)、最大输出 token 数,以及任何你想控制的东西。
返回的内容里有生成的消息、一个停止原因,还有输入和输出各自的 token 数。
最小结构
概念上,用任何语言写都是这样:
POST https://api.provider.com/v1/messages
Authorization: Bearer $API_KEY
{
"model": "<model-id>",
"max_tokens": 1024,
"system": "You are a concise technical assistant.",
"messages": [
{"role": "user", "content": "Explain what a token is in one sentence."}
]
}各家 SDK 是对它的封装,用 SDK 是值得的——重试、流式输出、错误类型它都替你处理了。不过原始结构仍然值得知道,因为它解释了 SDK 到底在做什么。
具体的端点、模型 ID 和参数名各家不同,而且会随时间变化。这些细节以最新文档为准,别信任何示例,包括这一个。
API key
永远不要把 API key 写进源码,也不要写进客户端代码。前端打包产物里的 key,在你部署那一刻就是公开的。
用环境变量,并且在把 key 写进去之前,先把 env 文件加进 .gitignore。万一 key 被提交过,就轮换它——删掉那次提交并不能让它不算泄漏。
浏览器或移动端应用,请求必须走你自己的后端。客户端跟你的服务器说话,你的服务器持有 key,再去跟厂商说话。这一步没得商量,而且只有这里,才放得下速率限制和防滥用控制。
人人都会撞上的四个报错
401 —— 认证失败
key 错了、没带上、过期了,或者混进了多余的空格。先确认环境变量真的被加载了——比起 key 本身有问题,这才是更常见的原因。
429 —— 触发速率限制
你超了请求数或 token 的上限。用指数退避(exponential backoff)加抖动重试:等一会儿,每次把等待时间翻倍,再加上随机量,免得并发客户端齐步重试。响应里有 retry-after 头的话,听它的。
这不是边缘情况。退避要从第一天就写进去,因为这是生产环境里你撞得最多的错误。大多数 SDK 都自带——去确认,别假设它有。
400 —— 超出上下文长度
你的输入加上要求的输出,超过了模型的上下文窗口。记住输出也占这份预算。
解决办法:裁掉输入、给对话历史设上限,或者少检索一点。
输出被截断
这不算报错——回复就是停了。去看 stop reason 字段。如果它指向长度上限,说明你的 max_tokens 设小了。这个坑让人困惑,因为请求成功了,只是答案缺了个结尾。
一上来就该做对的事
max_tokens 要有意识地设。 设低了会截断,设高了会放任它跑出一大笔花费。它是上限,不是目标值。
凡是抽取类任务都用温度 0。 分类、抽取、结构化输出。较高的值留给对话或创作类任务。
处理超时。 长回复就是慢。把超时设宽一点,并且接受偶尔会卡住。
从一开始就记录 token 数。 返回值里就有。记下来,你才能在账单之前发现成本问题。
只重试能重试的。 429 和 5xx:重试。400 和 401:重试没意义,是请求本身有问题。
成本是怎么算的
你按 token 付费,输入和输出分开计价,输出更贵。
陷阱在对话历史上。因为模型在两次调用之间没有记忆,每一轮都会把整份对话记录重发一遍——所以成本随对话长度的平方增长。要么主动给历史设上限,要么等它涨到出事为止。
要点回顾
- 每个请求都是:端点加认证、模型 ID、消息列表、参数。
- API key 属于环境变量和服务器——绝不进客户端代码。
- 四个报错:401 认证、429 速率限制(要退避)、400 上下文超限,以及
max_tokens设小了导致的静默截断。 max_tokens要有意识地设,抽取类任务用温度 0,第一天就开始记录 token 数。- 因为每轮都重发历史,对话成本是平方级增长的。
下一篇: 该用哪个模型?