ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI辅助编码烧token?用Skill构建上下文记忆分层管理

AI辅助编码烧token?用Skill构建上下文记忆分层管理

最近半年,我花了不少时间在折腾 AI 辅助编码,也就是大家常说的 vibe coding。这玩意儿用起来确实爽,思路能跑得飞快,但同时有一个很现实的问题:AI 模型对业务上下文、项目结构的理解经常出现偏差,导致生成的代码反复修改、返工重试。更让人心疼的是,每一次重新生成、每一轮对话澄清,都在“哗哗”地消耗 token。你说贵吧,这个贵不是单价的问题,而是无效消耗带来的巨额浪费,特别是当你用的是计费模型,比如 Claude 或者 GPT-4o 接入 IDE 时,一个下午的“快乐编码”可能就直接烧掉几十万 token,结果代码还是坑坑洼洼,需要大量手动修正。

为了解决这类痛点,我断断续续整了一个技能包,名字就叫memddc-ai-skill。说白了,这是给 AI 编码工具(比如 Cursor、Windsurf 这类基于 LLM 的编辑器)定制的一套思维链与记忆扩展协议。它不能像魔法一样让某个模型突然“变聪明”,但是它能大幅度提高 AI 输出的准确率,改一次、两次就能过,直接把来回试错的成本降到最低。这篇文我准备把这些天踩过的坑、调过的参数、试出的最优结构全部拆开揉碎,讲清楚这个 skill 是怎么让 vibe coding 从“碰运气”变成“有些稳”的。这篇文章适合正在重度使用 AI 写代码、对 token 开销敏感、或者被上下文清理搞到烦躁的开发者参考。

1. 项目整体设计与思路拆解

1.1 为什么需要一套 Skill 而不是直接改 System Prompt

先给不熟悉的朋友补个背景:无论是 Cursor 还是别的 AI IDE,其实你都可以在全局设置里塞入自定义指令,本质上就是修改 System Prompt,大约等于让模型维持预设的行为模式。那既然可以写 Prompt,为什么还要搞一个 Skill?

原因很简单,System Prompt 的空间有限,而且修改一次全局生效,影响范围太大。如果你只做前端页面,但你写了一个严格规定“后端优先”的全局指令,那很快就会发现 AI 在小任务上开始过度设计,带来新的 token 浪费。而 Skill 更像是一个“按需启动”的插件,在具体的工作场景里临时注入一套行为框架,把大量的思考模板、记忆库存、约束规则挂在特定入口下。这样做的好处是可插拔、可复用,几个项目切换时不会互相污染。

实际开发里我最早的版本就是往 system prompt 里塞了一大段记忆规则,后来每次对话刚开始的时候,模型确实会遵循,但随着对话轮次变多,尤其是 session 被自动压缩之后,记忆会迅速“漂移”,以前约定好的规则会被新指令覆盖。而做一个 skill,配合 context 的动态读取,可以保证规则在被需要的时候才注入,而且可以分模块加载,不用一股脑儿塞进去。

这个设计思路就像你请了一位资深代码评审人:他平时不说话,只在特定阶段检查你的上下文、梳理你的项目结构、提醒你潜在的遗漏点,而不是在你刚写完第一行注释时就跳出来说三道四。

1.2 记忆分层:短期任务与长期项目的融合策略

做这个 Skill 时要解决的最核心问题,不是一个普通的技术问题,而是一个“记忆管理”问题。LLM 的无状态特性意味着每次对话都像失忆了一样,我们需要想尽办法帮它记住我们项目里最重要的那些约定。

我的解法是把记忆分成两层:短期层和长期层。短期层负责本轮对话里产生的临时结论,比如当前正在写哪个函数、这次需要处理哪些文件、临时决定用什么方案。长期层则是跨会话、跨任务的核心记忆,比如数据库表字段命名规则、postcss 样式变量、接口调用路径前缀、部署脚本存放位置等等。

这套记忆分层的结构复刻了人类工程师的工作习惯。你写代码的时候,不可能把所有历史细节都记在脑子里,更多时候你知道去哪里查、需要时再翻出来看。Skill 也是如此:它把长期记忆固化成 markdown 文档,存放在项目的 .ai/memddc/ 目录下面;短期记忆则存在于每次会话的 prompt 拼接过程中,会话结束就被清理。

这种设计最直接的好处是节省了 token 的浪费。如果不分层,长期记忆和短期记忆全部塞进每轮请求中,哪怕一次只写一个函数,模型也得读完整个项目的完整记忆库,开销不可控。分开了之后,每次只加载和当前任务相关的模块,真正做到了“需要什么读什么”。

1.3 为什么要省 token:不只是省钱,更是效率提升

