API 使用与参数:system、温度、max_tokens、流式、重试
硬件前提
不需要 GPU,只需要一个 API key 和一段代码。这是投入产出比最高的一档。
消息结构:先搞清三个角色
| 角色 | 放什么 | 常见错误 |
|---|---|---|
system | 角色、规则、输出格式、边界 | 写得太长太虚;把每次变化的内容放这里(破坏缓存) |
user | 本轮请求 + 必要资料 | 把历史全塞进 user |
assistant | 之前的回答(历史) | 忘记回填,导致模型「失忆」 |
固定不变的部分(system、工具说明、常用资料)放前面,变化的放后面——这样前面那段才可能被缓存命中,成本能降一大截。
只调这四个参数
| 参数 | 建议 | 说明 |
|---|---|---|
temperature | 事实/抽取 0~0.3;生成 0.6~0.9 | 别用它调「聪明程度」 |
top_p | 默认(0.95~1.0) | 与 temperature 二选一调,别同时猛调 |
max_tokens | 按任务上限设,并留足 | 太小 → 输出被截断;不设 → 成本失控 |
stop | 需要时设停止串 | 结构化输出场景常用 |
其余参数(frequency penalty、seed 等)先别碰。
最小可用调用(含超时与重试)
import time, random
from openai import OpenAI
client = OpenAI(base_url="https://api.example.com/v1", api_key="...")
def ask(messages, retries=3):
for attempt in range(retries):
try:
r = client.chat.completions.create(
model="your-model",
messages=messages,
temperature=0.2,
max_tokens=800,
timeout=30,
)
return r.choices[0].message.content
except Exception as e:
if attempt == retries - 1:
raise
time.sleep((2 ** attempt) + random.random()) # 指数退避
必须有的四件事:超时、重试(指数退避 + 抖动)、失败后的降级(换小模型或返回兜底文案)、日志(记录 token 用量与耗时)。
流式输出
用户界面几乎都该用流式:首 token 时间不变,但体感快很多。
stream = client.chat.completions.create(..., stream=True)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
注意:流式中断要能恢复(保存已收到的部分),并且流式下 max_tokens 依然是硬上限。
成本与延迟控制(实操)
- 裁剪历史:只保留最近 N 轮 + 一段摘要。长对话成本接近平方增长,这一步最有效。
- 固定前缀:system 与工具说明保持稳定,别每轮改措辞。
- 限制输出:明确「不超过 200 字」比事后截断省得多。
- 路由:分类/抽取/改写走便宜模型,复杂推理才升级。先统计你的流量里简单任务占比,通常高得惊人。
常见失败与排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 429 / 限流 | 请求太快或额度用完 | 退避重试 + 队列限速;申请提额 |
| 输出到一半断 | max_tokens 太小 | 调大,或要求分点输出 |
| 答案前后矛盾 | 历史被裁掉了关键约束 | 把关键约束写进 system 并在末尾重复 |
| 成本突然翻倍 | 上下文滚雪球 / 重试风暴 | 记录每次调用的 token 数,设告警 |
| 结果不稳定 | 温度高 + 提示含糊 | 降温度 + 给 2~3 个示例 |
| 模型「不听话」 | 用了基座模型或模板不匹配 | 确认是指令模型,用官方对话模板 |
完成标志
你的调用代码里已经具备:固定前缀、历史裁剪、超时重试、降级、token 用量日志。这五件事齐了,才谈得上把它放进真实产品。