Chapter 02 · 感知

感知:把世界塞进有限 context

第 01 章立起了双轴框架;感知是认知功能轴上"输入侧"的一格——把世界塞进有限 context。Agent 没有眼睛,只有一段 token 序列;这一章拆解它怎么把工具结果、文件、截图统一文本化进 context,又怎么在 context rot 的逼迫下分诊、压实、按需取数、融合多模态。

本章你将建立的 schema

  • 感知不是新增模态通道,而是把一切——工具结果、代码输出、图像——统一序列化进同一条 token 流,作为 act→observe→reason 闭环的 observe 一步。
  • context 是有限且会因 context rot 贬值的资源,所以要按"类型 + 优先级"双轴分诊,对抗 n² 注意力与 lost-in-the-middle。
  • 逼近窗口上限时用 compaction 把高熵历史换成低 token 的高密度表示;调参顺序是先 recall 后 precision。
  • 渐进式披露用轻量标识符替代预加载,让 agentic search(grep/glob)边探边判;computer use 把视觉感知接进同一个 agent loop。
序列化 序列化 tools / MCP 结果 代码执行·检索 history · examples 对话·few-shot screenshot 像素 下采样为 token context state 同一条 token 流 有限·会贬值 策展 02.2 分诊 类型 + 优先级 02.3 压实 摘要重启窗口 02.4 渐进披露 按需取数 02.5 多模态 computer use
图 02.0感知层的全貌:左侧五类来源汇成同一条 token 流,右侧四种策略对这块稀缺资源做策展。注意:截图、工具结果、对话历史进 context 之后没有类型区别,都是 token,抢同一份注意力预算——这是后面四节所有取舍的共同根因。

02.1感知导论:感知即文本化

Agent 没有眼睛,只有 context window;所谓感知,就是把多模态输入与工具结果统一转写进同一条 token 序列,再作为闭环里的 observe 一步喂回推理。

为什么需要它

"给 agent 加感知"最自然的理解是"接更多模态输入通道"——加个视觉、加个语音。这个理解抓错了层次。感知不是新增模块,而是把一切(工具返回、代码执行结果、图像)压成同一条 token 流注入 context。把感知当成"独立的输入模块",是这一章要拆掉的第一个错误——它其实是双轴框架里 act→observe→reason 闭环的 observe 一步。

底层机制(比"多模态接口"深一层):Anthropic 把整块输入称作 context state——system instructions、tools、MCP、external data、message history 的总和。Building Effective Agents 把基础积木定义为 augmented LLM = model + retrieval + tools + memory,并强调 agent 每一步都要从环境取得 ground truth(tool 结果、代码执行结果)来评估进度。这正是感知作为"grounding 反馈侧"的精确含义:感知不是看世界,而是把世界的反馈文本化回填。代价随之而来——所有感知内容都占 context 预算,与 system prompt、history 抢同一份稀缺资源。这也是为什么"感知"这一章从头到尾都在讲"怎么省"。

表 02.1 · "给 agent 加感知"到底在加什么
理解它假设的动作为什么错 / 选中
新增模态输入通道给 agent 接一个视觉/语音模块把感知当独立模块,忽略了所有输入最终都落到同一条 token 流、抢同一预算
一次性把环境读满开局把所有沾边的数据全塞进 contextcontext rot 让超长 context 召回下降,塞满 ≠ 更聪明
把环境反馈统一文本化进 context stateact→observe→reason 闭环的 observe 一步选中——感知是 grounding 反馈侧,统一序列化才能让模型在一条流里推理
perception_loop.py Python
# 感知 = 把世界反馈文本化进同一条 token 流(observe),再喂回推理(reason)
ctx = ContextState(system, tools, examples, history=[])   # 五类信息同处一条流

