Skip to content

上下文窗口与历史裁剪 ​

模型输入通常同时包含系统约束、用户问题、历史轮次、工具定义和工具结果。窗口上限不是“还能放多少字符”,而是输入 token、预留输出和平台额外字段的总预算。裁剪策略的核心不是删得越多越好,而是删掉一轮后是否还保留了能解释当前结论的证据。

按完整轮次裁剪 ​

保存为 context_budget.py,使用教学中已知的 token 数;真实系统应换成目标模型 tokenizer 或平台计数接口。工具请求与对应结果不可拆开,系统约束和当前用户输入也不能被历史裁剪删除。

python
def pack(turns, window, reserved_output, fixed_tokens):
    remaining = window - reserved_output - fixed_tokens
    if remaining < 0:
        raise ValueError('fixed input exceeds window')
    selected = []
    for turn in reversed(turns):
        if turn['tokens'] > remaining:
            break
        selected.append(turn)
        remaining -= turn['tokens']
    return list(reversed(selected))

history = [
    {'id': 'u1-a1', 'tokens': 18, 'kind': 'complete_turn'},
    {'id': 'u2-a2', 'tokens': 28, 'kind': 'complete_turn'},
    {'id': 'u3-tool', 'tokens': 42, 'kind': 'tool_pair'},
]
assert [x['id'] for x in pack(history, 100, 20, 20)] == ['u3-tool']
assert [x['id'] for x in pack(history, 130, 20, 20)] == ['u1-a1', 'u2-a2', 'u3-tool']
try:
    pack(history, 100, 20, 90)
except ValueError:
    print('fixed budget rejected')
else:
    raise AssertionError('impossible fixed budget accepted')

100 的窗口扣掉固定输入 20 和输出预留 20 后只剩 60,最新工具轮占 42,较早的 28 轮不能被硬塞进去。若你的业务需要跨轮引用,就要在裁剪前生成带来源 ID 的摘要,或把关键事实落到外部状态;不能把“摘要成功”当作原文仍在上下文中。

三种常见错误 ​

字符数代替 token 数:中文、代码、JSON 和图片占用不同;字符估算只能作为上限预警。只保留最后一条文本:会丢失工具调用与结果的关联。先压缩再写库:摘要失败或版本错误时会覆盖唯一的原始证据。生产实现应记录裁剪前后的 token 估计、删除的消息 ID、摘要来源和模型版本。

变化实验:工具请求和结果拆开 ​

把 u3-tool 拆成 u3-call 与 u3-result,让裁剪器只保留结果。下一次模型请求虽然可能仍返回文本,但没有调用 ID 和工具名,无法判断这个结果属于哪一次执行;如果结果包含付款或写库反馈,更会把不可验证的文本当事实。

练习 ​

  1. 把 history 增加一个 16-token 的安全策略轮,固定输入改为 24,重新计算保留结果。
  2. 给每轮增加 source_ids,裁剪后断言所有 tool_pair 仍保留调用 ID 和来源版本。
  3. 写一个摘要记录结构,至少包含原消息 ID、摘要模型版本、生成时间和未解决问题;说明为什么不能只保存摘要文本。

完成后继续多模态输入、能力矩阵与兼容边界。

用心记录每一步成长