Skip to main content

什么是消息剪裁?

消息剪裁(Message Pruning)是一种自动管理对话历史长度的机制,在保持对话连贯性的同时,减少不必要的 Token 消耗。

为什么需要剪裁?

降低成本

减少 Token 使用,降低 API 调用成本

提升性能

减少输入长度,加快模型响应速度

避免超限

防止超过模型的上下文长度限制

保持质量

移除冗余信息,保留关键上下文

启用剪裁

设置 prune: true 启用消息剪裁:
{
  "model": "anthropic/claude-3-7-sonnet-20250219",
  "messages": [...],
  "prune": true
}

剪裁选项

通过 pruneOptions 自定义剪裁行为:
自定义剪裁配置
{
  "prune": true,
  "pruneOptions": {
    "targetTokens": 60000,
    "preserveRecentMessages": 5
  }
}
重要:如果不设置 pruneOptions,系统使用默认值(targetTokens: 80000),适用于大多数场景。只有在需要更激进的剪裁时才需要自定义配置。

参数说明

参数类型默认值说明
targetTokensnumber80000触发剪裁的阈值。当消息总 Token 数超过此值时,会执行剪裁优化
maxOutputTokensnumber100000剪裁后消息的绝对上限(超过会警告但不阻止)
preserveRecentMessagesnumber3始终保留的最新消息数量(确保对话连贯性,建议至少保留 3 条最新消息)
参数理解
  • targetTokens:小于此值不会触发剪裁,大于此值才开始优化
  • maxOutputTokens:剪裁的最终目标上限,但不是硬性限制
  • preserveRecentMessages:无论如何都会保留的消息数,设置过小可能影响对话连贯性

剪裁策略

系统会根据消息历史的特征自动选择最合适的优化策略
适用场景:消息总数适中,仅需轻度优化策略
  • 保留最近的 N 条消息(由 preserveRecentMessages 控制)
  • 从较早的消息开始逐步移除
  • 确保 user/assistant 消息对的完整性
  • 系统提示词始终保留
适用场景:消息中包含大量图片或文件附件策略
  • 优先移除历史消息中的图片和文件 part
  • 保留文本内容以维持对话连贯性
  • 显著降低 Token 消耗(图片占用大量 tokens)
适用场景:消息历史既长又包含附件策略
  • 结合移除旧消息和移除附件
  • 平衡对话历史和 Token 消耗
  • 根据消息重要性动态调整
适用场景:消息总数远超阈值,需要大幅减少策略
  • 仅保留最近的核心消息
  • 移除大部分历史对话
  • 优先保证响应速度和成本
适用场景:消息总数略超阈值策略
  • 最小化的调整
  • 仅移除少量最早的消息
  • 最大程度保留上下文
自动策略选择:您无需手动选择策略,系统会根据消息历史的长度、内容类型(是否包含图片)、Token 总数等因素自动选择最优策略。

检查剪裁结果

响应头 X-Message-Pruned 指示是否进行了剪裁:
X-Message-Pruned: true

完整示例

大多数情况下,使用默认配置即可:
const response = await fetch("https://huajune.duliday.com/api/v1/chat", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "anthropic/claude-3-7-sonnet-20250219",
    messages: longConversationHistory, // 对话历史
    prune: true, // 仅启用剪裁,使用默认配置
    stream: false,
  }),
});

// 检查是否进行了剪裁
const isPruned = response.headers.get("X-Message-Pruned") === "true";
if (isPruned) {
  console.log("消息已剪裁以优化成本");
}

const data = await response.json();
console.log(`输入 tokens: ${data.data.usage.inputTokens}`);
默认配置targetTokens: 80000, preserveRecentMessages: 3。这适用于绝大多数场景,无需手动调整。

最佳实践

不同场景使用不同的剪裁配置:
{
  "prune": true,
  "pruneOptions": {
    "targetTokens": 60000,
    "preserveRecentMessages": 8
  }
}
推荐策略
  • 默认配置适用于大多数场景(80000 tokens 阈值)
  • 只有在明确需要更激进的成本控制时才降低 targetTokens
  • preserveRecentMessages 建议保持在 3-8 之间
记录剪裁前后的消息数量和 Token 变化:
监控剪裁效果
const originalLength = messages.length;
const estimatedTokens = messages.length * 100; // 粗略估算

const response = await fetch(url, {
  method: "POST",
  headers: { /* ... */ },
  body: JSON.stringify({
    messages,
    prune: true,
    pruneOptions: { targetTokens: 50000 }
  })
});

const isPruned = response.headers.get('X-Message-Pruned') === 'true';
const data = await response.json();

