这是《深入理解 AI Agent》精读专题的第八篇,一次走完第 2 章的两条线索:Skills(能力的按需加载)和 Agent 状态栏(状态的提前提炼)。读的是李博杰的开源书第二章。
本章思维导图见 专题页 · 章节思维导图
Skills:先给目录,再给手册
Agent 覆盖的业务场景越来越多,系统提示词就会不断膨胀——全部塞进去有两个代价:浪费 token(大部分内容与当前任务无关)、注意力被稀释(无关信息淹没关键指令)。
Skills 的解法是渐进式披露:不是把所有知识一次性塞给 Agent,而是让它按需加载——像给新员工一份总目录,需要哪本操作手册再去取。一个 Skill 由三层组成:
- 元数据:
SKILL.md开头的 YAML frontmatter(name + description),目录在完整正文加载前就可见,让模型先判断要不要这项能力 - 核心流程:任务需要时才加载完整的 SKILL.md(用户斜杠命令显式触发,或模型读过目录后自己判断、调用 Skill 工具加载)
- 引用子文件:更细的子文档按需深入(如 PPTX Skill 的 html2pptx.md)
description 的写法是最值得学的一笔:它应当像路由条件,而不是功能介绍——「何时使用、何时不使用」的边界,配上典型的正例和反例。「何时该用我」比「我能做什么」重要得多;写得太宽泛(”help with backend”),任何后端相关的工作都会触发,路由就失准了。
Skill 还可以捆绑可执行的脚本和模板(PPT Skill 带 PPT 模板和解析脚本)。往大了看,每个 Skill 是自包含的知识模块,可独立开发、测试、版本控制——Agent 的能力扩展从集中式地编辑系统提示词,变成了分布式的 Skill 生态,像 pip / npm 的包管理。一个值得记的原则:选择 Agent 交互模式时,应与模型厂商的训练方法保持一致——厂商推行的用法是它们专门训练过的模式。
状态栏:上下文是台只有一半的检索引擎
状态栏的理论依据,是注意力机制的一个本质特性:上下文学习更像检索而非推理——模型擅长从已有内容里查找信息,但不擅长主动归纳总结。原文的比喻:上下文窗口是一台只有一半的检索引擎——
- 检索的那一半很强:注意力能从成千上万个 token 里捞出相关的原始记录,相当于把 RAG 内置进了每次前向传播
- 但它没有「提炼层」:上下文里的东西从不会被自动数一遍、总结成一条结论。任何「关于这些内容的结论」——一共多少次、有没有超标、进展到哪——模型每次都得从原始记录里现算,代价随上下文堆积量上涨
实际场景:系统提示词要求每个商家最多打 3 次电话,Agent 经常数不清打了几次,又打第 4 次,甚至循环拨打。「已经打了几次」这个知识没有被提炼出来,而是分散在轨迹的原始记录里,模型每次决策都要花思考 token 重新统计——效率低、错误率高。而当每次通话结果直接标明「本次是第 3 次呼叫」,错误率大幅下降。
这背后是两件事:把分散在各处的隐式状态提炼为可直接使用的显式知识(Harness 提前算好聚合信息,模型只需检索);以及强制性的注意力引导——长上下文里注意力有限,中段信息衰减(开头和结尾注意力高),把结构化的状态放在上下文末尾,空间上紧邻即将生成的新 token,自然获得最高权重。
数字很有说服力:提供提前算好的状态栏后,小模型(Qwen3-0.6B)的准确率能接近前沿大模型;思考 token 量、延迟、花费降低约一个数量级——不带状态栏时思考量随上下文变长持续增长,带上之后基本恒定。
状态栏怎么落地
放哪:作为一条 user 角色的消息挂在上下文末尾,内容用 <agent_status> 标签包裹——借助 user 槽位注入框架生成的状态,但特殊标签让模型能理解这不是真实用户在说话。不改 system 消息(那会破坏前缀缓存),追加也不影响任何已缓存内容——还是「动态信息追加末尾」那套。
状态会变,两种更新策略各有代价:
- 每轮替换:每次调用前移除旧状态、追加最新状态。上下文里永远只有一份最新状态;代价是移除会让其后的缓存失效——好在失效范围只覆盖上次注入后的短后缀(通常一轮),整个前缀仍可复用。适合状态较大、更新频繁的场景
- 持久追加:状态注入后永久留在轨迹里,每轮只在末尾追加新的。缓存完全友好(只增不改);代价是陈旧状态累积占 token,且要求模型只识别最新一条、忽略过时状态。Claude Code 的
<system-reminder>就是这个方式
状态栏常放三类信息:任务规划(TODO 列表放轨迹末尾,防止忘记原始诉求)、事件的侧信道信息(精确时间、地理位置、时间间隔)、环境状态的观察摘要(系统时间、工作目录、「该工具已被重复调用 N 次」的异常提醒)。实验里的五种技术(时间戳、工具调用计数器、TODO 管理、详细错误信息、系统状态感知)组合使用还有涌现效应——时间戳 + 计数器让 Agent 理解操作频率,TODO + 系统状态让策略随环境调整。
状态栏维护的三个注意点:
- 尽量用确定性的代码维护状态——实验发现模型几乎无条件相信状态栏(写 3 次它就当真 3 次,不会重算),而 LLM 做统计本来就容易出错。实在要用 LLM,也要逐条抽取、代码汇总,绝不让它批量统计。这也意味着状态栏投毒风险要认真对待
- 尽量避免删除原始数据——状态栏是对原始轨迹的有损投影,只提前算了「你预想会被问到」的维度。计数类任务可以只留状态栏;但只要有一个问题落在未计算的维度上,准确率断崖式下降
- 归位:书里明确说,Agent 状态栏本身就是上下文压缩(Context Compression)技术之一——用极低的 token 成本提前提炼信息,正是压缩思想的第一种形态。第 2 章最后一块(也是下一步要读的),就是更完整的压缩策略
我的理解与修正
读完状态栏这段,我最初的归因是:归纳弱,本质是 LLM 是生成式模型,靠概率预测 token——概率性的东西当然数不准。细想后这个归因站不住:把采样温度设为 0(greedy decoding),每一步都是确定性的,模型照样数不清 3 次电话。真正的原因在架构:注意力是并行的加权读取,一次矩阵运算就能从上万 token 里捞出相关内容,这是 Transformer 天生擅长的;而归纳统计需要循环加精确累加(数到几了、加一、比较),单次前向传播是固定深度的计算,没有可迭代的循环状态——需要循环的精确计算,架构上就做不稳。
所以模型不是不能归纳,是归纳很贵:思维链就是它现算的方式——实验 2-8 的对照组里,热力图显示思考 token 在草稿纸上一步步数数——成本随上下文增长,且一步数错、后面全错。状态栏的本质,是把「每次现算」替换成「一次检索」:把归纳从概率路径上挪走,交给代码在 Harness 里确定性完成,模型只消费结果。这也解释了书里为什么坚持「状态栏尽量用代码维护」——确定性计算就该交给确定性引擎。
下一步
- 第 2 章最后一块:线索三,上下文压缩(什么时候压、怎么压、怎么与 KV Cache 共存)
- 实验:
agent-status-bar(五种状态栏技术)
参考来源
- 《深入理解 AI Agent:设计原理与工程实践》第 2 章「上下文工程」,李博杰著,GitHub 开源——本篇覆盖「动态提示词与 Agent Skills」「Agent 状态栏」
- Anthropic: Equipping Agents for the Real World with Agent Skills——Skills 机制的源头设计
- 宝玉:《别再用提示词去 AI 味了,方向就是错的》——书里 Skill 写作四部分结构的出处