AI/ML 详解:Context 工程

Day 8 · 2026-05-25
面向:有编程经验的非 AI 方向工程师
工程对应 → super-individual D2: Context Engineering(lost-in-the-middle、信息排布)

上下文窗口Context Window

硬件约束注意力
一句话类比

Context window 就是模型的"工作集(working set)"——类似进程的虚拟内存:你以为它能装无限东西,实际上有硬上限,并且越靠近上限性能越糟。后端世界对应:缓冲池(buffer pool)、SQL 的 work_mem、CPU 的 L1/L2 cache——尺寸都是 trade-off,不是"越大越好"。

它解决什么问题 + 工作机制

Transformer 的 attention 是 O(n²) 计算复杂度——每个 token 都要和窗口里所有 token 算相关性。窗口 1M token 意味着 1M × 1M = 一万亿次相似度计算,显存按 KV cache 线性增长(每个 token 的 Key/Value 矩阵都要存)。所以窗口尺寸是硬件成本问题,不是"想多大就多大"。

2026 年主流模型窗口:Claude 4.7 / GPT-5 ~200K-1M、Gemini 2.5 ~2M、开源模型多在 32K-128K。但核心反直觉是 Liu et al. 2023 的发现——"Lost in the Middle":把关键信息放在 100K 上下文的开头或结尾,准确率 ~80%;放在中间,掉到 ~50%。注意力分布是 U 形的:

关键信息位置 → 模型召回率
开头 80%
1/4 处 60%
中间 48%(最低谷)
3/4 处 65%
结尾 82%
↑ U 型曲线:长上下文不等于全部被看到

即使是 2025 年宣传"100% needle-in-haystack 召回"的新模型,在多 needle + 推理任务上依然有显著的位置偏差。把 context window 当成"无限注意力"是常见的认知误区。

代码示例
from anthropic import Anthropic
client = Anthropic()  # 需要 ANTHROPIC_API_KEY

# 永远先用 SDK 量化 token 数,再决定要不要塞进去
long_doc = open("report.txt").read()
resp = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    messages=[{
        "role": "user",
        # 关键问题放最后——利用 U 型注意力的"近因端"
        "content": f"<document>{long_doc}</document>\n\n基于以上,回答:核心结论是什么?"
    }]
)
print(resp.usage.input_tokens, "input tokens")  # 监控用量
常见误区 + 实践场景
"我用 1M 窗口塞所有公司文档,就不用 RAG 了"——错。塞 200K token 一次调用既贵(成本随 token 线性涨)又慢(首字延迟随输入翻倍),中间内容召回率还差。Anthropic、Google 自己都明确推荐:RAG + 短上下文 > 直接长上下文,尤其是文档库稳定、查询多样的场景。
📌 妈妈场景:读论文时不要把整本书丢给模型,而是把当前章节 + 摘要 + 关键问题组成 8K-32K 的精炼上下文。质量比塞 200K 高得多,单次成本降 10 倍。
Takeaway + 思考题
💡 Context window 是工作集,不是数据库。优化目标是"放对的东西",不是"放更多东西"。
🤔 你过去把"上下文越长 = 模型越懂"当默认假设时,错过了哪些更便宜的工程方案?

上下文缓存Context Caching / Prompt Caching

优化成本
一句话类比

把 prompt 当成 HTTP 请求来看:不变的 system prompt + 工具 schema + few-shot 例子 就是"静态资源",每次请求都重新跑 attention 等价于不开 CDN。Context caching = 把这段 prefix 的 KV cache 持久化到 GPU 显存或快速 SSD,下次命中时直接复用——和 Redis 缓存、HTTP 304、Postgres prepared statement 是同一类东西。

它解决什么问题 + 工作机制

