Open Code Review 项目解析知识图谱 / 分组目录 / 核心架构 / 文件级并行与上下文隔离

文件级并行与上下文隔离

核心架构高级方法机制G-A · 核心架构

What · 是什么

每文件一个子 Agent 任务、独立上下文,信号量限流(默认 8 并发),防 token 雪球
每个文件拥有独立的子任务上下文:各自独立的 Plan、ReAct 循环、评论集合与 token 预算,互不共享也互不污染
并行度由信号量(semaphore)控制,默认 8 个并发 goroutine:超过上限的文件子任务排队等待
ConcurrentTaskTimeout 为每个文件子任务设置独立超时:单文件卡死不会拖垮整批审查
token 预算前瞻:每轮前检查 used+estimateDiffFileTokens 是否超过 MaxTokensBudget,超限即停止该文件,防止单文件耗尽总预算
panic recover 隔离:单文件子任务的运行时崩溃被 recover 捕获,不影响其他并发子任务
filterLargeDiffs 预过滤:超过 80% MaxTokens 的大文件在分派前即被丢弃,从源头规避超大上下文

Why · 为什么

原理 · Principle

文件级隔离使并行成为可能:每个文件独立上下文意味着无共享可变状态,goroutine 之间零锁竞争,天然可并行

默认 8 并发是在吞吐与 token 预算之间的平衡:并行过多会同时挤压多个文件的上下文预算,导致整体质量下降

超时与预算前瞻是规模化运行的刚性约束:真实仓库常有异常文件(超大、复杂、工具死循环),无约束会拖垮整批审查

panic recover 把『偶发崩溃』从全局事故降级为单文件失败:单个文件的 bug 不应中断整个审查流水线

上下文隔离同时是质量保证:文件间不串上下文,评论不会把 A 文件的代码误引到 B 文件

How · 怎么做

分派:过滤后的文件列表逐个申请 semaphore 许可(默认容量 8),获得许可后启动独立 goroutine 执行子任务
每文件子任务内部:Plan(单轮 LLM)→ MainTask(ReAct 循环,受限 6 工具)→ code_comment 异步定位 → REVIEW_FILTER 反思,全部在该文件私有上下文中进行
超时控制:ConcurrentTaskTimeout 从子任务启动开始计时,超时则该文件结果标记为超时失败,其余文件继续
预算前瞻:每轮 ReAct 迭代前计算 used(已用 token)+ estimateDiffFileTokens(预估 diff token)与 MaxTokensBudget 比较,超限立即终止该文件而非等待触发
崩溃隔离:goroutine 内 defer recover 捕获 panic,将错误记录到该文件结果而非向上抛
大文件预过滤:filterLargeDiffs 在分派前检测文件 diff 大小,超过 MaxTokens 的 80% 直接丢弃并记录原因,不进入并发队列

案例 · Cases

代表性案例
一次审查含 50 个文件:8 并发分批执行,其中一个文件 ReAct 循环异常膨胀被预算前瞻终止,一个文件发生 panic 被 recover 隔离,其余 48 个文件正常产出评论并汇总
超大单体文件(数万行 diff)在 filterLargeDiffs 阶段被丢弃,审查耗时与 token 消耗因此保持稳定,避免了单文件把整批预算吃光

反模式 · Anti-patterns

正反实例论证 · Evidence

正例 · Pro
每文件独立上下文 + 信号量 8 并发
sem := make(chan struct{}, 8)for _, entry := range filteredFiles { sem <- struct{}{} go func(e FileEntry){ defer func(){ <-sem; recover() }(); runFileTask(e) }(entry)}// 每个 goroutine 拥有独立 Plan/ReAct/评论集/token 预算,零共享可变状态
文件级隔离使并行无锁竞争,goroutine 间零共享;默认 8 并发平衡吞吐与预算,panic recover 把单文件崩溃降级为局部失败
反例 · Con
所有文件共享一个全局上下文
// 反例:先读全部文件再统一审查allFiles := readAll(filteredFiles)review(allFiles) // 文件间上下文互相串扰// A 文件的代码可能被误引到 B 文件的评论中,预算同时失控
共享上下文导致评论张冠李戴(文件归属错误),且总预算被全体文件同时消耗,规模化审查不可行
正例 · Pro
预算前瞻:used+estimateDiffFileTokens 超限即停
// 每轮 ReAct 迭代前检查if used + estimateDiffFileTokens(entry) > MaxTokensBudget { stopFileTask(entry) // 提前终止该文件,而非等待触发}// filterLargeDiffs: 超过 80% MaxTokens 的文件分派前即丢弃
前瞻式预算控制把『超限』从事后补救变成事前预防:异常膨胀的 ReAct 循环被及时终止,超大文件根本不进队列
反例 · Con
无预算检查、无超时地运行子任务
// 反例:裸 goroutine 无任何约束go runFileTask(entry) // 无 ConcurrentTaskTimeout、无预算前瞻// 一个 ReAct 死循环的文件可无限占用预算直到整批 OOM/超时
真实仓库存在异常文件(工具死循环、diff 超大),无超时无预算约束时单文件即可拖垮整批审查

实践资产 · Assets

源码节选
agent.go 核心节选:Run 流水线 / dispatchSubtasks / executeSubtask / REVIEW_FILTER
internal/agent/agent.go · 3451 B
源码节选
git 子进程并发限流(默认 16)
internal/gitcmd/runner.go · 1271 B

相关边

本节点没有与其他节点的关系边。