3.3 上下文组装的时机与策略


3.3 上下文组装的时机与策略

本节摘要:主循环四拍中的第一拍——感知——值得单独一节,因为它决定了模型"此刻的智商"。LLM API 无状态,messages 列表就是模型的全部世界;因此每一步决策前都是一次重新供料,而不是开局组装一次管到底。本节回答三个问题:装什么(上下文五层清单:系统提示词、任务与对话历史、工具定义、工具结果、环境状态);怎么裁(预算分配 + 截断 / 摘要 / 引用化三板斧);以及与主循环的接口约定——assemble_context() 必须是循环里一个可替换的策略函数,而不是散落各处的拼接代码。本节是第 7 章上下文工程的序章:那里将展开压缩、记忆分层与 Claude Code 式 compaction 的完整设计,本章只立骨架。

学习目标

阅读完本节,你应当能够:

  1. 解释"每一步都是重新组装"这条时序规则及其推论。
  2. 列出上下文五层清单及各层的典型预算占比。
  3. 说出裁剪三板斧(截断、摘要、引用化)的适用场景。
  4. 把上下文组装重构为 assemble_context() 策略函数。

一、时机:每一步决策前,重新供料

新手最常见的误解是"上下文在任务开始时构建一次"。实际上:

第 1 步前:组装(系统提示词 + 任务 + 工具定义) 第 2 步前:重组装(上面全部 + 第 1 步的工具结果) 第 3 步前:再重组装(…… + 第 2 步的结果;旧的日志可能要裁掉)

两条推论:

  1. 上下文是易耗品:每步的工具结果都在往 messages 里加东西,窗口迟早装满——不设计裁剪策略的 harness,长任务必然在某一步"窗口爆炸"或静默降智。
  2. 上下文是决策面:模型这一步表现好,前提是"该看见的在、不该看见的裁"。供料策略与模型能力同等重要——同一个模型,供料好坏可以差出档位(社区共识,也是第 7 章成章的理由)。

二、装什么:五层清单

内容 来源 典型占比(示意)
L1 系统提示词 身份、环境、约束、输出格式 harness 写死 / 配置 5~10%
L2 任务与历史 用户任务 + 对话与决策记录 会话累积 20~30%
L3 工具定义 可用工具的 schema 清单 工具系统(第 4 章) 10~15%
L4 工具结果 文件内容、命令输出、检索片段 每步执行产出 40~60%(大头)
L5 环境状态 文件树、git 状态、任务清单 按需探查 5~10%

(占比为教学示意值;真实分布随任务类型漂移——数据处理类任务的 L4 占比会显著更高。)

要点:L4 是唯一的"无限增长层",所有裁剪策略都主要冲它去;L3 是常驻税——工具一多,schema 清单本身就吃掉可观预算,这是第 4.2 节工具路由的动机之一(按任务只挂子集);L1+L2+L3+L5 加起来,就是一个 harness 的"供料个性"——第 2 章看到的 CLAUDE.md(随仓库走的项目约定)就住在 L1/L5 的交界处。

三、怎么裁:预算与三板斧

先分预算再裁剪。示意性的预算分配:总窗口预留 20% 给模型输出与余量,L1/L3 常驻固定,剩余按"近期优先"原则在 L2/L4 间动态分配。

超预算时,三板斧按代价从低到高:

斧法 做法 适用 代价
截断 只保留最近 N 轮历史 / 单条结果截首尾 陈旧对话、超长日志 丢失的信息可能正是关键
摘要 用模型把旧历史压成一段摘要替换原文 长任务中途压缩 一次额外模型调用 + 摘要有损
引用化 大内容存盘,上下文里只放"路径 + 摘要行",要用再读 大文件、批量检索结果 多一次工具往返

💡 预算第一课:永远给模型输出留 20% 余量。供料塞满窗口的循环,第一个症状是"模型说话越来越短"——很多人误以为是模型降智,其实是窗口见底(示意场景,第 7 章展开压缩的系统性解法)。

💡 引用化是 harness 独有的招:聊天产品里做不到"上下文里放个指针、要用再取",harness 有工具系统就能做到——把大文件读一次存到本地,上下文里只留 app.py(约 800 行,含 auth 模块)→ .cache/app.py。模型后续要用时自己调 read_file 取段。这一招把"上下文窗口"扩成了"文件系统 + 窗口"的两级存储。第 7 章的记忆分层是它的体系化版本。

四、接口:供料必须是策略函数

反模式:把消息拼接散在循环各处(append 完就不管)。正模式:循环只持有一句话——messages = assemble_context(state)——供料是一个可替换的策略

# context.py —— 上下文组装策略接口(写法示意,以实际工程为准) def assemble_context(state: "RunState", budget: int) -> list[dict]: """循环第一拍的唯一入口。state 含任务、历史、工具结果、环境。 职责:在 budget(token 数)内产出本步 messages。 第 7 章将替换为:分层预算 + 自动压缩 + 记忆存取的完整实现。""" msgs = [system_prompt(state), user_task(state), *tool_schemas(state)] msgs += fit_to_budget(recent_history(state), remaining(msgs, budget)) return msgs

这个接口约定的价值:第 7 章升级供料策略时,循环代码一行不改;第 9 章做观测时,在 assemble_context 出口记一行"本步装了什么、裁了什么",供料决策第一次变得可审计。组件化的意义再次出现:上下文工程不是一个模块目录,而是循环第一拍上的一族可替换策略。

五、本章积木盘点

第 3 章结束时,你的仓库应该有三块积木:mini_loop.py(四拍循环 + 终止判断)、breaker.py(熔断器)、context.py(供料策略接口)。它们就是第 10 章 mini-harness 的心脏、免疫系统和视网膜——但循环要转得有价值,还差一样东西:让模型真正有手有脚的工具系统。下一章进入。

本节要点回顾

  1. 时机规则:每步决策前重新供料;上下文是易耗品(L4 无限增长)也是决策面(供料好坏差出档位)。
  2. 五层清单:系统提示词 / 任务历史 / 工具定义 / 工具结果 / 环境状态;L4 是裁剪主战场,L3 是常驻税。
  3. 三板斧:截断、摘要、引用化(harness 独有:窗口 + 文件系统的两级存储)。
  4. 接口约定:供料是循环第一拍上的可替换策略函数 assemble_context(state, budget)

循环有了心脏(四拍)、免疫系统(熔断)、视网膜(供料)。下一章给它装上手脚——工具系统:怎么定义工具模型才用得对,工具多了怎么路由,以及失败时怎么把错误变成信息。

延伸阅读:同站教程库《smolagents》。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U