当我们赋予 AI Agent 代码仓库的写权限时,一个根本性的问题浮出水面:传统 Git 追踪的是开发者做了什么,而非 Agent 做了什么。Regent(项目名 re_gent)正是为解决这一痛点而生的开源项目 —— 它为 AI 编码 Agent 提供专属的版本控制能力,让变更可追溯、可回滚、可审计。
问题域:从「代码版本」到「行为版本」
传统 Git 的设计目标是记录人类开发者的代码变更,每一行修改都能追溯到具体的提交者和提交信息。然而,当 AI Agent 替代人类执行代码修改时,这套体系立即显现出两个核心缺陷。首先,Git 无法区分同一代码库背后是人类的直接操作还是 Agent 的工具调用 —— 所有变更都被扁平化为统一的「提交」,丢失了关键的上下文信息。其次,当 Agent 执行 /compact 或 /clear 等操作压缩对话历史时,传统的版本控制系统无力恢复这些被丢弃的对话上下文,导致变更的因果链条断裂。
Regent 的设计哲学正是针对这两个问题提出系统性解决方案。它不取代 Git,而是与 Git 互补运行 ——Git 继续负责代码版本的正式发布,而 Regent 专注于捕获 Agent 的每一次工具调用、每一轮对话切片、每一个导致代码变更的 prompt。这种「双轨制」使得开发者既能享受 Git 的协作工作流,又能在 Agent 行为出现异常时快速定位问题根源。
核心抽象:Step 与 DAG 的设计
Regent 借鉴了 Git 的对象模型,但进行了针对性改造。其存储层包含四种核心对象类型:Blob(原始字节内容)、Tree(文件结构快照)、Step(等同于 Git 的提交概念)以及 Ref(可变的命名指针)。每个 Step 记录了父 Step 哈希、当前工作区 Tree 哈希、对话转录哈希、导致变更的工具调用信息(ToolName、ArgsBlob、ResultBlob)以及会话标识符和时间戳。这种设计使得每一次 Agent 工具调用都形成了一个独立的版本节点,而非像 Git 那样需要显式执行 commit 命令。
Step 之间通过 parent 指针形成有向无环图(DAG)。关键设计在于:每个会话拥有独立的分支路径。多个 Agent 并发运行时,各自的会话 ID 作为独立的 Ref 存放在 refs/sessions/ 目录下,从共同的祖先节点分叉出去,自然避免了冲突。这意味着两个 Agent 同时修改同一文件时,Regent 不会像 Git 那样产生合并冲突,而是各自维护完整的变更历史,后续可以通过 rgt rewind 或比对工具进行差异分析。
这种设计带来了一个重要工程属性:并发安全。由于对象存储天然是不可变的(相同内容产生相同哈希),多个会话写入相同内容时不会产生数据竞争。唯一的竞争点在于 Ref 更新,Regent 采用了与 Git 相同的锁文件 CAS(Compare-And-Swap)模式,通过原子创建锁文件并验证预期值来实现无锁更新,配合重试机制处理高并发场景。
变更追踪:从快照到行级归属
Regent 的变更追踪分为两个层次:工作区快照与行级归属。每一 Step 创建时,系统会对当前工作区进行完整快照,生成新的 Tree 对象。这个过程通过遍历项目目录、跳过 .regentignore 指定的模式(如 node_modules、.git、venv 等),并将每个文件内容计算 BLAKE3 哈希后存入对象存储。关键优化在于,由于内容寻址的天然去重特性,未修改的文件不会重复占用存储空间。
行级归属(Blame)是 Regent 区别于传统版本控制的核心能力。其实现采用「写时计算」策略,而非查询时推导。每个 TreeEntry 除了包含文件内容的 Blob 哈希,还包含一个并行的 BlameMap 哈希。BlameMap 是一个数组,索引 i 对应文件的第 i+1 行,值为引入或最后一次修改该行的 Step 哈希。当 Agent 编辑文件时,系统通过 Myers diff 算法比对新旧内容, unchanged 的行继承原有的 Blame 归属,新增或修改的行则标记为当前 Step。这种设计将计算成本摊平到写入时,使得查询阶段的 rgt blame 可以在 10 毫秒内完成。
更关键的是,Blame 信息不仅包含变更的 Step 哈希,还能追溯到具体的工具调用和原始 prompt。当开发者执行 rgt blame src/handler.go:42 时,系统会解析该行对应的 Step,找到导致这次修改的 ToolUseID,然后从 Transcript 链中提取原始的用户请求和 Agent 响应。这意味着开发者可以明确知道「哪一行代码是由哪个 prompt 驱动生成的」,这在调试 Agent 行为时具有极高的价值。
会话与转录:对抗对话压缩
AI Agent 的一个典型操作是使用 /compact 或 /clear 压缩对话历史以节省上下文窗口。这一操作在传统架构下会导致变更上下文永久丢失 ——Git 不知道 Agent 曾经见过什么 prompt,开发者也无法恢复。Regent 通过独立的 Transcript 链解决了这个问题。
Transcript 是一个链表结构,每个节点包含指向前一节点的 Prev 哈希以及一组新消息的 Blob 哈希。每当 Agent 执行工具调用时,Hook 会从 Claude Code 的 JSONL 文件中提取自上次处理以来的新消息切片,将其 canonical 化后存入对象存储,并更新 Transcript 链。即使原始 JSONL 被 /compact 压缩,Regent 内部保存的消息副本仍然完整无损。开发者可以通过 rgt show <step> 查看任意 Step 时刻的完整对话上下文,包括用户提问、Agent 思考过程和工具调用结果。
这还带来一个重要工程意义:Agent 的行为审计变得可能。金融、医疗等合规要求严格的场景下,监管机构可能要求追溯某次自动化代码修改的完整决策链路。Regent 将每一次工具调用的因果关系完整保存,满足了这类审计需求。
多代理协作:分支模型的工程实现
多 Agent 协作场景是 Regent 设计的重要目标。考虑一个工作流中多个 Agent 分别负责代码生成、测试编写、文档更新的情况。传统 Git 需要复杂的分支策略和合并冲突处理,而 Regent 的方案更为优雅:每个 Agent 启动时自动获得一个唯一的会话 ID,该会话从当前 HEAD 分叉,形成独立的变更链。各 Agent 的修改可以随时通过 rgt log --session <id> 单独审查,也可以通过 rgt sessions 汇总查看所有活跃会话的状态。
这种设计的一个工程实践要点在于冲突检测。当多个 Agent 修改同一文件时,Regent 不会自动合并,而是记录各自的变更历史。rgt rewind 命令支持指定目标 Step 并可选地恢复磁盘文件,如果目标文件在目标时刻之后被其他会话修改过,系统会检测到冲突并拒绝执行(除非使用 --force 覆盖)。这种设计将合并决策留给人而非机器,符合版本控制的基本原则。
目前 v0 版本的重点是验证核心三项目标:存储与 Blame 算法、共享工作区上的并发会话、以及对话状态暂存。分支切换、检出(checkout)、工作树(worktree)等高级功能属于 v1 范畴,但底层数据模型已经预留了扩展空间 ——Step 中的 SecondaryParent 字段就是为未来支持子 Agent 合并而设计的。
实践参数与监控要点
对于希望在生产环境集成 Regent 的团队,以下工程参数值得关注。存储方面,默认跳过大于 10 MB 的文件以防止二进制文件的病理情况,可通过配置调整;对象存储采用 BLAKE3 哈希,单线程写入吞吐量可达数百 MB/s。性能方面,POC 阶段的基准目标是 1000 次单行编辑的存储增长不超过原始仓库的 5 倍,Step 写入 p99 延迟低于 100 毫秒,Blame 查询 p99 延迟低于 10 毫秒。SQLite 索引采用 WAL 模式以支持并发读取,但写入操作需要事务包装以保证原子性。
监控层面,应关注 .regent/objects/ 目录的存储增长率 —— 正常情况下每日增长应与 Agent 的代码修改量成正比;refs/sessions/ 下的会话 Ref 数量反映并发 Agent 数;SQLite index.db 的大小可作为查询性能的先行指标,如果超过对象存储的 50% 可能需要考虑重建索引。
总体而言,Regent 为 AI Agent 版本控制提供了一个工程上可行的参考实现。其核心贡献在于将 Git 的版本追踪思想延伸到 Agent 的行为层面,通过 DAG 结构支持并发会话、通过 Transcript 链对抗对话压缩、通过写时 Blame 计算实现可审计的行级归属。这些设计选择并非完美,但对于当前 AI Agent 开发的实际痛点而言,已经提供了足够实用的解决方案。
资料来源:Regent 官方 GitHub 仓库(https://github.com/regent-vcs/re_gent)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。