while not done:
    step   = model.reason(ctx)              # reason:基于当前 context 决定下一动作
    action = step.action                    # act:调工具 / 跑代码 / 点屏幕
    result = env.execute(action)            # 产生有副作用的真实反馈

    # observe = 感知:把任何反馈(文本、表格、图像)序列化成 token 回填
    ctx.history.append(serialize(result))   # 工具结果与截图在此不再有类型区别
    done = step.is_final
# 关键不变式:observe 的每一项都占 context 预算,与 system/history 抢同一稀缺资源
想一想

一个团队给客服 agent 接入了图像理解、语音转写、PDF 解析三个新模态,准备好"agent 现在能感知更多了"。上线后发现长对话里 agent 越来越答非所问。新增模态本身没坏,问题出在哪?

展开答案(先停 10 秒再点)

三个模态的输出最终都被序列化成 token,挤进同一条 context 流。每张图、每段转写、每页 PDF 都消耗注意力预算,且与 system prompt、对话历史抢同一份资源。token 越堆越多,context rot 让模型的精确召回随长度渐降——这是性能渐变,不是断崖,所以没报任何错。把感知当"独立通道"就会忽略这个共享预算;正确的心智是:每多感知一项,就在替换 context 里别的东西。这正是 02.2 分诊要解决的问题。

02.2上下文分诊:信息各归其位

Context engineering 不是一次性写好 prompt,而是每一轮推理都重新决定塞哪些 token——按"类型 + 优先级"双轴把信息各归其位。

为什么需要它

Prompt engineering 把"写指令"当成一次性的事:调好措辞就完工。Context engineering 是它的继任范式——Anthropic 的定义是 curating and maintaining the optimal set of tokens during inference,即每一轮推理都重新策展。因为 context 是有限且会贬值的资源(02.1 的 context rot),不分诊就等于让最稀缺的资源随机分配。

底层机制(双轴归位):分诊有两根轴。类型轴把信息分成 system prompt / tools / examples / history / retrieval 五类,各有右尺寸法则——system prompt 求 Goldilocks zone(既不过度硬编码也不空泛,用 XML/Markdown 分区);tools 是 agent 与信息和行动空间的契约,必须无歧义;examples 选 canonical 的少量样例而非堆 edge case。优先级轴对抗 lost-in-the-middle:模型对 context 首尾 token 赋予不成比例的权重(首因/近因偏置),中部信息易被忽略,所以高置信信息放头尾、次要放中间。为什么有效:分区标签降低模型在 n² 注意力里定位信息的难度,无歧义 tool 集减少 tool-selection 幻觉。这与 LangChain 的 Write / Select / Compress / Isolate 四策略框架同构。

一条 context 流:从头到尾的位置即权重 首因·高权重 近因·高权重 中部·易被忽略 system Goldilocks tools 无歧义契约 history 中段 次要放这里 examples canonical 少量 retrieval 最强放近因 RAG 反模式:按 rank 顺序堆叠 → rank1 应放头、rank2 放尾,而非全压在一起
图 02.2分诊的两根轴:类型决定"归到哪一格",位置决定"排在哪一段"。注意:把高价值信息埋在 context 中部是常见陷阱——lost-in-the-middle 会让它被忽略;RAG 按 rank 顺序从头堆到尾是反模式,应把最强证据放头尾。
表 02.2 · 五类信息的右尺寸法则
信息类型痛点设计回应
system prompt太硬编码则脆,太空泛则无效求 Goldilocks zone,用 XML/Markdown 分区标签降低定位难度
tools功能重叠、决策点模糊 → tool-selection 幻觉选中为分诊的关键——契约无歧义;检验法:人都分不清用哪个 tool,agent 必然更糊涂
examples堆满 edge case 反噪声选 canonical 少而精,覆盖典型而非穷举异常
history / retrieval全量预载撑爆预算走 just-in-time(见 02.4),按需取而非一次塞满
想一想