典型 Agent 应用的 prompt 80% 是不变的(角色定义 + 工具描述 + 历史对话),只有最后用户问题在变。但 LLM 默认每次都从头跑 prefill——对一个 50K token 的固定 prefix 来说,这就是 50K 次 attention 白算。Caching 的核心机制:

  • 命中条件:前缀必须逐 token 完全一致。改一个标点都会失效——和 Redis 的 key 哈希一样脆弱;
  • 顺序至关重要:不变内容必须放最前面,变动内容放最后。把 user query 插在 system prompt 中间 = cache 永远 miss;
  • 定价结构:Anthropic prompt caching 写入比正常贵 25%,命中读取便宜 90%。一次写多次读才合算——访问 ≥2 次就回本;
  • TTL:Anthropic 默认 5 分钟,可买 1 小时长 TTL;OpenAI 自动缓存约 5-10 分钟,不可控但免费。
Prompt 结构(顺序极重要)
① system prompt+② tools schema+③ few-shot+④ 对话历史+⑤ user query
└─────── 缓存命中(KV 复用,跳过 prefill)───────┘└── 每次必须重算 ──┘

反模式:user querysystem prompt = cache 永远 miss
代码示例
from anthropic import Anthropic
client = Anthropic()

# cache_control 标记"这一段及之前的所有内容"作为可缓存前缀
resp = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=512,
    system=[
        {"type": "text", "text": "你是资深财报分析师..."},
        {"type": "text",
         "text": long_company_filing,  # 50K token 财报,反复查询同一份
         "cache_control": {"type": "ephemeral"}}  # ← 标记缓存断点
    ],
    messages=[{"role": "user", "content": "营收增长来自哪个业务线?"}]
)
print(resp.usage.cache_creation_input_tokens)  # 第一次:写入
print(resp.usage.cache_read_input_tokens)      # 后续:命中(便宜 90%)
常见误区 + 实践场景
"我把对话历史也加上 cache_control 就更省钱"——错。对话历史每轮都在变,缓存命中率几乎为零,反而每次都按 +25% 写入价付费。规则:只缓存真正不变的前缀。判断方法:你能预测下次请求时这段内容一字不差吗?不能就别缓存。
📌 妈妈场景:把孩子的学习风格画像 + 历次错题 + 常用知识框架(合计 ~20K token)做成 system prompt 缓存,每次问"今天数学这道题怎么讲"时只付 user query 的钱。一个月省下的 token 费用是肉眼可见的。
Takeaway + 思考题
💡 Caching 是 prompt 工程里最简单、最被低估的杠杆——零智力投入,立刻降本 50-90%。
🤔 你的 AI 工具链里有哪些 prompt 是"几乎不变 + 反复用"的?它们现在被缓存了吗?

上下文压缩Context Compression

数据流总结
一句话类比

长会话的上下文管理 = 数据库的日志滚动(log rotation) + compaction。MySQL binlog 不会无限增长——超过阈值就 rotate + 压缩 + 归档。LLM 上下文同理:对话越长 token 越多,压缩是工程必需,不是可选项。

它解决什么问题 + 工作机制

当对话超过 50K-100K token,三个问题一起爆:窗口溢出(hard limit)、注意力稀释(lost in the middle)、每轮成本线性涨(所有历史每次都重算)。四类主流压缩策略,按"信息保真度 vs 成本"递增:

  • ① Sliding Window——只保留最近 N 轮。最便宜但最丢信息;适合"无需长期记忆"的短任务;
  • ② Summarization——用 LLM 把旧消息总结成 200-500 token 摘要,替换原文。主流选择;要注意"总结的总结"会逐渐失真;
  • ③ Hierarchical——多层摘要:最近 5 轮全文 + 5-20 轮分组摘要 + 20+ 轮一句话摘要。类似 LSM tree 的分层结构;
  • ④ Selective / RAG-style——把对话历史存外部 vector DB,每轮根据当前问题语义检索相关片段。最贵但最准。

Anthropic 2025 推出的 Memory 工具自动 compaction把这套机制内置——上下文接近上限时自动总结老消息,不需要应用层手写。但什么该被压缩压缩到什么粒度仍然是产品决策,不是默认值能解决的。

