OpenClaw Token 消耗太猛?这 3 招实测帮你砍掉 60% 开销
上周用 OpenClaw 接了个微信小助手的需求,功能不复杂——日程管理加信息摘要。跑了三天,Token 消耗直接飙到预算的 4 倍。看着后台用量曲线,整个人都不好了。
OpenClaw 能力确实强,阿里算力加持下推理速度也快,但不做 Token 优化,成本会把你吃穷。
核心思路就三个:压缩上下文、缓存高频请求、动态切换模型。实测组合使用可以把 Token 开销降 50%-70%,下面一个个拆。
先说结论
| 优化策略 | 实施难度 | Token 节省比例 | 适用场景 |
|---|---|---|---|
| Prompt 压缩 + 上下文裁剪 | ⭐⭐ | 30%-40% | 所有场景 |
| 语义缓存层 | ⭐⭐⭐ | 20%-50% | 高频重复查询 |
| 动态模型路由 | ⭐⭐ | 30%-60% | 多任务混合场景 |
三个方案可以叠加,我最终那个微信小助手项目综合下来 Token 消耗降了约 63%。
环境准备
我的开发环境:
- Python 3.11+
- openai SDK(OpenClaw 兼容 OpenAI 协议)
- redis(做缓存层用)
- tiktoken(Token 计数)
pip install openai tiktoken redis
OpenClaw 走标准 OpenAI 兼容协议,用 openai SDK 直接调。我这边统一走聚合接口,方便后面做模型路由切换:
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1" # 聚合接口,一个 Key 调 OpenClaw 和其他模型
)
方案一:Prompt 压缩 + 上下文裁剪
最简单也是回报最高的优化。很多人写 Prompt 跟写作文似的,废话一大堆,Token 就是这么烧掉的。
1.1 System Prompt 瘦身
我原来的 System Prompt 长这样(别笑,很多人都这么写):
# ❌ 反面教材:178 tokens
system_prompt_bad = """
你是一个非常专业的日程管理助手。你需要帮助用户管理他们的日程安排,
包括但不限于创建新的日程、修改已有的日程、删除日程、查询某个时间段的日程安排。
你应该用友好、专业的语气回复用户。当用户的请求不明确时,你应该主动询问更多细节。
你需要以 JSON 格式返回结构化的日程数据,包含 title、start_time、end_time、description 等字段。
请注意,所有时间都应该使用 ISO 8601 格式。
"""
优化后:
# ✅ 优化后:62 tokens
system_prompt_good = """日程助手。操作:创建/修改/删除/查询。
输出JSON:{title,start_time,end_time,desc},时间用ISO8601。
不明确时追问。"""
效果一样,Token 少了 65%。模型不需要你用「非常专业的」「包括但不限于」这种修饰语,它理解意图的能力比你想象的强。
1.2 对话历史滑动窗口
这才是 Token 消耗的大头。微信聊天场景下用户可能连续聊几十轮,每次把完整历史全塞进去,Token 会指数级增长。
import tiktoken
def count_tokens(messages, model="gpt-4o"):
"""计算消息列表的 token 数"""
enc = tiktoken.encoding_for_model(model)
total = 0
for msg in messages:
total += len(enc.encode(msg["content"])) + 4 # 每条消息的 overhead
return total
def trim_conversation(messages, max_tokens=2000):
"""
滑动窗口裁剪:保留 system prompt + 最近 N 轮对话
超出 max_tokens 时,从最早的用户消息开始砍
"""
system_msgs = [m for m in messages if m["role"] == "system"]
chat_msgs = [m for m in messages if m["role"] != "system"]
# 从最新的消息往前保留,直到塞不下
trimmed = []
current_tokens = count_tokens(system_msgs)
for msg in reversed(chat_msgs):
msg_tokens = count_tokens([msg])
if current_tokens + msg_tokens > max_tokens:
break
trimmed.insert(0, msg)
current_tokens += msg_tokens
return system_msgs + trimmed
# 实际使用
conversation = [
{"role": "system", "content": system_prompt_good},
# ... 可能有 30 轮对话历史
]
# 裁剪到 2000 tokens 以内
trimmed = trim_conversation(conversation, max_tokens=2000)
response = client.chat.completions.create(
model="openclaw", # 通过聚合接口调用
messages=trimmed,
max_tokens=500
)
实测 30 轮对话的场景,不裁剪每次请求大概 4000-6000 tokens,裁剪后稳定在 1500-2000 tokens。光这一步就砍掉了 60% 的输入 Token。
1.3 摘要压缩(进阶)
滑动窗口有个问题——早期上下文丢了。用户第 3 轮说了个重要信息,到第 20 轮已经被裁掉了。
解决方案:对被裁掉的历史做摘要,塞进 system prompt。
def summarize_old_context(old_messages):
"""用便宜的小模型给旧对话做摘要"""
summary_response = client.chat.completions.create(
model="deepseek-v3", # 用便宜模型做摘要
messages=[
{"role": "system", "content": "用50字内总结以下对话的关键信息,只保留事实。"},
{"role": "user", "content": str(old_messages)}
],
max_tokens=100
)
return summary_response.choices[0].message.content
def smart_trim(messages, max_tokens=2000):
"""智能裁剪:旧消息摘要 + 新消息保留"""
system_msgs = [m for m in messages if m["role"] == "system"]
chat_msgs = [m for m in messages if m["role"] != "system"]
if count_tokens(messages) <= max_tokens:
return messages
# 找到需要裁掉的部分
keep_msgs = []
cut_msgs = []
current_tokens = count_tokens(system_msgs) + 200 # 预留摘要空间
for msg in reversed(chat_msgs):
msg_tokens = count_tokens([msg])
if current_tokens + msg_tokens > max_tokens:
cut_msgs = chat_msgs[:chat_msgs.index(msg) + 1]
break
keep_msgs.insert(0, msg)
current_tokens += msg_tokens
if cut_msgs:
summary = summarize_old_context(cut_msgs)
system_msgs[0]["content"] += f"\n[历史摘要]{summary}"
return system_msgs + keep_msgs
摘要用 DeepSeek V3 这种便宜模型跑,成本几乎可以忽略,但保住了关键上下文。
方案二:语义缓存层
微信小助手上线后发现一个规律:40% 的请求在语义上是重复的。比如不同用户都在问「明天天气怎么样」「帮我看看明天天气」「明天天气」,意思一模一样,每次都调 API 太浪费了。
import redis
import hashlib
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_cache_key(messages):
"""
生成缓存 key
简单方案:直接对最后一条用户消息做 hash
进阶方案:可以用 embedding 做语义相似度匹配
"""
last_user_msg = ""
for msg in reversed(messages):
if msg["role"] == "user":
last_user_msg = msg["content"]
break
# 归一化:去空格、转小写
normalized = last_user_msg.strip().lower()
return f"llm_cache:{hashlib.md5(normalized.encode()).hexdigest()}"
def cached_completion(messages, model="openclaw", ttl=3600):
"""带缓存的 API 调用"""
cache_key = get_cache_key(messages)
# 查缓存
cached = r.get(cache_key)
if cached:
print("[Cache HIT] 省了一次 API 调用")
return json.loads(cached)
# 缓存未命中,调 API
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=500
)
result = {
"content": response.choices[0].message.content,
"usage": {
"prompt_tokens": response.usage.prompt_tokens,
"completion_tokens": response.usage.completion_tokens
}
}
# 写缓存,TTL 1 小时
r.setex(cache_key, ttl, json.dumps(result, ensure_ascii=False))
print(f"[Cache MISS] 消耗 tokens: {response.usage.total_tokens}")
return result
这个方案虽然简单粗暴(纯文本 hash),在我的场景下缓存命中率达到了 35%。想做得更精细可以用 embedding 算语义相似度,命中率能到 50% 以上,但要多一次向量计算的开销,小项目可能不值得。
方案三:动态模型路由
这是我觉得最"聪明"的优化——不是所有请求都需要用最贵的模型。
思路很简单:简单问题用便宜模型,复杂问题才上 OpenClaw 或 Claude Opus 4.6。
def classify_complexity(user_message):
"""
简单的复杂度分类器
实际项目中可以用关键词匹配 + 小模型判断
"""
simple_patterns = ["你好", "谢谢", "查询", "几点", "天气", "帮我看看"]
complex_patterns = ["分析", "对比", "总结", "规划", "建议", "方案"]
msg = user_message.lower()
for p in complex_patterns:
if p in msg:
return "complex"
for p in simple_patterns:
if p in msg:
return "simple"
# 默认中等
return "medium"
def route_model(user_message):
"""根据复杂度选择模型"""
complexity = classify_complexity(user_message)
model_map = {
"simple": "deepseek-v3", # 简单问题,成本约 0.001 元/次
"medium": "openclaw", # 中等问题
"complex": "claude-opus-4.6", # 复杂推理
}
model = model_map[complexity]
print(f"[Router] 复杂度={complexity}, 使用模型={model}")
return model
# 实际调用
def smart_chat(messages):
last_msg = ""
for m in reversed(messages):
if m["role"] == "user":
last_msg = m["content"]
break
model = route_model(last_msg)
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=500
)
return response
跑了一周数据,请求分布大概是:简单 45%、中等 35%、复杂 20%。算下来整体成本比全部用 OpenClaw 低了约 55%。
整体架构长这样:
DeepSeek V3、OpenClaw、Claude Opus 4.6 都通过 ofox.ai 的聚合接口调,一个 API Key 切换不同模型,不用分别管各家的鉴权和 SDK。ofox.ai 是一个 AI 模型聚合平台,兼容 OpenAI 协议,低延迟直连,支持支付宝/微信付款,做模型路由只需要换 model 参数,代码完全不用改。
踩坑记录
坑 1:tiktoken 不支持 OpenClaw 的 tokenizer
tiktoken 目前没有 OpenClaw 的编码器,我用 gpt-4o 的编码器近似计算,实测误差在 5%-10% 左右。做预算控制够用了,但精确计费还是以 API 返回的 usage 为准。
坑 2:缓存 key 的归一化不够
一开始只做了去空格+转小写,结果「查日程」和「帮我查一下日程」就对不上。后来加了停用词过滤,命中率从 20% 提到了 35%。上 embedding 方案能更高,但要多一次向量计算的开销,小项目可能不值得。
坑 3:模型路由的分类器别用大模型做
我一开始想用 LLM 来判断复杂度,结果判断本身就要消耗 Token——脱裤子放屁。后来改成关键词匹配加消息长度启发式规则,零成本搞定。
小结
三招总结:
- Prompt 压缩 + 滑动窗口:最简单,立刻能做,输入 Token 砍 30-40%
- 语义缓存:适合有重复查询模式的场景,省 20-50% 的 API 调用
- 动态模型路由:把便宜模型用在简单任务上,整体成本降 30-60%
三个叠加起来,微信小助手的日均 Token 消耗从 280 万降到了 103 万,成本从每天大概 40 块降到 15 块左右。对个人项目来说,这个差距就是"能跑下去"和"跑不起"的区别。
OpenClaw 本身能力没问题,关键是学会该省省、该花花。有问题评论区聊。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)