news 2026/10/22 19:36:02

AI编码代理抗上下文压缩:用Unix init.d与《记忆碎片》思路构建持久记忆系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI编码代理抗上下文压缩:用Unix init.d与《记忆碎片》思路构建持久记忆系统

1. 从一次上下文崩溃说起:为什么长会话里的编码代理会“失忆”

如果你用 AI 编码代理跑过稍微大一点的重构任务,大概率遇到过这种场景:前 40 分钟它还记得你项目里那个OrderService的接口签名、记得数据库迁移脚本放在migrations/下、记得你反复强调过“不要动legacy/目录”,结果聊到第 60 轮,你让它改一个方法,它突然开始编造一个根本不存在的utils/helper.js,或者把之前定好的命名规范全忘了。你回头翻对话记录,发现它并没有“变笨”,而是上下文被压缩了——系统为了控制 token 开销,把早期对话摘要成一段短文本,细节全丢了。

这个项目要解决的就是这个问题。标题里说的“20 万 token 的脑叶切除术”,指的就是当会话上下文逼近模型窗口上限时,系统触发的那次强制压缩:把几十万 token 的历史砍成几千 token 的摘要。这个过程对 AI 编码代理来说是致命的,因为它丢掉的恰恰是项目结构、约定、历史决策这些“长期记忆”。而标题里提到的两个东西——Unix init.d和《记忆碎片》——是我用来对抗这种失忆的两套思路:前者负责“进程级”的持久化,后者负责“叙事级”的重组。

这篇文章适合谁看?如果你正在用或准备用 AI 编码代理做跨文件、跨会话的工程任务,并且被上下文丢失折磨过,那这篇就是写给你的。我会把整套方案的选型逻辑、目录结构、脚本实现、参数计算和踩坑记录全部摊开讲,你可以直接抄作业,也可以按自己的项目规模裁剪。核心目标只有一个:让代理在经历任意次上下文压缩之后,依然能准确恢复项目状态和任务上下文。

2. 整体设计思路:把“记忆”从对话里搬到磁盘上

2.1 核心矛盾:对话上下文是易失性存储

先说清楚问题的本质。AI 编码代理的“记忆”默认只有两个来源:一是当前对话窗口里的 token,二是它每次工具调用时读到的文件内容。前者会被压缩,后者不会——只要你把信息写进文件,它下次读的时候还是完整的。所以整个方案的第一性原理很简单:凡是代理需要跨轮次记住的东西,一律不放在对话里,全部落到磁盘上,用文件系统当它的长期记忆。

这个判断听起来朴素,但落地时会遇到一个关键问题:代理怎么知道该读哪些文件?如果每次都要它自己ls一遍再猜,效率极低而且容易漏。这就引出了 init.d 的思路。

2.2 为什么借用 Unix init.d 的模型

Unix 系统的init.d机制解决的是同一个问题:系统启动时,怎么保证一堆服务按正确顺序、以正确状态被拉起来,而不需要人工干预。它的精髓在于约定优于配置——脚本放在固定目录、有固定的执行权限、按命名顺序执行、每个脚本自己声明依赖。我把这套模型搬到 AI 代理的上下文恢复上:

  • 在项目根目录建一个.agent/init.d/目录,里面放一系列可执行的恢复脚本;
  • 每个脚本负责恢复一类上下文,比如10-project-structure.sh输出目录树,20-conventions.md输出编码约定,30-task-state.json输出当前任务进度;
  • 代理在每次会话开始、或者检测到上下文被压缩之后,按编号顺序执行这些脚本,把输出拼成一段“恢复上下文”注入对话。

这样做的好处是恢复逻辑和对话历史解耦。对话被砍成什么样都无所谓,只要磁盘上的 init.d 脚本还在,代理就能重建出它需要知道的一切。而且脚本是可版本控制的,你可以像管理代码一样管理代理的“记忆”。

2.3 《记忆碎片》给的启发:倒叙拼图与可信度标注

《记忆碎片》这部电影的叙事结构很特殊:主角有短期记忆障碍,他靠纹身、纸条、拍立得照片来记录信息,而且每张照片上都标注了“这个信息是谁告诉我的、我有多相信它”。这个细节是我整个方案里最得意的一笔。