代码示例
def compress_history(messages, max_tokens=8000):
    # 简单分层:最近 6 轮保全文,更早的总结成一段
    recent = messages[-6:]
    older  = messages[:-6]
    if not older or count_tokens(messages) < max_tokens:
        return messages

    older_text = "\n".join(f"{m['role']}: {m['content']}" for m in older)
    summary = client.messages.create(
        model="claude-haiku-4-5-20251001",  # 总结用便宜模型
        max_tokens=400,
        messages=[{"role": "user",
                   "content": f"用 5 个 bullet 总结这段对话的关键事实、决策、未解问题:\n{older_text}"}]
    ).content[0].text

    # 拼回:摘要 + 最近原文(这样最近上下文细节不丢)
    return [{"role": "system",
             "content": f"<earlier_conversation_summary>\n{summary}\n</earlier_conversation_summary>"}] + recent
常见误区 + 实践场景
"压缩一切,省 token 就是赢"——错。把用户的明确指令("千万别用 X 库")、关键数字已经确认过的决策压进 5-bullet 摘要 = 几乎一定丢。经验法则:(1) 用户的原话偏好逐字保留;(2) 数字/代码/ID 不压;(3) "讨论过的但没采纳的方案"可以压。压缩是有损算法,要知道你愿意丢什么。
📌 妈妈场景:和 Claude 协作的"长期项目笔记本"——每周让模型总结上周对话成 200 字"决策清单 + 未解问题 + 关键原话",旧消息归档到 markdown 文件。一年下来主对话窗口始终轻盈,但历史完整可回溯。
Takeaway + 思考题
💡 压缩不是"省钱小技巧",是有损编码的工程决策——必须显式声明保留什么、丢弃什么。
🤔 你和 AI 的长对话里,哪些信息必须逐字保留,哪些可以变成一句话摘要?这个清单本身就是你的"个人 AI 协议"。

Memory 管理Memory Management

架构状态
一句话类比

LLM 本身是无状态的——每次 API 调用都是一次冷启动。要让它"记得你",必须像 OS 设计内存层级一样,给它配一套分层存储:CPU register(当前 context)→ L1/L2 cache(缓存的 prefix)→ RAM(最近会话)→ disk(向量库 + 笔记)。"Memory 管理"就是设计这套层级。

它解决什么问题 + 工作机制

把"过去三个月每次对话都塞 context"既不可能(窗口爆)也无意义(lost in middle)。认知科学借来的四类记忆,对应不同存储策略:

LLM Memory 层级(对应 OS 类比)

① Working Memory ≈ CPU register — 当前 context window 内的内容
② Procedural ≈ ROM / firmware — 长期不变的 system prompt、工作流(缓存友好)
③ Episodic ≈ RAM / SSD — 过去对话历史,按时间索引,必要时检索
④ Semantic ≈ knowledge base — 从对话提炼出的事实,存 vector DB("用户讨厌 emoji"、"项目截止 6/30")

读写路径:每轮 query → 检索 ③④ 相关片段 → 注入 ① → 模型推理 → 抽取新事实回写 ④

主流实现:MemGPT / Letta 用类操作系统的"分页"机制让 LLM 自己决定什么换入换出;mem0 / LangMem 把 episodic + semantic 抽象成 SDK;OpenAI ChatGPT 的"记忆"、Claude 的 Memory 工具是产品化版本。共同模式:提取(extract)→ 存储(store)→ 检索(retrieve)→ 注入(inject)四步。

关键工程决策:什么值得记?——不是"对话里说过的都记",而是用一个抽取 LLM 判断这条信息是否会影响未来回答。Mem0 论文 (2024) 显示,主动抽取 + 去重的 memory 比"全文存档 + 检索"准确率高 26%、延迟低 91%。

代码示例
from mem0 import Memory  # pip install mem0ai
m = Memory()

# 1) 写入:mem0 自己用 LLM 抽取"值得记的事实",去重后存向量库
m.add("我对花生过敏,孩子喜欢蓝色", user_id="bigcat")
m.add("上周和我讨论过 Mamba 架构,结论是 SSM 适合长序列", user_id="bigcat")

