第8章:压缩的约束空间
定位:本章是第三部分"AAAK 压缩语言"的起点。我们暂时离开宫殿的空间结构,转向一个完全不同的问题:如何将大量文本信息压缩到极小的 token 空间内,同时不丢失任何东西。本章不展示 AAAK 的具体语法(那是第 9 章的工作),而是通过约束满足分析,推导出"可行解"必须长什么样。
压缩问题的本质
前面几章讨论了记忆宫殿的空间结构如何将检索精度提升 34%。但结构只解决了"从哪里找"的问题,没有解决"装得下多少"的问题。
让我们回到序章中的那个核心数字:六个月的日常 AI 使用产生约 1950 万个 token。即便经过宫殿结构的组织,当 AI 需要在会话开始时加载"这个人是谁、在做什么项目、和谁一起工作"这样的基础上下文时,数据量仍然庞大得令人绝望。
这个问题的直觉表述很简单:我们能不能把一段 1000 token 的自然语言描述,压缩成 30-120 个 token,同时保证一个语言模型读完压缩结果后能准确还原出所有原始信息?
这个看起来不可能的要求,正是 AAAK 试图回答的。
但在讨论 AAAK 如何做到之前,有必要先严格定义"做到"意味着什么。工程中最常见的错误不是解法不够好,而是问题没有被正确定义。一个模糊的目标会产生无限多个看似合理的方案,而每一个最终都会在某个未被预见的维度上失败。
四个不可妥协的约束
MemPalace 的压缩需求可以被精确表述为四个约束条件。它们不是"最好能满足"的偏好,而是"必须同时满足"的硬性要求。任何一个不满足,整个方案就不可用。
约束一:30 倍压缩比
六个月 1950 万 token 的上下文,即使经过记忆层级的过滤(第 14-15 章将详细讨论),L1 层——也就是 AI 每次启动时必须加载的关键事实层——仍然需要容纳大量信息。
MemPalace 的 README 宣称 AAAK 可以达到 30 倍压缩。这个数字需要拆解。这里还需要先区分两件事:一是 README 和书里讨论的设计目标,二是当前开源仓库里 dialect.compress() 这类 plain-text 压缩器的具体实现。前者在讨论"什么样的压缩语言才有机会满足约束",后者则是一个带明显启发式筛选的当前版本。
AAAK 实际上做了两件不同的事:
- 结构化压缩目标(去停用词、缩写实体名、管道分隔结构化)——这是 README 和本章分析的理想方向:尽量用更紧凑的形式表达同一批事实断言。短示例里,它可以带来 5-10 倍 量级的压缩。
- 启发式筛选实现(关键语句提取、主题提取、实体/情感/标志截断)——这是当前 plain-text
compress()的真实路径:它会从长文本中选择"值得保留的内容",而不是逐断言做形式等价转换。
对于冗余度高的长对话记录(充满 "well, I think that maybe we should consider..." 这样的表达),两步叠加确实可以达到 30 倍。但对于已经比较紧凑的技术描述,压缩比通常在 5-10 倍。
因此,"30 倍"是长对话场景的上界,不是所有文本的典型值。更重要的是,当前实现中的筛选步骤不只发生在 _extract_key_sentence():topics、entities、emotions、flags 也都带有 top-k 或启发式裁剪。也就是说,今天仓库里的 plain-text AAAK 更接近"高压缩索引"而不是"严格无损编码"——尽管原文仍然保存在 Drawer 中可以回溯。
这个区分对于理解 AAAK 至关重要:README 里的无损 AAAK 是设计目标;当前 open-source plain-text compressor 是有损启发式索引;30 倍来自结构化表达与内容筛选共同作用。
约束二:事实断言的完整性
这是与所有"摘要式"记忆系统的关键分界线。
当 Mem0 或 Zep 的系统从你的对话中提取"用户偏好 Postgres"时,它丢掉了你花了两个小时解释为什么从 MongoDB 迁移过来的全部上下文。当一个 LLM 被要求"总结这段对话的要点"时,它必须做出判断——哪些是要点,哪些不是——而这个判断本身就是一种不可逆的信息丢弃。
MemPalace 的立场是:理想中的 AAAK 设计目标 应该尽可能保留事实断言。README 使用"零信息损失"(lossless)来描述这个目标,但需要给它一个精确的操作性定义;同时也要诚实地区分这个目标与当前 heuristic 实现。
在 AAAK 的语境中,"无损"更适合作为一个设计约束定义:对于原始文本中的每一个事实断言(谁、做了什么、什么时候、为什么、结果如何),理想的 AAAK 编码都应当存在对应表示,使得一个合格的语言模型能够正确还原该断言。
但这个定义有一个重要的边界:它描述的是理想约束,不是对当前 dialect.compress() 的逐行事实陈述。今天的 plain-text 实现会在 key sentence、topics、entities、emotions、flags 上做筛选;被筛掉的事实断言就不会出现在 AAAK 输出中。MemPalace 的安全网是:原文始终保存在 Drawer 中,AAAK 更像一个高压缩索引,而不是唯一副本。丢失的不是底层存储里的记忆,而是压缩索引的覆盖范围。
这个定义也有意排除了文体风格、修辞手法和措辞偏好——MemPalace 存储的是记忆,不是文学作品。
约束三:任何文本模型可读
这个约束的含义比它字面上看起来更加严格。
"任何文本模型"意味着 Claude、GPT-4、Gemini、Llama、Mistral——包括任何未来可能出现的、能够处理自然语言文本的大语言模型。压缩格式不能依赖于某个特定模型的训练数据、特殊 token 或微调行为。
这个约束直接排除了所有基于向量嵌入的压缩方案。一个由 OpenAI 的 text-embedding-ada-002 生成的向量,对 Llama 来说就是一串无意义的浮点数。即使是同一家公司的不同版本模型,嵌入空间也未必兼容。
它同样排除了所有基于特定分词器(tokenizer)行为的编码方案。不同模型对同一段文本的分词方式不同——BPE、SentencePiece、WordPiece 各有差异——任何利用分词边界来编码信息的方案都会在模型切换时失效。
这个约束的深层含义是:压缩格式必须在"文本"的层面上工作,而不是在"模型内部表示"的层面上。无论哪个模型来读这段压缩后的文本,它都应该能够仅通过语言理解能力——而不是某种特殊的解码能力——来获取其中的信息。
约束四:无需解码器或特殊工具
这是最后一个约束,也是最容易被低估的一个。
在传统的数据压缩领域,压缩和解压是成对出现的操作。gzip 需要 gunzip,zstd 需要 zstd -d,任何压缩格式都附带一个解码器。这在传统计算中不是问题,因为运行一个解码程序的成本极低。
但在 LLM 记忆系统中,这个假设不再成立。当 AI 在会话开始时加载上下文时,它看到的就是文本。没有中间层可以运行一个解码程序把压缩格式还原成自然语言,然后再传给模型。压缩后的文本必须直接作为模型输入被理解——不经过任何预处理、解码或转换。
更具体地说,这个约束排除的是任何需要在模型推理之外运行额外代码的方案。模型的上下文窗口就是唯一的"运行环境"。压缩格式必须在这个环境内自解释。
排除分析:什么方案不可能工作
定义清楚四个约束之后,我们可以系统性地排除那些看似可行但实际上必然违反至少一个约束的方案。这种排除分析不是为了贬低被排除的方案——它们中的许多在其他场景下非常有效——而是为了缩小可行解的搜索空间。
方案 A:二进制编码
最直观的高压缩比方案是二进制编码。将文本信息编码为某种紧凑的二进制格式,理论上可以实现远超 30 倍的压缩比。Protocol Buffers、MessagePack、CBOR 等格式在系统间通信中被广泛使用,压缩效率远高于文本。
违反约束三。 没有任何大语言模型被训练来理解二进制格式。当你把一段 protobuf 编码的字节流放入 GPT-4 的上下文窗口时,模型看到的是乱码。它无法提取其中的任何信息,就像一个只会读英文的人面对一段中文盲文一样。
问题的根源在于:大语言模型的训练语料是文本,它们的世界模型建立在对文本模式的统计学习之上。二进制格式处于这个世界模型的覆盖范围之外。
方案 B:JSON 压缩
既然二进制不行,那把信息组织成结构化 JSON 如何?JSON 是文本格式,所有模型都见过大量 JSON 训练数据,理解起来没有问题。
{
"team": {
"name": "Driftwood",
"lead": "Priya",
"members": [
{"name": "Kai", "role": "backend", "tenure": "3yr"},
{"name": "Soren", "role": "frontend"},
{"name": "Maya", "role": "infrastructure"},
{"name": "Leo", "role": "junior", "status": "new"}
]
},
"project": "saas_analytics",
"sprint": "auth_migration_to_clerk",
"decision": {
"by": "Kai",
"choice": "clerk_over_auth0",
"reasons": ["pricing", "developer_experience"]
}
}
违反约束一。 数一下 token:这段 JSON 大约 180 个 token。而它承载的信息,用自然语言描述大约需要 250 个 token。压缩比不到 1.5 倍。JSON 的语法开销——大括号、方括号、引号、冒号、逗号、键名——占据了大量空间,这些都是模型必须处理但不携带实际信息的 token。
你可以通过缩短键名、删除缩进来优化,但 JSON 的结构性冗余是内生的。"name": 这五个字符中只有值是有用的,键本身的含义可以从上下文推断。但 JSON 格式要求你必须写出每一个键。
更深层的问题是:JSON 是为机器解析设计的,它的冗余是有意为之——为了明确性和容错性。而我们需要的是为 LLM 阅读设计的格式,LLM 有上下文推断能力,不需要那么多显式标注。
方案 C:LLM 摘要
让一个语言模型阅读原始文本,输出一段简洁的摘要。这是大多数商业 AI 记忆系统采用的方案。
Summary: Priya leads a team working on SaaS analytics.
Key members include backend developer Kai (3yr) and
junior developer Leo (new). Currently migrating auth to Clerk.
违反约束二。 摘要是有损压缩的定义。上面的摘要中,Soren 和 Maya 完全消失了。"Kai recommended Clerk over Auth0 based on pricing and DX"这个具体的决策归因也丢失了。
你可以要求模型"不要遗漏任何细节",但这只是把信息损失从显式变成了隐式。模型仍然需要判断什么是"细节"——而这个判断本身就是一种有损操作。更何况,摘要越详尽,压缩比越低,最终趋向于复述原文。
摘要的另一个致命问题是不可逆性。当你发现摘要遗漏了某个关键细节时,你无法从摘要本身恢复它——你必须回到原始文本。这意味着摘要不能作为唯一的压缩表示,它最多只能是一个索引。但 MemPalace 已经有了一个更好的索引系统(宫殿结构),不需要再用另一个有损索引来补充。
方案 D:自定义编码表
设计一套自定义的编码表:为常见概念分配短代码,用查找表来编码和解码。类似于莫尔斯电码,但面向语义而非字母。
例如:T1=Priya T2=Kai T3=Soren R1=backend R2=frontend P1=Driftwood,然后用 T1(lead,P1) T2(R1,3yr) T3(R2) 来表示团队结构。
违反约束四。 读这段文本的模型不知道 T1 是 Priya、R1 是 backend。它需要一个编码表——一个解码器——来理解这些代码。而这个编码表本身也是需要加载到上下文中的文本,占用额外 token,进一步降低实际压缩比。
更严重的是,编码表是与特定数据集绑定的。换一组人物、换一个项目,就需要一套新的编码表。这使得系统变成了一个需要维护的有状态组件,违背了 MemPalace "简单到不可能出错"的设计哲学。
当然,如果编码足够直觉——比如用 PRI 表示 Priya,用 KAI 表示 Kai——那么即使没有显式的编码表,模型也能推断出代码对应的实体。但这时候,"编码"就不再是任意的符号映射,而是一种基于自然语言直觉的缩写系统。这个区分很重要,因为它指向了可行解的方向。
方案 E:向量嵌入压缩
将文本编码为向量嵌入(embedding),用 384 维或 768 维的浮点数组来"记忆"语义信息。
同时违反约束三和约束四。 前面已经讨论过,嵌入向量对其他模型来说是无意义的数字。而且,从嵌入中还原原始信息需要一个解码器(或至少一个相似度匹配引擎),这又违反了约束四。
向量嵌入在 MemPalace 中有其位置——ChromaDB 使用它来驱动语义搜索——但它是检索工具,不是存储格式。这个区分在设计中被严格维护。
可行解的形状
五种方案被排除后,约束空间急剧收窄。让我们从排除结果中反向推导可行解必须具备的特征:
必须是文本格式——因为约束三要求任何文本模型可读,而所有文本模型的公共能力交集就是理解文本。
必须是自解释的——因为约束四要求无需解码器,压缩文本本身必须携带足够的上下文让模型理解它的含义。
必须保留所有事实断言——因为约束二要求格式压缩阶段不丢弃任何实体、关系、属性和事件。
必须极度紧凑——因为约束一要求高压缩比(格式层 5-10 倍,结合内容筛选可达 30 倍),每个 token 必须携带远高于自然英语的信息密度。
把这四个特征放在一起,一个结论开始浮现:可行解必须是某种极度缩写的自然语言。
不是一种新发明的编码——因为那需要解码器。不是一种全新的语法——因为模型没有见过它的训练数据。它必须是英语(或更准确地说,是任何自然语言的极度浓缩形式),利用大语言模型已经具备的语言理解能力来"解码"缩写。
这个推导结果有一个重要的性质:它不是从 AAAK 的设计中逆向推出的,而是从约束条件中正向推出的。即使 MemPalace 的设计者从未存在过,任何面对同样四个约束的工程师,经过同样的排除分析,都会到达同样的结论——可行解必须是极度缩写的英语。
自然语言的信息冗余
既然可行解必须基于自然语言的缩写,一个自然的追问是:自然语言到底有多少冗余可以被移除?
信息论给出了一个定量的回答。Claude Shannon 在 1951 年的实验中估计,英语的信息熵约为每字符 1.0-1.5 比特,而英语字母表的最大熵约为每字符 4.7 比特。这意味着英语文本中大约有 70% 的内容是冗余的——它们的存在是为了帮助人类处理(语法标记、功能词、形态变化),而不是为了传递独立的信息。
但 Shannon 的估计是针对字母级别的。在词级别上,冗余的来源更加多样:
语法冗余。 "The team is currently working on the project" 中,"the"、"is"、"currently"、"on"、"the" 都是语法功能词,不携带团队、工作或项目的信息。去掉它们,"team working project" 仍然传达了核心语义。
修辞冗余。 "Kai, who has been with the team for three years and has extensive experience in backend development, recommended Clerk." 中,"who has been with the team for"、"and has extensive experience in" 都是修辞润色,核心信息是 "Kai(backend,3yr) rec:Clerk"。
解释冗余。 当你说 "Priya manages the Driftwood team" 时,"manages" 暗含了 Priya 是 leader 的信息。在压缩表示中,"PRI(lead)" 就足够了——"manage" 这个动词所传达的额外语义(监督、决策权、汇报关系)可以从 "lead" 这个角色标签中由模型自行推断。
叙事冗余。 自然语言倾向于线性叙述——先说背景,再说事件,最后说结论。压缩表示可以打破这个顺序,直接用结构化的方式陈列事实,由模型在需要时自行重构叙事。
这些冗余加在一起,为格式压缩的 5-10 倍提供了充足的空间。当叠加内容筛选(从长对话中提取关键语句),压缩比可以进一步推高到 README 宣称的 30 倍——但后者涉及对"什么是关键"的判断,不再是纯粹的去冗余。关键在于:去除冗余不等于丢失信息。冗余是信息的额外包装,去掉包装不改变内容物,前提是接收方有能力从裸露的内容物中重建完整的理解。
大语言模型恰好具备这种能力。它们在数万亿词的文本上训练,已经深度内化了英语的语法规则、语义关系和世界知识。当它们看到 "KAI(backend,3yr)" 时,不需要有人告诉它们这意味着 "Kai is a backend developer with 3 years of experience"——它们的语言模型自动完成了这个推断。
这就是可行解的核心洞见:大语言模型本身就是解码器。 不需要外部的解码程序,因为模型的语言理解能力就是解码能力。约束四看似排除了所有需要解码器的方案,但实际上,它只排除了需要外部解码器的方案——而利用模型自身作为解码器的方案,完美地满足了这个约束。
从约束到设计空间
总结一下本章的推导链:
- 问题定义:将大量上下文信息压缩到极小的 token 空间,供 LLM 即时加载。
- 约束定义:高倍压缩(格式层 5-10x,叠加内容筛选可达 30x)、事实断言完整性、模型通用、无需解码器。四个约束缺一不可。
- 排除分析:二进制(模型不可读)、JSON(压缩比不够)、LLM 摘要(有损)、自定义编码(需解码器)、向量嵌入(模型不可读且需解码器)——全部出局。
- 正向推导:可行解必须是文本格式、自解释、保留全部事实、极度紧凑。交集:极度缩写的自然语言。
- 理论基础:自然语言的 70% 冗余为高倍压缩提供了空间,而 LLM 的语言理解能力充当了隐式解码器。
这条推导链的意义在于:它将 AAAK 从一个看似随意的"发明",重新定位为一个在严格约束下唯一可行的设计方向。AAAK 不是因为"聪明"而被设计出来的,而是因为在给定的四个约束条件下,解空间只剩下了这一个角落。
当然,"极度缩写的自然语言"仍然是一个很大的设计空间。缩写什么、保留什么、用什么符号来标记结构——这些具体的语法决策仍然有大量的自由度。下一章将深入 AAAK 的具体语法设计,分析它在这个收窄后的设计空间中做出的每一个选择。
但在此之前,值得记住一件事:AAAK 之所以能够工作,不是因为它的语法有多巧妙,而是因为它正确地识别了约束空间的形状。好的工程从来不是从解法开始的——它从约束开始。