可能有人会问,token 省下来真的重要吗?如果是本地跑开源小模型,token 确实不值钱,但对于依赖云 API 的重度 vibe coder,token 就是金钱。更关键的是,上下文长度再长也有上限,现在已经有不少模型支持 32k、200k,但如果每一轮对话都堆入大量无效信息,早期输入的内容很快会被挤掉。曾经我遇到过一个现象:聊到第 20 轮的时候,模型已经开始忘记项目最基础的技术栈选择了,原因就是窗口被高频碎片信息占满。

token 的消耗是可以精确拆解的。举个例子,假设你每轮对话都会向模型发送 6k token 的项目背景与用户说明,而一次编码任务的完整会话大概需要 40 轮对话,那这 40 轮中有多少 token 是单纯在反复传输同样的记忆?答案是 6k × 40 = 240k token。如果通过 skill 机制把每轮的固定累赘降到 1.5k,会话总体开销就能砍掉大约 70% 的冗余背景。这还不算因为准确率提升,AI 减少返工所节约的额外生成 token。

所以我做这个 skill 的初衷,可以总结为一句话:用结构化的上下文管理,把每一轮对话里的词都花在刀刃上。

2. 核心细节解析:Skill 的运行机制与关键设计

2.1 核心机制拆解:一次性注入还是爬虫式读取

Skill 的做法,不是一次性把整个仓库都塞给模型,而是通过一些策略决定“哪些内容必须进上下文,哪些内容只需要知道索引路径”。

这里我参考了 RAG(检索增强生成)的思路,但并没有做得很重。没有引入向量数据库、没有用 embeddings、没有复杂的检索服务,而是采用了一套“结构化索引 + 按需加载”的方式。具体来说:

  • 项目的根目录里会放一份 CORE.md,里面是项目的全局约定和核心路径。
  • 有一个 INDEX.md,像是地图,里面记录哪个领域细节放在哪个文件。
  • Skill 本身会通过指令告诉模型:如果你是处理 UI 样式,请去查看 styles.md;如果你是处理 API 联调,请去查看 backend-api.md。

这种方式看似简单,但在 token 受限的 IDE 插件场景里非常实用。模型不需要每次都知道所有细节,它只需要知道“去哪儿查”。

我为这种机制起了个内部名——文件系统引导。它相当于给模型装了一个“grep 能力”,通过 markdown 链接而不是真正的命令行,让模型在虚拟空间里追踪所需信息。在 Cursor 这类工具里,其实你也可以让模型直接打开某个文件,但 Skill 里做到的是每次自动提示模型先读索引,再决定下一步动作。

这个做法的弊端也有,就是要求开发者维护文档。如果文档跟不上代码变化,模型反而会被过时信息误导。所以我设计了一个终端命令,项目内跑一下,能自动把最近的代码改动追加到相对应的记忆文档中,每次开发完就是一个新的快照。

2.2 提示压缩与前置引导:给用户的输入做“减法”

除了管理项目侧的记忆,Skill 还有一个非常关键的功能——对用户输入做提炼引导。众所周知,在 vibe coding 里,用户语言往往是含糊的,有人喜欢把需求描述得特别空泛,比如“帮我修一下登录的问题”,但问题具体是什么、期望效果是什么,都不说清楚。AI 模型在这种情况下只能猜,猜错的概率自然很高。

Skill 专门设计了一个“五要素问题模板”:目标、范围、约束、验收、优先级。它会在每一轮对话开头,引导用户补充这五个要素,如果用户漏掉某一项,Skill 会主动标注一个 TODO,提醒用户补充,而不是强行让模型猜。

可能有人会觉得这增加了使用复杂度,但实测下来,多花 30 秒完善需求描述,换取的是后续半小时不返工。而且这个引导过程本身也会帮助用户整理自己的思路,让交流更高效。这个模块就是典型的“花小钱省大钱”。

另外还有一种情况,是用户已经描述了需求,但描述中混杂了大量无关背景。Skill 的引导模板会自动提炼出核心约束,过滤掉感性的、上下文无关的措辞,保证注入模型的那部分内容足够精炼和完整。结果就是,同样一个问题,输入 token 变少,准确率反而上升。

2.3 拼接规则与上下文窗口的优先级控制

在构建 skill 的指令时,我花了很大心思在“优先级”设计上。如果把所有信息一视同仁地放进 prompt,那模型在处理复杂问题时往往会迷失重点。Skill 通过“指令权重分层”来解决。

优先级最高的部分是“全局安全红线与不可触碰原则”,这部分的内容通常是标准 SQL 之类的高危操作,或者删除文件等重要命令。第二优先级是“当前任务短指令”,比如“只修改 xxx 函数,不要动其他文件”。第三优先级才是“项目偏好和风格约定”。

