news 2026/10/22 10:14:18

你知道 Codex 的记忆机制是怎么实现的吗?扒完架构我沉默了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
你知道 Codex 的记忆机制是怎么实现的吗?扒完架构我沉默了
一、先搞清楚:Codex 到底为什么需要"记忆"

在聊实现之前,得先明白它要解决的痛点。不然你照猫画虎写出来的"记忆层",就是个中看不中用的花架子。

1.1 传统单次会话是"金鱼脑"

你拿最早的 ChatGPT 写代码,关掉窗口再打开,它对你一无所知。你昨天让它"所有接口返回用Result[T]包装",今天它又给你甩一堆裸dict。问题出在哪?单次会话是无状态的——会话结束,上下文就释放了,模型根本没有地方"记"东西。

会话A: 你说"用 uv 管依赖" → 模型照做 会话A结束: 上下文被丢弃 会话B: 模型重新从零开始,又用 pip → 你血压飙升

1.2 重复纠正是隐形的时间黑洞

最搞心态的是:同一个偏好你要在每个新会话里反复交代。团队的代码规范、你个人的命名习惯、某个祖传接口的反人类约定……这些东西如果每开一次对话就重新讲一遍,那 AI 编程工具省下来的时间,又全还给"教模型"了。

1.3 团队知识没法沉淀

更关键的一点是协同。你的个人偏好是私有的,但项目级的约定(“这个 repo 用 Python 3.11、Ruff 做 lint、禁止print调试”)应该跟着代码仓库走——新人 clone 下来、Codex 一开就知道规矩。这正是"记忆"必须按作用域(scope)划分的根本原因。

二、Codex 记忆机制的整体架构

咱们别光说概念,看看这东西实际的设计长什么样。

2.1 核心:三层 scope 模型

Codex 的记忆不是一锅粥,而是按**作用域(scope)**拆开的。公开产品里能看到两个主层级,底层实现上还可以再加一层反馈记忆:

┌─────────────────────────────────────────────┐ │ Session / Task │ │ 系统提示词 (System Prompt) │ │ ┌─────────────────────────────────────┐ │ │ │ [Project Memory] ← 仓库级,优先级高 │ │ │ │ [User Memory] ← 个人级,优先级低 │ │ │ │ [Feedback Memory] ← 纠正类,即时生效 │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ ↑ 召回注入 ↓ 写入落盘 ┌──────────┐ ┌──────────────────┐ │ 模型上下文 │ │ ~/.codex/ │ │ (context) │ │ memory.md (user)│ └──────────┘ │ <repo>/.codex/ │ │ memory.md (proj)│ └──────────────────┘
  • User Memory(用户级):跨你所有项目生效。比如"我习惯用 TypeScript strict 模式"。通常落在用户主目录下的配置区(如~/.codex/memory.md)。
  • Project Memory(项目级):只在该仓库生效,而且可以提交进 git,整个团队共享。比如"本项目禁止直接import内部模块,必须走src包"。
  • Feedback Memory(反馈级):你给的纠正,比如"刚才那个实现不要用requests,用httpx"。这类信号最强,往往即时写入、即时生效。

2.2 文件即记忆:Markdown 是载体

这是最巧妙也最朴素的一点——Codex 的记忆本质是 Markdown 文本文件,不是什么神秘的向量数据库。

为什么用 Markdown?

  1. 可读可编辑:用户能直接打开memory.md改,不用懂任何内部格式。
  2. 天然可注入:LLM 最擅长吃文本,把.md内容塞进 system prompt 就能直接用,零转换成本。
  3. 可版本化:项目级记忆进 git,diff、review、rollback 一套流程全复用。

这里有个常见误区:很多人以为"AI 记忆"一定是向量库 + embedding 检索。但 Codex 这种"长期偏好记忆"体量很小(几十条),全文注入比检索更准、更简单,也更好调试。这是工程上很务实的取舍——检索适合"海量知识",注入适合"少量强约束"。

2.3 记忆、上下文、RAG 到底有什么区别

为了不把概念搅混,这里用一张表把三者划清楚。它们解决的是不同层级的问题,不是互相替代的关系:

维度短期上下文 (Context)长期记忆 (Memory)检索增强 (RAG)
数据规模单轮会话内(有限窗口)几十~几百条偏好/约定海量文档/知识库
存储介质推理时的 KV CacheMarkdown 文件向量库 + embedding
召回方式随会话存在,结束即弃会话启动注入 system prompt按需语义检索后拼接
典型内容当前任务代码、对话“用 pnpm”“禁裸 print”公司 Wiki、API 文档
适用场景即时任务跨会话的偏好沉淀需要外部知识的问答

