以观书法
108.85M · 2026-02-05
Hacker News 上一条评论引发了广泛关注:
另一位用户补充:
为什么一个"AI 助手"会如此昂贵?
当你首次启动 Moltbot(原 Clawdbot) 并发送第一条消息时:
clawdbot gateway start
# T@elegrimm: "你好"
实际发送给 Claude API 的内容:
=== System Prompt (约 3,000 tokens) ===
You are Moltbot, a personal AI assistant...
[完整的系统提示词,包含:]
- 角色定义 (500 tokens)
- 可用工具列表 (1,500 tokens)
- 操作指南 (1,000 tokens)
=== Memory/Context (约 2,000 tokens) ===
[如果有历史记忆]
- 用户偏好 (500 tokens)
- 历史对话摘要 (1,000 tokens)
- Skills 定义 (500 tokens)
=== Tool Definitions (约 8,000 tokens) ===
{
"tools": [
{
"name": "bash",
"description": "Execute shell commands...",
"input_schema": {...} // 详细的 JSON Schema
},
{
"name": "browser",
"description": "Navigate web pages...",
"input_schema": {...}
},
// ... 20+ 个工具,每个 300-500 tokens
]
}
=== 用户消息 (约 10 tokens) ===
"你好"
=== 总计:约 13,010 tokens ===
Claude API 计费:
输入: 13,010 tokens × $3/M = $0.039
输出: 50 tokens × $15/M = $0.00075
单次交互: $0.04
看起来不多,但这只是"你好"的成本。
场景:让 Moltbot(原 Clawdbot) 查天气
用户: "查一下北京明天的天气"
Moltbot(原 Clawdbot) 的执行流程:
Step 1: 理解意图 (13k+ tokens 输入)
上下文: 13,000 tokens (System + Tools)
用户消息: 20 tokens
总输入: 13,020 tokens
输出 (工具调用): 100 tokens
Step 2: 执行 browser tool (30k+ tokens 输入)
// Clawdbot 决定使用 browser 访问天气网站
browser_navigate("https://weather.com/weather/tomorrow/l/Beijing")
// 网页内容返回 (HTML → Markdown)
约 15,000 tokens 的网页内容
下一轮 API 调用:
上下文: 13,000 tokens
历史消息:
- User: "查一下北京明天的天气" (20 tokens)
- Assistant: tool_use(browser_navigate...) (100 tokens)
- Tool Result: [15,000 tokens 的网页内容]
总输入: 28,120 tokens
输出: 200 tokens (解析天气信息)
Step 3: 格式化回复 (30k+ tokens 输入)
上下文: 13,000 tokens
完整历史:
- 所有之前的消息和工具调用 (15,220 tokens)
总输入: 28,220 tokens
输出: 150 tokens (用户友好的回复)
总计:
输入 Token:
13,020 + 28,120 + 28,220 = 69,360 tokens
输出 Token:
100 + 200 + 150 = 450 tokens
成本:
输入: 69,360 × $3/M = $0.208
输出: 450 × $15/M = $0.0068
总计: $0.215
一个"查天气"的请求,成本是"你好"的 5倍以上。
用户在一天内执行的任务:
1. 查天气 (3次交互)
2. 整理文件 (10次交互,Agent loop)
3. 发送邮件 (5次交互)
4. 浏览网页总结 (8次交互)
5. 创建提醒 (3次交互)
...
总计: 100+ 次交互
每次交互都包含完整上下文,Token 线性累积:
交互1: 13k tokens
交互2: 13k + 15k (上一轮历史) = 28k tokens
交互3: 13k + 15k + 15k = 43k tokens
...
交互100: 13k + 87k (99轮历史) = 100k tokens
如果历史记录没有及时清理,后期每次交互都是巨额消耗。
Claude API 是无状态的,每次调用都需要重新发送所有上下文:
// Clawdbot 的调用逻辑
async function sendMessage(userMessage: string) {
const history = await db.getAllMessages(); // 获取所有历史
const response = await claude.messages.create({
model: 'claude-opus-4.5',
system: SYSTEM_PROMPT, // 3,000 tokens
tools: ALL_TOOLS, // 8,000 tokens
messages: [
...history, // 可能有几万到几十万 tokens
{role: 'user', content: userMessage}
]
});
return response;
}
即使 Anthropic 有服务端缓存(Prompt Caching),也只缓存"完全相同"的前缀。
如果历史消息哪怕改变一个字符,缓存失效,全部重新计费。
Moltbot(原 Clawdbot) 支持 20+ 个工具,每个工具的 input_schema 非常详细:
{
"name": "browser",
"description": "Navigate and interact with web pages...",
"input_schema": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["navigate", "click", "type", "scroll", "screenshot", ...],
"description": "详细描述每个 action..."
},
"url": {
"type": "string",
"format": "uri",
"description": "完整的 URL 规则..."
},
"selector": {
"type": "string",
"description": "CSS selector 或 XPath..."
},
// ... 还有十几个参数
},
"required": ["action"],
"additionalProperties": false
}
}
每个工具 300-500 tokens,20 个工具就是 6,000-10,000 tokens。
而且每次调用都要重新发送这些定义,因为 API 无状态。
Browser Tool 返回的内容是完整的网页(转成 Markdown):
原始 HTML: 150 KB
转换后 Markdown: 50 KB
Token 数: 约 15,000
如果网页内容很长(比如新闻网站、文档页面),可能超过 50,000 tokens。
Moltbot(原 Clawdbot) 没有做"智能截断"或"摘要",直接把全部内容喂给 AI。
有时 Agent 会进入"无限循环":
User: "帮我找一下最新的 AI 新闻"
Agent 执行:
1. browser_navigate(hackernews.com)
→ 发现需要点击"More"
2. browser_click("More")
→ 发现还有"More"
3. browser_click("More")
→ 又有"More"
4. browser_click("More")
...
[循环 20 次]
每次循环都是一轮完整的 API 调用,上下文不断增长。
最终可能消耗 几百万 tokens,用户才意识到出问题了。
为什么 Claude Code 不会"烧钱",但 Moltbot(原 Clawdbot) 会?
1. 使用订阅 Token
Claude Code 使用 Claude Pro/Max 订阅的配额,不按 token 计费:
Claude Pro: $20/月,"无限"对话(有速率限制)
Claude Code: 使用同一配额
用户不会看到具体的 token 消耗,只会遇到速率限制("请稍后再试")。
2. 上下文窗口限制
Claude Code 主动限制上下文:
// 伪代码
const MAX_CONTEXT_TOKENS = 100000;
function trimContext(messages) {
let tokens = 0;
let result = [];
// 从最近的消息开始往回取
for (let i = messages.length - 1; i >= 0; i--) {
const msgTokens = estimateTokens(messages[i]);
if (tokens + msgTokens > MAX_CONTEXT_TOKENS) break;
tokens += msgTokens;
result.unshift(messages[i]);
}
return result;
}
如果历史超过 10 万 tokens,只保留最近的部分。
3. 工具动态加载
Claude Code 不是一次性发送所有工具,而是根据任务动态选择:
用户: "读取 README.md"
→ 只发送 filesystem 工具定义
用户: "访问 example.com"
→ 只发送 browser 工具定义
这样每次调用的 tools 定义只有 500-1000 tokens,而不是 8000 tokens。
设计哲学差异:
Claude Code:
- 专注单一任务(coding)
- 明确的任务边界
- Anthropic 控制成本
Moltbot(原 Clawdbot):
- 通用助手(什么都能做)
- 模糊的任务边界
- 用户自己承担成本
Moltbot(原 Clawdbot) 追求"全能",代价是无法精细优化。
Anthropic 提供了 Prompt Caching 功能(2025年底推出):
const response = await claude.messages.create({
model: 'claude-opus-4.5',
system: [
{
type: 'text',
text: SYSTEM_PROMPT,
cache_control: {type: 'ephemeral'} // 缓存这部分
}
],
tools: ALL_TOOLS.map(tool => ({
...tool,
cache_control: {type: 'ephemeral'} // 缓存工具定义
})),
messages: history
});
效果:
第1次调用:
输入: 13,000 tokens (全部计费)
缓存: 11,000 tokens (System + Tools)
第2次调用:
输入: 2,000 tokens (只计费新增的历史)
缓存命中: 11,000 tokens (减免计费)
节省: 约 85% 的 token 成本
但需要注意:
将历史消息分成三层:
class ContextManager {
async getContext(sessionId: string) {
// 短期记忆:最近 10 轮,完整保留
const recentMessages = await db.getMessages(sessionId, 10);
// 中期记忆:最近 100 轮,只保留摘要
const midTermSummary = await this.summarize(
await db.getMessages(sessionId, 100, 10)
);
// 长期记忆:所有历史,提取关键事实
const longTermFacts = await db.getKeyFacts(sessionId);
return {
recent: recentMessages, // 完整对话
summary: midTermSummary, // "用户询问了天气、日程、邮件"
facts: longTermFacts // "用户是素食者、住在北京"
};
}
async summarize(messages) {
// 使用便宜的模型(Haiku)生成摘要
const summary = await claude.messages.create({
model: 'claude-haiku-4.5', // $0.25/M 输出 token
messages: [{
role: 'user',
content: `总结以下对话的关键信息,忽略闲聊:n${messages.join('n')}`
}]
});
return summary.content[0].text;
}
}
效果:
之前:
上下文: 10 万 tokens (所有历史)
现在:
最近 10 轮: 5,000 tokens
中期摘要: 500 tokens
长期事实: 200 tokens
总计: 5,700 tokens
节省: 94% 的 token
不要一次性发送所有工具定义,根据任务类型动态选择:
function selectTools(userMessage: string): Tool[] {
const intent = classifyIntent(userMessage);
const toolGroups = {
filesystem: ['read_file', 'write_file', 'list_dir'],
web: ['browser', 'web_fetch'],
communication: ['gmail', 'telegram', 'slack'],
system: ['bash', 'cron'],
// ...
};
// 根据意图选择相关工具
let selectedTools = [];
if (intent.includes('file')) {
selectedTools.push(...toolGroups.filesystem);
}
if (intent.includes('web')) {
selectedTools.push(...toolGroups.web);
}
return selectedTools;
}
效果:
之前:
工具定义: 8,000 tokens (20+ 工具)
现在:
工具定义: 1,500 tokens (3-5 工具)
节省: 81% 的工具 token
对 Browser Tool 返回的内容进行智能截断:
async function fetchWebContent(url: string) {
const html = await browser.navigate(url);
const markdown = htmlToMarkdown(html);
// 如果内容过长,进行摘要
if (estimateTokens(markdown) > 10000) {
const summary = await claude.messages.create({
model: 'claude-haiku-4.5', // 使用便宜的模型
messages: [{
role: 'user',
content: `总结以下网页的核心内容,保留关键信息:n${markdown}`
}]
});
return summary.content[0].text; // 约 500-1000 tokens
}
return markdown;
}
效果:
之前:
网页内容: 15,000 tokens
现在:
摘要: 800 tokens
节省: 95% 的内容 token
设置硬性上限,防止失控:
class CostGuard {
private dailySpent = 0;
private sessionSpent = new Map<string, number>();
async checkBudget(sessionId: string, estimatedCost: number) {
const config = {
dailyLimit: 10.0, // $10/天
sessionLimit: 2.0, // $2/会话
alertThreshold: 0.8
};
// 检查日总量
if (this.dailySpent + estimatedCost > config.dailyLimit) {
throw new Error(
`日预算已用尽 ($${this.dailySpent.toFixed(2)}/${config.dailyLimit})`
);
}
// 检查会话总量
const spent = this.sessionSpent.get(sessionId) || 0;
if (spent + estimatedCost > config.sessionLimit) {
throw new Error(
`会话预算已用尽 ($${spent.toFixed(2)}/${config.sessionLimit})n` +
`建议运行 'session clear' 清理历史`
);
}
// 预警
if (spent + estimatedCost > config.sessionLimit * config.alertThreshold) {
console.warn(`️ 会话成本接近上限:$${(spent + estimatedCost).toFixed(2)}`);
}
}
recordCost(sessionId: string, cost: number) {
this.dailySpent += cost;
this.sessionSpent.set(
sessionId,
(this.sessionSpent.get(sessionId) || 0) + cost
);
}
}
不是所有任务都需要 Opus-4.5:
function selectModel(task: Task): string {
// 简单任务:Haiku (便宜 60 倍)
if (task.type === 'simple_qa' || task.type === 'summarize') {
return 'claude-haiku-4.5';
}
// 中等任务:Sonnet (便宜 5 倍)
if (task.type === 'code_review' || task.type === 'analysis') {
return 'claude-sonnet-4.5';
}
// 复杂任务:Opus
if (task.type === 'complex_reasoning') {
return 'claude-opus-4.5';
}
}
成本对比:
Haiku: 输入 $0.25/M, 输出 $1.25/M
Sonnet: 输入 $3/M, 输出 $15/M
Opus: 输入 $15/M, 输出 $75/M
如果 50% 的任务可以用 Haiku,成本降低 40%+
按照上述优化方案,重新计算"查天气"的成本:
优化前:
3 次交互,每次 28k tokens
总输入: 84,000 tokens → $0.252
总输出: 450 tokens → $0.007
总计: $0.259
优化后:
启用 Prompt Caching:
第1次: 13,000 tokens (全部计费)
第2次: 2,000 tokens (缓存命中)
第3次: 2,000 tokens (缓存命中)
总输入: 17,000 tokens → $0.051
网页摘要:
原 15,000 tokens → 800 tokens
节省 14,200 tokens → $0.043
使用 Haiku 生成摘要:
原 Opus $0.007 → Haiku $0.001
节省: $0.006
总计: $0.259 → $0.051
节省: 80%
如果用户一天执行 100 个类似任务:
优化前: $0.259 × 100 = $25.9/天
优化后: $0.051 × 100 = $5.1/天
月成本:
优化前: $777
优化后: $153
# 查看当前会话的 token 消耗
clawdbot session info telegram:@your_username
# 如果消耗过大,清理历史
clawdbot session clear telegram:@your_username
# 查看今日消耗
clawdbot cost today
# 设置预算上限
clawdbot config set cost.dailyLimit 10.0
如果任务执行超过 5 分钟还没完成,手动中断:
Ctrl+C
# 或在 T@elegrimm 发送 "/stop"
# 修改配置
clawdbot config set agent.model claude-sonnet-4.5
# 或根据任务手动指定
clawdbot agent --model haiku "总结这篇文章"
这些优化可以将成本降低 70-90%,让 Moltbot(原 Clawdbot) 真正可用。
目前的状态:能用,但太贵。
优化后的状态:能用,且可承受。