为什么这样排?因为模型的行为很大程度上取决于 prompt 中信息的先后排列和标记程度,越是靠前的信息,越会被当作金科玉律。如果优先级倒置,将一些风格建议塞到最前,模型很可能为了符合风格而忽略了安全约束,造成不必要的破坏。

我还做了一个实验:同样的任务,在不同优先级的 Skill 配置下分别跑了五遍,结果发现安全约束置顶时,模型不仅安全性好,生成的代码质量也更高,因为它在每一步都被提醒“这是一次外科手术,不是重写”。

3. 实操过程:打造自己的 memddc 技能套件

3.1 最小化配置:两步跑起来

如果说你看完前面的设计思路,已经想动手了,那可以直接试试这套最简方案。我们不需要完整复制我那一大堆工具链,只需要两样东西:一个存放技能文件的目录,以及一份核心指令文档。

第一步是先建立项目根目录下的.ai/memddc/文件夹,并赋予它以下结构:

.ai/memddc/ ├── CORE.md ├── INDEX.md ├── STYLES.md ├── API.md ├── TASKS.md

复杂吗?不复杂。这些文件的功能用一句话就能说明白:CORE 是全局约定,INDEX 是导航地图,STYLES 是代码风格约定,API 是接口信息,TASKS 是当前任务记录。新手阶段,你只需要维护好 CORE 和 INDEX 就够了,其他文件可以空着,等用到了再填充。

第二步是告诉 AI 工具学会读这些文件。在 Cursor 的规则里(或者你使用的工具对应的指令配置),写入类似这样的指令:

在开始任何任务前,先读取 .ai/memddc/INDEX.md 获取项目上下文地图;随后根据任务类型访问对应文档;所有代码改动需遵守 CORE.md 中的安全红线。

没错,就这么简单。后面运行的时候,你完全可以用自然语言跟 AI 说“去看一眼 CORE”,也能起到类似的效果。但如果想自动化,就写好这套规则,让 AI 每次根据关键词自动触发读取动作。

3.2 为 Skill 写一段高质量的核心指令

真正好的 Skill 不是靠“堆字数”取胜,关键在指令的可执行性。我写指令过程中最有价值的一次更新,是把大量描述性语言换成了少量命令式语句。对比一下就知道:

早期版本:“为了确保代码风格统一,建议参考项目中已有的代码风格进行编写,保持一致性。”

优化版本:“在生成任何新文件前,必须抽查 STYLES.md 中至少三条规范,并逐条对照执行。”

前者模型当它是建议,偶尔忽略没太大问题;后者是硬性要求,模型知道不照做就会被扣分。这就是指令的“确定性”带来的区别。

在 CORE.md 里,我也会放下最核心的几条硬性规定,比如:

- 禁止在未给出完整实现方案前直接修改 function 内部逻辑; - 所有对外接口必须补充类型定义; - 删除文件前必须输出被删文件的简要内容摘要; - 遇到不确定的需求,必须发出需要用户确认的信号;

这些条条框框看起来像是给模型戴上了紧箍咒,实际操作里反而让模型更游刃有余,因为边界明确了,AI 就不用花大量算力去自己猜“哪些动作是被允许的”,而是可以把精力集中在真正的业务逻辑上。

3.3 让 Skill 与 IDE 无缝配合

Skill 不能只是一个摆在那里的文档集合,得让它跟 IDE 的交互习惯接上轨。目前我是这么用的:

几乎每天开工的时候,我就会先让 AI 加载当天的 TASKS.md,并根据任务迭代情况自动更新 Index。这种“先盘点、再动手”的流程养成了肌肉记忆后,整个编码过程的词token使用都变得很经济。

我给情绪比较急的开发者一个建议:如果不想花太多精力维护文档,那你至少得做到创建项目时就生成一份基本的 CORE,把技术栈、命名方式、项目启动命令写清楚。这些内容可能两个月都不会变,但每轮对话都起着关键锚定作用。

再进一步,可以把 Skill 的加载入口绑定到 IDE 的指令面板里。比如在 Cursor 里定义斜杠命令/memddc:plan,让它自动去汇总当前任务相关的记忆片段,生成一份简明的计划书,然后再开始代码生成。这套组合极大降低了 vibe coding 的随机性。

3.4 参数选择过程:温度、模型与上下文策略的组合

在配置 Skill 时我还花了不少精力在模型参数调节上。我们平时在聊天界面里用的模型,往往默认参数偏向创造性、发散性,在编码场景里这未必是好事。代码生成更重要的是确定性和一致性。