一个 agent 配了 12 个工具,其中 search_docs、find_in_files、lookup_reference 功能高度重叠。开发者觉得"工具越多越强"。结果 agent 频繁调错工具、绕远路。怎么用一句话判断这个工具集是不是有病?

展开答案(先停 10 秒再点)

检验法:人都说不清该用哪个 tool,agent 必然更糊涂。bloated tool set 的功能重叠和模糊决策点会直接诱发 tool-selection 幻觉——tools 是 agent 与行动空间的契约,契约一旦有歧义,概率节点就会在重叠选项间乱选。修法不是加更多说明,而是合并重叠工具、让每个决策点唯一。"更多工具 = 更强"是反直觉的错误:扩张工具集常常降效。这呼应 01 章的核心——agent 是概率节点,歧义直接放大它的不确定性。

02.3语义压缩:逼近预算就压实

Compaction 是用一次额外推理,把高熵的对话历史换成低 token 的高密度表示,再用摘要重启新窗口——目标是 find the smallest set of high-signal tokens。

为什么需要它

02.2 教会了"怎么摆",但长任务里 token 只增不减,迟早撞窗口上限。最朴素的反应是"等它撞墙"或"换更大的窗口"。两条都不解决问题:撞墙直接报错,更大窗口让 context rot 更重。compaction 给出第三条路——在逼近上限时主动把历史压实,腾出预算继续跑。

底层机制(先 recall 后 precision):compaction 的本质是用一次 LLM 调用把高熵历史换成低 token 的高密度表示。最轻量的形态是 clearing tool calls/results——历史里调用过的 tool 原始输出是信息密度最低的部分,调用过即可丢,已作为 Claude Developer Platform 一等功能上线。更重的形态是摘要:Claude Code 保留架构决策、未解 bug、实现细节,丢弃冗余 tool 输出。代价与失败模式有两个:其一,压缩本身要花一次 LLM 调用(延迟 + token);其二,过度压缩会丢"当时不知道重要、后来才知道"的细节——这是不可逆的信息损失。所以调参顺序是先最大化 recall(不漏关键信息)再提 precision(去冗余),反过来必丢关键信息。量化上:SWE-bench 实测每 10–15 次 tool call 调度一次压缩可省 22.7% token(14.9M→11.5M)且不掉点;BATS(2025-11)用 Budget Tracker 给出 HIGH/MEDIUM/LOW/CRITICAL 四档剩余预算,达临界即把历史轨迹换成摘要,10x 省预算。

表 02.3 · 窗口快满了,怎么腾预算
方案优势为什么没选 / 选中
无限增长直到撞窗口上限零实现成本直接报错,且越长 context rot 越重
clearing tool calls/results最低风险、丢的是密度最低的内容最轻量起点,但只清 tool 输出,对话本体超预算时仍不够
compaction(摘要重启窗口)维持对话连续性、保留高信号选中(适合大量来回的对话)——代价是一次 LLM 调用 + 不可逆信息损失风险
纯 note-taking / 纯 multi-agent记事抗重置;多 agent 可并行note-taking 适合有里程碑的迭代开发,multi-agent 适合可并行的复杂研究——是另一类任务的解
陷阱 · 压缩是有损且 blocking 的

compaction 不是"顺手压一下":它会停住 agent 跑一次完整 LLM 推理(延迟 + token),长任务里频繁触发是真实的吞吐瓶颈。更危险的是调参方向反了——先求 precision 会漏掉关键信息。Anthropic 的选择矩阵把它和别的策略分开:compaction 适合大量来回的对话,note-taking 适合有里程碑的迭代开发,multi-agent 适合可并行的复杂研究。压缩不是万能键,是三选一里的一个。

02.4渐进式披露:按需取数,边探边判

渐进式披露不预加载全部数据,只持有轻量标识符(file path / query / link),运行时用 tool 动态拉取——元数据本身即信号。

为什么需要它

