Bootstrap

超越限制:大模型token管理与优化实践

前言

在大型语言模型(LLM)的应用中,token数量的管理是一个核心挑战。无论是模型的输入限制、计算资源的分配,还是成本的控制,token计数都至关重要。然而,当调用超过预期范围时,我们该如何应对?本书以一段简单的Python代码为起点,探索token管理的实用方法,帮助开发者从临时方案走向系统化解决方案。

第一章:问题的起源——调用超预期

1.1 大模型的token限制

  • LLM为何对token敏感?从输入上下文窗口到输出生成长度。
  • 案例:调用API时意外超出限制的后果(错误、成本激增)。
  • 引出问题:如何提前发现和管理超预期情况?

1.2 临时方案的诞生

  • JSON结构:"original_data"作为输入,"generated_text"作为输出。
  • 代码简介:统计token的简单工具。
  • 临时方案的优势与局限性。

第二章:代码解构——从临时到实用

2.1 核心功能分析

以下是代码,我将逐部分解释其在token管理中的作用:

import os
import json
import tiktoken

def calculate_token(text, model="deepseek-v3"):
    """计算文本的token数量"""
    try:
        encoding = tiktoken.encoding_for_model(model)
        tokens = encoding.encode(text)
        return len(tokens)
    except KeyError:
        print("模型编码未找到。使用默认编码。")
        encoding = tiktoken.get_encoding("cl100k_base")
        tokens = encoding.encode(text)
        return len(tokens)

def calculate_total_tokens(output_dir):
    """计算输出目录中所有JSON文件的总输入和输出token数量"""
    total_input_tokens = 0
    total_output_tokens = 0
    total_files = 0

    for filename in os.listdir(output_dir):
        if filename.endswith(".json"):
            file_path = os.path.join(output_dir, filename)
            try:
                with open(file_path, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    input_tokens = calculate_token(data["original_data"])
                    output_tokens = calculate_token(data["generated_text"])
                    total_input_tokens += input_tokens
                    total_output_tokens += output_tokens
                    total_files += 1
                    print(f"文件: {filename}, 输入token: {input_tokens}, 输出token: {output_tokens}")
            except Exception as e:
                print(f"处理文件 {filename} 时出错: {e}")

    print(f"\n总文件数: {total_files}")
    print(f"总输入token数: {total_input_tokens}")
    print(f"总输出token数: {total_output_tokens}")

output_dir = "generated_jsons"
calculate_total_tokens(output_dir)
  • calculate_token:计算单段文本的token数,支持特定模型(如“deepseek-v3”),并提供备用编码。
  • calculate_total_tokens:扫描目录,统计所有JSON文件的输入和输出token总数。
  • JSON结构:临时设计的"original_data""generated_text"字段,直观反映模型的输入输出。

2.2 代码的应用场景

  • 调试:快速检查每次调用的token消耗。
  • 成本估算:按token计费时,预估总费用。
  • 优化提示:识别长输入或冗长输出,调整策略。

2.3 局限性与改进方向

  • 临时性:JSON结构简单,但缺乏元数据(如模型参数、时间戳)。
  • 单一性:仅支持固定字段,难以扩展。
  • 性能:对大量文件处理效率低。

第三章:应对超预期——策略与实践

3.1 识别超预期情况

  • 定义“预期范围”:输入token上限、输出token预算。
  • 使用代码监控:实时统计token,设置阈值告警。

3.2 优化输入

  • 文本压缩:去除冗余内容,精简"original_data"
  • 分段处理:将长输入拆分为多个调用。
  • 示例代码:扩展calculate_token以支持分段。

3.3 控制输出

  • 生成参数调整:限制"generated_text"长度(如设置max_tokens)。
  • 后处理:截断或总结超长输出。
  • 示例代码:添加输出token阈值检查。

3.4 成本管理

  • 计算token成本:结合API定价(如每千token $0.002)。
  • 扩展代码:输出成本估算报告。

第四章:从临时到系统化

4.1 改进JSON结构

  • 增强版JSON:
    {
      "input": {
        "text": "Hello, world!",
        "token_count": 4,
        "timestamp": "2025-03-12T10:00:00"
      },
      "output": {
        "text": "Hello, world! How are you?",
        "token_count": 8,
        "model_params": {"max_tokens": 50}
      }
    }
    
  • 优点:自描述性强,可追溯。

4.2 构建token管理系统

  • 数据库存储:从JSON文件升级到SQLite或MongoDB。
  • 实时监控:集成API调用,动态更新token统计。
  • 可视化:用Matplotlib生成token使用图表。

4.3 示例实现

  • 扩展代码:添加数据库支持、阈值告警和可视化。
import sqlite3
import matplotlib.pyplot as plt

def save_to_db(data, db_path="token_usage.db"):
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS usage 
                 (filename TEXT, input_tokens INTEGER, output_tokens INTEGER)''')
    for filename, input_t, output_t in data:
        c.execute("INSERT INTO usage VALUES (?, ?, ?)", (filename, input_t, output_t))
    conn.commit()
    conn.close()

# 结合calculate_total_tokens,保存结果到数据库并绘图

第五章:未来展望

  • 自动化token优化:AI驱动的输入输出调整。
  • 跨模型兼容:支持更多模型的token化方案。
  • 云端集成:将token管理部署为服务。

附录

  • 代码完整版:包含所有扩展功能。
  • 资源链接tiktoken文档、LLM优化指南。

示例章节:第三章 - 应对超预期

3.1 识别超预期情况

当模型调用超出预期时,可能表现为:

  • 输入超限"original_data"超过模型上下文窗口(例如,GPT-3.5的4096 token)。
  • 输出冗长"generated_text"超出预算,增加成本。

使用现有代码,我们可以:

  1. 运行calculate_total_tokens,获取统计。
  2. 设置阈值,例如输入token > 3000 或输出token > 1000 时警告。
if total_input_tokens > 3000:
    print("警告:输入token超出预期范围!")

3.2 优化输入

"original_data"过长,可尝试:

  • 手动精简:删除不必要内容。
  • 自动分段
def split_text(text, max_tokens=2000):
    encoding = tiktoken.get_encoding("cl100k_base")
    tokens = encoding.encode(text)
    if len(tokens) <= max_tokens:
        return [text]
    segments = []
    for i in range(0, len(tokens), max_tokens):
        segment = encoding.decode(tokens[i:i + max_tokens])
        segments.append(segment)
    return segments
;