# 2) 检索:根据当前 query 拉相关 memory(不是塞全部历史)
hits = m.search("给孩子做生日蛋糕的建议", user_id="bigcat", limit=3)

# 3) 注入 prompt——只附加相关的几条
ctx = "\n".join(h["memory"] for h in hits["results"])
resp = client.messages.create(
    model="claude-opus-4-7", max_tokens=512,
    system=f"<known_about_user>\n{ctx}\n</known_about_user>",
    messages=[{"role": "user", "content": "周六给孩子做生日蛋糕,推荐配方"}])
# → 模型会自动避开花生,知道孩子可能喜欢蓝色装饰
常见误区 + 实践场景
"Memory 越多越聪明"——错。Memory 系统最大的失败模式是污染:错误事实("用户讨厌 Python"——其实是某次气话)被持久化后,永久影响后续回答。生产经验:(1) 给 memory 打置信度分(明确陈述 > 推断),(2) 让用户能查看 + 删除,(3) 定期跑 "memory 审计"——LLM 评估每条 memory 是否仍然有效。
📌 妈妈场景:建一个"BigCat 操作手册" memory——你的工作偏好(深色主题、精炼输出、不要表情)、家庭关键事实(孩子年龄段、过敏、兴趣)、思考框架(佛学/复杂性科学/分布式系统类比偏好)。让所有 AI 工具读这份共享 memory,跨工具一致体验,比每次重复说一遍高效得多。
Takeaway + 思考题
💡 Context 是工作集,Memory 才是持久存储——把两者混为一谈是 AI 应用最常见的架构错误。
🤔 如果把"和 AI 共事一年"看作设计一个有状态系统,你的"数据 schema"长什么样?哪些字段需要持久化,哪些只是 session state?

深入资源Further Reading

深入思考Deep Questions