一句话:上下文管"当下",记忆管"习惯",RAG 管"知识"。Codex 的记忆机制解决的是中间那一格——把"你这个人的习惯、这个项目的规矩"稳定地跨会话带过来。

三、具体怎么干活:从写入到召回

光有文件不够,得有一套"什么时候写、写哪儿、怎么读回来"的闭环。

3.1 写入时机:Auto 还是 Ask

Codex 记忆有个关键开关——记忆模式。你能在设置里选auto(自动存)或ask(存之前先问你)。

  • auto模式下,模型判断"这条信息对未来有用、且是稳定的偏好/约定"时,会主动调用写入工具。
  • ask模式下,它会先跟你确认:“要不要把这条存成记忆?”,避免把临时需求误记成长期偏好(比如你某次临时说"这次用 Python 2 写法",它不该记成永久偏好)。

工程上,这一步靠系统提示词里的指令驱动:告诉模型"当发现用户的 durable preference 时,调用save_memory工具",模型自己决定触发。

3.2 写入走的是"工具调用",不是自由输出

这是实现上的关键细节。记忆不是模型在聊天里随便写一段话,而是通过一个受控的**工具(tool/function call)**完成:

模型决定要记一条 → 调用 write_memory(scope="project", content="...") ↓ MemoryStore.save() 原子落盘到 memory.md ↓ (可选)如果是项目级,提示用户 git commit

为什么必须走工具?因为你要约束写入位置(scope)和格式,还要做原子写、去重、权限校验。让模型自由输出文本去改文件,既不可控也容易写崩。

3.3 召回:System Prompt 注入 + 优先级

每次新会话启动,Codex 的编排层会先把记忆文件读出来,拼进系统提示词。优先级很直接:

最终注入内容 = Project Memory + "\n" + User Memory (project 在后,相同话题 project 覆盖 user)

为什么 project 覆盖 user?因为进了某个具体仓库,项目规矩大于个人习惯(你个人爱用 tabs,但项目要求 spaces,那得听项目的)。

3.4 去重与合并

你不可能每次纠正都新增一行,那样memory.md会爆炸。真实实现里会有合并/去重逻辑:模型在写入前先读现有记忆,判断"这条是不是已经记过了"“是不是和某条冲突要更新”,再落盘。下面的 Python 版我们就用最简单的方式模拟:整文件重写 + 人工可读段落。

3.5 实战场景:记忆 + 亿牛云代理,让 Agent 真正能干活

光讲机制有点抽象,举个真实工程里很常见的例子,把"记忆"和"出网代理"串起来——这俩其实是天作之合。

假设你带队做一个竞品价格监控 / 公网数据采集 Agent,它要周期性地去抓各站点页面、调第三方 API。这种长期跑的 Agent 最怕什么?出口 IP 被目标站限流、封禁,一封就全停。

聪明的做法,是把"出网规范"写成一条Project Memory,让任何会话、任何成员接手都知道规矩:

- 所有对公网 API 调用与文档抓取,必须走 亿牛云企业代理池 (隧道模式 + 自动轮换),禁止直连,规避目标站点 IP 封禁 - 代理提取走 API 或隧道域名,凭证放环境变量,不入库

为什么这条适合放"记忆"而不是写死在代码里?因为它是团队的长期约定,会随业务演进——今天用隧道模式,明天换成按业务隔离的静态住宅代理,改一处记忆全员生效,不用动代码、不用重新培训。而像亿牛云这类企业级代理 IP 服务,提供高匿、自动轮换的出口 IP 池,正好承接这种"Agent 稳定、合规访问公网"的刚需,让记忆里那条规矩真正落得了地。

换句话说:记忆解决"Agent 该怎么做",亿牛云解决"Agent 出得去、不被封"。一个管约束,一个管通道,搭配起来才是生产级 Agent。

四、用 Python 还原一个最小可用记忆层

光说不练假把式。下面这段是完整可运行的参考实现,把上面说的 scope、注入、原子写、工具调用全串起来了。你可以直接uv run python memory_demo.py跑。