02.3 在"已经塞太多"之后做补救;渐进式披露在源头就不塞满。开局把所有沾边的数据填进 context,是最浪费 attention budget 的做法。just-in-time 反过来:只持有指向数据的轻量标识符,需要时才用 tool 取回,让每次交互的结果指导下一步决策。这与 03 章"记忆"里 just-in-time / agentic search 是同一套机制。

底层机制(为什么 grep 在 agent 场景胜过 RAG):progressive disclosure 用轻量标识符替代预加载,运行时按需取数。元数据本身即信号——文件大小约等于复杂度、命名揭示用途、时间戳揭示相关性,agent 边看元数据边判断要不要钻进去。关键决策是检索策略:Anthropic 早期试过 RAG,最终发现 agentic search(模型自己 grep/glob/head/tail,看结果再决定钻不钻)大幅胜出,且绕开 stale index 与复杂语法树。arXiv 2605.15184 实证:inline grep 在所有 harness-model 对上胜过 vector,最高 +23.3pt,因为任务答案多落在 verbatim span(精确日期、计数)。代价:runtime exploration 比预取慢,且需要工程师精心设计 tool 与启发式让模型"会探"。落地形态是混合加载——CLAUDE.md 朴素预载求速度,glob/grep 按需即时取文件求新鲜度。

progressive_disclosure.py Python
# 渐进式披露:先持轻量标识符,看元数据再决定钻不钻(just-in-time)
hits = grep(pattern) or glob("**/*.py")        # 不预加载,只取路径/名字
for f in hits:
    meta = stat(f)                             # 元数据本身即信号:
    #   大小 ~ 复杂度,命名 ~ 用途,时间戳 ~ 相关性
    if not promising(meta):                    # 边探边判:不值得就跳过
        continue
    snippet = head(f, n=50)                    # 按需深入,逐层 disclosure
    ctx.history.append(snippet)                # 只把值钱的那几十行塞进 context

# 混合加载:CLAUDE.md 预载求速度,grep 按需取求新鲜度
ctx.preload("CLAUDE.md")                       # 朴素塞进 context,绕过 index 同步
# 对比 RAG:grep 是确定性精确匹配,无 stale index、无 embedding 语义噪声
表 02.4 · 给 agent 配检索:预加载 vs 按需
方案优势为什么没选 / 选中
开局预加载全量数据运行时零延迟撑爆 attention budget、加重 context rot,多数预载的数据从没被用到
预建 embedding 向量库 + RAG懂语义改写stale index 要同步维护;verbatim-span 任务上 inline grep 胜 vector 最高 +23.3pt
agentic search(grep/glob 现查)+ 混合加载无索引维护、确定性精确匹配、元数据成探索信号选中——代价是 runtime 探索比预取慢、要精心设计 tool 与启发式
structured note-taking(写到 context 外)跨数千步维持精确状态、抗 reset长程对策(Claude 打 Pokémon 案例),与按需取数互补而非替代
想一想

"agentic search 永远胜 RAG"听起来像一条定律。但同一篇 2605.15184 实测里,有两种情况向量检索反而追平甚至反超 grep。是哪两种?并且实验还发现一个让"换检索策略"显得没那么重要的因素,是什么?

展开答案(先停 10 秒再点)

两种反超场景:其一,答案需要跨多文档语义聚合而非落在 verbatim span 时,纯 grep 召回不足;其二,file-based 交付下 vector 反超。第三个因素更关键——harness 设计的影响可达 ±16pt,与换整套检索策略的影响相当。所以检索策略不是孤立的准确率决定项,它和 scaffolding 纠缠在一起。结论:默认从 agentic search 起步,但别把它当定律;混合加载(CLAUDE.md 预载 + grep 按需)才是 Anthropic 的实际落地。

02.5多模态融合:截图进 context 的 agent loop

Computer use 把视觉感知接进同一个 agent loop:Claude 收 screenshot,回 coordinate-based 的鼠标键盘动作,harness 执行后回新 screenshot——循环本身就是 agent loop。