1. "Prompt engineering"(Day 3)和"Context engineering"(今天)的关系是什么?后者是前者的升级,还是不同的层次?
它们是不同抽象层,不是版本迭代。Prompt engineering 关注"这一次 LLM 调用,prompt 怎么写最有效"——CoT、few-shot、role play,本质是单次推理的技巧。Context engineering 关注"跨多次调用、跨长时间,模型该看见什么"——caching 策略、压缩策略、memory 架构,本质是系统级数据流设计。一个工程师可以是顶级 prompt engineer 但完全没思考过 context 架构(结果就是写出"单次 Demo 完美、跑一周就崩"的系统);反之亦然。两者关系类似"SQL 查询优化" vs "数据库 schema 设计"——一个看 query,一个看 schema。BigCat 你的分布式背景在 context engineering 上是巨大优势:缓存一致性、数据生命周期、热/冷数据分层——这些经验直接可迁移。2024-2025 业界共识:模型能力到 Claude 4.7 / GPT-5 这个水平后,应用质量的瓶颈从模型转移到 context engineering,这是为什么"context engineering" 在 2025 年成为热词。
2. Context caching 的 KV cache 在 GPU 显存有限的情况下也会被淘汰(eviction)。这和你熟悉的 Redis LRU / OS page replacement 算法有什么异同?设计你自己的 caching 策略时该考虑什么?
相似点:都是受限存储 + 热数据保留 + 冷数据淘汰的经典缓存问题。Anthropic / OpenAI 的实现细节没完全公开,但行业普遍用 LRU 或 LFU 变种 + 显式 TTL。差异点:(a) 淘汰粒度不同——Redis 按 key 整体淘汰,KV cache 按 prompt prefix 的哈希链淘汰,prefix 不一致就部分失效;(b) 写入成本不对称——Redis 写入和读取成本接近,KV cache 写入贵 25%、读取便宜 90%,读写比对 ROI 影响巨大;(c) 外部不可控——你不知道 provider 端 GPU 当前负载,连续两次同样 prompt 可能一次命中一次不命中。设计策略:(1) 用 1-hour cache 而不是默认 5-min——如果 prefix 调用频率 > 每小时一次;(2) 预热——业务低峰主动用一次"空"请求注入缓存;(3) 监控 cache_read / cache_creation 比率,低于 5:1 就考虑下调缓存策略(写入贵了不划算);(4) 稳定 prefix 边界——别在 system prompt 里塞当前时间戳、随机 session_id 这种破坏哈希的内容。
3. 长上下文(1M-2M token)vs RAG,2026 年应该怎么选?什么时候长上下文已经"够好"以致于不需要 RAG?
2024 长上下文出现时业界喊"RAG is dead",2025 年实践打脸——大部分场景两者并存。决策框架按三轴:(a) 知识库稳定性——固定文档(一本书、一份合同)适合长上下文+caching;动态库(新闻、产品文档、用户笔记)必须 RAG;(b) 查询多样性——查询和文档高度相关("这份合同第 N 条说什么")长上下文够;查询发散("我们去年所有客户中类似 A 的有哪些")RAG 必胜,因为长上下文里这种"全局聚合"召回率极低;(c) 成本预算——长上下文每次调用 token 都是全量入参费,月活 10 万的应用不可承受;RAG 每次只查 5-10K,可线性扩展。真正不需要 RAG 的场景:单文档分析(论文阅读助手、合同审查)+ 文档 ≤ 500K token + 查询频率不高 + caching 能命中。其他场景都是 RAG + 长上下文混合:用 RAG 把候选缩到 50K-100K,再用长上下文一次性推理。BigCat 你的"读论文/读财报"场景属于第一类,"个人知识库长期查询"属于第二类——架构不同。
4. Memory 系统会引入"AI 记忆污染"——错误事实被持久化后影响后续所有回答。这和数据库的"脏数据治理"有什么共通的工程模式?
本质相同:低质量写入 → 持久存储 → 污染下游推理,是所有有状态系统的核心难题。可迁移的工程模式:(1) 写入前校验(schema validation)——Memory 写入用一个独立 LLM 评估"这条事实明确还是推断?""是用户陈述还是 AI 推论?",只持久化高置信度信息,对应数据库的 constraint check;(2) 软删除 + 审计日志——never DROP,标记为 invalidated,保留追溯,方便事后调试为什么模型突然出错;(3) 定期 GC / 一致性检查——周期性用 LLM 扫一遍 memory 库,发现矛盾事实("用户喜欢深色"和"用户最近偏好亮色")就提示用户/降权;(4) 用户可见 + 可编辑——所有 memory 必须有 UI 让用户看到、删除、修改——这是知情同意也是脏数据治理;(5) 多源交叉验证——重要事实(如医疗、法律相关)至少两次独立确认才持久化。Mem0 / Letta 已经在做前 3 条,但用户可见性和分级置信度普遍做得不好——这是 BigCat 你做"个人 AI 操作手册"时该自己 enforce 的。
5. 如果把"和 AI 共事"看成认知外包,那么哪些记忆应该外包给 AI,哪些必须留在你自己脑子里?这个问题对个人成长有什么意涵?
这是 context engineering 在个人层面最深刻的延伸。可外包的:(a) 事实记忆(人名、日期、配置参数)——AI 比你强 100 倍,外包零损失;(b) 流程记忆(如何配 Kubernetes、如何写 PR 模板)——AI + 文档完全够,但偶尔回顾保持手感;(c) 低频专业知识(一年用一次的法律条款、报税流程)——纯外包合理。必须留在自己脑子里的:(i) 核心判断力——"什么是好代码""什么是好决策",外包了就丧失主体性;(ii) 情感联结——和孩子的对话内容、家人的喜好细节,外包给 AI 等于把关系外包;(iii) 跨学科直觉——你的佛学 × 分布式 × 复杂性科学的连接能力,本身是组合记忆,外包则 connection 消失;(iv) 身体性技能——任何需要"做中学"的事,外包了就永远学不会。深层意涵:context engineering 不只是技术问题,它逼你回答"我是谁"——什么记忆构成"我"的不可外包部分。BigCat 你追求"AI 超级个体"的本质,是要清晰地知道:哪些扩展你(augment),哪些会替代你(atrophy)。这条界线是个体的"context schema 设计"——只有你能定。