- 人工智能
- AI Agent
- 深度研究
- 自主智能体
- Agent 编排
【免费下载链接】OpenResearch
Turn your coding agents into research agents
OpenResearch(orx)把 Git 当作"实验历史的数据库":每一个实验节点都对应一条本地orx/<slug>分支,每一次运行都从这条分支的已提交 commit 构建不可变源码归档,GitHub 发布仅用于协作者可见性、从不参与计算传输。本文以agent-skills/orx-git/SKILL.md为骨架,结合仓库源码(src/local/git.rs、src/local/experiments.rs、src/compute.rs、src/local/localrun.rs等)深入讲解会话工作树模型、分支协作规则、提交即运行机制、父子实验对比以及"历史不可变"纪律。读完后,你将能在多 Agent 并行会话中安全地操作实验代码、避免重复劳动与分支冲突,并能准确理解"已提交内容才是可复现结果"这条底层契约。
一、核心原则:Git 记录实验,但 Git 不是计算传输通道
orx-git技能的第一条纪律是定位问题:
- Git 记录每一个实验:分支与提交是实验节点事实状态的唯一来源,任何一次运行都要能精确回溯到"跑的是哪一段代码"。
- GitHub 发布是可选项:发布(publication)可能被启用,目的是让协作者看到进展,它绝不参与计算传输(compute transport)。计算后端拿到的是从已记录 commit 构建出的源码归档,而不是远程仓库。
- 遵守项目 playbook 的发布状态:不要仅仅为了启动计算而
push;同时不要从论文的上游仓库fetch,也不要把结果发布回论文的上游仓库——实验仓库与论文源仓库是两个互相隔离的宇宙。
这一原则在源码里被反复落实。例如 src/local/git.rs 中的github_publication与remote_matches_publication会检查github、origin、upstream三个 remote 的 fetch/push URL 是否都指向项目声明的owner/repo,只有完全匹配才算"发布已配置";而 src/compute.rs 的模块注释则直接写明:本地 Git 是实验历史数据库,启动运行时"绝不要求远端后端克隆这段历史,而是把精确记录的 commit 归档一次、按 SHA-256 寻址、交给选定的提供方适配器"。计算传输的单元是内容寻址的源码归档,不是 git clone。
二、多会话协作模型:同一克隆上的兄弟工作树
2.1 会话工作树从哪来
在orx up的本地会话中,每个聊天会话(chat session)都工作在同一个克隆的**兄弟工作树(sibling worktree)**里。源码层面,src/local/git.rs 给出了目录约定:
- 共享克隆:
<data>/repos/<owner>/<repo> - 会话工作树:
<data>/worktrees/<project_id>/<session_id>
ensure_session_worktree(src/local/git.rs)的注释精确描述了这套设计的收益:工作树共享 hub 的对象存储和 refs——在一个工作树里创建的分支,其他所有工作树立即可见;一次fetch更新所有人;git 本身会拒绝在两个工作树同时检出同一个分支。这正是技能文档要求"开工前先勘察现场"的原因。
2.2 开工前的现场勘察
因为其他会话可能正在同一个克隆的兄弟工作树里工作,动手前必须先回答"别人在做什么":
# 查看所有分支(本地 + 远端跟踪),了解谁占了哪些 orx/<slug> git branch -a # 查看项目最近运行记录,避免重复跑已经回答过的问题 orx runs <projectId> # 查看相关实验节点的备注,读取兄弟会话留下的上下文 orx exp desc <expId>orx runs <projectId>的实现见 src/commands/runs.rs,它把项目运行记录渲染成表格(含状态、时长、commit 短 SHA)。orx exp desc <expId>支持--set "<text>"写备注、cat notes.md | orx exp desc <expId> --stdin从文件灌入,实现位于 src/plane/local_plane.rs。技能强调"边学边记":让实验备注保持最新,兄弟会话才能据此定位。
2.3 一分支一 owner:检出冲突的处理规则
分支和 remote 是共享的,工作树目录是私有的。因此一条分支只有一个工作树 owner:
- 如果
git checkout报"branch is already checked out",只有当错误信息里列出的路径就是你自己的工作树时才继续操作; - 否则,把那条分支留给它的 owner 会话,不要抢占。
这背后是 git worktree 的硬约束:同一分支只能在一个工作树中被检出。正是利用这一点,OpenResearch 才能放心让多个 Agent 并行——冲突在 git 层就被拒之门外。
2.4 工作树以 detached 状态起步
会话工作树默认从 baseline 以 detached HEAD 起步(src/local/git.rs 的注释:直接检出 baseline 分支本身会"认领"它、堵死所有兄弟会话),所以:
- 进入会话后第一件事是
git checkout orx/<slug>切到自己的实验分支; - 在编辑之前完成切换,避免把改动落在游离的 HEAD 上。
底层命令是git worktree add --detach <path> <start_ref>(见ensure_worktree_from,src/local/git.rs),start_ref 默认取项目的 baseline 分支。这也是为什么技能里说"check out the experiment branch before editing"。
三、一个实验节点 = 一条 orx/ 分支
3.1 分支如何创建
每个实验节点都有自己的一条本地orx/<slug>分支。orx create-experiment负责从父节点创建它:
orx create-experiment <projectId> --title "<title>" [--parent <experimentId>] [--description "<text>"] [--run-command "<cmd>"]用法定义在 src/commands/create_experiment.rs,形状选择规则见该文件头部注释:
--parent <id>→ 从该父实验分支出去的子实验;--baseline→ 新建一条 baseline(根节点),项目可持有多个 baseline;- 不带参数 → 取项目最老的根节点(树为空时新建 baseline)。
slug由标题派生并去重。实现位于 src/local/experiments.rs:unique_slug扫描项目里所有已有实验的 slug 与全部本地分支的orx/前缀,生成base、base-2、base-3…… 这样第一个可用值;随后用git branch --no-track <new> <parent>(src/local/git.rs)从父分支的本地 tip拉出orx/<slug>。注意--no-track:实验分支不绑定上游跟踪,避免与远端发布互相干扰。
3.2 标准工作流:编辑 → 提交
在每个会话工作树里,只做"这一个实验"的改动,然后:
git checkout orx/<slug> git status --short # 确认起点干净 git add <changed files> git commit -m "describe the experiment change"提交信息应当描述实验变更本身(如调整的学习率、换用的数据集、修改的损失函数),而不是泛泛的 "update"。
3.3 边界情况:baseline 之前的老根实验
源码里还处理了一个历史遗留问题:src/local/experiments.rs 的legacy_root_warning会警告:在 baseline 拥有自己的orx/*分支之前创建的根实验,是骑在项目 base 分支上的。遇到这类节点时把它当作"base 分支上的根实验"处理,不要误解成"分支丢失"。
四、提交即运行:不可变源码归档
4.1 运行只认已提交的 commit
runner 从记录的 commit 构建不可变源码归档(immutable source archive),已提交的内容在所有后端上都是充分的(sufficient)。未提交的文件永远不会被包含进一次运行。
具体机制在 src/compute.rs 的SourceSnapshot::create:
- 用
git rev-parse取实验分支的 HEAD 作为revision(local_head_sha,见 src/local/git.rs); - 调用
git archive --format=tar <revision>(archive函数,src/compute.rs)把该 commit 的完整树打成 tar; - 对 tar 计算 SHA-256 摘要,按
<digest>.tar内容寻址存放于<data>/source-snapshots/,权限收紧到 0600/0700; - 运行记录里写入
commit_sha(StoredRun.commit_sha,见 src/local/localrun.rs)。
因为快照按内容寻址,同样的代码只归档一次;install_content_addressed(src/compute.rs)还会在复用缓存时做 digest+size 双校验,防止缓存被篡改。运行侧的脚本(snapshot_script,src/compute.rs)则是:
set -eo pipefail; mkdir -p repo; tar -xf <archive> -C repo; cd repo; <run-command>即:从归档解出精确的 commit 树,在独立的运行目录里执行,绝不动 Agent 的工作树(src/local/localrun.rs 的注释:"the run extracts the recorded revision into its own run dir, never the agent's worktree")。远程后端同理——src/local/k8s.rs 的注释强调代码"在记录的 revision 上被读取,与 job 收到的 commit 完全一致"。这也解释了为什么每个后端(HF、Modal、K8s、Ray、Slurm、SSH、OpenResearch、Local/Tinker)的启动代码里都带着source_digest/source_path字段(见 src/jobs/mod.rs 与各src/local/*.rs的BackendDescriptor构造)。
4.2 启动前检查
因此,在启动一次运行之前,务必确认:
git status --short # 必须为空:未提交改动不会进运行 git show --stat --oneline HEAD # 核对将要被归档的 commit 内容git show --stat --oneline HEAD让你在按下运行键之前,用眼睛确认"将要运行的就是这条提交"。一次干净的git status --short+ 一条符合预期的git show,是"我的运行是可复现的"的最小证明。
4.3 备注信息与运行命令的继承
orx exp desc <expId>的备注、--run-command都会随节点保存;运行命令解析遵循"实验自带 > 项目默认"的优先级(src/local/localrun.rs、src/local/experiments.rs)。运行记录(StoredRun)里同时保存了commit_sha、command、status等,供orx runs与orx exp status <expId>展示(后者会打印"last run: … commit …",见 src/plane/local_plane.rs)。
五、对比子实验与父实验:只使用本地 refs
要弄清"子实验相对于父实验改了什么",只使用本地 ref,不要上网:
# 三点 diff:merge-base 语义,累计展示父分支与子分支之间的全部差异 git diff <parent-branch>...orx/<child-slug> # 仅列出子分支上多出的提交(<parent>..<child>) git log --oneline <parent-branch>..orx/<child-slug>这套命令与仓库内部实现完全一致:diff_range使用base...head(三点、merge-base 语义,src/local/git.rs),list_commits_between使用base..head(src/local/git.rs),且都通过resolve_commitish(src/local/git.rs)优先解析本地 ref、其次回退到refs/remotes/origin/。原因很直接:Agent 的工作先提交到本地orx/<slug>分支,本地 ref 才是最新、最权威的对比基准;远端可能还没 push,甚至不该 push。
六、历史不可变:永不 merge / rebase 实验分支
一次运行回答了某个实验之后,该分支及其历史就是不可变的(immutable)。它精确记录着"当时跑过的那段代码",任何改写都会让历史失去证词价值。因此:
- 绝不merge 或 rebase 一条已完成的实验分支;
- 需要并入其他工作成果时,创建子实验,把 merge commit 放在子分支上;
- 绝不rebase 实验历史——它记录的是实际运行过的精确代码。
这条纪律在 UI 和模型层同样有呼应:例如 UI 中的文件版本/分支变更视图(ui/src/components/BranchChanges.tsx、ui/src/components/GitDiff.tsx)都围绕"分支 + commit"呈现,而非工作区草稿;运行记录的 diff 上限(MAX_DIFF_BYTES,src/local/git.rs)也保证了任何被展示的 diff 都源于 git 对象库,可追溯。
七、GitHub 发布:只推 baseline 与 orx/*
发布用于协作者可见性,遵循项目 playbook 的发布状态即可。仓库实现的发布边界非常清晰:
- 只推送 baseline 分支和
orx/前缀的分支:push_all(src/local/git.rs)过滤branch == baseline_branch || branch.starts_with("orx/"),按 baseline 优先排序后逐条git push -u <remote> <branch>; - 发布 remote 按
github→origin→upstream顺序识别(publication_remote,src/local/git.rs),要求 fetch 与全部 push URL 都指向项目声明的仓库; - 推送走认证通道:
authenticated_git_command(src/local/git.rs)显式禁用交互提示(GIT_TERMINAL_PROMPT=0、ssh -oBatchMode=yes),并把凭据 helper 限定为!gh auth git-credential,避免把用户的全局 git 配置卷进来; - 发布状态可查询:
publication_sync_status(src/local/git.rs)会对比本地与远端的 heads,返回not configured/not pushed/local changes to push/synced之一。
与论文上游仓库的关系要始终保持"只读隔离":不要fetch论文上游、更不要发布回上游。涉及论文仓库导入时,仓库还做了浅克隆重定根(reroot_shallow_repository、prepare_shallow_repository_for_publication,src/local/git.rs)与克隆时对 URL 的严格校验(public_clone_url,src/local/git.rs),目的都是保证"论文源仓库"与"实验仓库"两条线互不污染。
八、常见故障与边界情况速查
| 现象 | 处理方式 | 源码依据 |
|---|---|---|
checkout报分支已被检出 | 仅当列出的路径是自己的工作树时才继续,否则留给 owner 会话 | ensure_session_worktree注释(src/local/git.rs) |
| 工作树处于 detached HEAD | 编辑前先git checkout orx/<slug> | git worktree add --detach(src/local/git.rs) |
想启动运行但git status --short非空 | 先提交,未提交文件不会进归档 | SourceSnapshot::create(src/compute.rs) |
| 想确认将运行的代码 | git show --stat --oneline HEAD | snapshot_script(src/compute.rs) |
| 老根实验警告 | 按"base 分支上的根实验"理解,无需修复 | legacy_root_warning(src/local/experiments.rs) |
手动删除了工作树目录导致worktree add失败 | 仓库会自动git worktree prune清理陈旧注册 | ensure_worktree_from(src/local/git.rs) |
| 克隆/发布遇到认证 | 发布走gh auth git-credential,克隆优先 ssh、回退 https,均禁交互 | authenticated_git_command、ensure_clone(src/local/git.rs) |
| 运行记录的源码归档缺失 | 按 digest 校验失败会明确报错,不会静默降级 | SourceSnapshot::from_run(src/compute.rs) |
九、总结:orx-git 的三条纪律
把agent-skills/orx-git/SKILL.md浓缩成三条纪律,也就把握住了 OpenResearch 实验版本管理的全部精髓:
- 先勘察、后动手:
git branch -a+orx runs+orx exp desc三连,尊重"一分支一 owner",避免与兄弟会话互相踩踏。 - 提交即事实:运行只认
orx/<slug>分支上已提交的 commit;源码归档按 SHA-256 内容寻址、跨后端一致;启动前用git status --short和git show --stat --oneline HEAD自检。 - 历史是证词,不可改写:已回答的实验分支永不 merge/rebase,需要合并就开子分支;发布只推 baseline 与
orx/*,且与论文上游仓库彻底隔离。
遵循这三条纪律,多 Agent 并行研究会话就能在同一克隆上互不干扰地工作,而每一行跑过的代码都能精确回溯——这正是"把编码 Agent 变成研究 Agent"的版本管理地基。相关实现可继续深入 src/local/git.rs、src/local/experiments.rs、src/compute.rs 与 src/local/localrun.rs 阅读。
- 人工智能
- AI Agent
- 深度研究
- 自主智能体
- Agent 编排
【免费下载链接】OpenResearch
Turn your coding agents into research agents
相关推荐
OpenResearch `orx-create` 实战指南:从 `orx up` 建项目到 `orx create-experiment` 构建实验树
OpenResearch orx create 实战指南:从 orx up 建项目到 orx create experiment 构建实验树 导读 orx cr
人工智能AI Agent深度研究自主智能体Agent 编排note-gen与Git版本控制:提交历史与分支管理功能
note gen与Git版本控制:提交历史与分支管理功能 引言:AI笔记与版本控制的融合痛点 你是否曾在写作过程中误删重要内容?是否需要追踪笔记的修改轨迹?作为
AI 应用桌面应用移动开发知识管理OpenResearch 后端实战:用 `orx exp run --backend openresearch` 按次计费拉起临时 GPU/CPU 沙箱
OpenResearch 后端实战:用 orx exp run backend openresearch 按次计费拉起临时 GPU/CPU 沙箱 本指南讲解 O
人工智能AI Agent深度研究自主智能体Agent 编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考