为什么需要它

前四节都在管文本与工具结果。但很多任务的接口只有 GUI——没有 API、没有文件。为每个应用造专用 tool 不可扩展;computer use 反过来教会 agent 通用电脑技能:任何人类能用的软件都能操控。它把 02.1 的"感知即文本化"推到极致——连屏幕像素也被序列化成 token 进同一条流。

底层机制(grounding 为何脆):computer use 把视觉接进 agent loop——screenshot 进 context(每张约 1,000–1,800 input token),模型输出坐标动作,harness 在沙箱执行回传新图。当前 beta 头是 computer-use-2025-11-24(Opus 4.8/4.7/4.6、Sonnet 4.6、Opus 4.5)。最大的失败源是 GUI grounding——把"点哪里"的语义意图对齐到像素坐标。API 把图下采样到 ≤1568px(早期模型)/~1.15MP,模型在缩小空间返回坐标,点击却发生在原始屏幕空间,错位即来;macOS Retina 2x、4K 源尤其严重。对策有四:指令文本放在 screenshot 之前(先给目标描述再处理图像提升点击精度)、enable_zoom 让模型放大看小字、基线分辨率用 1280x720、提示用键盘快捷键绕开难点的下拉/滚动条。Anthropic 明确承认三大局限:延迟太慢(只适合非实时场景)、计算机视觉坐标会幻觉、tool 选择在小众/多应用场景可靠性下降。OSWorld(真实 OS + 截图/a11y 树)是事实标准 benchmark,早期 SOTA 仅约 20%,说明 grounding 远未解决。

① 截图 下采样≤1568px ② 模型出坐标动作 在缩小空间给 (x,y) ③ 沙箱执行 原始空间点击 缩小空间≠原始空间 → 错位 回传新截图 → 下一轮,每动作 = 一次完整往返 + 一张图 token 缓存友好修剪:保留最近 3 张、每 25 轮剪一次,保前缀字节稳定
图 02.5computer use 闭环:截图→坐标→执行→回传新图,循环即 agent loop。注意:每轮丢一张旧截图看似省 token,实则每轮改变 prompt cache 前缀使缓存全失效,反而更贵。必须 batch 修剪(保留最近 3 张、每 25 轮剪一次)保前缀字节一致。
表 02.5 · GUI 感知接口怎么选
方案优势为什么没选 / 选中
为每个应用造专用 API tool精确、无坐标问题不可扩展,逐应用集成成本高,覆盖不了长尾软件
纯 accessibility tree / DOM结构化、比像素精确覆盖不全、依赖应用主动暴露 a11y 信息
screenshot 像素 + 坐标动作通用——任何人类能用的软件都能操控,无需逐应用集成选中——代价是 grounding 脆(坐标-像素错位)、每图 1–1.8K token、延迟高、小 UI 易失败
想一想

一个 agent 跑 computer use,开发者为省 token 在每一轮都丢掉最旧那一张截图。账单不降反升,延迟也变差。明明 context 里 token 更少了,为什么更贵?

展开答案(先停 10 秒再点)

问题在 prompt cache。每轮丢最旧一张截图,会改变 context 的前缀字节,让整个 prompt cache 前缀失效——下一轮所有 token 都得重新计算、重新计费,缓存命中率归零。这就是"省了几百 token,赔上整段缓存"。正确做法是 batch 修剪:保留最近 3 张、每 25 轮才剪一次,让前缀字节在多数轮里保持稳定,维持缓存命中。代价只是 context 里多留几张已过期截图。这是"局部省 token"与"全局省钱"冲突的典型——感知层管理永远要算整条流的账。

陷阱 · 坐标空间错位与 prompt injection