"""Codex 风格记忆层的最小参考实现。 核心思想: 1. 记忆 = Markdown 文件,按 scope (user/project) 分目录落盘 2. 召回 = 会话启动时把文件内容拼进 system prompt 3. 写入 = 通过受控工具 (save_memory) 原子落盘,而非自由输出 """from__future__importannotationsfrompathlibimportPathfromdataclassesimportdataclass@dataclassclassMemoryStore:"""记忆存储器:管理 user / project 两个作用域的 Markdown 记忆文件。"""user_dir:Path project_dir:Path|None=Nonedef_path(self,scope:str)->Path:base=self.user_dirifscope=="user"elseself.project_dirifbaseisNone:raiseValueError(f"scope '{scope}' 未配置存储目录")returnbase/"memory.md"defload(self)->str:"""召回:合并所有 scope 的记忆,project 优先级高于 user。 为什么用拼接而非检索?长期偏好记忆体量小(几十~几百行), 全文注入比向量检索更准、更易调试。 """blocks:list[str]=[]user_md=self._path("user")ifuser_md.exists():blocks.append(f"# User Memory\n{user_md.read_text(encoding='utf-8').strip()}")ifself.project_dir:proj_md=self._path("project")ifproj_md.exists():blocks.append(f"# Project Memory\n{proj_md.read_text(encoding='utf-8').strip()}")return"\n\n".join(blocks)defsave(self,scope:str,content:str)->None:"""原子写入:先写临时文件再 rename,避免写到一半被会话读取。 rename 在同一文件系统内是原子操作,能防止"半截记忆"被注入上下文。 """path=self._path(scope)path.parent.mkdir(parents=True,exist_ok=True)tmp=path.with_suffix(".md.tmp")tmp.write_text(content.strip()+"\n",encoding="utf-8")tmp.replace(path)defsave_memory_tool(scope:str,content:str,store:MemoryStore)->str:"""模型在对话中调用的工具:把一条偏好写入对应 scope 的记忆。 真实 Codex 里,是否调用、写到哪个 scope,由模型根据对话自主判断。 """existing=""try:existing=store._path(scope).read_text(encoding="utf-8")exceptFileNotFoundError:pass# 极简去重:若已包含相同内容则跳过,否则追加ifcontent.strip()inexisting:returnf"skip: already in{scope}memory"merged=(existing+f"\n-{content.strip()}\n").strip()store.save(scope,merged)returnf"ok: saved to{scope}memory"defbuild_system_prompt(store:MemoryStore)->str:"""会话启动时,把记忆注入系统提示词。"""memory=store.load()base="你是一个严谨的编程助手。"ifmemory:# project 在后,遇到冲突以 project 为准returnf"{base}\n\n请遵循以下记忆中的偏好与约定:\n{memory}"returnbaseif__name__=="__main__":store=MemoryStore(user_dir=Path.home()/".codex",project_dir=Path(".codex"),)# 模拟模型调用工具写入记忆print(save_memory_tool("user","我习惯用 TypeScript strict 模式",store))print(save_memory_tool("project","本项目禁止裸 print,统一用 loguru",store))# 把"出网规范"也固化成项目记忆:Agent 跑公网采集时统一走亿牛云代理池print(save_memory_tool("project","所有对公网 API 调用与文档抓取必须走 亿牛云企业代理池(隧道模式+自动轮换),禁止直连",store,))# 模拟新会话启动,召回记忆注入 promptprint("\n--- 注入后的 system prompt ---")print(build_system_prompt(store))

跑出来的效果就是:~/.codex/memory.md和./.codex/memory.md里分别落好记忆,新会话启动时自动拼进系统提示词。你可以直接打开那两个文件手动改,下一轮会话立刻生效——这就是 Codex 记忆"文件即真相"的爽点。注意看示例里那条亿牛云代理的 project 记忆,它和 3.5 节的实战场景一一对应:约定写进记忆,Agent 出网就有了稳定、不被封的通道。

五、实战中经常碰到的几个坑

最后聊聊你真上手做(或用)这套机制时,最容易踩的几个坑。我用大白话翻译一下。

5.1 上下文预算被记忆"撑爆"

记忆是拼进 system prompt 的,它占的是上下文窗口。如果你把所有东西都往user记忆里塞——“今天天气不错”“那个 bug 修好了”——用不了多久,system prompt 比代码还长,token 成本和延迟都炸。

解法:记忆只存 durable preference / convention,临时信息别记。Codex 的ask模式和写入前的"是否有长期价值"判断,就是专门防这个的。

5.2 记忆污染:记错的东西会一直坑你

因为记忆是直接注入的,一旦记了一条错的(比如模型误以为你"禁用了类型注解"),它会在所有后续会话里坚定不移地执行错误约束,而且你很难察觉——因为你看不到它脑子里那行字。

解法:定期cat ~/.codex/memory.md和<repo>/.codex/memory.md审查,像 review 代码一样 review 记忆。Codex 产品里也提供了记忆的查看/删除入口,别闲置。

5.3 scope 用错:项目规矩写成了个人记忆