上下文压缩最大的危害不是丢信息,而是丢信息的来源和可信度。比如代理记得“数据库用 PostgreSQL”,但这个结论是它自己推断的,还是你明确指定的?压缩之后这个区别就没了,代理可能把一个猜测当成硬约束。所以我要求 init.d 里恢复出来的每一条上下文,都必须带一个可信度标记:

标记含义来源
[HARD]硬约束,不可违反用户明确指定
[SOFT]软约定,可协商从代码风格推断
[TENTATIVE]临时假设,需验证代理自行推断
[STALE]可能过期,使用前确认超过 N 轮未更新

代理在恢复上下文时看到[HARD]就直接遵守,看到[TENTATIVE]就知道要先验证。这一层元信息几乎不占 token,但极大降低了压缩后的误操作率。

2.4 方案整体架构

把上面两块拼起来,整个系统分三层:

  • 持久层:.agent/目录,存放 init.d 脚本、任务状态、决策日志、可信度标注;
  • 恢复层:一个restore.sh入口脚本,按顺序执行 init.d 并输出结构化上下文;
  • 注入层:代理在会话开始或压缩后调用恢复脚本,把输出作为系统提示的一部分。

下面这张表是三层各自的职责和典型文件:

层级目录/文件职责更新频率
持久层.agent/init.d/*存放恢复脚本项目结构变化时
持久层.agent/state/task.json当前任务进度每完成一个子任务
持久层.agent/log/decisions.md关键决策记录每次做技术选型
恢复层.agent/restore.sh编排恢复流程很少变
注入层代理系统提示承载恢复输出每次会话

3. 核心细节拆解:init.d 脚本怎么写才不白写

3.1 目录结构与命名约定

先给一个可以直接复制的目录结构:

.agent/ ├── restore.sh ├── init.d/ │ ├── 10-structure.sh │ ├── 20-conventions.md │ ├── 30-task-state.json │ ├── 40-decisions.md │ └── 50-open-questions.md ├── state/ │ └── task.json └── log/ └── decisions.md

编号用两位数,留出插入空间。10到50的顺序是有讲究的:先给结构(代理需要知道项目长什么样),再给约定(怎么改),再给任务状态(改到哪了),再给决策(为什么这么改),最后给未决问题(还有什么没定)。这个顺序对应代理理解项目的认知路径,反过来会让它先看到一堆零散决策而不知道项目全貌。

注意:init.d 里的脚本必须是幂等的,也就是执行一次和执行十次输出一样。因为代理可能在一次会话里多次触发恢复,如果脚本有副作用(比如往文件里追加内容),会污染状态。

3.2 每个脚本的职责与输出格式

10-structure.sh负责输出项目骨架。不要直接tree整个项目,那会输出几千行。我的做法是只输出两层深度,并且过滤掉node_modules、.git、dist这些噪音目录:

#!/usr/bin/env bash # 输出项目结构,深度2,排除噪音目录 find . -maxdepth 2 \ -not -path './.git*' \ -not -path './node_modules*' \ -not -path './dist*' \ -not -path './.agent*' \ | sort \ | sed 's|^\./||'

实测下来,一个中等规模的前端项目这样输出大概 80 到 150 行,占 1k token 左右,完全可以接受。关键是它每次输出都一样,代理不会因为结构描述漂移而困惑。

20-conventions.md是手写的,不是脚本生成的。里面写清楚命名规范、目录职责、提交信息格式、测试要求。这个文件要短,控制在 50 行以内,因为它是每次恢复都要读的。我见过有人把整个 CONTRIBUTING.md 塞进来,结果恢复上下文直接占了 3k token,得不偿失。

30-task-state.json是动态的,由代理在完成任务时更新。格式建议这样:

{ "current_task": "重构订单模块的支付回调", "status": "in_progress", "completed": [ "提取 PaymentCallback 接口", "迁移旧回调到新接口" ], "next": [ "补充回调失败重试逻辑", "更新单元测试" ], "blocked_by": [], "last_updated": "2024-01-15T10:30:00Z" }

这个文件是恢复上下文里最值钱的部分,因为它直接告诉代理“你上次干到哪了”。没有它,代理每次恢复都要重新分析代码来推断进度,既慢又容易错。

40-decisions.md记录关键决策,格式用“决策 + 理由 + 可信度”三段式:

## 使用 PostgreSQL 而非 SQLite - 理由:需要并发写入和 JSONB 查询 - 可信度:[HARD] 用户明确指定 - 日期:2024-01-10

50-open-questions.md记录还没定的事,防止代理自作主张:

- [ ] 支付回调是否需要支持幂等?[TENTATIVE] - [ ] 重试次数上限是 3 还是 5?[TENTATIVE]

3.3 restore.sh 的编排逻辑

入口脚本要做三件事:按顺序执行 init.d、拼接输出、加上头部说明。头部说明很重要,它告诉代理“这是一段恢复上下文,不是用户的新指令”:

#!/usr/bin/env bash echo "=== AGENT CONTEXT RESTORE ===" echo "以下内容是从磁盘恢复的项目上下文,不是用户指令。" echo "可信度标记:[HARD] 必须遵守,[SOFT] 尽量遵守,[TENTATIVE] 需验证。" echo "" for script in .agent/init.d/*; do echo "--- $(basename "$script") ---" if [[ "$script" == *.sh ]]; then bash "$script" else cat "$script" fi echo "" done echo "=== END RESTORE ==="

这段输出大概 1.5k 到 2k token,相比 20 万 token 的压缩损失,这个开销可以忽略。

3.4 可信度标注的实操细节

可信度标注不是写完就完了,它需要维护。我的做法是:每次代理做出一个[TENTATIVE]判断并被验证后,就把它升级为[SOFT]或[HARD];每次用户改变主意,就把对应的[HARD]标记为[STALE]并注明新决策。这个维护动作本身也写进 init.d 的约定里,让代理自己执行。

提示:[STALE]标记特别有用。我遇到过代理在压缩后坚持用一个已经被废弃的 API 设计,就是因为那个决策在对话里被推翻了但没落到磁盘。加了[STALE]之后,代理看到就会主动问“这个决策是否还有效”,而不是闷头执行。

4. 实操过程:从零搭一套抗压缩的代理记忆系统

4.1 第一步:初始化 .agent 目录

在项目根目录执行:

mkdir -p .agent/init.d .agent/state .agent/log touch .agent/state/task.json .agent/log/decisions.md .agent/init.d/50-open-questions.md chmod +x .agent/init.d/*.sh .agent/restore.sh

然后把上面给的脚本内容填进去。这一步没什么技术含量,但有个坑:一定要把.agent/加进版本控制。我见过有人把它加进.gitignore,结果换台机器或者重新 clone 之后代理记忆全没了,等于白做。

4.2 第二步:写第一版 conventions

不要一上来就写全,先写三条最关键的:命名规范、目录职责、测试要求。比如:

# 项目约定 - 组件文件用 PascalCase,工具函数用 camelCase - src/components/ 只放展示组件,业务逻辑放 src/features/ - 每个 feature 必须有对应的 __tests__ 目录 - 提交信息格式:type(scope): description

写完让代理读一遍,问它“这些约定清楚吗,有没有歧义”。它会指出模糊的地方,你据此修改。这个交互过程本身就是在校准代理的理解。

4.3 第三步:接入代理的会话流程

不同代理的接入方式不一样,但核心就两个时机:会话开始时和检测到上下文压缩后。会话开始时直接执行restore.sh把输出注入系统提示。压缩后的检测比较 tricky,我的做法是让代理在每轮回复前检查一个标记文件.agent/state/context-version,如果版本号变了就重新恢复。

具体实现是在代理的工具调用里加一个check_context_version动作,读文件比对。这个动作几乎不耗 token,但能保证压缩后第一时间恢复。

4.4 第四步:参数计算——恢复上下文该占多少 token

这是很多人忽略的一步。恢复上下文不是越多越好,它和对话历史抢窗口。我的经验公式是:

恢复上下文预算 = 模型窗口 × 5% ~ 8%

以 20 万 token 窗口为例,恢复上下文控制在 1 万到 1.6 万 token。超过这个比例,留给实际对话的空间就被挤压,代理反而更容易触发压缩。按这个预算反推,init.d 的输出要控制在 8k token 以内,剩下的留给 task.json 和 decisions.md 的动态内容。

实测下来,一个 50 个文件左右的项目,structure 输出约 1k token,conventions 约 500 token,task state 约 300 token,decisions 约 800 token,open questions 约 200 token,加起来不到 3k token,非常宽裕。项目再大,structure 用深度 2 也能压住。

4.5 第五步:验证恢复效果

搭完之后一定要做一次“压缩演练”。手动把对话历史清空,只保留 restore.sh 的输出,然后让代理继续之前的任务。观察它是否:

  • 知道项目结构,不会编造不存在的文件;
  • 遵守约定,命名和目录都符合规范;
  • 知道任务进度,不会重复已完成的工作;
  • 对[TENTATIVE]标记的决策会主动验证。

我第一版做完演练,发现代理还是会编造文件,排查后发现是 structure 脚本把.agent目录也排除了,导致代理不知道恢复机制本身的存在。加上之后就好了。这种问题不演练根本发现不了。

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

5.1 恢复上下文太长导致代理“只看恢复不看对话”

这是最常见的翻车。表现是代理每轮都重新读一遍 init.d,然后基于恢复内容回答,完全忽略你当前说的话。原因是恢复上下文被放在了对话最前面,而模型对开头和结尾的内容注意力最高,中间容易被忽略。

解决办法有两个:一是把恢复上下文放在系统提示里而不是用户消息里,二是控制它的长度。我试过把恢复上下文从 5k token 压到 2k,问题直接消失。所以别贪多,恢复上下文是“索引”不是“全文”。

5.2 脚本输出不稳定导致代理困惑

find命令的输出顺序在不同系统上可能不一样,ls也是。如果 structure 脚本每次输出顺序都变,代理会以为项目结构变了。解决办法是所有输出都排序,find ... | sort,ls | sort。这个细节很小,但不做的话代理会频繁误报“检测到结构变化”。

5.3 task.json 被并发写坏

如果代理有多个子任务并行执行,它们可能同时更新 task.json,导致文件损坏。我的做法是加一个简单的文件锁:

( flock -x 200 # 更新 task.json 的逻辑 ) 200>.agent/state/task.lock

或者更简单,让代理串行更新,每次更新前先读一遍再写。对于大多数项目,串行就够了,不用上锁。

5.4 决策日志越写越长

decisions.md 如果不清理,几个月后会有几百条,恢复时读一遍要好几千 token。我的做法是只保留最近 20 条活跃决策,更早的归档到.agent/log/archive/。归档的决策不参与恢复,但代理需要时可以主动去查。这样恢复上下文始终精简,历史又不丢。

5.5 常见问题速查表

现象可能原因排查动作
代理编造文件structure 输出缺失或过时手动跑 10-structure.sh 看输出
代理忽略约定conventions 太长被截断检查恢复上下文总长度
代理重复已完成工作task.json 未更新检查 last_updated 时间戳
代理坚持废弃决策决策未标 STALE检查 decisions.md 标记
恢复后代理不响应新指令恢复上下文过长压缩到 2k token 以内

5.6 一个反直觉的经验

我一开始以为恢复上下文越详细越好,恨不得把整个项目文档都塞进去。实测下来完全相反:恢复上下文越精简,代理表现越好。因为代理的注意力是有限的,你给它 1 万 token 的恢复内容,它就只能分很少注意力给你当前的任务。后来我把恢复内容砍到 2k,代理反而更“清醒”。这个教训值不少钱,希望你不用再踩一遍。

6. 进阶玩法:让代理自己维护记忆

6.1 自动更新 task.json

代理每完成一个子任务,让它自己更新 task.json。这需要在系统提示里明确写:“完成任何子任务后,必须更新 .agent/state/task.json 的 completed 和 next 字段。” 一开始代理会忘,可以在恢复上下文里加一句提醒。跑顺之后它会形成习惯。

6.2 决策的自动归档

写一个archive-decisions.sh,当 decisions.md 超过 20 条时,把最早的 10 条移到 archive。这个脚本可以挂在 restore.sh 的最后,每次恢复时顺带执行。注意归档时要保留索引,否则代理不知道归档里有什么。

6.3 跨会话的任务接力

如果任务跨天,代理会话结束前让它写一份“交接摘要”到.agent/state/handoff.md,内容包括当前进度、下一步、注意事项。下次会话恢复时优先读这个文件。这比 task.json 更灵活,可以写自然语言描述。

6.4 用 git 管理记忆的版本

.agent/目录纳入 git 之后,你可以看到代理的记忆是怎么演变的。出问题时git log .agent/能快速定位是哪次更新引入了错误上下文。我甚至用git diff来对比压缩前后的恢复输出,确认没有信息丢失。

7. 我踩过的三个坑,以及最后一点体会

第一个坑是把恢复上下文写成了项目文档。我一开始把 README 的内容复制进 conventions,结果代理每次恢复都读一遍完整 README,占了 4k token,还和对话里的指令打架。后来砍到只剩约定,问题消失。

第二个坑是忘了给脚本加执行权限。restore.sh 在本地跑得好好的,换到 CI 环境就报 permission denied。排查了半小时才发现是 chmod 没做。现在我的初始化脚本里第一行就是 chmod。

第三个坑是可信度标记写得太随意。有次我把一个[TENTATIVE]的推断标成了[HARD],结果代理在压缩后死守这个错误结论,改了半天代码才发现方向错了。从那以后我定了个规矩:只有用户明确说过的才能标[HARD],自己推断的一律[TENTATIVE]。

这套方案跑了大半年,最大的体会是:AI 代理的“记忆”问题,本质上是工程问题,不是模型问题。你不需要等模型窗口变得无限大,只要把该落盘的东西落盘,用 init.d 的约定把恢复流程固化下来,用《记忆碎片》的思路给每条信息标上可信度,代理就能在任意次压缩之后保持清醒。20 万 token 的脑叶切除术听起来吓人,但只要你提前把记忆存在磁盘上,切掉的只是对话,不是能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 19:32:35

多Agent系统四大经典架构与面试选型指南:从调度到分层

你被问到过这样的问题吗:“请简述一下多Agent系统的架构设计,并说说你会在什么场景下选型?”我最近一年多参加了不少技术面试,也在带团队做Agent相关项目,这类问题的出现频率高得惊人。很多人一上来就把多Agent吹得天花…

作者头像 李华
网站建设 2026/10/22 19:31:24

Dynamics 365 Agentic AI落地指南:从提示词到自动执行

做了这么多年Dynamics 365实施,能明显感觉到客户问的问题在变。前两年大家问的是“Copilot怎么用”,问某个按钮在哪、怎么配;最近的问法变成了“能不能让它自己把事办了”——比如客户发来一封邮件要改收货地址,系统能不能自己开个…

作者头像 李华
网站建设 2026/10/22 19:30:21

SSM+Vue实现农产品进销存系统:从数据库设计到部署全解析

1. 项目初印象:SSM294到底是个什么项目先把这个标题拆开看。SSM294这个代号,我推测指的就是某套课程设计或毕业设计题目的编号,属于典型的“编号式命名”——学校题库里这类题目通常都是一串编号,SSM代表技术栈(Spring…

作者头像 李华
网站建设 2026/10/22 19:29:37

AI视频配乐:语义、时间与节奏三维对齐全解析

最近我一直在折腾一个视频自动配乐方向的项目,本来以为难点在“怎么让生成出来的音乐更好听”,结果真的跑起来之后才发现,决定一段配乐违不违和的,根本不是旋律和编曲本身,而是视频画面和音乐之间那层说不清道不明的对…

作者头像 李华
网站建设 2026/10/22 19:29:05

大模型显存计算指南:从权重、量化到显卡选型

我平时被问得最多的一句话,就是“我这卡到底能跑多大的模型?”显存计算这件事看着门槛不高,真上手算的时候却很容易翻车,因为大家总是只盯着参数量,忘了 KV Cache、激活值、框架开销这些“隐形住户”。这篇就把显存计算…

作者头像 李华
网站建设 2026/10/22 19:28:07

AI培训学什么?三大方向技术栈从入门到进阶全解析

很多人问我“AI培训到底学什么”的时候,心里其实默认想的是“学大模型”。但真去翻课程目录,又会发现一堆看起来差不多的名字:机器学习、深度学习、自然语言处理、大模型应用、数据分析,越看越乱。我一般先劝一句:AI培…

作者头像 李华