两个高频失败模式。其一,把 display_width_px/display_height_px 设得与实际发送图像尺寸不符,或图超 API 限被静默下采样,点击就会系统性偏移;macOS Retina 2x 必须先 downscale 或把坐标减半。其二,prompt injection——网页或图像里的指令会覆盖用户意图。必须沙箱隔离、限域名白名单、关键动作人工确认。computer use 只适合后台信息收集、自动化测试等非实时场景。

§本章 self-check

先合上教程,把你能想到的答案写在纸上或编辑器里。写完再点开答案对照——直接点开等于把这一节当再读一遍。

  1. "给 agent 加感知 = 接更多模态通道"错在哪?用"同一条 token 流"和 context 预算解释。
  2. 上下文分诊的两根轴分别是什么?优先级轴对抗的是哪个具体现象?
  3. compaction 调参为什么必须先 recall 后 precision?反过来会丢什么?
  4. 在 agent 场景,agentic search(grep/glob)相对预建向量库的三个具体优势是什么?又在哪两种情况会被 vector 反超?
  5. computer use 里每轮丢一张旧截图为什么反而更贵?正确的修剪策略是什么?
答案(先做完再展开)
  1. 所有模态输入最终都被序列化成 token、进同一条 context 流,与 system prompt、history 抢同一份 attention budget。token 越多 context rot 让精确召回越差(性能渐变非断崖)。感知是 act→observe→reason 闭环的 observe 一步,不是独立通道。
  2. 类型轴(system / tools / examples / history / retrieval,各有右尺寸法则)与优先级轴。优先级轴对抗 lost-in-the-middle:模型首尾权重高、中部易丢,故高置信信息放头尾。
  3. 过度压缩会丢"当时不知道重要、后来才知道"的细节,且这是不可逆损失。先求 precision(去冗余)会先削掉这些尚未显现价值的内容。正确顺序是先最大化 recall 再提 precision。
  4. 三优势:无 stale index 要维护、确定性精确匹配(绕开 embedding 语义噪声)、元数据成为探索信号。verbatim-span 任务上 inline grep 胜 vector 最高 +23.3pt。两种反超:跨多文档语义聚合任务、file-based 交付。
  5. 每轮丢最旧截图会改变 prompt cache 前缀字节,使整段缓存失效、所有 token 重新计费。正确做法是 batch 修剪:保留最近 3 张、每 25 轮剪一次,保前缀稳定维持缓存命中。
进阶挑战 · 刚好够不着

为一个跨数百步的 GUI 自动化 agent 设计感知预算策略

一个 computer use agent 要在真实桌面上跑数百步(OSWorld 风格任务)。它面对三股相互拉扯的压力:截图累积极快撑爆 context;compaction 会丢掉早期看似无关、后来才关键的界面状态;每轮乱丢截图又会击穿 prompt cache。设计一套策略,让它在数百步里既保住 grounding 精度、又不爆预算、还不击穿缓存。说清你的策略在四节(分诊 / 压实 / 渐进披露 / 多模态)的哪几处介入,以及每处的代价。

提示(卡住再展开)

四节都得用上。多模态:batch 修剪保留最近 3 张截图、每 25 轮剪一次保缓存前缀,并把指令文本放在图像之前提升点击精度。渐进披露:不要每步都全屏截图,能用 a11y 树或裁剪到相关区域就别送全图,元数据(窗口标题、焦点元素)先判再决定要不要送像素。压实:在压缩阈值之前就把"已完成的子目标 + 当前界面状态摘要"用 structured note-taking 写到 context 外(呼应 03 章把状态外化到文件),这样 compaction 丢掉早期截图也无所谓——状态已经在文件里。分诊:把当前目标描述和最近一张截图放在 context 头尾(对抗 lost-in-the-middle),中间放历史轨迹。代价:a11y 树覆盖不全、裁剪有漏掉关键区域的风险、写笔记要花额外推理、batch 修剪让 context 多留几张过期图。这正好把本章四节串成一条"为长程而设计的感知预算"的链。