Skip to content
SCOPE: Semantic Code Operation & Propagation Engine

SCOPE: Semantic Code Operation & Propagation Engine

May 10, 2026

在vibe coding越来越流行的今天,很多拥抱coding agent的项目都面临着同样的问题:明明引入了外部智能体来代理完成项目,却反而导致项目越改越乱。

一开始只是些预兆:明明没改过的功能突然报错;修复完一个 bug 又出现两个;agent修改忘了考虑1-2处细节。后面却变得越来越严重:修复漏洞的速度从一开始的马上发现,变得需要各种调试手段才能勉强完成;实现新feat引发的bug越来越多…

这不是模型不够聪明。也不是人类描述得不够细。而是 vibe coding 在人和最终运行的代码之间,楔入了一个全新的间隙,即语言模型本身。这个间隙带来了两种以前从未被正视过的不对齐。

为此,本文提出SCOPE (Semantic Code Operation & Propagation Engine)来缓解此问题。

错误的根源:两层不对齐

我认为,vibe coding目前有两层不对齐问题,它们共同导致了工程走向劣化。

这两层可以概括为人和代码的不对齐。在传统工程中,代码直接由人的思维逻辑借程序语法产生。因此,bug只可能来自于思维逻辑的漏洞和对语法不了解所导致的错误使用。而在vibe coding中,代码并不直接由人产生,这就导致了人的思维模型和代码实际逻辑产生了新的空隙(即中间用于生成代码的agent)。这空隙最终反映到软件上就产生了bug。

也就是说,vibe coding引入的问题只来自于两类: 人和agent的不对齐agent和代码的不对齐

人和agent的不对齐来自于过度模糊的意图和反馈的缺乏。比如,“帮我编写一个聊天软件”,这里即使agent完整的产出了软件代码,也会产生巨大的空隙。因为agent无从得知具体应该使用怎么样的技术栈,通信模型等等信息,它只能根据自己的内部参数组合出一套逻辑模型,而人基本没有动力去了解和同步这一大长串代码,这又导致了无法通过反馈来同步逻辑模型。

或者,如果模型能力过弱,直接无法理解人类的逻辑模型,也会导致这种情况,不过这不是工程上可以解决的问题,这里不讨论。

agent和代码的不对齐来自于编写工作流本身。假设我们有一个手动管理状态的连接池(这在不方便使用 RAII 的异步状态机或底层 FFI 交互中很常见):

// connection_pool.rs
pub struct ConnectionPool {
    active_conns: usize,
    max_limit: usize,
}

impl ConnectionPool {
    /// 获取连接 ID
    pub fn acquire(&mut self) -> Result<u32, Error> {
        if self.active_conns >= self.max_limit { 
            return Err(Error::Busy); 
        }
        
        // 增加计数,并分配底层资源
        self.active_conns += 1;
        let conn_id = unsafe { ffi_allocate_connection() };
        
        Ok(conn_id)
    }

    /// 释放连接 ID
    pub fn release(&mut self, conn_id: u32) {
        unsafe { ffi_free_connection(conn_id); }
        if self.active_conns > 0 {
            self.active_conns -= 1;
        }
    }
}

现在,人类提出: “连接时,加一个自检逻辑:如果底层的底层分配失败,请直接返回SystemError,不要把无效的 ID 返回给外部调用方。”

Agent 通过正则或语义搜索定位到了 acquire 函数。敏锐地理解了人类的要求,并在局部做出了看起来极其完美的修改:

--- a/src/connection_pool.rs
+++ b/src/connection_pool.rs
@@ -5,9 +5,14 @@
         if self.active_conns >= self.max_limit { 
             return Err(Error::Busy); 
         }
         
         self.active_conns += 1;
         let conn_id = unsafe { ffi_allocate_connection() };
         
+        // Agent 增加的自检与拦截逻辑
+        if conn_id == 0 {
+            return Err(Error::SystemError);
+        }
+
         Ok(conn_id)
     }

​这段代码编译完全通过,且非常符合人类直觉(拿到无效 ID 就报错)。在局部测试中,它也完全符合人类的要求。​

但实际上,Agent 埋下了一颗静默崩溃的炸弹:由于 Agent 缺乏全局的工程上下文(它没有意识到 self.active_conns += 1; 已经发生在这个提前返回(Early Return)之前),当底层分配失败时,acquire 返回了 Err。由于返回了错误,外部调用方根本拿不到 conn_id,自然也就永远不会调用 release()。

结果就是:每次分配失败,都会导致 active_conns 计数器永久性 +1(状态泄漏)。运行一段时间后,活跃连接数会被虚假的失败请求占满,整个系统陷入死锁,再也无法处理新请求。

SCOPE: 消除空隙的引擎

SCOPE的核心是一个事件队列。

    graph LR
    subgraph Event Queue
        direction LR
        E1[Event 1] --> E2[Event 2] --> E3[...] --> EN[Event N]
    end
  

首先,将用户的修改意图作为第一个事件推入队列首部。

    graph TD
    User((User)) -->|push intent<br/>as first event| Queue[Event Queue]
  

然后开始循环从队列首部弹出并处理事件。第一个事件让agent根据初始的修改意图搜索并修改代码库。

    graph TD
    Queue[Event Queue] -->|pop head| Agent[Agent]
    Agent -->|read / search / edit / delete| Codebase[(Codebase)]
  

为此,SCOPE提供五个工具:

  • read_code(selector)
  • edit_code(selector, patch_v4a)
  • delete_code(selector):独立工具,单独传播规则。
  • search_code(query)
  • ack_next_event()

每当编辑工具被调用时,SCOPE内部的传播分析引擎(基于tree sitter & lsp)就会分析出影响的代码范围,并基于修改的selector暂存它们。

    graph TD
    Edit["edit_code / delete_code"] --> Engine[Propagation Engine<br/>tree-sitter & LSP]
    Engine -->|affected selectors + ranges| Store[(Temporary Store)]
  

agent完成事件后,将会调用ack_next_event 表明此事件完成,请求下个事件。此时之前暂存的修改传播经过去重处理后,会以selector为id整合为多个ReviewEvent进入队尾。

    graph TD
    Store[(Temporary Store)] -->|dedup + group by selector| Dedup[Dedup & Group]
    Dedup -->|ReviewEvents| Queue["Event Queue<br/>(append to tail)"]
  

因此agent得到的下个事件就会是审查某个修改的影响范围,如果它发现问题并进行修改,就会产生新的ReviewEvent。反复这个过程直到清空队列。

下面是整个流程的时序图:

    sequenceDiagram
    participant U as User
    participant E as SCOPE Engine<br/>(Queue & Propagation)
    participant A as Agent

    U->>E: 推入初始修改意图事件(队首)
    E->>A: 弹出事件 (首次为初始意图)
    loop 队列非空期间
        A->>E: 调用工具 (read_code / search_code / edit_code / delete_code)
        alt 编辑类工具 (edit_code / delete_code)
            E->>E: 传播分析引擎分析影响范围,基于 selector 暂存受影响代码
        end
        A->>E: ack_next_event() (表明事件完成,请求下一个事件)
        E->>E: 去重暂存传播 → 按 selector 生成 ReviewEvent → 推入队尾
        E->>A: 弹出下一个事件 (ReviewEvent)
    end
  
Last updated on