AI API 账单变高,通常不是某一次请求突然很贵,而是多个小问题叠加出来的结果:
- 请求量上涨;
- 上下文越来越长;
- 输出内容不受控制;
- 简单任务也使用高能力模型;
- 失败后不断重试;
- Agent / 工具调用链路过长;
- 离线任务被当成实时任务逐条调用。
很多团队第一反应是"换一个更便宜的模型"。这个方向可以做,但不建议作为唯一手段。更稳妥的做法是先把调用链路拆开,看清楚成本花在哪里,然后再分别处理:
- 哪些请求根本不该发;
- 哪些 token 可以省;
- 哪些任务可以走低成本模型;
- 哪些非实时任务可以异步或批量处理;
- 哪些异常需要通过监控、预算和告警提前拦住。
本文按工程落地视角整理一套 AI API 成本优化方案,重点放在可配置、可验证、可排错的实现方式上。
1. 成本排查:先把 AI API 调用数据打全
在做缓存、模型路由、上下文压缩之前,建议先补齐调用日志。否则很容易优化错方向。
例如:
- 以为贵在请求次数,实际贵在输出 token;
- 以为贵在模型单价,实际是失败重试过多;
- 以为压缩 prompt 有用,实际是 RAG 召回片段过多;
- 以为 batch 能省钱,实际单条任务本身 prompt 就很浪费。
1.1 建议记录的调用字段
生产环境中,建议每次 AI API 调用至少记录以下字段:
| 字段 | 作用 |
|---|---|
request_id |
追踪单次调用链路 |
user_id / tenant_id |
统计用户或租户成本 |
business_type |
区分客服、摘要、审核、分类等业务 |
model |
统计不同模型使用占比 |
input_tokens |
分析输入 token 消耗 |
output_tokens |
分析输出 token 消耗 |
latency_ms |
观察延迟 |
success |
统计成功率 |
error_code |
统计失败类型 |
retry_count |
统计重试成本 |
cache_hit |
评估缓存收益 |
estimated_cost |
估算单次与总成本 |
注意:不同平台的 token 统计方式、价格和计费规则可能不同,具体应以各平台最新文档为准。这里重点是日志字段设计,不涉及具体价格承诺。
1.2 一个通用的调用日志结构
可以先用类似下面的结构记录:
{
"request_id": "req_20250101_000001",
"user_id": "u_10001",
"tenant_id": "t_001",
"business_type": "customer_service_qa",
"model": "default-model",
"input_tokens": 1200,
"output_tokens": 300,
"latency_ms": 1820,
"success": true,
"error_code": null,
"retry_count": 0,
"cache_hit": false,
"estimated_cost": null,
"created_at": "2025-01-01T10:00:00Z"
}
如果暂时没有接入精确成本计算,estimated_cost 可以先为空,至少先把 token、模型、业务线和失败率记录下来。
后续再按模型单价、输入 token、输出 token 做成本估算。
2. 环境变量配置:把 Endpoint、模型名和鉴权信息统一管理
AI API 成本优化通常不应该写死在业务代码里。建议把 API 地址、模型名、超时时间、重试次数、输出长度等都做成配置项。
2.1 推荐的环境变量结构
# API Endpoint
AI_API_BASE_URL=https://api.example.com/v1
# 鉴权 Key
AI_API_KEY=your_api_key_here
# 默认模型
AI_MODEL_DEFAULT=default-model
# 小模型 / 低成本模型
AI_MODEL_SMALL=small-model
# 强模型 / 高能力模型
AI_MODEL_STRONG=strong-model
# 请求超时时间,单位:秒
AI_REQUEST_TIMEOUT=30
# 最大重试次数
AI_MAX_RETRY=2
# 默认最大输出长度
AI_MAX_OUTPUT_TOKENS=512
# 是否启用缓存
AI_CACHE_ENABLED=true
# 缓存过期时间,单位:秒
AI_CACHE_TTL=3600
这样做有几个好处:
- 不同环境可以使用不同 Endpoint;
- 模型切换不需要改代码;
- 可以按业务逐步灰度模型路由;
- 可以快速调整超时、重试、输出长度;
- 排错时更容易定位是鉴权、Endpoint、模型名还是参数问题。
2.2 基础客户端封装示例
下面是一个偏通用的 Python 伪实现,用于说明封装思路:
import os
import time
import uuid
import requests
AI_API_BASE_URL = os.getenv("AI_API_BASE_URL")
AI_API_KEY = os.getenv("AI_API_KEY")
AI_MODEL_DEFAULT = os.getenv("AI_MODEL_DEFAULT", "default-model")
AI_REQUEST_TIMEOUT = int(os.getenv("AI_REQUEST_TIMEOUT", "30"))
AI_MAX_RETRY = int(os.getenv("AI_MAX_RETRY", "2"))
AI_MAX_OUTPUT_TOKENS = int(os.getenv("AI_MAX_OUTPUT_TOKENS", "512"))
def call_ai_api(messages, model=None, max_tokens=None, business_type="default"):
request_id = str(uuid.uuid4())
model = model or AI_MODEL_DEFAULT
max_tokens = max_tokens or AI_MAX_OUTPUT_TOKENS
url = f"{AI_API_BASE_URL}/chat/completions"
headers = {
"Authorization": f"Bearer {AI_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"messages": messages,
"max_tokens": max_tokens
}
retry_count = 0
start_time = time.time()
while True:
try:
resp = requests.post(
url,
headers=headers,
json=payload,
timeout=AI_REQUEST_TIMEOUT
)
latency_ms = int((time.time() - start_time) * 1000)
if resp.status_code == 200:
data = resp.json()
# 这里根据具体平台返回字段做适配
usage = data.get("usage", {})
input_tokens = usage.get("prompt_tokens")
output_tokens = usage.get("completion_tokens")
log_ai_call(
request_id=request_id,
business_type=business_type,
model=model,
input_tokens=input_tokens,
output_tokens=output_tokens,
latency_ms=latency_ms,
success=True,
error_code=None,
retry_count=retry_count,
cache_hit=False
)
return data
if should_retry(resp.status_code) and retry_count < AI_MAX_RETRY:
retry_count += 1
time.sleep(0.5 * retry_count)
continue
log_ai_call(
request_id=request_id,
business_type=business_type,
model=model,
input_tokens=None,
output_tokens=None,
latency_ms=latency_ms,
success=False,
error_code=str(resp.status_code),
retry_count=retry_count,
cache_hit=False
)
raise RuntimeError(f"AI API error: {resp.status_code}, {resp.text}")
except requests.Timeout:
latency_ms = int((time.time() - start_time) * 1000)
if retry_count < AI_MAX_RETRY:
retry_count += 1
time.sleep(0.5 * retry_count)
continue
log_ai_call(
request_id=request_id,
business_type=business_type,
model=model,
input_tokens=None,
output_tokens=None,
latency_ms=latency_ms,
success=False,
error_code="timeout",
retry_count=retry_count,
cache_hit=False
)
raise
def should_retry(status_code):
return status_code in [429, 500, 502, 503, 504]
def log_ai_call(**kwargs):
# 生产环境建议写入日志系统、数据库或监控平台
print(kwargs)
这段代码不是绑定某个具体平台的 SDK,而是展示封装思路:
- Endpoint 从环境变量读取;
- API Key 统一管理;
- 模型名可配置;
- 最大输出长度可配置;
- 请求超时可配置;
- 重试次数可控;
- 每次调用都记录日志。
3. 方法一:缓存与去重,先减少不必要的调用
缓存是 AI API 成本优化中 ROI 很高的一类方案,因为它不是让单次调用变便宜,而是直接避免重复调用。
3.1 适合缓存的场景
适合缓存的请求一般有两个特点:
- 输入相对稳定;
- 输出可以复用。
常见场景包括:
- FAQ 客服问答;
- 文档问答中的高频问题;
- 文本分类;
- 内容安全审核;
- 翻译;
- 改写;
- 摘要。
不适合强缓存的场景包括:
- 实时数据查询;
- 个性化推荐;
- 高度依赖最新上下文的多轮对话;
- 复杂推理任务;
- 需要严格时效性的业务。
3.2 缓存 Key 不要只用用户输入
很多人会直接用用户输入做缓存 Key,例如:
用户问题 -> 模型回答
这种方式实现简单,但风险比较大。
更稳妥的缓存 Key 至少应包含:
- 用户输入;
- system prompt 版本;
- 模型名称;
- 温度等关键参数;
- 业务配置版本。
否则会出现一种隐蔽问题:
prompt 已经改了,模型也换了,但缓存仍然命中了旧答案。
3.3 缓存 Key 示例
import hashlib
import json
def build_cache_key(
user_input,
system_prompt_version,
model,
temperature,
business_config_version
):
raw = {
"user_input": user_input,
"system_prompt_version": system_prompt_version,
"model": model,
"temperature": temperature,
"business_config_version": business_config_version
}
text = json.dumps(raw, ensure_ascii=False, sort_keys=True)
return hashlib.sha256(text.encode("utf-8")).hexdigest()
3.4 完全输入缓存示例
def ask_with_cache(user_input):
cache_key = build_cache_key(
user_input=user_input,
system_prompt_version="v3",
model=os.getenv("AI_MODEL_DEFAULT"),
temperature=0.2,
business_config_version="faq_2025_01"
)
cached = cache_get(cache_key)
if cached:
log_cache_hit(cache_key)
return cached
messages = [
{"role": "system", "content": "你是客服助手,请基于知识库回答用户问题。"},
{"role": "user", "content": user_input}
]
result = call_ai_api(
messages=messages,
model=os.getenv("AI_MODEL_DEFAULT"),
max_tokens=512,
business_type="customer_service_qa"
)
answer = extract_answer(result)
cache_set(cache_key, answer, ttl=3600)
return answer
3.5 缓存的边界
缓存不是万能的,主要风险包括:
- 缓存过期;
- 知识库更新后仍返回旧答案;
- 相似问题误命中;
- 多租户数据隔离不严;
- 不同模型或 prompt 版本混用旧结果。
建议顺序是:
- 先做完全相同输入缓存;
- 再评估语义相似缓存;
- 严肃业务中要设置 TTL 和版本号;
- 知识库更新时要能批量失效缓存。
4. 方法二:模型分层与路由,简单任务不要占用强模型
很多 AI API 费用偏高,是因为所有任务都使用了同一个高能力模型。
但实际业务里,不同任务的难度差别很大:
- 文本分类;
- 标签提取;
- 固定格式改写;
- 简单摘要;
- JSON 信息抽取;
这些任务通常不一定需要最高能力模型。
更合理的方式是做模型分层:
- 简单任务:优先小模型或低成本模型;
- 中等任务:使用通用模型;
- 复杂推理、长文理解、高风险任务:使用强模型;
- 小模型失败或置信度不足时,再升级到强模型。
4.1 模型路由策略
| 任务条件 | 推荐策略 |
|---|---|
| 文本分类、标签提取、固定格式改写 | 优先小模型 |
| 命中 FAQ 或 RAG 片段很明确 | 小模型 + RAG |
| 输入很长、问题复杂、需要多步推理 | 使用强模型 |
| 小模型输出格式错误 | 升级模型重试 |
| 小模型置信度低 | 升级模型重试 |
| 涉及合规、金融、医疗等高风险判断 | 提高模型等级,并保留人工审核 |
重点不是"永远选便宜模型",而是按任务难度和质量要求分配模型。
4.2 模型路由代码示例
AI_MODEL_SMALL = os.getenv("AI_MODEL_SMALL", "small-model")
AI_MODEL_DEFAULT = os.getenv("AI_MODEL_DEFAULT", "default-model")
AI_MODEL_STRONG = os.getenv("AI_MODEL_STRONG", "strong-model")
def route_model(task_type, input_text, risk_level="normal"):
text_len = len(input_text)
if risk_level == "high":
return AI_MODEL_STRONG
if task_type in ["classification", "tag_extract", "format_rewrite"]:
return AI_MODEL_SMALL
if task_type in ["summary"] and text_len < 3000:
return AI_MODEL_DEFAULT
if task_type in ["complex_qa", "multi_step_reasoning", "long_context"]:
return AI_MODEL_STRONG
return AI_MODEL_DEFAULT
4.3 小模型失败后升级
def classify_text(text):
model = route_model(
task_type="classification",
input_text=text,
risk_level="normal"
)
messages = [
{
"role": "system",
"content": "你是文本分类器,只输出 JSON,不要输出额外解释。"
},
{
"role": "user",
"content": text
}
]
result = call_ai_api(
messages=messages,
model=model,
max_tokens=128,
business_type="classification"
)
parsed = try_parse_json(result)
if not parsed or parsed.get("confidence", 0) < 0.7:
result = call_ai_api(
messages=messages,
model=AI_MODEL_STRONG,
max_tokens=128,
business_type="classification_fallback"
)
parsed = try_parse_json(result)
return parsed
这里的关键是:
- 小模型不是无条件使用;
- 要有质量校验;
- 要有失败回退;
- 要监控升级比例;
- 要观察人工介入率是否上升。
如果模型路由导致人工纠错、用户投诉或业务失败增加,那只是把 API 成本转移到了其他地方。
5. 方法三:压缩上下文与控制输出长度,减少 token 浪费
AI API 的输入 token 和输出 token 都会影响成本。很多系统刚上线时费用正常,运行一段时间后变贵,通常和以下问题有关:
- 多轮对话历史越来越长;
- RAG 检索片段越塞越多;
- system prompt 不断追加规则;
- 输出不限制长度;
- 模型返回大量无用解释。
5.1 输入端:控制上下文长度
输入侧可以从这些地方优化:
- 删除无关历史消息;
- 多轮对话使用摘要记忆;
- RAG 控制分块大小;
- RAG 控制召回数量;
- 清理重复、空泛、冲突的 prompt;
- 长文任务先切分、筛选,再送入模型。
尤其是 RAG 场景,不是召回越多越好。
召回片段过多会带来两个问题:
- 输入 token 增加;
- 噪声变多,模型可能被干扰。
更合理的方式是:
- 优化文档分块;
- 优化检索排序;
- 必要时做重排;
- 只把最相关片段送给模型。
5.2 RAG 上下文拼接示例
def build_rag_messages(question, retrieved_chunks):
# 只保留排序靠前的片段
top_chunks = retrieved_chunks[:5]
context = "\n\n".join([
f"文档片段 {idx + 1}:\n{chunk['content']}"
for idx, chunk in enumerate(top_chunks)
])
messages = [
{
"role": "system",
"content": (
"你是知识库问答助手。"
"请只基于提供的文档片段回答。"
"如果文档中没有答案,请说明无法从现有资料确定。"
)
},
{
"role": "user",
"content": f"文档片段:\n{context}\n\n用户问题:{question}"
}
]
return messages
这里的 retrieved_chunks[:5] 只是示例,实际数量要结合业务效果评估,不能简单固定。
5.3 多轮对话摘要记忆
多轮对话中,不建议每次都把完整历史传给模型。
可以把历史对话压缩成摘要,再结合最近几轮对话:
def build_chat_messages(summary_memory, recent_messages, current_question):
messages = [
{
"role": "system",
"content": "你是客服助手,请结合对话摘要和最近消息回答用户。"
}
]
if summary_memory:
messages.append({
"role": "system",
"content": f"历史对话摘要:{summary_memory}"
})
messages.extend(recent_messages[-4:])
messages.append({
"role": "user",
"content": current_question
})
return messages
需要注意:上下文不能压缩过度。压缩后要观察:
- 平均输入 token 是否下降;
- 回答命中率是否稳定;
- 用户追问率是否上升;
- 人工介入率是否增加。
如果用户追问明显变多,可能说明关键上下文被删掉了。
5.4 输出端:限制模型自由发挥
输出 token 同样会带来成本。
建议在三个层面控制:
- API 参数设置最大输出长度;
- prompt 中明确输出格式;
- 对分类、抽取、摘要任务使用固定 schema。
例如分类任务:
messages = [
{
"role": "system",
"content": (
"你是文本分类器。"
"请只输出 JSON,不要输出 Markdown,不要解释。"
"JSON 字段包括:category、confidence、reason。"
"reason 不超过 30 个字。"
)
},
{
"role": "user",
"content": "用户输入文本..."
}
]
result = call_ai_api(
messages=messages,
model=AI_MODEL_SMALL,
max_tokens=128,
business_type="classification"
)
对于分类、标签、信息抽取等任务,没有必要让模型输出很长的解释。
6. 方法四:批量处理与异步化,非实时任务不要逐条实时跑
不是所有 AI API 调用都必须同步返回。
适合批量处理的任务包括:
- 批量摘要历史文章;
- 批量生成商品标签;
- 批量清洗用户评论;
- 批量评估问答质量;
- 离线构建知识库问答对。
这些任务如果全部使用实时接口逐条调用,会带来几个问题:
- 并发峰值难控制;
- 失败重试分散;
- 成本统计困难;
- 实时链路压力大。
更好的方式是放入队列,异步执行。
如果平台支持 Batch API,也可以结合使用。不同平台的 Batch 规则、限制和价格可能不同,具体以各自最新文档为准。
6.1 适合与不适合 batch 的场景
| 适合批量处理 | 不适合批量处理 |
|---|---|
| 用户不需要立即看到结果 | 在线客服即时回复 |
| 可以延迟几分钟到几小时 | 实时搜索问答 |
| 输入输出格式统一 | 高度个性化多轮对话 |
| 可以失败后统一重跑 | 强交互式 Agent |
6.2 队列化处理示例
def submit_offline_task(task_type, payload):
task = {
"task_type": task_type,
"payload": payload,
"status": "pending",
"retry_count": 0
}
task_id = save_task_to_db(task)
push_to_queue(task_id)
return task_id
消费者处理:
def consume_task(task_id):
task = get_task_from_db(task_id)
try:
if task["task_type"] == "article_summary":
result = run_article_summary(task["payload"])
elif task["task_type"] == "tag_generation":
result = run_tag_generation(task["payload"])
else:
raise ValueError("unknown task type")
mark_task_success(task_id, result)
except Exception as e:
if task["retry_count"] < 2:
increase_retry_count(task_id)
push_to_queue(task_id)
else:
mark_task_failed(task_id, str(e))
6.3 批量化之前先优化单条调用
批量处理不等于一定省钱。
如果单条任务存在这些问题:
- prompt 过长;
- RAG 片段过多;
- 输出不限制;
- 失败重试失控;
那么批量处理只是把浪费放大。
建议顺序是:
- 先优化单条 prompt;
- 控制输出长度;
- 做好失败重试;
- 再放入异步队列或 batch 流程。
7. 方法五:监控、预算与告警,形成成本闭环
没有监控的成本优化,很容易停留在"感觉省了"。
建议从三个维度做预算:
- 日预算:防止单日异常峰值;
- 月预算:控制整体支出;
- 用户 / 租户预算:避免少数用户打爆成本。
7.1 建议监控指标
| 指标 | 排查方向 |
|---|---|
| 每千次请求成本 | 判断整体优化效果 |
| 平均输入 token | 判断上下文是否膨胀 |
| 平均输出 token | 判断输出是否失控 |
| 失败率 | 判断接口或参数问题 |
| 重试率 | 判断异常重试成本 |
| 缓存命中率 | 判断缓存是否有效 |
| 模型升级比例 | 判断模型路由是否合理 |
| 平均延迟 | 判断链路性能 |
| 单用户成本 | 判断是否存在异常用户 |
| 单业务线成本 | 判断哪个业务最烧钱 |
7.2 告警规则示例
告警不一定一开始就很复杂,可以先做简单规则:
- 当日成本超过过去 7 天均值一定比例;
- 某个接口失败率突然升高;
- 平均输出 token 明显上涨;
- 缓存命中率快速下降;
- 某个用户或租户成本异常增加;
- 重试次数突然增多;
- 强模型调用比例异常升高。
这些告警不会直接降低单次调用费用,但可以防止成本继续失控。
8. 常见报错与排查方法
下面整理一些 AI API 成本优化和接入过程中常见的问题。
8.1 401 / Unauthorized
常见原因:
- API Key 没配置;
- API Key 配错;
- 环境变量没有生效;
- Header 格式错误;
- 使用了错误的 Endpoint。
排查步骤:
echo $AI_API_BASE_URL
echo $AI_API_KEY
检查请求头是否类似:
Authorization: Bearer your_api_key_here
Content-Type: application/json
注意不要把不同环境的 Key 混用,例如测试环境和生产环境。
8.2 404 / model not found
常见原因:
- 模型名写错;
- 当前 Endpoint 不支持该模型;
- 使用了错误的接口路径;
- 模型配置没有在环境变量中更新。
排查:
echo $AI_MODEL_DEFAULT
echo $AI_MODEL_SMALL
echo $AI_MODEL_STRONG
如果做了模型路由,要检查实际请求中传入的模型名,而不是只看默认模型。
8.3 429 / rate limit
常见原因:
- 并发过高;
- 短时间请求过多;
- 重试策略过激;
- 队列没有限速;
- Agent 链路重复调用。
处理建议:
- 加指数退避;
- 限制最大重试次数;
- 对非实时任务改为队列;
- 对重复问题做缓存;
- 监控
retry_count和error_code=429的比例。
不要无限重试,否则会进一步放大成本。
8.4 context length exceeded
常见原因:
- 多轮历史太长;
- RAG 召回片段太多;
- 文档没有切分;
- system prompt 过长;
- 把无关内容全部塞进上下文。
处理建议:
- 只保留相关历史;
- 长对话做摘要;
- 控制 RAG 分块大小;
- 控制召回数量;
- 删除重复 prompt;
- 长文先筛选再调用模型。
8.5 JSON 解析失败
常见原因:
- prompt 没有限制输出格式;
- 输出长度被截断;
- 模型返回了 Markdown;
- 小模型格式遵循能力不足;
- schema 太复杂。
处理建议:
- 明确要求"只输出 JSON";
- 限制字段;
- 减少无用解释;
- 对 JSON 做校验;
- 失败后升级模型重试;
- 记录格式错误率。
示例 prompt:
请只输出 JSON,不要输出 Markdown,不要添加解释。
字段包括:
- category: 字符串
- confidence: 0 到 1 之间的小数
- reason: 不超过 30 个字
8.6 timeout
常见原因:
- 输入太长;
- 输出太长;
- 模型响应慢;
- 网络不稳定;
- 并发过高。
处理建议:
- 设置合理超时时间;
- 控制
max_tokens; - 对非实时任务异步化;
- 对超时请求限制重试次数;
- 记录超时对应的输入 token 和模型。
9. 一个完整示例:客服问答系统如何降低 AI API 成本
假设有一个客服问答系统,最初实现如下:
- 用户每问一个问题;
- 系统取完整历史对话;
- 检索知识库片段;
- 拼接固定 prompt;
- 统一发送给强模型。
这个方案实现简单,但成本容易高在三个地方:
- 重复问题多;
- 上下文太长;
- 所有请求都走强模型。
9.1 第一步:补调用日志
先记录:
- 用户 ID;
- 业务类型;
- 模型;
- 输入 token;
- 输出 token;
- 是否命中缓存;
- 是否命中知识库;
- 是否升级模型;
- 失败率;
- 重试次数。
没有这些数据,后续无法判断优化是否有效。
9.2 第二步:对高频 FAQ 做缓存
例如:
- 退换货规则;
- 发票说明;
- 物流时效;
- 售后流程。
这些问题重复率通常较高,没有必要每次都调用模型。
处理流程:
用户问题
-> 生成缓存 Key
-> 查询缓存
-> 命中:直接返回
-> 未命中:调用 AI API
-> 写入缓存
-> 返回结果
9.3 第三步:增加意图识别和模型路由
先用小模型判断用户问题类型:
- 是否是 FAQ;
- 是否命中标准答案;
- 是否需要人工;
- 是否是复杂投诉;
- 是否需要跨多个文档推理。
简单问题直接返回标准答案或让小模型轻微润色。
复杂问题再升级到强模型。
用户问题
-> 小模型意图识别
-> 明确 FAQ:返回标准答案
-> 简单知识库问答:小模型 + RAG
-> 复杂投诉 / 多文档推理:强模型
-> 低置信度:强模型兜底
9.4 第四步:压缩多轮上下文
没有必要每次都传完整历史。
可以保留:
- 历史摘要;
- 最近几轮对话;
- 当前问题相关的知识库片段。
这样能降低输入 token,同时减少无关信息干扰。
9.5 第五步:离线分析未解决问题
夜间或低峰期,可以批量分析:
- 哪些问题未解决;
- 哪些问题重复出现;
- 哪些问题需要补充 FAQ;
- 哪些知识库片段质量较差。
这些任务不需要放在实时链路里,可以异步处理。
10. 常见误区
10.1 只看模型单价
便宜模型如果需要更多轮对话才能解决问题,总成本未必更低。
应该看:
- 每千次请求总成本;
- 成功率;
- 升级模型比例;
- 人工介入率;
- 用户追问率。
10.2 过度压缩上下文
上下文删得太狠,模型可能拿不到必要信息。
结果可能是:
- 回答不完整;
- 准确率下降;
- 用户追问增加;
- 总调用次数反而上升。
10.3 缓存不做失效
知识库更新后仍返回旧答案,在客服、合规、金融等场景中风险较高。
缓存必须考虑:
- TTL;
- prompt 版本;
- 知识库版本;
- 模型版本;
- 多租户隔离。
10.4 盲目追求最便宜模型
高风险任务更应该关注:
- 稳定性;
- 可解释性;
- 回退机制;
- 人工审核;
- 业务风险。
不能只看 API 单价。
10.5 没有监控就上线
没有 token、失败率、重试率、缓存命中率这些数据,就无法证明优化是否有效。
10.6 把 batch 当万能方案
实时交互任务如果强行异步化,会影响用户体验。
Batch 更适合:
- 离线任务;
- 后台分析;
- 批量生成;
- 数据清洗。
11. 推荐落地顺序
比较稳妥的 AI API 成本优化顺序是:
-
先做监控
记录 token、模型、业务线、用户、失败率、重试次数和预估成本。
-
再做缓存与去重
对重复问题、固定任务、可复用结果建立缓存。
-
做模型分层与路由
小模型能解决的任务不要默认走强模型,小模型失败再升级。
-
压缩输入与输出 token
清理无效历史上下文,控制 RAG 片段数量,限制输出长度。
-
将非实时任务批量化或异步化
后台任务放入队列,不要全部挤在实时链路上。
AI API 成本控制不是一次调参,而是一套持续优化闭环。核心不是简单换成更便宜的模型,而是让每一次调用都有必要,让每一个 token 都有价值,让每一种任务匹配合适的模型。
如果需要第三方 Claude API 兼容接入服务