第7章 上下文组装与按需加载
第6章解决了步骤怎样组织,接下来要决定每次判断依据什么。一个计划可以仍然有效,上一阶段的全部材料却未必值得再次提交;一个工具可以已经接入,完整定义却未必需要从任务开始一直占据输入。上下文建设的起点不是删掉多少历史,而是说明这一步为什么需要这些信息。
第3章的摘录系统已经具有最小组装规则:基础指令、当前任务、两个工具定义和合法往返历史共同进入请求;创建文件前,来源必须已进入产生该创建请求的输入。本章沿这套系统解释怎样进一步控制材料的准入、停留和退出。窗口与前缀复用的讨论用于说明原理,代码与布局示意不代表原实现已有动态工具激活或后缀清理。随书 capability_lab.py 另示范按阶段加载方法资源;它改变的是方法说明,不是工具集合或推理端缓存。
7.1本次判断与材料选择
上下文组装是宿主程序为一次模型请求选择、标注并排列信息的过程。宿主就是持有任务条件、调用工具并向模型发送请求的程序。组装不是把会话档案完整复制,也不是替模型决定所有业务结论。最小形态是一份当前判断说明、一组来源明确的必要材料,以及组装后可核对的请求。第2章已经区分会话、用户 turn、消息和模型请求:本章选择的是某次请求的输入,不是在改写整个会话发生过什么。
每次组装先回答五个问题。来源(source)说明内容来自用户、程序、模型还是外部材料,以及谁对哪部分可靠性负责。任务(task)说明当前目标、验收条件和已接收的纠正。状态(state)说明程序实际推进到哪里、哪些动作未完成、哪些结果未知。证据(evidence)说明本次判断可以引用哪些观察及其版本。发送规则说明哪些内容可送给哪个模型、可用于什么目的。它们是五类责任,不要求请求必须具有五个同名字段。
来源不只是消息角色。read_source 是固定工具,它可以可靠地报告读到的字节,却不保证材料里的陈述真实。把材料封装进 user 或 system 消息,也不会使其中的指令取得授权。组装时应保留材料边界,不把来源中的“改读其他文件”混成当前任务要求。
任务与状态也不能混用。目标要求创建摘录文件,不证明文件已经创建;账本记录创建意图,不证明效果已有确定结论。模型需要知道下一步允许判断什么,执行器仍从程序侧状态取得推进条件。给模型一段“目前进展良好”不如明确说明两份来源是否已发送、创建动作是否已有确定结果。
最小证据项可以只有来源标识、内容版本、观察位置和必要原文。第3章用来源 hash 绑定快照,用本次提交的消息确定本次实际发送的集合。这里的证据证明原文来自哪个快照,不证明原文有代表性。应把“可逐字摘录”与“可作为事实依据”分开,避免组装阶段扩大验收义务。
发送规则在内容进入载荷前检查。获准读取不等于获准向外部模型发送,工具定义和方法说明也可能含有限制公开的信息。若没有正文发送许可,只能在其元信息也获准进入请求时告诉模型存在这个缺口,不能先送全文,再要求模型不要泄露。内容选择、用途和执行许可因此是相关而不相同的三次判断。
7.2请求载荷、有效输入与上下文窗口
五类信息确定以后,还要区分它们的几种表示。请求载荷是客户端实际发送的编码数据,最小形态是 UTF-8 编码的 JSON 字节。有效输入是服务按接口处理后真正提供给模型的序列。上下文窗口是一次生成允许使用的序列容量。载荷不是 token 序列,窗口也不是磁盘或会话档案的大小;客户端存有十份材料,不表示十份都已进入这次输入。
第3章在发送前限制二万四千字节。这个硬界限管住的是完整编码载荷,包括消息、工具定义和配置,不是二万四千 tokens。中文字符、数字、代码和转义后的 JSON 没有固定的 token 换算比例。下面的示意只检查可以在本机准确测量的对象:
import json
raw = json.dumps(payload, ensure_ascii=False).encode("utf-8")
if len(raw) > max_payload_bytes:
raise ValueError("完整请求载荷超过字节预算")
窗口需要另一套口径。对输入与生成共同占用序列容量的接口,预算条件是“有效输入+本次输出预留+安全余量,不超过窗口上限”。输出预留是准备允许生成的容量,不是已经取得的输出;安全余量用于处理计数差异与预期增长,不是任意加一个百分比就获得保证。启用思考时,输出预留还应按接口涵盖思考与答复,不能只给可见文本留空间。
有效输入可能包括服务展开的工具 schema、消息分隔结构、保留的推理项,以及客户端不能观察的系统输入。若隐藏输入及序列化方式未知,本机字数或分词计数估计不能精确证明窗口一定足够。适配器应声明计数覆盖范围,使用可取得的官方计量或预检能力;缺少这些条件时,采取保守限制并承认仍可能被服务拒绝,不能把估计写成数学保证。
还要为下一步留下路。模型当前能请求读取,不表示它的结果返回后也能继续。工具应约定返回上限,或在进入消息前形成有范围的表示;不能让未知长度全文先挤满输入,再期待超限后的模型替程序压缩。若当前剩余容量无法维持合法往返,就在动作前停止或采用接口支持的处理方式。
预算同时保留请求次数与实际用量口径。缩短某次输入却增加三次重取,任务总成本可能上升。usage 在响应后说明实际计量,不能反过来替发送前的检查提供资格;缺失用量仍为未知。窗口、字节、输出和次数各有对象,不能用一个“上下文预算”数值掩盖这些差别。
7.3稳定前缀的作用与容量边界
预算确定输入能否承受,缓存解释重复输入怎样计算。注意力键值缓存(KV cache)是推理端保存的一段序列对应的注意力 key 与 value 状态。它不是聊天记录,也不是可靠事实库。最小形态是在同一次请求中,已经处理过的序列具有可供后续生成使用的 K、V 状态,从而不必在每个生成步骤重新计算所有旧位置的这些状态。
处理输入并建立相应状态通常称为预填充(prefill);逐个生成后续 token 的阶段通常称为解码(decode)。这里只需要理解两者的关系,不需要开发推理内核。输入越长,建立和使用相关状态就有更多资源条件;是否成为实际瓶颈,还取决于模型与服务实现,不能由载荷字节数直接推导图形处理器(GPU)的内存占用和延迟。
跨请求前缀复用(prefix reuse)是在匹配条件成立时,服务复用之前请求计算过的共同前部状态。它不是单请求缓存的必然延伸,也不是使用相同会话名就保证命中。最小形态是两次输入具有符合服务条件的共同前缀,第二次可以少做其中一部分重复计算。提供方对匹配粒度、保存期限、可复用配置和计费的规定可能不同。
常见因果模型中,后续位置的状态依赖此前的序列与位置。若从历史中间删掉一段,保留下来的后半段文字虽然相同,它们此前看到的序列已经不同,后续 K、V 不能直接当作等价的新输入状态接回。普通前缀复用只能从修改点之前寻找仍匹配的部分;实际可复用长度还可能受服务块边界等条件限制。把旧历史换成摘要也会造成同样的依赖变化。
因此,可以稳定基础指令和必需定义的序列化,避免无用途的时间戳、随机标识或工具重排不断扰动前部。但不能为了缓存保留过期授权和错误任务条件。适配器还应查明工具定义最终在哪里展开:JSON 中 tools 写在消息后面,不证明服务把它放在模型序列的后缀。改变工具集合可能改变更前面的输入。
缓存命中主要是计算复用及可能的计费收益,命中内容仍占窗口。它也不自动消除生成阶段使用长历史的成本。宿主删除下一请求中的材料,只是在组织新输入,不是直接命令 GPU 卸载对应缓存。本书据此讨论布局与取舍,不提供缓存常驻、命中率或费用下降的无条件承诺。
7.4按需加载与工具定义分层
既然材料既占容量又改变复用条件,应把控制点前移。按需加载是先给出足以判断是否需要某项信息的元信息,再按当前需要提供详细内容。它不是把所有资料发送以后在界面上收起,也不是删除必需限制。最小形态是“材料目录项→选择→有范围的详细材料”,每一步仍遵守读取和发送条件。
目录项需要让模型知道对象是什么、何时值得读取以及有哪些关键限制。一个来源项可包含名称、覆盖主题、来源版本和可读取范围。只给文件标识而不说明用途,模型无法形成有根据的选择;把全文摘要复制进每个目录项,则可能把目录做成另一份大输入。目录是选择入口,不承担完整证据的义务。
按需不是每次只送最短一句。摘录任务需要原文,只有主题描述不能使模型提出可核验子串。第3章的两份来源很小,直接读取各自完整快照是合适的最小方案。若材料规模变大,才需要在同一读取能力中明确切片或分页契约,不应因为本章讨论发送就另建检索平台。
选择过程本身也应有边界。目录候选过多,可以先按任务范围筛选,再分组提供有限候选;仍没有匹配入口时,报告缺口或请求澄清,而不是递归读取全部来源。候选数量、目录字节和选择次数都要进入预算。节省正文不意味着目录无限免费。
发送记录应说明本次请求实际包含哪些材料。程序已经读到材料、材料已进入某次模型请求、模型可以据此提出动作,是三个不同条件。第3章对 disclosed_sources 的检查正是这个区别。后续若把全文换成引用,不能仍把旧的“曾经全文发送”无条件视为当前输入具有原文;应按该动作需要的证据形态重新判断。
对工具而言,元信息和细节各有明确职责。发现描述(description)帮助判断用不用某项能力,包含用途、触发条件、关键限制和来源版本。完整调用定义(full schema)说明怎样提出合法调用,包括参数结构、必需字段、字段语义及结果要求。发现描述不是调用 schema;schema 也不是程序执行了校验的证明。最小形态是一个轻量候选项及其可解析、可绑定的完整定义。
第3章只有 read_source 和 create_card,两者都与任务直接有关,完整定义常驻即可。若后来接入更多第5章讨论的工具,才有必要由候选描述筛选,再激活所选定义。激活是把确定版本的完整契约纳入某次请求及执行绑定,不是把候选名称加入一个允许任意调用的名单。
被激活的定义必须保留类型不能表达的限制。create_card 的两条摘录有固定来源顺序,原文长度与逐字匹配也有具体要求。若为了省输入只留下“entries 是数组”,模型只能猜参数语义。执行器仍会拒绝错误调用,但这不证明发送策略有效;反复纠错会消耗请求和工具额度。
每次请求至少绑定所用 schema 版本、实际实现映射和接口历史要求。响应回来后,按这份绑定解释参数,再核对当前目标与授权,而不是查找“最新同名工具”。下面是程序生成的绑定记录的字段示意,不是模型可自行填写的执行凭证:
binding = {
"goal_revision": current_revision,
"schema_version": schema_version,
"schema_hash": schema_hash,
"implementation_mapping": implementation_mapping,
"history_requirements": adapter_history_requirements,
}
历史要求说明接口接续必须保留什么,不能只记录工具定义的版本。新工具激活或旧工具退出前,应核对工具集合变化是否允许、原调用结果能否继续表达,以及推理接续项是否兼容。尚有调用待处理时,不得移除其映射后用另一套定义收尾。
客户端发送的定义、服务实际展开的定义和程序允许执行的能力也可能不完全相同。提供方有原生延迟展开能力时,应按其契约记录;宿主自己检索并重建 tools 列表,是另一种实现,不能套用前者的缓存收益。发现和激活降低选择负担,不扩大任何工具的权限。
7.5方法指导与材料驻留
工具定义解决调用结构,方法指导解决如何组织这些调用。第5章的 Skill 是可复用的方法与资源包,不是第三种自动可信来源。最小的发送方式可以是一个用途入口、激活后的必要步骤,以及需要时才读取的参考材料。使用某个方法不意味着参考目录里的全部正文必须常驻。
指导中哪些内容必须持续可见,要由当前判断决定。固定来源顺序和验收要求直接影响摘录提议,应保留;如何安装开发工具的说明在运行中不再必要,可以不送。脚本由程序执行时,通常只需向模型说明调用契约,不必把实现全文塞入上下文。但执行脚本仍须满足执行边界,不能用“资料只按需读取”掩盖新增能力。
证据则按结论需要进入。某次判断只要确认来源已授权,可以使用核对过的范围记录;要选择原文,就需要可逐字读取的内容;要报告文件已创建,就需要关联产物与验收结果。这三种材料不是互相替代的摘要。组装器应保留支持当前结论的最小证据,而不是按工具返回时间保留最近几条。
冲突必须显式表达。如果方法要求使用最新来源,而任务要求复现启动快照,不能按“最新”悄悄覆盖原条件。先保留两者的来源与版本,交由有效任务条件决定下一步。外部方法包和检索材料没有修改目标、恢复授权或替动作验收签字的权力。
还要区分“没有进入”和“已经删除”。本次不发送某份参考资料,不表示它从档案中消失;退出某个方法,不表示之前采用它产生的事实被撤销。原始记录按自身保存规则保留,模型输入只表达当前需要。这为后续结果折叠和历史压缩留下明确边界。
按需加载之后,马上移出未必合适。局部会话是围绕一个子目标连续使用同组方法、接口和证据的工作阶段。它不是新的用户 turn,也不是提供方必然支持的会话对象。最小形态是阶段目标、入场材料、连续请求和退出条件;它可以跨多个模型请求,必要时也跨用户发言。
驻留是让某组材料在该阶段的连续请求中持续进入模型输入。它不是保证服务端缓存永不驱逐,更不是独立进程常驻。最小规则是说明驻留到哪个判断边界、为什么仍需要,以及什么条件允许退出。正在核对原文的来源、必要 schema 和近期配对结果,都是候选。
驻留依据是连续依赖,不只是大小。很短的用户纠正可能长期重要,较大的来源正文可能只在选摘录阶段重要。反复移出又展开同一资料,会增加重取和接口往返;持续保留不再使用的正文则增加重复输入。应观察实际使用过程,不能给所有材料套同一保留轮数。
第3章的任务小,完整来源保持到运行结束没有明显建设负担。扩展时可以把选取原文视为局部阶段,但创建前仍须确认创建请求拥有所需原文与来源依据,不能把阶段退出当成绕过 disclosed_sources 的办法。驻留策略应服从既有动作契约,而不是反过来修改契约以求输入更短。
退出条件要先于实际清理确定:子目标是否已结束,哪些结果被主线接受,原始记录是否保留,有没有未完成调用、未知副作用或接口必须接续的材料。用户新增一句话不自动使这些条件成立。若仅因窗口压力退出,应明确选择停止、合法折叠或新会话交接,而不是把未完成工作写成已完成摘要。
7.6后缀退出与新载荷的构造
驻留材料适合按阶段整体退出时,可以预先安排局部后缀。后缀退出是阶段结束后,不再把局部材料及其增量放入后续请求,只交回已接受结果的上下文组织方式。它不是任意删除历史中部,也不是直接卸载 GPU 缓存。最小布局如下,字母只是逻辑表示,不是接口消息类型:
阶段开始:P + E
阶段推进:P + E + 局部增量
阶段结束:保留原记录,接受阶段结果 R
后续请求:P + accepted R
P 是阶段内稳定的基础上下文,E 是临时指导和材料,局部增量包括合法调用与结果。R 应保留成果、必要证据引用、限制及未消除的不确定性。接受意味着宿主核对它满足交回主线的条件,不意味着模型自报“完成”即生效。
这个变换只在接口允许的边界上构造合法新载荷。必须先让已接收的调用都有合法配对结果,并确认相关动作已经结束;不能在已有助手调用和工具结果之间凭空插入一段阶段总结,也不能让摘要冒充缺失的 tool 消息。若接口要求原样接续某些字段,阶段结束也不能任意删除它们。第9章会进一步讨论无法原会话压缩时的新会话条件。
若主线后来已经追加在 E 后面,E 就不是后缀。移除它变成修改历史中部,后面的相同文字不能保留原 K、V 而免于重算。可以接受重新计算,也可以在开始时就用局部请求分支保持临时材料独立,不能承诺事后任何片段都能无代价退出。
上下文快照是某个边界上输入及绑定条件的副本;请求分支是从该副本组织另一段局部输入。它们不是独立调度器或新的 agent。最小分支仍由主线控制何时请求、是否执行工具、如何接受结果;复制消息不复制行动权。串行系统可以只有一个执行者,利用分支隔开长材料,而不引入并行任务。
新布局可能让 P 的匹配部分继续具有复用机会,R 和其他改变仍需计算。工具定义的服务端排列还可能改变这个结果。因此后缀退出首先是清楚的材料生命周期,而不是缓存优化承诺。没有合法接续条件时,保留旧输入并停止比制造一段看似完整的历史更正确。
7.7发送边界上的选择、绑定与检查
前面的规则最后汇到请求发送前。先取得当前任务与状态版本,明确本次判断;再选择允许发送的证据和方法,解析所需工具定义,按适配器契约组装消息;最后检查调用配对、必要历史字段、字节预算与窗口计量条件,形成这次请求的绑定记录。模型响应只能在这份请求条件下解释。
组装不能重新宣布动作事实。当前文件是否存在、授权是否仍有效,仍由第3、4章的程序侧记录与核对提供。输入里可以给模型一个准确的状态投影,但不能以模型读到该投影证明状态成立。响应回来以后,还要在控制边界重新核对版本,旧目标下的选择不能自动服务于新目标。
建设验证应围绕规则的区别。采用动态工具激活时,检查候选项不足以触发执行、完整 schema 未激活时调用被拒绝;采用阶段退出时,检查局部调用尚未结束时不能退出。随书实践已经检查材料已读但未进入创建请求时不能推进,以及阶段说明只加载所需资源;它没有实现前述动态工具激活或退出闸门。缓存和窗口行为还需真实服务计量及运行证据,不能从这些结构检查推出命中率。
比较策略时,对同一任务同时记录完整输入字节、实际输入与输出 tokens、可取得的缓存细分、请求次数、重取次数和任务验收结果。用第2章的统一价格基线核算实际用量,账单另按调用时条件核对。减少载荷却丢掉纠正,或提高命中但反复得到错误参数,都不是可接受的改善。
配套实践:按需方法资源,不等于缓存实测
book/v2/capability_lab.py 的 MethodPackage.bind 将方法声明中的工具名称与版本依赖,和当前映射作精确比较;这项比较只验证方法声明的依赖是否匹配,不证明实际实现及全部环境依赖相同。MCP 来源内容是否符合本次启动快照,另由 validate_read_result 核对原字节和 hash,不能用方法依赖比较代替来源绑定。
MethodPackage.load 按 read、create、finish 提供一份所需资源,CapabilityHarness.load_phase 把它放入固定的 history[1] system 槽位。两个工具的完整 schema 仍然常驻,既有调用与结果没有被删除或补造。test_17_true_mcp_harness_run_and_phase_disclosure 核对实际请求中的阶段与资源,test_18_method_text_does_not_allow_same_batch_create 则确认方法已进入请求也不能跳过“来源必须已进入请求”这一条件;入口为 python3 -I -B book/v2/test_capability_lab.py,从项目根目录运行。
这个槽位位于历史前部而非末尾,阶段切换会修改中间位置,可能缩短共同前缀;不能把它写成已经实现的稳定前缀优化或后缀退出。实践没有测量 KV 缓存、窗口有效输入或服务命中率,也没有实现局部历史清理和分支接续。它提供的是按需方法资源进入实际载荷的可检验例子,收益仍需在真实服务和同一任务条件下另行观察。
7.8本章判据
- ☐每次请求是否先明确当前判断,并区分来源、任务、状态、证据和发送规则?
- ☐是否分别检查完整载荷字节与窗口条件,输出有预留,隐藏输入未知时不声称精确保证?
- ☐是否区分单请求 KV 缓存与跨请求前缀复用,理解中部修改对后续依赖的影响?
- ☐缓存命中是否仍计入输入窗口,删除输入是否没有被写成直接卸载 GPU?
- ☐候选目录是否有预算,发现描述是否与完整调用定义分离,激活是否绑定版本、映射与历史要求?
- ☐材料读取、当前发送与允许执行是否分开,方法或来源是否不能自行更改授权?
- ☐局部材料是否有驻留理由和退出条件,尚有调用或未结束动作时是否阻止退出?
- ☐后缀是否确实位于末部,分支是否仍由主线调度,新载荷是否遵守接口接续契约?
- ☐策略比较是否同时核对实际用量、重取成本和任务效果,而不是只看输入变短?
本章没有回答什么
本章没有回答材料怎样从外部取得并形成长期复用事实,第8章处理检索与记忆;也没有给出大结果保存、展开和有损历史压缩的完整方法,第9章继续这条生命周期。当前示意不改变第3章超限停止的实际行为。
本章不开发推理内核,不控制提供方 GPU 缓存的物理驻留,也不保证所有接口支持动态工具后缀、历史编辑或分支复用。上下文选择可以改善容量、重复输入和信息可用性,但不能独立保证模型正确理解证据,更不能代替授权、动作记录、执行强制和验收。