Agent上下文管理新思路:用文件系统抽象解决大模型“失忆”难题
写技术教程最怕两件事:一是概念讲得云里雾里,二是代码拿回去跑不通。之前在业务里接触 Agent 开发时,一直觉得上下文管理是个“玄学”——明明对话记录都在,模型却总是“失忆”;明明上下文窗口还有余量,运行效率却直线下降。后来看到 OpenViking 这类把 Agent 上下文设计成文件系统的思路,才意识到问题的本质:我们一直在用“对话流”的方式管理上下文,但真正需要的其实是“文件系统”式的组织能力。
这篇文章就围绕 OpenViking 的核心思想展开,讲清楚为什么 Agent 上下文需要文件系统抽象、它的目录结构怎么设计、读写语义怎么定义,以及怎样在真实工程中落地上层。文章会给出可运行的示例代码,也会把常见的坑整理成排查清单,适合正在做 Agent 开发、研究 AI 编程助手上下文管理、以及想了解上下文工程(Context Engineering)的开发者阅读。
1. 背景与核心概念
1.1 Agent 上下文到底是什么
我们先从最基础的问题说起:Agent 上下文到底是什么?
从大模型应用的角度看,Agent 上下文是模型在某一轮推理过程中可以访问的全部信息。它不只是用户和助手之间的聊天记录,还包括:
- 系统提示词(System Prompt)中定义的规则、人格、工作流。
- 用户在当前会话中提供的输入。
- Agent 调用工具后返回的结果。
- 模型自己生成的中间推理过程(Chain of Thought)。
- 从外部存储、数据库、知识库中检索到的片段。
- 代码仓库中的文件内容、执行环境的状态、前端页面结构等环境信息。
也就是说,上下文是 Agent 的“工作台”,是它思考和行动的依据。
在传统软件工程里,程序的状态可以通过变量、数据库、文件持久化来保存。但大模型 Agent 不一样,它每一次推理都要把相关信息塞进上下文窗口。窗口越大,能塞的东西越多,但同时也会带来两个问题:
- 成本增加:Token 越多,API 调用费用越高。
- 效果下降:上下文过长时,模型对中间信息的关注度会衰减,出现“迷失在中间”(Lost in the Middle)现象。
所以 Agent 上下文管理,本质上是在做“如何在有限窗口内,保留最有价值的信息”这件事。
1.2 上下文管理的经典痛点
做过 Agent 开发的读者,应该都经历过下面这些场景:
场景一:新开会话丢失记忆
用户在使用一个 AI 编程助手时,刚写完一段核心逻辑,然后新开了一个会话,结果助手完全不记得之前的代码了。原因很简单——会话结束了,上下文没有持久化。这是当前很多 Agent 工具的通病。
场景二:上下文过大,自动总结也没用
对话进行了几十轮,程序不断调用自动总结功能,把前面的内容压缩成摘要。但总结本身也占 Token,而且总结过程中可能丢失细节。最常见的结果是:
Context length exceeded. Please start a new conversation.
有些框架里会报错,比如类似 “The agent execution provider did not respond in time”,本质都是上下文或者执行链路超过了处理边界。
场景三:上下文压缩导致信息失真
自动总结确实能压缩篇幅,但它不是无损的。比如前面有用户明确指定的一个技术选型:“不要用 Spring Security,用自研过滤器”,压缩后可能就变成了“用户对权限方案有要求”,细节全没了。Agent 后续的行为就会偏离用户预期。
场景四:多个上下文之间难以协同
一个大型 Agent 项目可能包含多个子 Agent:负责代码生成的、负责测试的、负责文档的。每个子 Agent 都有自己的上下文,但它们之间如何共享信息?目前大多数方案的答案是:没有方案,各自为战。
这些痛点的共同根源是:上下文被当作“一条流”,而不是“一组有结构的数据”。
1.3 为什么选择“文件系统”作为抽象
文件系统(File System)是操作系统中用于管理持久化数据的机制。Linux、Windows、macOS 都有文件系统,它们负责把数据组织成文件和目录,并提供统一的访问接口。
如果把 Agent 上下文比作数据,那么我们很自然地会想到一个问题:能不能用文件系统的方式来管理上下文?
OpenViking 的核心思路正是如此。它把 Agent 的上下文建模成一个虚拟文件系统,上下文中的每一项信息都可以映射为一个文件或一个目录,并通过路径(Path)来寻址。
这种设计带来的价值非常明显:
-
统一寻址 所有上下文条目都有固定路径,例如
/memory/user_preference.md、/workspace/code/main.py。Agent 可以通过路径精准读写,不需要在冗长的对话流里搜索。 -
支持增量更新 文件系统支持按需读取。Agent 不需要把整个上下文读进来,只需要读取当前任务对应的目录或文件。这天然解决了上下文过大的问题。
-
天然持久化 文件系统本身就是持久化存储。Agent 的任务执行完,上下文可以落盘(Sync),下次启动时自动挂载(Mount),会话记忆不会因为窗口关闭而消失。
-
灵活的信息组织 目录天然支持层级分类,可以把工作区、用户偏好、工具缓存、对话历史分开管理。不同的 Agent 还可以通过目录权限隔离,避免互相污染。
-
兼容现有工具链 文件系统的概念已经存在几十年,开发者熟悉
ls、cat、grep这些操作。如果 Agent 的上下文可以通过类文件系统接口操作,那么自定义工具、脚本、CI/CD 流程都可以复用现有经验。
这里需要区分一个容易混淆的概念:OpenViking 不等于“把上下文保存成磁盘上的文件”。它做的是一种抽象层,底层可能确实使用磁盘文件,也可能使用数据库、内存或对象存储,但对上层暴露的是文件系统的语义。就像 Linux 的 VFS(Virtual File System)一样,它屏蔽了不同底层存储的差异,对外提供统一的文件操作接口。
2. 环境准备与版本说明
2.1 运行环境
本文的示例代码基于 Python 3.9+ 编写,不依赖第三方框架,核心逻辑使用标准库即可运行。操作系统方面,Windows、macOS、Linux 都可以,但如果你希望在本地体验“挂载目录、查看文件数”这类操作,建议使用 Linux 或 macOS,体验更贴近文件系统语义。
依赖项:
- Python 3.9 或更高版本。
- 操作系统自带文件系统权限(用于演示本地目录读写)。
- 如果希望接入大模型 API,需要准备对应的 API Key;但本文的核心示例不强制调用模型,只演示上下文文件系统的构建与检索。
版本说明:OpenViking 目前还处于快速迭代阶段,不同版本的 API 可能有差异。本文的代码以“思路 + 可运行示例”的方式呈现,重点帮助你理解设计模式。真正接入具体项目时,需要根据你使用的版本调整包名和调用方式。
2.2 需要掌握的基本概念
在开始写代码之前,先约定几个文件系统领域的术语,方便后文阅读。
| 术语 | 含义 | 在上下文文件系统中的对应 |
|---|---|---|
| Mount(挂载) | 将一个文件系统连接到某个目录下 | 加载 Agent 历史上下文到当前会话 |
| Path(路径) | 文件或目录在文件系统中的位置 | 上下文条目的唯一地址 |
| Directory(目录) | 用于组织文件的容器 | 上下文的分类,如工作区、记忆 |
| File(文件) | 存储具体数据的单元 | 一条具体上下文,如一段对话 |
| Read(读) | 从文件获取数据 | 将某部分上下文放入提示词 |
| Write(写) | 将数据保存到文件 | 新增或更新上下文 |
| Sync(同步) | 将内存中的变更持久化 | 将上下文快照写回存储 |
| Snapshot(快照) | 某一时刻的完整状态 | 上下文版本备份 |
理解这些概念后,我们进入核心原理拆解环节。
3. 核心原理拆解:上下文文件系统的设计思路
3.1 挂载点:上下文从哪里来
在 Linux 中,
mount
命令将一个块设备或远程文件系统挂载到某个目录。在 OpenViking 的设计中,挂载点就是 Agent 上下文的“根目录”。
假设我们定义根目录为
/ctx
,那么 Agent 的上下文都从这个根目录开始寻址。第一次启动时,根目录可能为空;如果是恢复上一次会话,Agent 会从持久化存储中读取快照并恢复整个目录结构。
示例流程:
- Agent 启动。
- 检查是否有历史快照。
- 如果没有,创建空目录树;如果有,从快照恢复。
-
将工作目录挂载到
/ctx/workspace。 -
加载用户偏好到
/ctx/memory/user_profile.md。 -
加载系统提示词到
/ctx/system/prompt.md。
这个过程非常像 IDE 打开一个项目:先恢复上次的工作区状态,再加载各类配置文件。
3.2 目录结构:上下文的分层组织
一个合理的上下文文件系统应该按“关注点”划分目录,而不是按时间线平铺。下面是一棵推荐的目录树:
/ctx
├── system/ # 系统级上下文,Agent 运行规则
│ ├── prompt.md # 主系统提示词
│ ├── tools.md # 工具描述说明
│ └── skills/ # 技能定义
│ ├── coding.md
│ └── testing.md
├── memory/ # 长期记忆,跨会话保留
│ ├── user_profile.md # 用户偏好与画像
│ ├── decisions.md # 项目中做过的关键决策
│ └── facts/ # 领域事实
├── workspace/ # 当前任务工作区,短期上下文
│ ├── code/ # 源代码文件
│ ├── data/ # 数据文件
│ └── output/ # 输出结果
├── session/ # 当前会话相关的中间状态
│ ├── plan.md # 当前执行计划
│ ├── progress.md # 已完成/待办状态
│ └── cache/ # 临时缓存
└── logs/ # 运行日志与审计
├── actions.log
└── tokens.log
这个设计有几点考虑:
- system 和 memory 属于高频引用内容,可以常驻上下文窗口或按需加载。
- workspace 属于任务相关内容,任务结束后可以归档或清理。
- session 是易变状态,每次会话都会重写。
- logs 用于审计和调试,不参与模型推理。
通过这种分层,Agent 可以快速确定“当前任务需要加载哪些目录”,而不是把所有内容一股脑塞进提示词。
3.3 读写语义:open / read / write / close
文件系统最核心的操作是打开、读取、写入、关闭。OpenViking 把这种语义搬到了上下文管理中。
下面是一个伪代码级的设计示例:
# 文件路径:context_fs.py
class ContextFile:
def __init__(self, path: str, content: str = ""):
self.path = path
self.content = content
self.is_open = False
def open(self):
self.is_open = True
return self
def read(self) -> str:
if not self.is_open:
raise RuntimeError("File is not open")
return self.content
def write(self, data: str):
if not self.is_open:
raise RuntimeError("File is not open")
self.content = data
def append(self, data: str):
if not self.is_open:
raise RuntimeError("File is not open")
self.content += data
def close(self):
self.is_open = False
在这个设计中,
open
类似于把上下文文件“加载到内存”,
read
返回内容用于拼进 Prompt,
write
更新内容,
close
释放句柄。如果 Agent 只读取了几个文件,那么这几个文件的内容才是本轮推理的上下文。
这与传统的对话式上下文管理最大的区别在于:传统方式通常会一次性把所有历史消息发送给模型,而文件系统方式允许按路径精确选择要发送的内容。
3.4 同步与落盘:sync 的意义
文件系统里有一个重要概念叫“脏页”,即内存中被修改但尚未写入磁盘的数据页。
sync
命令的作用就是把脏页写入磁盘,防止断电丢数据。
上下文文件系统同样需要同步机制。Agent 在一轮推理中可能会写入很多临时信息,这些信息最初保存在内存中,风险是:
- 进程崩溃后,所有临时上下文丢失。
- 模型上下文窗口清理后,未持久化的数据无法找回。
- 多个 Agent 之间无法共享内存中的数据。
引入
sync
操作后,Agent 可以在关键节点主动持久化。比如:
-
每完成一个子任务,执行一次
sync。 -
在调用外部工具前
sync,防止工具运行失败导致状态丢失。 -
在会话结束时强制
sync,保存完整快照。
类比 Linux VFS,OpenViking 的设计可以理解成:上层提供统一的
sync
抽象,底层可能调用本地磁盘、远程存储或数据库的写入接口。这一层抽象让上下文管理变得可插拔。
3.5 快照与版本回滚
文件系统的另一个优势是支持快照。快照是文件系统在某个时间点的完整副本,可以用来回滚。
在 Agent 项目中,快照的价值体现在:
- 如果 Agent 执行了一系列错误操作(比如改坏了代码),可以回退到执行前的上下文状态。
- 如果自动压缩上下文时丢失了细节,可以回到压缩前的快照重新压缩。
- 如果调试时发现某个决策有误,可以查看当时上下文快照来定位原因。
快照不需要做完所有变更,建议采用“关键节点 + 定期”的策略。
4. 完整实战案例:用文件系统管理 Agent 上下文
这一节我们实现一个简化版的上下文文件系统。它包含以下能力:
- 创建目录结构和基础文件。
- 按路径读取上下文。
- 增量写入上下文。
- 将内存状态同步到磁盘。
- 创建快照。
- 根据关键词检索上下文。
代码可以独立运行,不需要连接任何大模型 API。
4.1 定义上下文文件系统类
# 文件路径:context_vfs.py
import os
import json
import shutil
from datetime import datetime
from pathlib import Path
class ContextFile:
"""上下文文件,对应文件系统中的一个文件"""
def __init__(self, path: str, content: str = ""):
self.path = path
self.content = content
self.is_open = False
def open(self):
self.is_open = True
return self
def read(self) -> str:
if not self.is_open:
raise RuntimeError(f"File {self.path} is not open")
return self.content
def write(self, data: str):
if not self.is_open:
raise RuntimeError(f"File {self.path} is not open")
self.content = data
def append(self, data: str):
if not self.is_open:
raise RuntimeError(f"File {self.path} is not open")
self.content += data
def close(self):
self.is_open = False
def to_dict(self):
return {"path": self.path, "content": self.content}
class ContextVFS:
"""简化版上下文文件系统"""
def __init__(self, root: str = "/ctx"):
self.root = root
self.files = {}
self.dirty = set()
self._init_default_tree()
def _init_default_tree(self):
"""初始化默认目录结构"""
default_files = {
"/ctx/system/prompt.md": "你是专业的技术开发助手。",
"/ctx/system/tools.md": "可调用工具列表:代码搜索、文件读写、命令执行。",
"/ctx/memory/user_profile.md": "用户偏好:Python 技术栈,注重代码可读性。",
"/ctx/memory/decisions.md": "关键决策记录:使用 SQLite 存储元数据。",
"/ctx/workspace/code/main.py": "# 主程序入口\n",
"/ctx/session/plan.md": "当前计划:实现上下文文件系统。",
"/ctx/session/progress.md": "已完成:目录设计。\n待办:编码实现。",
}
for path, content in default_files.items():
self.files[path] = ContextFile(path, content)
def open(self, path: str) -> ContextFile:
"""打开文件,如果文件不存在则创建空文件"""
if path not in self.files:
self.files[path] = ContextFile(path, "")
return self.files[path].open()
def read(self, path: str) -> str:
f = self.open(path)
try:
return f.read()
finally:
f.close()
def write(self, path: str, data: str):
f = self.open(path)
try:
f.write(data)
self.dirty.add(path)
finally:
f.close()
def append(self, path: str, data: str):
f = self.open(path)
try:
f.append(data)
self.dirty.add(path)
finally:
f.close()
def list_dir(self, path: str = "/ctx") -> list:
"""列出某个目录下的文件与子目录"""
prefix = path.rstrip("/") + "/"
result = set()
for p in self.files:
if p.startswith(prefix):
relative = p[len(prefix):]
top = relative.split("/")[0]
result.add(top)
return sorted(result)
def search(self, keyword: str) -> list:
"""按关键词搜索上下文内容"""
hits = []
for path, f in self.files.items():
if keyword in f.content:
hits.append(path)
return hits
def sync(self, base_dir: str = "./ctx_disk"):
"""将内存中的上下文同步到磁盘"""
os.makedirs(base_dir, exist_ok=True)
for path, f in self.files.items():
# 将 /ctx/system/prompt.md 转为 ./ctx_disk/system/prompt.md
relative = path.lstrip("/")
disk_path = Path(base_dir) / relative
disk_path.parent.mkdir(parents=True, exist_ok=True)
disk_path.write_text(f.content, encoding="utf-8")
self.dirty.clear()
print(f"[sync] 已同步 {len(self.files)} 个文件到 {base_dir}")
def snapshot(self, snapshot_dir: str = "./ctx_snapshots"):
"""创建当前上下文快照"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
target = os.path.join(snapshot_dir, f"snapshot_{timestamp}")
os.makedirs(target, exist_ok=True)
for path, f in self.files.items():
relative = path.lstrip("/")
disk_path = Path(target) / relative
disk_path.parent.mkdir(parents=True, exist_ok=True)
disk_path.write_text(f.content, encoding="utf-8")
print(f"[snapshot] 快照已保存到 {target}")
return target
def export_meta(self, path: str = "./ctx_meta.json"):
"""将上下文元数据导出为 JSON,便于其他工具消费"""
meta = {
"root": self.root,
"file_count": len(self.files),
"total_chars": sum(len(f.content) for f in self.files.values()),
"files": [f.to_dict() for f in self.files.values()],
}
with open(path, "w", encoding="utf-8") as fp:
json.dump(meta, fp, ensure_ascii=False, indent=2)
print(f"[meta] 元数据已导出到 {path}")
if __name__ == "__main__":
vfs = ContextVFS()
print("=== 初始目录结构 ===")
for item in vfs.list_dir():
print(f"/ctx/{item}")
print("\n=== 读取用户偏好 ===")
print(vfs.read("/ctx/memory/user_profile.md"))
print("\n=== 追加一条执行记录 ===")
vfs.append("/ctx/session/progress.md", "\n新增:写入上下文 VFS。")
print(vfs.read("/ctx/session/progress.md"))
print("\n=== 搜索包含“文件系统”的文件 ===")
for hit in vfs.search("文件系统"):
print(hit)
print("\n=== 同步到磁盘 ===")
vfs.sync()
print("\n=== 创建快照 ===")
vfs.snapshot()
运行这个脚本,预期输出如下:
=== 初始目录结构 ===
system
memory
workspace
session
=== 读取用户偏好 ===
用户偏好:Python 技术栈,注重代码可读性。
=== 追加一条执行记录 ===
已完成:目录设计。
待办:编码实现。
新增:写入上下文 VFS。
=== 搜索包含“文件系统”的文件 ===
/ctx/workspace/code/main.py
/ctx/session/plan.md
=== 同步到磁盘 ===
[sync] 已同步 8 个文件到 ./ctx_disk
=== 创建快照 ===
[snapshot] 快照已保存到 ./ctx_snapshots/snapshot_20250101_120000
4.2 生成 Prompt:只选择必要上下文
有了文件系统,我们可以按需生成 Prompt。下面这个示例展示如何只选取“系统提示词 + 用户偏好 + 当前计划”三条信息来组织 Prompt,而不是把整个上下文全部发送给模型。
# 文件路径:build_prompt.py
from context_vfs import ContextVFS
def build_prompt(vfs: ContextVFS, task: str) -> str:
sections = []
system_prompt = vfs.read("/ctx/system/prompt.md")
sections.append(f"[系统指令]\n{system_prompt}")
tools = vfs.read("/ctx/system/tools.md")
sections.append(f"[可用工具]\n{tools}")
user_profile = vfs.read("/ctx/memory/user_profile.md")
sections.append(f"[用户偏好]\n{user_profile}")
plan = vfs.read("/ctx/session/plan.md")
sections.append(f"[当前计划]\n{plan}")
sections.append(f"[本次任务]\n{task}")
return "\n\n".join(sections)
if __name__ == "__main__":
vfs = ContextVFS()
prompt = build_prompt(vfs, "请实现一个上下文检索工具")
print(prompt)
执行后,模型收到的上下文是高度结构化的,而不是一长串无差别聊天记录。这个思路也是 AI Agent 开发中“上下文工程(Context Engineering)”的核心——不是把所有东西都交给模型,而是精心设计交给模型的内容。
4.3 上下文压缩与恢复
当某个上下文文件过大,比如对话历史累积到几万字,我们可以对它做压缩,并保留原始快照以便恢复。
# 文件路径:compress_context.py
import re
from context_vfs import ContextVFS
def compress_content(content: str, max_lines: int = 100) -> str:
"""简化的上下文压缩:保留头尾,中间摘要化"""
lines = content.strip().splitlines()
if len(lines) <= max_lines:
return content
head = lines[: max_lines // 2]
tail = lines[-max_lines // 2:]
# 统计中间被折叠的行数
folded_count = len(lines) - max_lines
summary = [
f"\n[中间 {folded_count} 行已折叠]",
"摘要:对话主体部分被自动压缩,如需完整内容请读取原始快照。",
]
return "\n".join(head + summary + tail)
if __name__ == "__main__":
vfs = ContextVFS()
# 模拟一个非常大的会话日志
long_log = "\n".join([f"第 {i} 行:用户输入与模型回复的详细内容" for i in range(1, 300)])
vfs.write("/ctx/session/chat.log", long_log)
# 压缩前
original = vfs.read("/ctx/session/chat.log")
print(f"压缩前行数:{len(original.splitlines())}")
# 创建快照
snapshot_dir = vfs.snapshot()
# 压缩并写回
compressed = compress_content(original, max_lines=60)
vfs.write("/ctx/session/chat.log", compressed)
print(f"压缩后行数:{len(compressed.splitlines())}")
# 同步到磁盘
vfs.sync()
这里的关键点是:压缩不是覆盖原文件,而是先生成快照,再写压缩版本。一旦 Agent 需要查看被折叠的细节,可以从快照目录中恢复原始日志。这种“先快照、再压缩”的方式,比直接在上下文窗口里强制截断要安全得多。
5. 常见问题与排查思路
在实现和使用上下文文件系统时,会遇到下面几类典型问题。我们整理成表格,方便快速定位。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| Agent 启动时恢复上下文失败 | 快照目录不存在或快照文件损坏 | 检查快照路径是否存在,校验快照元数据,考虑保留最近 N 份快照 |
| 不同会话之间内存状态冲突 | 多个 Agent 实例同时读写同一路径 |
在路径上添加命名空间或会话 ID,如
/ctx/session/{session_id}/
|
| 上下文文件越来越大 | 长期追加日志,但没有归档策略 |
设计归档任务:旧日志移入
/ctx/logs/archive/
,主文件保持精简
|
| 压缩后上下文丢失关键细节 | 压缩策略太激进,直接截断 | 先创建快照再压缩;压缩时保留头部规则和尾部最新状态 |
| Agent 读取了无用上下文导致 Token 超限 | Prompt 构建时没有按需选择 |
用
read
精确指定文件,而不是一次性读取整个目录列表
|
| 同步到磁盘后元数据不一致 | 只同步了文件内容,没有同步文件索引 |
同时导出 JSON 元数据文件(如
export_meta
),再做校验
|
| 目录结构混乱,开发人员看不懂 | 没有约定目录规范 | 在团队内统一上下文目录规范,像约定代码工程结构一样约定上下文结构 |
| 并发写文件时互相覆盖 | 多个协程或 Agent 同时写入同一个文件 | 引入文件锁,或者按任务拆分到不同子目录 |
下面单独说一下最麻烦的“上下文过大导致 Agent 报错终止”的场景。
典型报错现象是:
Agent terminated due to error. You can prompt the model to try again or start a new conversation.
这类错误通常不是因为模型能力不足,而是执行链路中某一环超出了限制。排查顺序建议如下:
- 查看日志,确认是上下文长度超限,还是工具执行超时。
- 如果上下文超限,统计当前 Prompt 实际包含的 Token 量,找出占用最大的文件。
- 将占用大的文件拆分成多个小文件,并在 Prompt 中按任务选择性加载。
- 为历史会话开启快照,然后对旧日志进行压缩归档。
- 重跑任务,观察错误是否消失。
这里要强调一个原则:不要等到 Agent 报错才处理上下文,而是在 Agent 每轮执行结束后主动做同步和清理。文件系统的意义不在于“出了问题能修复”,而在于“通过结构化管理,从源头避免问题发生”。
6. 最佳实践与工程建议
6.1 路径命名规范
上下文文件系统的路径就是上下文的“地址”,命名规范非常重要。
推荐以下规范:
-
目录使用小写字母,多个单词用下划线连接,如
user_profile。 -
文件使用小写字母和点号,如
prompt.md、session.log。 -
临时文件统一放在
/ctx/session/cache/,不要散落在根目录。 -
长期记忆统一放在
/ctx/memory/,和短期工作区严格分离。 -
涉及多个版本的内容,在文件名中标注版本号,例如
plan_v2.md。
一个清晰的命名规范,能让 Agent 在检索时更快地命中目标,也能让调试时人更容易理解目录结构。
6.2 按需加载,而非全量加载
这是上下文文件系统最核心的价值。每次构建 Prompt 之前,应该先明确一个问题:
当前这个任务,模型需要知道哪些信息?
通常 Agent 的任务可以拆成多个子任务,每个子任务只加载自己需要的上下文目录。比如:
-
代码生成任务:加载
/ctx/workspace/code/、/ctx/memory/decisions.md。 -
测试任务:加载
/ctx/workspace/test/、/ctx/system/tools.md。 -
文档任务:加载
/ctx/workspace/docs/、/ctx/memory/user_profile.md。
通过按需加载,可以把原本需要 50k Token 的上下文降低到 10k 甚至更少,同时模型关注度更高,输出质量更好。
6.3 关键节点自动同步
建议在以下时机触发
sync
:
- 子任务完成后。
- 调用外部工具前。
- 从外部 API 返回结果后。
- Agent 会话结束前。
- 压缩上下文之前。
同步操作可能有一定的性能开销,所以不需要每一条消息都同步。重点保证“关键状态不丢失”。
6.4 快照策略
快照是回滚的保障,但不建议每次都全量快照。推荐的策略是:
- 每次会话结束时创建一次快照。
- 执行高风险操作(如修改代码、删除文件、发布配置)前创建快照。
- 设置快照保留数量,比如保留最近 20 份,防止磁盘膨胀。
-
在快照目录下附带一份
meta.json,记录快照对应的任务和时间。
6.5 安全与权限意识
上下文文件系统中可能包含敏感信息,比如用户密钥、数据库密码、内部 API 地址。需要注意:
-
敏感信息放在独立目录,比如
/ctx/secret/,并在默认 Prompt 构建时排除。 - 给不同 Agent 分配不同目录权限,不要所有 Agent 共享同一份完整上下文。
- 在日志中避免打印完整密钥,脱敏后再输出。
- 当上下文文件需要跨环境传输时,先检查是否包含敏感字段。
权限思维在 Agent 开发中常常被忽略。一个子 Agent 本来只应该访问测试环境的配置,但如果上下文是全量共享的,它就可能把生产环境的密钥也读进窗口,带来安全风险。
6.6 与现有 Agent 框架的集成思路
OpenViking 这类上下文文件系统,可以嵌入到常见的 Agent 开发框架中。一段典型的集成逻辑是:
# 文件路径:agent_integration.py
from context_vfs import ContextVFS
class AgentEngine:
def __init__(self):
self.vfs = ContextVFS()
self.model_client = None # 假设接入某个大模型客户端
def run_task(self, task: str):
# 1. 从上下文文件系统构建 Prompt
prompt = self.build_prompt(task)
# 2. 调用模型
response = self.model_client.chat(prompt)
# 3. 将模型输出写回上下文
self.vfs.append("/ctx/session/chat.log", f"\n用户:{task}\n助手:{response}")
# 4. 同步到磁盘
self.vfs.sync()
return response
def build_prompt(self, task: str) -> str:
system_prompt = self.vfs.read("/ctx/system/prompt.md")
plan = self.vfs.read("/ctx/session/plan.md")
return f"{system_prompt}\n\n{plan}\n\n任务:{task}"
这样,Agent 的上下文不再是隐形的“临时变量”,而是一个可以随时检查、恢复、迁移的持久化系统。
7. 总结
OpenViking 的核心思想并不复杂:把 Agent 上下文从“对话流”变成“文件系统”。这一抽象带来了四个直接收益:上下文可以按路径精确读取,避免 Token 浪费;上下文可以持久化同步,解决新会话丢失记忆的问题;上下文可以用快照回滚,降低自动压缩带来的风险;上下文可以分层组织,支持多 Agent 协作和权限隔离。
从工程角度看,理解上下文文件系统,本质上是在理解“上下文工程”的落地方式。无论是做 AI 编程助手,还是开发通用 Agent 框架,都需要认真思考一个问题:模型该看到什么,不该看到什么,以及这些信息如何被持久化、检索、压缩和恢复。
建议下一步从三个方面继续深入:第一,研究 Linux VFS 的实际实现,理解文件系统抽象层是怎么处理性能与一致性的;第二,调研主流 Agent 框架(如 Claude Code、各类 Agent harness)是如何管理上下文的,对比它们的优劣;第三,动手改造一个小型 Agent 项目,把上下文结构调整成目录树,并加上同步和快照机制。
如果这篇文章对你有帮助,可以收藏备用。你在做 Agent 开发时遇到过哪些上下文相关的问题?欢迎在评论区分享,大家一起讨论解决方案。
更多推荐



所有评论(0)