我的经验是:对于定义清晰、范围明确的任务,尽量使用低温参数(比如 temperature 在 0.1-0.3 之间);对于开放式探索、架构设计类的任务,温度在 0.5-0.7 之间会比较舒服。而在 IDE 插件里,如果支持 per-rule 的设置,可以把 Skill 内的代码生成规则设置为低温度,把用户自由交流的部分调回默认值。

还有就是模型选择策略。小任务可以用 4-bit 量化模型快速响应,大任务切到云端推理更强的模型。Skill 的好处是可以把这套“场景-模型”映射关系也写进 rules 里,AI 在接手任务时会自动判断应该采用哪种模型策略。

4. 常见问题与排查技巧实录

4.1 为什么 Skill 装了之后模型反而变笨了

这是最常被反馈的问题。明明加了记忆和规则,AI 却没以前“聪明”,写出来的东西更僵化、更机械。我的第一反应就是去查指令优先级和上下文长度。大概率是两种情况:一种是 Skill 里塞入了过多冗余细节,导致模型被无效信息干扰;另一种是规则之间互相冲突,模型每次生成前都要花大量推理去符合规则,发挥空间被大幅压缩。

技巧是每次新增规则时,必须同时删除一条旧的近似规则,保证规则总数不涨。我用一个表来记录规则版本,每周做一次 review,发现超过两周没有触发过的规则就直接移出核心区,降级放到参考文档。

4.2 文档更新不及时,记忆反成负担

维护记忆文档是整套机制里最反人性的环节。绝大多数开发者不可能主动记得每天更新文档。我的自动化策略是在 git 提交后的 hook 里追加一个只跑一次的动作,将本次提交涉及的文件路径与改动摘要自动追加到当天的 TASKS 文档里。

这套自动化逻辑避免了“打开文档时发现里面还是两周前的状态”的尴尬,也让模型接手会话时能直接见到最新记忆。如果你实在不愿意做自动化,至少在自己意识到有重大约定变动时,手工更新一下 CORE 文件,这个动作对长期体验的提升非常非常明显。

4.3 多项目并行导致记忆乱串

我也遇到过在项目 A 和项目 B 之间反复切换,模型开始把 A 项目的命名风格用到了 B 项目上。说到底还是上下文污染的问题。目前的解法是每个项目一套独立的 Skill 目录,并且在 CORE.md 最顶部写上项目代号,Symbol 级别的隔离需要做到位。

另外,如果在同一 IDE 工作区里打开多个项目,建议用一个极简的启动指令明确当前激活目录。比如“当前项目代号是 B-Project,所有建议作用于当前工作区”,这样模型就不会拿错剧本了。

4.4 Token 没有显著减少的排查路径

有些用户反馈说,用上 Skill 后 token 好像没减少多少。第一步排查是看是不是每一轮对话,模型仍然把整套 INDEX 和规则都读取了。如果是这样,说明过滤机制失效了,需要检查是不是把“按需加载”的指令权重定得太低,模型选择性忽略了。

第二个常见原因是对话轮次太多,历史上下文里堆积了大量早轮细节,导致 token 不断上涨。这时候需要通过“会话精简”或者“任务切割”的方式来分段,虽然 Skill 本身不直接处理对话压缩,但它通过明确的任务边界,能引导你在更早的时刻结束旧会话、开启新回合。

5. 经验心得与扩展思路

5.1 使用 Skill 的收益测算

做个简单估算。以一次中等级别的功能开发为例,比如为一个管理后台新增权限管理页面。没有 Skill 时,一次性通过的概率可能只有一半,平均要改三次,加上每次来回的上下文传递,总体 token 消耗大约在 80k 左右。上了 Skill 之后,一次性通过率提升到八成,平均改动次数降到 1.2 次,总体 token 消耗可以控制到 30k 上下。

这个数据不是实验室吹出来的,而是我自己的项目实践里记录的。token 节省比例能达到 60% 以上,而这里最值钱的还不是钱,是耐心。少返工几次,你的心流就不会断,coding 体验会好非常多。

5.2 未来可以怎么扩展这套机制

现在的 Skill 版本还比较偏“静态规则 + 手动维护”,其实完全可以往更动态的方向演进。比如接入项目的 commit message 记录,或者调用编译器的报错日志,让 AI 根据失败信息自动更新记忆库。再比如利用语义化提示词动态生成文档索引,或者对接项目管理工具里的任务描述。

说到底,skill 不一定要是一个复杂的应用,它可以就是一套方法论的固化。而 vibe coding 把上手门槛降得足够低之后,真正决定产出的,是你有没有一套好的上下文管理习惯和约束机制。Skill 帮我解决了最大的瓶颈,希望这篇文章里的思路也能让你少烧点冤枉 token。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进