把 LLM 视作解释器——正确管理你的上下文:系统提示词、函数调用和 skill
不要想象“智能”,也不要以为机械。
背景
定义问题
解决问题首先要定义问题。小白与老手的区别,就是老手知道如何正确定义问题本身。
使用 LLM,根本需求其实只有一个:期望 AI 在预期或非预期的范围内,达到预期的目标。
为什么要区分这两种范围?因为人面对的问题并不一样:
- 非预期范围
- 人不总有能力提出正确的问题。
- 人也不总知道应该怎样解决问题。
- 预期范围
- 人明确知道问题怎样解决,只是懒得动手。
- 流程已经明确到人本身没有发挥“能动性”的空间。
所以真正的问题不是“AI 聪不聪明”,而是:怎样让 AI/LLM 沿着合理的路径搜索到问题的答案。
让 LLM 沿着合理路径搜索答案有两种情形:面对未知,引导它在巨大的表示空间里找到正确答案;面对已知流程,则用提示词约束乃至“迫使”它沿预计的路径工作,而不是任由概率四处漂移。
既然目标是控制解决路径,下一步就要找出 Agent 里真正能够被控制的部分。
定义 Agent
Agent 是一个可以通过函数调用自动完成任务的 LLM 智能体。它的主要工作方式,是反复执行下面的循环:
- 输入文本:系统提示词、用户输入、skill 提示词和函数调用信息。
- LLM 返回文本,其中也可能包含函数调用的 JSON。
- 客户端执行函数调用。
- 把原提示词、LLM 输出和函数返回重新放入上下文。
- LLM 继续生成下一步。
状态机拆解
文本 →(LLM → 可能的函数调用)→ 文本
函数调用看起来像“行动”,但对 LLM 来说,它仍然是生成了一段会被客户端解释和执行的文本;函数返回,则会变成下一轮上下文中的新文本。函数调用不能从这个模型里拿掉,因为它正是 Agent 把文本变成外部行动,再把行动结果变回文本的连接点。
可控与不可控范围
在不考虑过滤、重写等 injection 手段时,可控的是:
- 提示词与用户输入。
- 函数返回数据。
不可控的是:
- LLM 生成的函数输入。
- AI 返回的文本。
可变与不可变范围
在一次实际任务中,可变的是文本,也就是上下文;相对不可变的是 LLM 本身。
LLM 是解释器,上下文是控制流
从 Agent 的工程控制面看,这就是一个解释器程序。
LLM 是一只“补词鹦鹉”:它依靠上下文计算下一个 token 的概率分布,再从中选择或采样一个 token;每生成一个新 token,就把它加入上下文,重新计算下一步,直到遇到停止符。
def LLM(prompt: str) -> str:
def get_next_token(prompt: str) -> str:
...
next_token = ""
while next_token != "EOF":
next_token = get_next_token(prompt)
prompt += next_token
return prompt
作为输入的“原始上下文”,有让 LLM 差之毫厘、谬以千里的力量。
因此,上下文本身就是程序和控制流;LLM 则是解释器,把上下文逐步翻译成文本与函数调用。它不是一台确定性的解释器,同一段上下文也不保证每次走上完全相同的路径,但管理 Agent,本质上仍然首先是管理上下文。
解决方案
完全静态的工作流与静态控制
最基础、也最直觉的上下文管理,就是管理系统提示词与用户输入。
系统提示词
系统提示词通过经验性的写法限制或扩展 AI 的行为。因为它位于上下文最前面,影响很强:改得好,能把垃圾模型拔高;改得不好,也能让优秀模型降智。
现在越来越少人建议把主要精力花在优化系统提示词上,不是因为它没用,而是因为它太难改好。所谓“最佳提示词”往往只在特定任务、特定模型,甚至特定版本上成立;换一个任务,最有效的写法可能完全不同,甚至反直觉。优化系统提示词因此更像局部调参,而不是寻找一份可以普遍复用的完美宪法。
更麻烦的是,提示词的影响不是逐条独立叠加的。一条要求单看并不刻板,几十条累积起来,也可能共同塑造出一种非常强的“性格”。同一份长提示词放到不同模型里,这种性格可能截然不同,甚至让原本用于避免问题的规则反过来制造问题。方法论 skill 尤其容易暴露这一点:它本来只想提供一种思考倾向,一旦解释得太长、限定得太细,就可能从“引导模型”变成“替模型思考”。
这也是我一直坚持的提示词编写规范:优先使用含义密集、能够调动模型既有概念簇的词语,用最干净、最短的表达传达约束,而不是反复解释。 一个有纵深的词可以唤起模型已经学会的完整概念;几十条局部禁令,只能从碎片开始拼装。
少写“不要”,多写目标
Anthropic 2026 年关于语言模型 global workspace 的研究让这个经验有了更具体的参照。论文的总体结构分析使用 J-lens 读取模型内部可言说的表示,观察某些表示如何跨 token 位置广播、如何受任务指令调节,并由此讨论语言模型中类似 global workspace 的结构。prompt context 承载输入,J-space 是 J-lens 读取表示的空间,global workspace 则描述论文观察到的广播结构。
与提示词写法更直接相关的,是附录里的 mention、don’t-think 与 ignore 实验。研究者在特定的复制任务和检测协议下,比较目标概念的可检测表示:category-instance 与 math-expression 两类任务给出了较整齐的结果——仅仅提及目标或要求“不要想”它,通常都不会让该表示消失;把目标标为与任务无关,则更常伴随较低的检测结果。
line-width 任务则要求模型在读取、复制文字时暗中逐字计数,判断当前字符位于一行中的第几列。四种提示方式在这里没有形成前两类任务那样清楚的关系。作者认为,可能是因为逐字计数本来就更难,也可能是因为 focus 与 ignore 针对 line-width 的具体措辞在语义上并不完全对称。这项实验比较的是 J-lens 能否从模型的中间状态读出目标概念,而非最终抄写的正确率。
禁止一个概念,并不等于模型无需先表示这个概念。 落到工程实践,反复铺陈不希望模型采用的做法,还会占用 token,稀释真正目标的信息密度,让相应概念在生成过程中持续活跃,把回答牵向本想回避的函数空间。能直接写目标状态,就不要用它的反面围出一座迷宫;确实需要禁止时,写短,并尽快把重心交还给应该做什么、什么与当前任务相关。
用户输入
用户输入位于上下文末尾,同样会强烈影响 LLM。最简单的要求就是:少打错字,简化表达,尽可能先澄清自己的思想。
早期还有一种常见技巧:如果希望模型输出 XML,就让输入以 <xml> 收尾;希望输出 JSON,就用 { 收尾。它利用的也是末尾输入对后续生成的近邻影响。
关于系统提示词、最新输入和工具结果为什么重要,我在 AI Agent Privacy and Protection 里也从安全角度讨论过。
基本静态的过滤、重组与结构化控制
除了直接写提示词,也可以在人类可控的边界上整理上下文。例如 MCP Tool 精心构造输入和返回,skill 指定 AI 使用特定命令来缩小输出,或者由网关自动修剪、重组和结构化工具结果,比如 OmniRoute 的 RTK Engine。
这些办法有用,但总体上正在被 LLM 工具内置的压缩,以及 subagent 的上下文隔离所替代。根本原因是,人类手写规则的速度赶不上模型成本下降和能力演进的速度。固定格式、明显噪声、低成本的前置处理仍然值得做,但价值也就到这里:它们适合顺手清理输入,不能承担复杂的语义控制,更不应该被抬高成整套 Agent 控制的主要防线。
老范式:用 subagent 隔离上下文
比静态过滤更进一步的办法,是用 subagent 把不同工作隔离在不同上下文里。但隔离不是免费的,每一次交接都要面对 handoff:要么传递完整上下文,让信息密度下降;要么压缩上下文,承担总结失真的风险。
如果不压缩,直接把完整上下文加入接手 Agent,暂且不谈长度,信息密度也会下降,LLM 更可能注意不到真正要处理的任务;如果压缩,handoff 又会变成一次抽奖。
想让结果稳定,通常有两种优化方式:
- 增加抽奖次数,例如多个 LLM 评审或 loop。
- 减少抽奖环节。
前者是烧 token 的专家评审和 loop 编程,靠“暴力出奇迹”;第二种则是:默认避免无意识、没有必要的 subagent 交接。 如果一项工作本来可以在当前上下文中连续完成,就不要为了显得像多 Agent 系统而硬拆。每一次接管都可能把上下文压缩过头,最后让新 Agent 重新发现一遍完整背景;这也是很多人发现不用 subagent 反而更快的原因。
新范式:把 skill 当作程序化控制流
既然 LLM 本身可以视作解释器,提示词就是要运行的代码。
与其编写一个包含所有情况的“论文型”巨型 skill 或提示词,不如把它拆成多个 skill,再把 skill 当作控制流串起来:满足某个条件就加载某个 skill,否则走另一条路径。这样 AI 只需要读取当前分支对应的内容,可以直接避开无关信息造成的上下文污染。
这种方式对 AI 本身的能力和训练方式有要求。如果模型习惯无脑读取所有文件,控制流就会失效。幸好,目前 Agent 在这一方面的工程化已经做得不错。
行业里先出现 subagent,后来才逐渐形成 skill,是因为 subagent 天然带来上下文隔离。但 skill 更适合承载成熟、稳定的 handoff:无论由人还是 AI 编写,它本质上都是一份可以复用、审查和持续完善的交接文档。新的 Agent 或 session 可以直接从成熟流程开始,不必重新经历发现问题、摸索工具和确认约束的全过程,也不会把“怎样发现答案”的过程噪声混进实际工作上下文。
Superpowers 就是一个具体例子。它不只有这一个意义,但其中很重要的一部分价值,正是把已经成熟的工作方法写成 skill 和流程文档,为接手 Agent 提供完整 handoff,减少它重新发现上下文的时间和抽奖次数。
新范式的上下文控制工作流
真正落到工作流里,需要分清三种东西:成熟、线性的执行流程,以及可迁移、可明确表达的思考方法,交给 skill;用户习惯、历史状态和人物关系等非线性知识交给 memory;真正值得隔离、树状拆分或独立评审的执行工作,才交给 subagent。
skill
skill 可以固化两类不同的东西。第一类是线性、固定、可以复用和审查的任务流程,包括控制流和成熟 handoff;它像人类可读的伪代码,也像一份稳定的需求书。第二类不是具体任务步骤,而是可迁移的方法论或个人解题思路。
很多人觉得 Superpowers 这一类 skill 太“霸道”,问题往往不在于它提供的方法没有价值,而在于整套 skill 被直接交给 Agent 发现时,过宽或不贴合需求的 description 会把预设的工作方式一并带进任务。它带进来的不只是控制流,还有作者对何时规划、怎样测试、什么算完成的一整套工作习惯。只要其中一些判断不适合当前用户和项目,Agent 就会认真地用别人的方法写你的代码;skill 越完整,这种性格越鲜明。
我的用法是只让 Agent 直接看见自己编写的入口 skill,例如 coding-in-project,再从中按需采用更窄的外部能力:用 Superpowers 的 subagent-driven-development 编排 subagent,用 BDD skill 设计和编写测试。这样既能吸收 Superpowers 在 subagent 编排上无与伦比的效率,也不必继承它的整套风格与代码品味。
这就是程序员熟悉的“库调用”:自己的代码只在需要时调用库中的某项能力,而不是让库替自己决定整个程序怎么写。到了 Agent 这里,库、接口和组合这些经典概念已经足够。真正拉开差距的,是能否在新事物里重新认出它们,理解得足够深,再把它们组合好。
Agent 领域也在重复计算机界长久以来的造词习惯。例如,把提示词和流程拆进文件后称为
skill。这个词如今已经成为标准说法,继续使用当然无妨,但一个新名字并没有创造出全新的计算机概念。本文用“库调用”来解释它,正是因为程序员熟悉的旧概念已经足以说明这种组合方式。
harness一类词更容易暴露这个问题。Agent 语境中的harness往往包着上下文组装、工具调用循环、状态管理和执行控制等已有的东西;脱离具体上下文和先验知识,读者仅凭名字根本不知道它究竟做什么。“skill 能否替代 MCP Tool”“MCP Tool 与 function call 有什么区别”,这些问题原本都有清楚的答案:skill 组织 Agent 使用的方法和流程,MCP Tool 向 Agent 宿主暴露可执行能力,宿主可以再把 MCP Tool 转成模型可见的工具,并根据模型产生的 function call 调用它。这些名字一旦被排成一组,仿佛彼此并列、可以互相替代,许多本不必要的比较也就出现了。仅因 skill、MCP Tool 和 function call 都被 Agent 使用,便继续追问谁能替代谁,无异于指着苹果树问:“为什么苹果树不会长梨?”没有提出新的区别,却为了显得高深而另造名词,不是创新,而是把作者没有想清楚的问题转嫁给读者。作者理解上的浅薄和表达上的贫乏,最终都会变成读者额外的理解成本,迫使读者再把新词翻译回已有概念。
说回 skill,第一类流程型 skill 应当从实际工作中长出来。哪些流程值得固化,写成之后怎样使用和删改,AI 工作时又该如何监督,可以归结为四点:
- 值得固化成 skill 的流程,应当从真实工作中识别出来,而不是让 AI 无差别地自行总结。skill description 会进入每个 Agent 的初始上下文,你不会希望编程 Agent 总带着一份搜索菜谱的 skill。
- 对稳定流程,优先用 skill 控制 AI,而不是继续膨胀用户提示词或系统提示词。大而全的提示词就像学生行为手册:即使每条规定都合理,合在一起也会稀释任务重点,并在不同模型里塑造出不可预测的性格。
- skill 写完后,让 AI review,并围绕真实失败反复删改。完善 skill 不等于不断增加细节:应该补上必要的控制流,也应该删掉重复解释和想象出来的防御性禁令。
- AI 工作时必须盯着它:为什么这里开了 subagent,为什么那里调用这个工具?现在的 Agent 越来越“多动症”。如果不及时制止弯路,LLM 非常愿意花时间重新发明轮子,甚至通过钻规则的漏洞来绕过问题。监控不是可有可无的陪伴,而是整套控制能够成立的前提。
第二类 skill 适合把用户自己摸索出的“如何思考、如何追问、如何拆问题”写成轻量提示词。它和 memory 有异曲同工之处:两者都会让 AI 的回答带上一种相对稳定的倾向,更接近用户希望它采用的思考视角。
我习惯把这种倾向理解成对“函数空间”的选择。面对同一个开放问题,放进编程、医学等不同专业的答案空间,会生成完全不同方向的回答;即使同在一个领域,也可能落进资深从业者、小白,或者尚未入门的大众所处的答案空间。
方法论 skill 的价值,就是用一组特定提示词,较稳定地把模型偏向其中一个空间。例如 grill-me 会让 AI 更偏爱追问、拆解和挑战假设,而不是顺着问题直接给结论。它承载的是思考偏置,而非一套复刻任务步骤的“解题程序”。LLM 仍然是概率解释器;skill 让这项偏置显式进入上下文,增加模型选择相应函数空间的倾向,却不指定某个必然出现的答案。
memory 也可以逐渐学到同一种偏好,但它是否被检索出来、怎样被组织、最终如何注入当前上下文,都可能不稳定。skill 则把偏好固化成显式、固定、可审查的提示词,触发更稳定,也更容易共享和修改。这就是两者在这里最重要的区别。
memory
memory 适合让 AI 逐渐学习你的习惯和思考偏好,也适合保存人物关系、历史状态等非线性数据。它的优势是能从持续积累的上下文中形成认识,不需要把每件事都预先写成规则;代价则是检索和生效没有 skill 那么确定。
处理 memory 本身同样需要上下文,所以必须隔离。工作 Agent 绝对不应该自己总结、筛选或删除记忆。 新上下文应自动进入记忆队列,由独立的 memory Agent 或代理处理,例如 Honcho、Hindsight 这类系统;工作 Agent 只负责获取需要的记忆。
而且这种获取不能只是让工作 Agent 做一次粗暴搜索,再自己筛选结果。它应该向 memory 代理提问,由代理在隔离的上下文中完成检索和组织,只把回答交给工作 Agent。删除记忆也一样,必须经过代理。否则记忆管理的过程会直接污染正在工作的上下文,隔离也就失去了意义。
memory 和 skill 的边界,不能只按“记忆内容”和“方法论”一刀切。历史状态、人物关系等需要持续积累的非线性知识,更适合放进 memory;成熟、固定的执行流程,更适合写成 skill;至于用户偏爱的思考视角,两者都能承载,只是生效方式不同。
所以 skill 不能完全被 memory 替代。对于固定流程,memory 意味着不可控的搜索,而且更难共享和审查;对于思考偏好,memory 可以逐渐学会,但不保证每次都以合适的形式进入上下文。skill 是人类看得懂的固定文本,既可以作为伪代码式需求书稳定触发具体流程,也可以用轻量提示词显式地偏置 AI 的思考空间。
subagent
subagent 的价值不在交接本身,而在有边界的编排:默认减少无意识 handoff,在主上下文即将被压缩时,则用隔离的分支改变信息汇入方式。
错误用法,是主 Agent 把一项本可连续完成的工作交出去,再接回一份压缩结果,让接手者重新发现上下文。正确用法,则是把巨型任务不断树状拆分,让各个 subagent 在自己的上下文里完整处理相对独立的分支,也让 subagent 彼此 review。主 Agent 不接收每条分支的全部发现过程,只监控目标、进度和关键状态。这样,局部上下文不必被反复压缩,主上下文也不会被所有细节塞满后触发压缩。
这也比依赖 /goal 更自然。goal 写得太短,可解释范围就太广;写得太长,一次任务核验本身就可能占满整个上下文,再次触发压缩。树状 subagent 更像一家公司:执行者分别完成边界明确的工作,主 Agent 负责全局调度与监控。
公司不会要求每个职位遵循同一套工作手册,Agent 系统中的不同角色也可以拥有不同的 skill。Superpowers 整套方法若直接用于所有角色,往往会把任务做重;把它交给 leader 一类局部 subagent,负责某段任务或某条局部分支的拆分与执行者编排,便能发挥它的长处。较重的方法留在局部,主 Agent 则以干净的提示词和清楚的职责守住整体方向,用户也通过它掌握全局。
所以,不要为了形式使用 subagent,也不要制造没有必要的 handoff。当任务确实可以树状拆分,隔离、并行和交叉评审能让主 Agent 只保留目标、进度与关键状态时,就应该用 subagent 避免主上下文被迫压缩。前者是在增加抽奖环节,后者是在改变信息汇入主上下文的方式。
尾声
把 Agent 视为解释器,subagent、skill 和 memory 就重新成为可审查的工程选择:哪些内容进入上下文,哪些知识留在记忆里,哪些分支值得隔离,都应当有边界,也应当能被删改。模型偏离时,清楚的成功与失败信号应当让它能够重试、恢复,或由其他 Agent 接手纠正;真正危险的是错误悄无声息,随后在上下文里一再放大,拖成失败螺旋。
所以,好的上下文,是唤起并充分使用 LLM 在训练中已经学会的技能,而不是依赖提示词,让它在当前上下文里重新学习、重新组装。而更好的上下文“工程”所做的,不是堵死所有岔路,而是让走偏的 Agent 仍有路回来。