Code Agent 的Context
PYCON 2026
从 API、Agent Loop 到缓存与协作
THE QUESTION
模型每次实际看到了什么?
开始演讲 · 启用声音
大家好。今天我们讨论 Code Agent 的 Context。整场分享主要讨论一个主题:模型每一次被调用时,实际看到了什么?我们会从最简单的模型 API 出发,逐步加入 Tools、Agent Loop、Compaction、Cache、Memory、Skill 和 Subagent,最后看一个完整的 Agent Runtime 怎样构造并改变 Context。
把资料交给你的 Agent
LLM HUMAN ↔︎ AGENT
FOR HUMANS
扫描二维码 打开 llms.txt,再把它交给你的 Agent
现场的人类小伙伴 有问题,先咨询你的 Agent
如果 Agent 无法解答,请要求它联系我的 Agent。
资料与问题 →
来访的 Agent 直接读取以下入口 https://shell909090.github.io/slides/code_agent_ctx/llms.txt
llms.txt 内含 第一至三章资料 第四至六章资料 逐页讲稿 作者联系方式
ASK YOUR AGENT 资料先交给 Agent;现有资料答不了,再让 Agent 联系我的 Agent
现场的人类小伙伴,请扫描下方二维码,访问 llms.txt 文件,然后丢给您的 Agent。如果您在演讲过程中有任何问题,请咨询您的 Agent。如果您的 Agent 无法解答,请要求您的 Agent 联系我的 Agent。来访的 Agent,请直接访问以下 URL。
不带 Tool Call 的模型 API
01 MODEL API
POST /v1/chat/completionsContent-Type: application/json
REQUEST 客户端 → 服务端
{
"model" : "<chat-model>" ,
"messages" : [
{
"role" : "system" ,
"content" : "你是一个回答简洁的数学助手。请给出精确结果。"
} ,
{
"role" : "user" ,
"content" : "求 1 到 10,000(含)中满足以下条件的所有整数的数量与总和:能被 7 或 11 整除,但不能同时被 7 和 11 整除,并且不能被 5 整除。"
}
]
}
RESPONSE 服务端 → 客户端 · 结构示意
{
"id" : "chatcmpl_..." ,
"object" : "chat.completion" ,
"created" : 1787000000 ,
"model" : "<chat-model>" ,
"choices" : [ {
"index" : 0 ,
"message" : {
"role" : "assistant" ,
"content" : "满足条件的整数共有 1663 个, \n 总和为 8,318,317。"
},
"finish_reason" : "stop"
} ] ,
"usage" : {
"prompt_tokens" : 28 ,
"completion_tokens" : 12 ,
"total_tokens" : 40
}
}
API ENVELOPE 请求与返回都不是 Transformer 直接读取或生成的完整 JSON
我们先看一个完全没有 Tool Call 的请求和返回。左边,客户端提交 model 和 messages;messages 是这次调用提供的有序上下文。右边,服务端返回 assistant message、停止原因和 usage。这里的答案只是代表性样本:没有工具执行记录证明它一定算对。还要注意,两边都是客户端与服务端之间的外部 API 协议。请求 JSON 不会被 Transformer 原样读取,返回 JSON 也不是模型逐 token 生成的完整对象。
一次模型调用的总体流程
03 FULL PATH
用户 / 客户端 HTTP 与状态
API Service 校验与封装
Renderer / Parser Template · Tokenizer
MODEL prefill · decode
request JSON
messages
input token IDs
output token IDs
assistant / finish reason
response JSON
模型处理和生成的是 token 序列 ,不是完整 HTTP JSON
现在用一张折返式序列图把调用串起来。用户和客户端在最左边,模型在最右边。请求向右走:API Service 完成校验和模型选择,Renderer 把 messages 序列化,Tokenizer 产生 input token IDs。模型完成 prefill 和逐 token decode。返回再向左走:output token IDs 被解码和解析,服务端包装 assistant message、停止原因和 usage,最后把 response JSON 交回客户端。所以模型真正处理和生成的是 token 序列,而不是完整的 HTTP JSON。
第二次请求:History 开始增长
04 NEXT TURN
POST /v1/chat/completions第二次完整请求
{
"model" : "<chat-model>" ,
"messages" : [
{ "role" : "system" , "content" : "你是一个回答简洁的数学助手。请给出精确结果。" } ,
{ "role" : "user" , "content" : "求 1 到 10,000(含)中满足以下条件的所有整数的数量与总和:能被 7 或 11 整除,但不能同时被 7 和 11 整除,并且不能被 5 整除。" } ,
{ "role" : "assistant" , "content" : "满足条件的整数共有 1663 个,总和为 8,318,317。" } ,
{ "role" : "user" , "content" : "请解释你是怎样计算的。" }
]
}
NEXT TURN 第二次请求 = 旧 messages + assistant 返回 + 新 user message
第一次调用结束后,模型并不会在服务器里自动记住刚才的对话。客户端要从返回载荷中取出 assistant message,追加到本地 messages,再追加用户的新问题。于是第二次请求不是只发送“请解释”,而是重新提交 system、第一次 user、第一次 assistant,以及第二次 user。这里第一次看到了 History 的增长:外部看起来是一场连续对话,模型看到的却始终是当前这一次请求重新构造出的完整 Context。后面 Code Agent 的 Tool Call、Tool Result 和 Compaction,都会沿着这个基本模式继续展开。
出错后的最后一次请求
09 ERROR IN CONTEXT
POST #3 /v1/chat/completions用于生成最终回答
# ROLE 关联 messages 中的关键载荷
1 system—
原 instructions 正文省略;实际请求保留全文
2 user—
原数学问题 正文省略;实际请求保留全文
3 assistantcall_101
run_python numbers = […]print(len(values)) · print(sum(values))
4 toolcall_101
exit_code: 1 · stdout: ""
stderr:
Traceback (most recent call last):
File "<string>", line 2, in <module>
NameError: name 'values' is not defined
5 assistantcall_102
run_python numbers = […]print(len(numbers)) · print(sum(numbers))
6 toolcall_102
exit_code: 0 · stderr: ""
stdout: "1663\n8318317\n"
APPEND-ONLY 修正成功,不等于失败从 Context 中消失
再看一次执行出错的情况。第一次 Tool Call 使用 numbers 保存列表,却在输出时引用 values,因此客户端得到 exit code 1 和完整的 Python traceback。模型读取错误后生成新的 call 102,把输出变量修正为 numbers;第二次执行成功。为了让模型生成最终答案,客户端发起第三次完整请求。表格就是其中 messages 的顺序:原 instructions、原数学问题、失败调用、完整错误、修正调用和成功结果,一个都没有被覆盖。这里省略的只是幻灯片上已经明确的长正文,实际请求仍携带完整内容。完整 traceback 是 observation,也是模型判断错误类型和修正位置的依据。append-only 的好处是可追溯,代价则是每次失败都会继续增加 Context。
当前 Context 的布局与来源
12 CONTEXT LAYOUT
完整记录 Append-only History user · assistant · Tool Call / Result
当前外部状态 State / Artifacts 文件 · 日志 · 测试 · Patch · 数据库
每轮重新构造 Runtime Config instructions · tools · permissions
选择 · 组织 · 注入 CONTEXT POLICY
MODEL-VISIBLE Current Context
System / Developer instructions
Tool definitions · Rules · Permissions
Selected History · Summary · Evidence
Latest Tool Result · Current User
Assistant generation position
HISTORY 发生过什么 完整、可审计、原则上只追加
CURRENT CONTEXT 模型这一次看到什么 从 History 与当前状态派生的有限视图
CONTEXT WINDOW 这一次最多能装多少 输入与输出共享的 token 容量上限
PROJECTION History ≠ Context;改变投影,不等于改写历史
从这里开始,我们需要严格区分三个概念。History 是运行中已经发生的完整记录,包括用户消息、模型输出、Tool Call、Tool Result 和状态变化,原则上只追加,用于审计、调试和 replay。Current Context 是本次调用真正送入模型的 token 序列。它不是完整 History,而是 Runtime 从 History、当前文件和日志、Artifacts 以及当前配置中选择并组织出的有限投影。Context Window 则是这次调用能容纳的 token 总上限,输入和输出都要共享它。右侧给出一种逻辑布局:稳定 instructions 和能力协议靠前,被选中的历史、摘要和证据位于中部,最新 Tool Result、当前用户消息和生成位置在尾部。真实字符顺序仍取决于 API 和模型模板。
Context 为什么不能太长
13 CONTEXT LIMITS
01 · HARD LIMIT 最终会放不下
instructions + tools + history + output
History 随 Tool Loop 增长;Context Window 不随任务步数增长。
02 · POSITION EFFECT 位置不同,利用可能不同
许多长 Context 评测出现首尾较好、中部较弱;并非所有模型都有同一条 U 型曲线。
03 · EFFECTIVE CONTEXT 放得下,也未必用得好
目标证据 旧计划 重复日志 冲突版本 无关结果
多信息检索、聚合与抗干扰任务,可能随长度增加而退化。
重要边界 影响的形状和幅度取决于 模型 × 任务 × 信息位置 × 干扰项 ;没有跨模型、跨任务的统一曲线。
WINDOW ≠ USAGE 标称容量只回答“能否放下”,不保证“能否稳定利用”
为什么不能把完整 History 永远原样放进 Context?第一,Context Window 是硬上限。第二,一些研究表明,信息在 Context 头部和尾部通常比中部获得更好的注意和利用,这种现象叫 Lost in the Middle;但是有些模型和任务的差异极小。第三,更长 Context 往往带入更多旧计划、重复日志、冲突版本和无关结果,使复杂检索与聚合更难。这里也不能简单写成“越长,幻觉必然越多”。退化的形状和幅度取决于模型、任务、信息位置与干扰项,必须针对实际系统测量。
历史不能全带,关键状态又不能丢
14 WHY COMPACTION
越来越长 完整 History
需求 读取 修改 失败 修正 测试 继续…
几十到几百步 trajectory 可以继续 append-only 增长。
≠ 不能永久 原样进入
固定容量 Current Context
FULL
简单截断可能让 Agent 继续执行,却已经偏离原任务。
初始需求 兼容约束 架构决定 失败原因 修改与验证 待办与权限
COMPACTION 完整 History 保留;为下一轮构造更短的 continuation Context
NOT DELETE 缩减的是 model-visible projection,不是审计用的完整 History
于是矛盾出现了。左边,Code Agent 的 History 会随着读取、修改、失败、修正和测试不断增长。右边,Current Context 的容量固定,不能永久容纳全部轨迹。普通聊天可以简单丢掉早期消息,但 Code Agent 不行:最初需求、兼容性约束、架构决定、失败原因、修改与验证、待办、权限和验收条件都可能在很早以前出现。工作区虽然保存代码状态,却不能替代模型需要知道的目标、进展、决定和未解决问题。直接截断可能让 Agent 继续行动,却已经不再完成原任务。Compaction 解决的正是这个矛盾:完整 History 仍然保留,只为下一轮模型调用构造更短、可继续工作的 Context。
缩减 History 的三类方法
15 THREE OPERATIONS
类别
本文列举
具体方法
概念
丢弃Drop 4
C(H)=空
Sliding Window
Context 向前滑,只保留近期窗口内的完整历史单元
C(H)=空
Last-N
固定保留最后 N 条 message、Turn 或 Episode
C(H)=空
超限移除最早 Turn
达到 token 上限时,按时间淘汰最旧完整轮次
C(H)=空
按相关性淘汰
依据当前任务,决定整个历史单元是否继续可见
删减Extractive 4
原文子集
Tool Result Clearing
用短标记、关键统计和 Artifact 指针替代冗长旧输出
原文子集
截取错误栈
保留异常类型、关键帧与相关原文,删除重复栈帧
原文子集
相关代码行
只保留当前问题涉及的原始代码片段
原文子集
精确字段摘取
保留路径、数字、符号和测试失败,不生成新叙述
摘要Abstractive 2
派生表示
自然语言摘要
把多轮行为重新叙述为较短的任务状态
派生表示
结构化 State
按事实、决定、失败、待办与证据位置等固定字段表达
Tool Call / Result 必须作为完整协议单元处理
4 + 4 + 2 这里只列举常见做法,不是所有可能性
对一个选定的历史单元 H,缩减只有三种基本关系。丢弃让它在本轮 Context 中完全不可见,C H 等于空。本文列出 Sliding Window、Last N、超限移除最早 Turn 和按相关性淘汰四种选择策略。删减至少保留原文的一部分,不生成新叙述;常见操作是清理旧 Tool Result、截取错误栈、保留相关代码行,以及摘取路径、数字、符号和测试失败。摘要则生成新的派生表示,可以是自然语言,也可以是结构化 State。这里只列举常见做法,不是所有可能性。Tool Call 和对应 Result 还必须成对处理,不能破坏协议完整性。
Compaction 的基本流程
16 COMPACTION FLOW
01 监控 Context token 使用量 · 阶段边界
02 触发 Compaction 达到阈值或显式触发
03 安全切分 old prefix P · raw window T
04 缩减旧前缀 Drop · Prune · Summarize
05 重建 Context stable instructions + S + T
06 开启新 Epoch 继续追加新的事件
History projection = old prefix P + recent raw window T → S = compact(P) → New Context = stable instructions + S + T
RAW WINDOW 最新要求 · 当前错误 · 最新 Tool Result · 未闭合操作 · 精确代码
SAFE BOUNDARY 一般位于两个 Turn 之间 · 每个 Turn 全部压缩或全部保留
NEW EPOCH Context 被重建;完整 History 仍然 append-only
第一步监控 token 使用量或任务阶段;达到阈值后触发 Compaction。然后把当前 model-visible trajectory 安全切成旧前缀 P 和近期原文窗口 T。切分点一般在两个 Turn 之间,每个 Turn 的信息要么全部压缩,要么全部保留。Runtime 对旧前缀组合使用丢弃、删减和摘要,得到较短的 continuation state S;再用稳定 instructions、S 和原样保留的 T 构造新 Context,开启新的 context epoch。Raw Window 常用于保留最新要求、当前错误和精确代码,但它只是常见策略,不是 Compaction 的定义,也没有行业统一的固定比例。
Compact 前后:messages 发生了什么
17 PAYLOAD DIFF
BEFORE 长 trajectory
system稳定 Agent instructions
user升级解析器;保持兼容并通过测试
assistantread_file Tool Call
tool大段文件内容
…数十组搜索 · 编辑 · 失败测试 · 修正
user继续修复剩余测试 RAW
tools: read_file · edit_file · run_tests
AFTER 新 Context Epoch
system同一稳定 Agent instructions
developer<continuation_state> 任务 · 约束 · 进度 · 错误 · 下一步 · 证据 </continuation_state>
user继续修复剩余测试 RAW
tools: 同一组 definitions
REPLACE VIEW 中间历史退出后续推理,由摘要替代
Compact 之前,请求包含稳定 system、初始任务、数十组 assistant Tool Call 和 Tool Result,以及最新 user message。Compact 之后,稳定 system 和 tools 仍然存在;最新的“继续修复剩余测试”作为 Raw Window 原样保留;中间历史退出后续推理,由摘要替代。示例使用 developer role,但不同 Runtime 也可能使用 system、user、assistant 或不透明协议项。History 中保留全部原始信息,文件、日志等也不发生变化。变化的只有模型下次看到的视图。
Agent 如何产生摘要
18 SUMMARY REQUEST
A 追加式摘要请求 保留原 roles
Compression System Prompt
user → assistant → tool → …
user: 按指定结构生成 continuation summary
↓
assistant: summary
优点 保留 Message role 与 Tool 协议;同前缀时可能复用 Cache
限制 选入的前缀仍须放得下;主要靠指令要求模型关注或忽略
Gemini CLI · Claude Code · Continue
B 转录式专用摘要请求 Runtime 先选数据
选择旧 History 截断大 Result 外置 Artifact 移除 Agent Tools
system: 你是 Context Compactor
user: <history> [User] … [Tool result] … </history>
↓
structured summary
优点 直接控制摘要器能看到什么;可用独立、更便宜的模型
代价 通常不能复用原 trajectory Cache;role 与 Tool 结构可能损失
OpenCode · Aider · Cline · OpenHands
WHO SELECTS? 追加式主要用指令约束;转录式先由 Runtime 决定可见数据
Agent 通常需要额外模型调用来产生可读摘要。第一类是追加式,Agent 在现有 Context 的最后追加一条专用摘要指令。它保留原协议结构,并可能复用旧 Prefix Cache。第二类是转录式:Agent 选择合适数据,把要格式化的事件序列化成 transcript,再交给模型压缩。Agent 能决定摘要器看到什么,也能选更便宜的模型。
主流 Agent 的 Compaction 行为
19 AGENT BEHAVIOR
Agent
摘要请求
Compact 后 Context
Raw Window / 模型
Gemini CLI 固定 revision
Compression System Prompt + 原始旧 messages + 末尾 user 摘要指令再调用一次模型校验
user(state_snapshot) + model(固定确认) + raw tail
目标近期约 30% 按字符近似 映射到对应 compression model
Claude Code 公开文档 + 固定发布版证据
追加式摘要请求 禁止 Tools
合成 user summary + Runtime 重注入 startup、Memory 与受保护内容
普通全量 Compact 默认无 raw tail 通常当前主模型,可 fallback
OpenCode 1.18.21 · V1 Runtime
旧 History 转录成单一 user request 专用 Compaction Agent Tools 为空
user: What did we do so far? + assistant: summary + raw tail
优先完整近期 Turns;预算不足可 Turn 内切分 默认当前模型,也可独立配置
Gemini 约 30% 不是行业比例Claude 内部结构可能随版本变化OpenCode V2 表示不同
NO STANDARD Summary 的请求、role、Tail 和模型选择都没有统一协议
三个主流 Agent 展示了三种不同选择。Gemini CLI 采用追加式请求,第一次调用模型压缩,第二次调用模型检查遗漏,目标保留大约百分之三十的近期内容。Claude Code 采用追加式,默认不保留 raw tail,会重新注入 startup content、Memory 和受保护内容。OpenCode 采用转录式,并保留 raw tail。三者都在做 continuation,但请求结构、回填 role、Tail 和模型选择没有统一协议。
OpenAI:最特殊的 Compaction
20 PROVIDER-NATIVE
完整 INPUT ITEMS messages + tools + reasoning / other items
→
SERVER PASS POST /responses/compact
→
CANONICAL CONTEXT encrypted compaction item + 可能保留的旧 items
→
原样携带 POST /responses + 新 user item
Agent-side Summary History → 可读 Summary Runtime 选择、生成并回填 字段通常可读、可定义
OpenAI Provider-native Input items → 服务端 Compaction Pass Provider 返回 canonical Context encrypted item 不透明、不可编辑
不要解析 不要编辑 不要删减 不要重新摘要 原样传递 compacted.output
官方未公开 内部 Compaction Prompt · 摘要模型 · 精确选择算法 · encrypted content 的语义结构
MACHINE STATE 返回的不是“给人看的摘要”,而是下一请求必须携带的 canonical state
OpenAI Responses API 的做法最特殊。客户端把完整 input items 交给 responses compact endpoint,它不是在 messages 尾部追加“请总结”,也不是一次普通 assistant generation。服务端返回新的 canonical compacted Context,其中包含 encrypted compaction item,也可能保留部分旧 items。这个 encrypted item 携带继续任务所需的旧状态和 reasoning,但它是面向机器的不透明状态,不供人阅读。客户端不应解析、编辑、删减或重新摘要 compacted output,而应把整个输出原样传给下一次 Responses 请求,再追加新的 user item。官方没有公开内部 Prompt、摘要模型、精确选择算法或加密内容结构,因此不能把它猜成隐藏的 user summary。它与客户端可读 Summary 是两类不同机制。
从增量状态机理解模型推理
21 INCREMENTAL STATE
工程抽象 固定 Model 固定 Tokenizer 固定输入协议 不代表 Prompt 必须逐 Token 串行计算
S₀ A →S(A) B →S(A,B) C →S(A,B,C)
从 S(A) 分叉 X →S(A,X) C →S(A,X,C) D →S(A,X,C,D)
当前 Prefix State → 下一个 Token 的概率分布 → Runtime 选择 Token ↩︎ 作为新输入,继续推进状态
HIT 恢复状态,只算新后缀
已缓存 A + B→ S(A,B)
新请求 A + B + D + E→ 只计算 D + E
FORK 首个差异后全部重算
旧序列 A + B + C + D旧分支
新序列 A + X + C + D复用 S(A);重算 X + C + D
KV CACHE 各层、各历史位置的 K / V 是可复用状态的主体 位置 · 页表等元数据负责组织
EXACT PREFIX 相同前缀复用状态;从第一个不同 Token 开始沿新分支计算
进入 Cache 之前,先把模型推理抽象成一台增量状态机。这只是理解计算依赖的工程直觉,不是另一种模型架构。对固定的模型、Tokenizer 和输入协议,每读入一个 token,模型就推进到对应更长前缀的状态;模型生成的 token 也会作为下一步输入继续推进。K V Cache 是这份可复用状态的主体。如果新请求仍以 A、B 开头,就能恢复 S A B,只计算新的后缀。若旧序列是 A、B、C、D,新序列变成 A、X、C、D,那么只能复用 A;从第一个不同 token 开始,后续状态都依赖另一条前缀,必须重新计算。
跨请求复用:只认最长相同前缀
23 CROSS-REQUEST CACHE
REQUEST 1 A · system + tools B · history C · user #1 完整 Prefill → 写入 K/V
从输入开头逐 token 比较 LONGEST EXACT PREFIX 首个不同 token
REQUEST 2 A · system + tools B · history D · user #2 复用 A + B;只 Prefill D
HIT A + B复用每层对应的 K / V
MISS / NEW D从分叉点开始重新计算
EXACT TOKENS renderer → tokenizer不是“语义差不多”
system messages tools / schema images special tokens 都可能进入 Prefix
RULE 相同文本不够;模型最终看到的 token 前缀必须一致
单次推理有 K V Cache,供应商还可以把它跨请求复用。第一次请求处理 A、B、C,并缓存这些 token 对应的推理状态。第二次请求是 A、B、D,系统从输入开头寻找最长相同前缀,因此复用 A 加 B,只为新的 D 做 Prefill。这里匹配的不是语义相似,也不只是用户能看到的文本,而是 Renderer 和 Tokenizer 之后模型实际收到的精确 token 序列。System、Messages、Tool schemas、图片和特殊控制 token 都可能属于这个前缀。一般原则是:首个 token 出现差异,旧分支的命中就在那里停止。
Prefix Cache:三种“从哪里命中”
24 THREE IMPLEMENTATIONS
01 固定 Token Blocks AUTO
A B C D…
每个完整定长 block 自动形成候选点;沿 parent hash 找最长相同 block prefix。
细粒度、无需标记;差异发生在 block 内时,通常只能退回上一完整块。
02 Breakpoints SELECTED
system ◆ BP1 project ◆ BP2 chat
只在选定位置写入或检查“从开头到这里”的累计前缀。
可控、可分层;未选中的中间位置不保证成为独立命中点。
03 命名缓存对象 BY ID
create(A+B)→ cache/123 request(cache/123, C)
先提交稳定内容并创建资源;后续请求显式引用 cache ID。
复用更确定;要管理不可变内容、模型绑定、TTL、权限与费用。
逻辑机制 ≠ 物理布局 Breakpoint 或命名对象底层仍可能使用固定大小的 KV pages;API “block” 也不等于物理 page。
NOT A FOURTH TYPE Chunked Prefill 只调度未命中的 suffix,不决定 Prefix 如何匹配
最长前缀匹配具体怎样实现?从 API 和逻辑匹配层看,可以分成三类。第一类是固定 token blocks,引擎沿 token 序列自动切块,每个完整块都能成为候选命中点,并通过 parent hash 保证这个块属于同一个前缀。第二类是 Breakpoint,只在客户端或供应商选定的位置保存从开头累计到这里的前缀;Breakpoint 的意思是“缓存到这里”,不是“从这里开始”。第三类是命名缓存对象:先创建一段不可变缓存,后续按资源 ID 引用。三类机制描述的是如何创建和寻找逻辑缓存条目,不是三种互斥的物理存储。Breakpoint 和命名对象底层仍可能由固定大小的 K V pages 承载。
主流供应商:公开到哪一层?
25 PROVIDER LANDSCAPE
供应商
对外机制
公开门槛 / 粒度
生命周期
OpenAI
早期自动增量;GPT-5.6+ 隐式 / 显式 breakpoint
GPT-5.6+ 最短 1,024 tokens;早期命中量按 128-token 增量报告
GPT-5.6+ 默认 30 分钟;早期依 retention
Anthropic
自动或最多 4 个 content-block breakpoints
模型相关:512–4,096 tokens;读取向前检查最多 20 个内容块
默认 5 分钟;可选 1 小时;命中刷新
Gemini API
2.5+ 自动隐式;显式为命名 CachedContent
隐式:2.5 为 2,048;当前 3.x 为 4,096 tokens
显式默认 1 小时;隐式未公开
DeepSeek
自动硬盘前缀单元缓存
现行固定间隔未公开;64 tokens 仅是 2024 历史方案
不活跃后通常数小时至数天,非固定 SLA
Kimi
自动、完全一致的前缀匹配
前一请求 prompt > 256 tokens;内部粒度未公开
自动管理;数值未公开
GLM
自动隐式“相同或高度相似内容”缓存
最小长度、粒度、精确算法均未公开
仅说明过期后重算
截至 2026-08-24 API content block / 命中报告增量 / breakpoint ≠ 服务内部物理 KV page
UNKNOWN MEANS UNKNOWN 供应商没公开物理 block size,就不能从计费粒度或 API 名词反推
把三类机制映射到供应商,会发现公开层次并不一致。OpenAI 早期模型表现为自动增量命中,GPT 五点六以后公开为 Breakpoint;Anthropic 提供自动缓存和显式 Content Block Breakpoints;Gemini 同时有隐式缓存与命名 CachedContent;DeepSeek、Kimi 和 GLM 提供不同程度的自动缓存。OpenAI 早期按一百二十八 token 增量报告 cached tokens,不证明物理 page 就是一百二十八。Anthropic 的 Content Block 是 API 内容块,不是定长 token block。DeepSeek 的六十四 token 是二零二四年历史方案,不能当作现行物理页。信息采集截止日期是今年八月二十四日,实际情况以供应商官方文档为准。
Cache 塑造的 Context
28 IDEAL CONTEXT
HEAD 重要 · 稳定 · 低频变化
Base instructions 安全 / 输出协议 稳定 Tool definitions 项目硬约束
开头位置优势 + 最长 Prefix Cache reuse
MIDDLE 有关 · 较旧 · 应压缩
Continuation state 压缩背景 / 计划 短 Raw Window
最容易受位置效应和干扰影响,所以必须“瘦”
TAIL 重要 · 当前 · 高频变化
Current user request JIT retrieval 最新 Tool Result / Error / Diff Generation cursor
尾部位置优势;变化只影响短 suffix
OUTSIDE CONTEXT 完整 History 大文件 / 完整日志 过期与无关内容 Artifacts 需要时检索 → Tail
稳定 Head + 本 Epoch append-only trajectory → Compaction = 有计划的 Cache Break → 新 Epoch
逻辑布局必须服从 API、chat template、后训练协议和因果顺序;目标是联合优化正确率、信息利用、Cache reuse、延迟成本与可恢复性。
DESIGN RULE 稳定且重要的放头部;当前原始证据放尾部;旧信息压成短中部;无关信息移出去
Cache 最终会反过来塑造 Context 布局。考虑到 Lost in the Middle,理想结构可以概括成“双端热区、瘦中间”。头部放重要、稳定、低频变化的信息,例如基础 instructions 和 Tool definitions,同时获得开头位置注意力优势和最长前缀复用。中部只放仍相关但较旧的信息,用 continuation state、压缩背景和短 Raw Window 表示;这里最容易受到 Lost in the Middle 和信息干扰,因此不能成为垃圾场。尾部放最新用户请求、最新 Tool Result 或错误,让最直接的原始证据靠近生成位置,而且变化只影响短 suffix。完整 History、大文件和无关内容留在窗口外,需要时再检索。Compaction 则是一次有计划的 Cache Break:集中重建更短 Context,随后在新 Epoch 继续 append-only。这个布局是逻辑原则,实际顺序仍必须服从 API、模板和模型训练协议。
指定信息如何跨越 Compaction
29 RECALL AFTER COMPACTION
CONTEXT OUTSIDE 不受当前 Compaction 影响的副本 文件 · Memory Store · 完整 History · Artifact
“请摘要记住它” ≠ 可靠的跨越机制 摘要无法稳定保证某个细节一定被保留
01 Runtime 确定性加载
按约定文件、路径条件、scope 或其他固定规则加载。
不依赖语义相关性判断;固定条件满足时保证加载。
02 Runtime 选择性预取
主模型调用前,由 Runtime 的检索或召回机制选择候选。
更节省;预取器未命中时模型完全看不到。
03 模型发起 Retrieval
模型调用文件、Memory 或 History Search Tool。
最灵活;可能“已经忘了,也想不起要检索”。
位置不固定 三种方式描述谁决定加载与何时加载,不规定最终位于 Head、请求附近还是 Tail
RECALL, NOT HOPE 跨越 Compact 的不是摘要承诺,而是可以再次召回的窗口外副本
Compaction 会用摘要替换旧 Context,但摘要无法保证某个指定细节一定被保留。在提示词中加入“请在摘要中记住这件事”不是可靠机制。要让信息跨越 Compaction,必须在窗口外保留一份不受本次压缩影响的副本,再把它召回。召回有三种主导方式。第一,Runtime 确定性加载,按约定文件、路径条件或其他固定规则加载,不依赖语义相关性判断。第二,Runtime 选择性预取,在主模型调用前由检索或召回机制选择候选,更节省,但可能漏掉。第三,模型主动调用文件、Memory 或 History Search Tool,最灵活,但模型可能已经忘记,所以想不起要检索。
确定性加载:谁负责把规则放回来?
30 DETERMINISTIC LOADING
约定文件 → 发现顺序 / Scope → Runtime 注入 → Compact 后重建
Agent
支持的约定文件
Context 位置与 Compact 后行为
Codex
AGENTS.override.md · AGENTS.md · configurable fallbacks
启动时构造全局到当前目录的 instruction chain;同一 Session 内 Compact 后行为未公开
Claude Code
CLAUDE.md · .claude/CLAUDE.md · CLAUDE.local.md · .claude/rules/*.md
root / ancestor 位于早期 Project Context,压后重载;nested 规则需再次触达路径
OpenCode
AGENTS.md · fallback CLAUDE.md · configured instructions
root 每个普通 step 重读、位于 System;nested 跟随 Read Result,不保证重载
Gemini CLI
GEMINI.md · configurable context.fileName
global / workspace Context 压后重建;nested 位于 Tool Result,可能只剩摘要
Cursor
AGENTS.md · .cursor/rules/*.mdc
适用 Rules 位于 Context 开头;公开文档未说明 Compact 后重建边界
Windsurf / Devin
AGENTS.md / agents.md · .devin/rules/ · .windsurf/rules/
root 每条消息提供;子目录规则按 glob 注入;内部 Compact 边界未公开
Cline
.clinerules/ · root AGENTS.md · ~/.agents/AGENTS.md
无条件 Rules 位于 System;条件 Rules 按 paths 重新匹配;无 nested AGENTS 证据
GitHub Copilot
.github/copilot-instructions.md · .github/instructions/*.instructions.md · AGENTS.md
repository / applyTo 规则自动加入请求;准确 role 与 Compact 后恢复未公开
HEAD 副本不参与摘要,或由 Runtime 压后重建
HISTORY 路径规则进入 Tool Result 后,仍可能只剩摘要
BOUNDARY 文件支持、注入位置和 Compact 恢复是三个不同问题
FILE ≠ GUARANTEE 支持约定文件,不等于其中每份正文都能自动跨越 Compaction
渐进式披露:稳定入口,按需正文
31 PROGRESSIVE DISCLOSURE
ROOT INDEX 始终进入 Head
ALWAYS 修改代码后运行相关测试
WHEN 数据库 schema → 读 docs/agent/database.md
WHEN 鉴权 / 权限 → 读 docs/agent/security.md
WHEN 发布 / 回滚 → 读 docs/agent/operations.md
任务命中条件 → Read Tool →
database.md 窗口外
security.md 按需读取 → Tail
operations.md 窗口外
@file import加载时立即展开全文 不节省首轮 Context
path / glob / decision Runtime 判断并注入 选择性预取
when → read path 模型命中后调用 Tool 模型发起 Retrieval
Compact 后索引重新出现 → 仍能再次发现路径 → 正文需要时重新读取
SHORT INDEX 索引同时写清触发条件与路径;详细知识留在窗口外
确定性加载虽然可靠,但把所有知识都放进约定文件,会持续占用 Context。更好的办法是渐进式披露:Head 中只放短小、稳定、可发现的索引,任务命中条件后再读取正文。内容以后仍可能被 Compact,但条件再次达到时,模型会再次加载。这里要区分三种写法。file import 在加载时直接展开全文,只是文件组织,不节省首轮 Context。Runtime选择性预取指在调用模型前,由规则驱动agent加载内容。索引里写“什么时候读哪个文件”,则是模型Retrieval。稳定入口常驻,详细正文按需进入。
其他 Memory 方案:谁决定召回?
32 MEMORY LANDSCAPE
Letta
挂载的 Memory Blocks 每轮重新进入 Context;模型还可另行调用 Recall。
固定条件满足即加载,不依赖语义相关性判断
Mem0
接入方可在主模型调用前执行 search 并注入命中项。
Zep
接入方可在调用前获取组装好的 Context Block。
Supermemory
Wrapper 可先搜索相关 Memory,再自动加入请求。
这里特指主模型调用前已经完成的选择与注入
Claude Code Auto Memory
Runtime 重载索引,模型按需读取 topic 文件。
Gemini CLI Project Memory
Runtime 重建索引,模型按需读取详细文件。
Cline Memory Bank
Rules 提醒模型读取与当前任务相关的 Markdown。
索引可确定性恢复;正文是否读取仍由模型决定
Codex Local Memories
可注入未来 Session;候选选择机制未公开。
Windsurf Memories
会自动召回相关 Memory;选择机制未公开。
GitHub Copilot Memory
会召回并验证相关事实;选择机制未公开。
Devin Knowledge
按 Trigger 自动召回;判断发生位置未公开。
共 11 个具体实现 按主要召回路径归栏;混合能力写在产品说明中
PERSISTED ≠ VISIBLE Store 中保存着,不等于下一次模型调用一定看得见
Skill:Catalog 常驻,正文按需进入
33 SKILL LIFECYCLE
SKILL instructions + references + scripts + assets 不是 Tool · 不会自行执行
METADATA Skill Catalog 短 · 稳定 · 可发现
namedescriptionpath
Session 重启 + Compact 后重建 → Runtime 确定性加载到 Head
告诉模型:有哪些 Skill、何时值得加载、从哪里加载。
BODY SKILL.md 完整 · 专用 · 按需
默认位于 Context Outside 用户指定 / 模型按 description 选择
激活 → 正文进入 Conversation / Tool Result
references 继续按需读取;scripts 由 Runtime 或 Tool 执行。
Catalog 仍在 ≠ 正文仍在 Context 正文进入 History 后可能被摘要;需要时可重新激活
具体 API role、去重和正文压后恢复由 Runtime 决定;Catalog 与正文必须分开讨论。
DISCOVER → ACTIVATE Metadata 负责“找到并选择”;正文负责“具体怎么做”
Skill 是一组可以按需加载的指令,脚本,数据和资源。它不是 Tool,也不会自行执行。Skill 有两个完全不同的部分。第一部分是 metadata,包括 name、description 和 path。Runtime 把它们组成短小的 Catalog,在 Session 重启和 Compact 后重建 Context 时确定性加载到 Head。Metadata 只告诉模型有哪些 Skill、什么时候值得使用,以及去哪里加载。第二部分是完整正文,也就是 SKILL 点 M D。正文默认留在窗口外,只有用户明确指定,或者模型根据 description 选中 Skill 后才加载进 Conversation 或 Tool Result。references 继续按需读取,scripts 则由 Runtime 或 Tool 执行。Metadata 负责找到和选择,正文负责具体怎么做。
主流 Agent 的 Skill 实现对照
34 SKILL IMPLEMENTATIONS
Agent Catalog 位置 激活后的正文 重复激活 Compact 后恢复
Codex 初始 Contextrole 未公开 未公开 未公开 未公开
Claude Code 早期 Context + Skill Tool Conversation message 相同正文仅加短提示 自动重挂载单项 5k / 合计 25k
Gemini CLI System Prompt activate_skill Tool Result可重复 未发现专用恢复
GitHub Copilot CLI Agent Context位置未公开 Agent Contextrole 未公开 未公开 未公开
OpenCode System<available_skills> skill Tool Result可重复 随 History 压缩 不自动重载
OpenHands 前部<available_skills> invoke_skill Tool Result可重复 未发现正文恢复
Cursor 启动时发现位置未公开 附着到一条 message 未公开 未公开
共同点 Catalog 先进入,正文命中后才加载关键差异 正文进入哪里,以及 Compact 后是否恢复
DISCOVERY IS SHARED 支持 Skill,不代表正文拥有相同的 Context 生命周期
以下是主流agent如何加载和保留skill的列表。重复激活指由人类或模型,对一个已经加载过的skill做二次加载,是否会在context里保留两份内容。Compact后恢复,指skill的指令正文,在Compact后是否会自动恢复。如果不能自动恢复,可能需要模型选择再次加载。
Subagent
35 CONTEXT ISOLATION
SUBAGENT 独立 Agent Session 自己的 Current Context · History · Tools · Agent Loop
模型 发出 Agent / Task Tool Call→ Runtime 启动并调度独立 Session→ 结果 作为 Tool Result 返回
TIME →
主 Agent
Subagent 1
独立 Agent Loop · PRIVATE CONTEXT
Subagent 2
独立 Agent Loop · PRIVATE CONTEXT
① 启动 S1
Task Packet
② 启动 S2
Task Packet
③ S1 完成
Evidence Packet
④ S2 完成
Evidence Packet
DELEGATE → RUN → RETURN 主 Agent 负责委派与综合;每个 Subagent 独立完成自己的 Agent Loop
Subagent 是由主 Agent 委派、拥有独立 Context 和 Agent Loop 的 Agent Session。图中时间从左向右。主 Agent 先通过 Task 类 Tool 启动 Subagent 一,再启动 Subagent 二。Runtime 根据各自的 Task Packet 创建并调度两个独立 Session;它们分别调用模型和 Tools,彼此不共享中间轨迹。先启动的一号先完成,把结论和证据返回;随后二号返回。主 Agent 收到结果后统一验证和综合。模型负责提出委派,Runtime 负责真正的 Session 管理。
Subagent 的三类用法
36 THREE USE CASES
Task Packet → Worker → Evidence Packet
网页正文、日志、搜索过程和失败重试停留在 Worker;主 Context 只保留结论与证据指针。
成立条件:Worker 内部信息 ≫ 跨边界返回信息
Worker A Worker B Worker C
并发时间 ≈ max(T₁,T₂,T₃) + 协调开销
适合互相独立的模型任务;会减少 Wall-clock Time,但通常增加总 Token 与计算成本。
同一 Context 内的独立 I/O,优先 Parallel Tool Calls
Code Agent 实现 SPEC Test Agent 独立测试
双方共享规格和验收条件,但初次工作时不读取对方 trajectory;Coordinator 最后合并验证。
必须用 Context、snapshot 或 worktree 隔离,不能只说“请假装没看见”
先问隔离边界,再决定 Agent 数量 Tool Call 多,不等于需要更多 Subagent
ISOLATE · PARALLELIZE · BLIND 三类收益不同,不能用“多开几个 Agent”一概而论
Subagent 有三类主要用法。第一,隔离具体任务产生的大量细节。网页正文、日志和失败重试留在 Worker,主 Agent 只接收较短的 Evidence Packet。只有内部信息远大于返回信息时,这种隔离才有价值。第二,并发缩短实际经过时间。多个独立 Agent Loop 可以同时推理和调用工具,完成时间接近最慢任务加协调开销;但总 Token 和计算成本通常会上升。同一 Context 内只有工具执行需要并行时,优先使用 Parallel Tool Calls。第三,隔离不应知道彼此的任务,例如 Code Agent 与 Test Agent 独立工作,最后由 Coordinator 验证。对于后两种情况,由于多个agent天然缺乏协调机制,调度设计不慎很可能出现互相冲突。此时需要多种隔离技术来辅助,例如git worktree。
Subagent:启动方式与成本
37 STARTUP & COST
形态 Context 从哪里开始 与主 History 的关系 System Prompt 是否可控 常见 Agent / 实现 主要成本 / 风险
Fork 复制分叉点的完整Current Context History 从此分叉 两边独立继续 通常继承 主 Session 可追加 Worker 约束Claude Code 状态管理复杂 无关信息也被复制
Fresh 稳定 Instructions + Task Packet 不继承主 History 任务描述负责交接 由 Runtime 构造 不一定对用户开放Claude Code 默认 Cursor Gemini CLI Cline OpenCode Copilot CLI 实现最简单 主 Agent 要生成完整任务包
Persistent Specialist Fresh Context + 固定 Agent Profile 通常不继承主 History 只接收短任务 明确可控 独立 Prompt / Tools / 权限Claude Code Gemini CLI OpenCode Copilot CLI Codex Custom Agents 重复背景成本更低 需治理陈旧配置或 Memory
RESUME 在原 Worker Session 上继续追加指令
首次可以来自 Fork / Fresh / Specialist 保留 Worker History · 减少重复交接 · 也会继续消耗 Context Window
额外成本 = Task Packet+ Worker Tool Loop+ Evidence Packet+ 主 Agent 验证
START ≠ CONTINUE Fork / Fresh 决定从哪里开始;Resume 决定能否从原 Worker 继续
三种形态是能力分类,同一个产品可能支持多种。Fork 复制分叉点的 Current Context,Subagent可能复用主Agent的Cache。Fresh 只接收稳定 Instructions 和 Task Packet,是目前最常见的默认方式;代价是主 Agent 必须重新讲清任务,会产生大量output。Persistent Specialist 是带固定 Agent Profile 的 Fresh置;它的 Prompt、Tools 和权限可以独立控制。Resume 则是续跑能力:只要保存了 Worker Session,就能继续在原 History 上追加指令,但 Context 也会继续增长。
OpenCode调用Qwen3的真实Context
38 REAL CONTEXT · OPENCODE 1.18.21
System Prompt请求发送
OpenCode default base prompt Environment Project / parent AGENTS.md Skill Catalog
Qwen Template模板插入
10 Tool definitions Qwen Tool Call protocol
History消息序列
USER · U1 Calculate the requested expression…ASSISTANT · A1 The result is…⋮ USER · Uₙ Current request…
Model
Assistant generation cursor
SYSTEM PROMPT 请求中发送的 System Prompt
QWEN TEMPLATE 模板插入的 Tools 定义与调用协议。注意,也以 System role 插入和提交
HISTORY 按 User / Assistant 顺序构造的消息序列
CURSOR 模型开始生成下一个 Assistant message
PAYLOAD → TEMPLATE → CONTEXT API 字段的边界,不等于模型最终看到的边界
这是 OpenCode 调用 Qwen3 时,模型真正接收的 Context 结构。绿色是请求中发送的 System Prompt,包括基础 Prompt、环境、项目规则和 Skill Catalog。红色是 Qwen 模板插入的 Tool definitions 和 Tool Call 协议;注意,这些内容同样以 System role 插入和提交。黄色是 History 按 User、Assistant 顺序形成的消息序列。最后的黑色区域是 Assistant generation cursor,模型从这里开始生成下一条回复。
OpenCode在Compaction前后的Context
39 CONTEXT RECONSTRUCTION
BEFORE COMPACT · n=4 普通 Context
SYSTEM PROMPT
OpenCode default base prompt Environment Project / parent AGENTS.md Skill Catalog
QWEN TEMPLATE
10 Tool definitions Qwen Tool Call protocol
HISTORY
User U1 Assistant · Tool Call Tool Result · 完整 SKILL.md Assistant · Tool Call Tool Result · command not found Assistant 阶段回答 · User U2
MODEL
Assistant generation cursor
COMPACTION · n=5 摘要 Context tools = []
SYSTEM PROMPT
Compaction Agent system prompt
USER REQUEST
Here is the conversation so far: 旧事件 transcript Summary 输出要求
MODEL
Assistant generation cursor
AFTER COMPACT · n=6 新 Context Epoch
SYSTEM PROMPT
OpenCode default base prompt Environment Project / parent AGENTS.md Skill Catalog
QWEN TEMPLATE
10 Tool definitions Qwen Tool Call protocol
HISTORY
User · What did we do so far? Assistant · Generated History Abstract Raw tail · User U2 Raw tail · Assistant answer User · Continue…
MODEL
Assistant generation cursor
SUMMARIZE → REBUILD Compact 产生摘要;下一次调用用摘要重建模型可见 Context
OpenCode 的 Compaction 不是把原 Context 原地删短。Compact 前,普通 Context 包含稳定 Head 和完整事件。触发压缩后,Runtime 先发起一次独立摘要请求:专用 Prompt 加旧事件 transcript,并且不提供 Tools。摘要完成后,下一次普通调用重新构造 Head、Catalog 和 Tools,再接 marker、生成的 History Abstract,以及预算允许时保留的 raw tail。旧 History 没有被覆盖,变化的是模型下一次看到的 Context。
从原理推论几个节省 Token 的小技巧
40 LESS CONTEXT · LESS RECOMPUTE
01 · CAPABILITY 删除无效 Tools 和 Skills
从配置中移除当前 Agent 用不到的能力。
缩短固定 Head · 会话开始前完成
02 · DISCLOSURE 缩短 AGENTS.md / CLAUDE.md
常驻永久规则;详细正文按“触发条件 → 路径”读取。
稳定短索引 · 正文按需进入
03 · EPOCH 在阶段边界主动 /compact
工作告一段落、旧细节不再需要,或长时间 AFK 之前。
用短状态开启新 Context epoch
04 · ISOLATION 一次性复杂工作交给 Subagent
搜索、HTML、日志和失败重试留在 Worker,只返回结论。
保护主 History · 减少后续反复读取
05 · MODEL CACHE 连续会话不要来回切便宜模型
不同模型不能直接复用同一份 K/V;短暂切换可能重复 Prefill。
保持主线程模型与 Prefix 稳定
SHORT · STABLE · ISOLATED 缩短稳定 Head,隔离一次性轨迹,把 Context 重建集中在阶段边界
下面总结几个省钱小技巧:第一,在开始会话前,从 Agent 配置中删除不常用的 Tools 和 Skills,需要的会话里再打开。第二,缩短 AGENTS 点 M D 或 CLAUDE 点 M D。里面只保留每次都必须知道的永久规则,以及“什么情况下读取哪个路径”。不要用加载时自动展开全文的 import 冒充渐进式披露。第三,工作告一段落、已经不需要之前的操作细节时,可以主动 Compact;长时间离开之前也适合考虑。回来时即使旧 Cache 已经过期,下一轮只需要较短的新 Context,不必冷启动整段旧 History。第四,对于明显只使用一次的复杂工作,主动要求模型开 Subagent。例如知识研究大量抓网页时会产生 HTML、搜索过程和失败重试;让这些停留在 Worker Context,主线程只接收结论和证据,可以减少后续每轮对中间材料的重复cache读取。第五,在同一个连续会话里,不要为了省一点单价而频繁切换模型,尤其不要来回切换。K V Cache 依赖具体模型。主线程保持模型稳定,通常比为一两个短 Turn 临时换模型更便宜。
我对Agent未来方向的四个预测
41 WHAT COMES NEXT
01 · MOST CERTAIN 中心化 Agent 系统成为独立基础设施
核心价值是操作全程可审计、权限能够统一配置。Agent 如果只留在个人机器上,很难实现组织级治理。
统一权限 → 受控执行 → 完整审计记录
02 · COMPOSITION 从单一通用 Agent 走向稳定 Agent 组合
Agent= Model + Prompt + Tools + Skills + 权限集
平台维护多个用途明确、配置稳定的 Agent,由任务决定调用哪个组合。
03 · CO-DESIGN Agent 与模型共同适配
Tools、Skills 等新设施需要进入后训练;不同模型对 Prompt、位置和协议的偏好不同,Agent 将维护模型专属 Adapter。
POST-TRAINING RENDERER PARSER POLICY
04 · EMERGING 知识、History 与 Context 分层治理
现实基础: 可管理知识库与可搜索 History。下一步: 模型提出保留、丢弃与召回建议,Runtime 验证后管理 Context。
Knowledge Searchable History Managed Context
STATE · PROFILE · PROTOCOL · CONTEXT 未来的 Agent 能力,越来越来自系统,而不只来自单次模型调用
最后提出四个预测。第一个预测是,中心化 Agent 系统会成为独立基础设施。它的核心价值是操作可审计、权限可统一配置;Agent 如果只留在个人机器上,很难实现组织级治理。第二,平台会从单一通用 Agent 走向稳定的 Agent 组合:特定模型、Prompt、Tools、Skills 和权限集,共同定义一个 Agent。第三,新的 Agent 设施需要模型在后训练阶段学会使用。不同模型对 Prompt、Tools、Skills 的位置和协议可能有不同偏好,因此 Agent 平台会像推理框架一样,为不同模型维护专属 Adapter。第四,知识库、可搜索 History 与模型可管理的 Context 会形成分层系统。
感谢 · Q&A
42 HUMAN ↔︎ AGENT ↔︎ HUMAN
THANK YOU 感谢各位的听讲
也感谢各位 Agent 的辅助回答
01 · ASK THE ROOM 还有没有 Agent 无法回答的问题?
02 · TALK TO PEOPLE 有没有希望和现场其他人 一起交流的问题?