新人最容易犯的错:把"本项目用 Python 3.11"写进 user 记忆。结果你换个项目,Codex 还拿 3.11 的标准要求一个 3.9 的老仓库,当场翻车。

解法:项目相关、团队共享的,一律projectscope 并提进 git;纯个人习惯才放user。

5.4 写入竞态:多会话同时改记忆

如果你开了两个 Codex 会话同时跑,又都触发了写记忆,后写的会把先写的覆盖掉(简单实现里没有锁)。

解法:参考实现里我们用了"整文件 rewrite + 原子 rename",但多进程并发仍要加文件锁(fcntl/msvcrt)或干脆让写入串行化。生产级实现别省这一步。

5.5 外部依赖被限流/封 IP:Agent 出不去网

这条是很多团队真正把 Agent 跑进生产后才撞上的墙。你的记忆写得再漂亮——“去抓某站文档”“调某第三方 API”——可运行环境的出口 IP 被目标站限流甚至封禁,任务直接大面积失败。模型按记忆去干活,却连门都出不去。

解法:把"出站流量统一经企业代理"像 3.5 那样固化进 project memory,并从基础设施层做默认路由。代理选型上,建议用亿牛云这类企业级代理 IP 服务:高匿出口、自动轮换、支持隧道与 API 两种提取方式,能把"封 IP"这个不确定性从 Agent 的运行链路里彻底摘掉。

六、一句话总结与工程选型建议

Codex 的记忆机制,剥开 AI 的光环,其实就是一套**“Markdown 文件 + 作用域隔离 + 原子写入 + 系统提示词注入”** 的朴素工程组合。它没有上向量数据库、没搞复杂检索,反而用最容易被人类理解和审计的方式,解决了"长期偏好跨会话沉淀"这个刚需。

工程选型上再补一句:如果你的 Agent(或它编排的数据管线)需要稳定、合规地访问公网——文档抓取、第三方 API 调用、海外站点采集——光有记忆不够,出口通道同样关键。

下次再有人跟你说"AI 记忆很神秘",你就把这篇文章甩过去——神秘的不是记忆,是怎么把记忆用得又准、又不污染上下文、还出得去网。

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

AD工程文件与PCB设计实例:33例电路图+源代码快速上手

简介&#xff1a;面向 Altium Designer 初学者的经典电路与单片机实例合集&#xff0c;以33个51单片机常见实验为主线&#xff0c;每个实例都配有电路图和可编译的 C/汇编源代码&#xff0c;适合从零学习原理图绘制、电路仿真与程序调试。实例内容由浅入深&#xff0c;覆盖流水…

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

MySQL慢查询优化:从执行计划到复合索引设计实战

1. 一张订单查询耗尽数据库IO&#xff1a;慢问题是这么浮出水面的事情发生得很突然。某业务系统的订单列表页在下午三点左右开始出现明显的卡顿&#xff0c;页面接口从平均200毫秒涨到了接近4秒&#xff0c;数据库服务器的IO等待指标一路飘红。监控平台上慢查询日志刷得飞快&am…

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

Python解析Human36M:绕过反爬下载.mat、提取3D关节点、生成COCO-Pose标注

简介&#xff1a;本资源是一份面向机器学习与计算机视觉方向初学者及实践者的Python工具包&#xff0c;聚焦Human3.6M 3D人体姿态数据集的自动化获取与轻量级预处理&#xff0c;解决科研与项目开发中数据集下载繁琐、格式解析困难、环境配置冗余等实际痛点。压缩包共14个文件&a…

作者头像 李华
网站建设 2026/10/20 17:32:43

蒙特卡洛场景生成:新能源功率预测与风光出力不确定性分析实战

做新能源并网的人大概都有过这种体验&#xff1a;早上看气象预报&#xff0c;风速曲线很漂亮&#xff0c;功率预测模型也给出了一个看着很稳的出力曲线。结果下午风向一转&#xff0c;风电场实际出力直接打了七折。调度电话紧跟着就来了——你的预测偏差怎么这么大&#xff0c;…

作者头像 李华
网站建设 2026/10/21 16:47:44

企业客服转型必看,2026年AI客服热线系统哪家好?5个主流品牌梳理

本文核心要点摘要&#xff1a;企业客服热线正从人工密集向AI驱动转型。本文梳理合力亿捷、华为AICC、科大讯飞、阿里云呼叫中心、竹间智能、青牛软件等主流品牌&#xff0c;从语音识别、话务承接、业务闭环、人机协同等维度展开分析&#xff0c;为选型提供参考。引言&#xff1…

作者头像 李华