console.log('剪裁统计:');
console.log(`  - 原始消息数: ${originalLength} 条`);
console.log(`  - 是否剪裁: ${isPruned ? '是' : '否'}`);
console.log(`  - 实际输入 tokens: ${data.data.usage.inputTokens}`);
console.log(`  - 节省比例: ${isPruned ?
  Math.round((1 - data.data.usage.inputTokens / estimatedTokens) * 100) : 0}%`);
使用返回的 usage 信息监控和优化成本:
Token 成本监控
const response = await fetch(url, { /* ... */ });
const data = await response.json();
const { inputTokens, outputTokens, totalTokens } = data.data.usage;

// 计算成本(以 Claude 3.7 Sonnet 为例)
const INPUT_COST_PER_1M = 3.0;   // $3 per 1M input tokens
const OUTPUT_COST_PER_1M = 15.0; // $15 per 1M output tokens

const inputCost = (inputTokens / 1_000_000) * INPUT_COST_PER_1M;
const outputCost = (outputTokens / 1_000_000) * OUTPUT_COST_PER_1M;
const totalCost = inputCost + outputCost;

console.log(`Token 使用情况:`);
console.log(`  输入: ${inputTokens} tokens (\$${inputCost.toFixed(4)})`);
console.log(`  输出: ${outputTokens} tokens (\$${outputCost.toFixed(4)})`);
console.log(`  总计: ${totalTokens} tokens (\$${totalCost.toFixed(4)})`);

// 如果成本过高,考虑调整 targetTokens
if (inputTokens > 70000) {
  console.warn('⚠️ 输入 tokens 较高,建议降低 targetTokens 参数');
}
成本优化建议
  • 定期监控每次请求的 Token 使用量
  • 如果输入 tokens 持续偏高,考虑降低 targetTokens
  • 平衡成本与对话质量,避免过度剪裁
根据实际使用情况动态调整剪裁参数:
动态调整策略
async function chatWithAdaptivePruning(messages) {
  // 根据消息数量动态决定是否需要剪裁
  const messageCount = messages.length;

  let pruneConfig = {
    prune: false  // 默认不剪裁
  };

  if (messageCount > 100) {
    // 超长对话:更激进的剪裁
    pruneConfig = {
      prune: true,
      pruneOptions: {
        targetTokens: 45000,
        preserveRecentMessages: 10
      }
    };
  } else if (messageCount > 50) {
    // 长对话:启用剪裁
    pruneConfig = {
      prune: true,
      pruneOptions: {
        targetTokens: 60000,
        preserveRecentMessages: 8
      }
    };
  }

  const response = await fetch(url, {
    method: "POST",
    headers: { /* ... */ },
    body: JSON.stringify({
      model: "anthropic/claude-3-7-sonnet-20250219",
      messages,
      ...pruneConfig,
      stream: false
    })
  });

  return response.json();
}
动态策略优势
  • 短对话无需剪裁,保持完整上下文
  • 长对话自动优化,降低成本
  • 根据业务场景灵活调整

注意事项

剪裁的权衡考虑剪裁会移除部分对话历史,可能影响:
  • 对早期内容的引用(AI 无法访问已删除的消息)
  • 需要完整上下文的任务(如长篇文档分析)
  • 多轮复杂推理(依赖历史推理步骤)
建议
  • 在成本敏感的场景中优先使用剪裁
  • 关键对话或需要完整上下文的任务中谨慎使用
  • 通过 preserveRecentMessages 保留足够的最新消息(建议 ≥ 3)

性能对比

以下是使用自定义激进配置targetTokens: 40000)的性能对比:
场景不剪裁启用剪裁(激进)节省
100 条消息对话~25,000 tokens~10,000 tokens60%
50 条消息对话~12,000 tokens~8,000 tokens33%
20 条消息对话~5,000 tokens无需剪裁-
包含图片的 50 条对话~45,000 tokens~15,000 tokens67%
说明
  • 上表基于 targetTokens: 40000 的自定义配置,非默认值
  • 使用默认配置targetTokens: 80000)时,100 条消息对话(~25k tokens)不会触发剪裁
  • 图片和文件附件占用大量 tokens,使用 aggressive_image_removal 策略可显著降低成本
  • 实际节省比例取决于消息长度、内容类型和配置参数

成本节省示例

以 Claude 3.7 Sonnet 为例(输入 $3/1M tokens,输出 $15/1M tokens):
场景原始成本剪裁后成本节省金额
1000 次调用$75.00$30.00$45.00 (60%)
10000 次调用$750.00$300.00$450.00
100万次调用$75,000.00$30,000.00$45,000.00
对于高频调用的应用,启用消息剪裁可以显著降低 API 成本,特别是在长对话和包含附件的场景中。

下一步