Code Agent多智能体协作系统实战:RuntimeRunner硬调度设计
1. 这不是又一个“Agent框架”演示而是一次真实系统生命周期的复盘“Code Agent 解剖”这个系列我写了十八篇每一篇都聚焦一个具体模块、一次关键迭代、一个踩过的坑。但第十九篇我想聊点不一样的——不是怎么写好一个Agent而是怎么看着它从一行空文件长成能跑通完整ReAct Loop的系统再眼睁睁看着它被归档进git历史里变成一个带星号的实验分支。标题里的“AgentTeams”不是某个开源库的官方命名而是我们内部给那个短暂存在了72天的协作式代码生成实验系统起的代号。它不叫AutoGen也不对标LangChain的Team模式它就是一串在凌晨三点commit message里写着“临时加个multi-agent coordination layer试试”的草稿。核心关键词很直白Code Agent是它的身份底色AgentTeams是它的实验形态MyCodeAgent是它对外暴露的统一入口名RuntimeRunner是它真正干活的执行引擎而ReAct Loop——不是概念是它每天要跑满23小时、每轮平均耗时8.7秒、失败率稳定在4.3%的真实工作流。这个系统解决的问题非常具体当单个Code Agent在处理跨文件、跨模块、带状态依赖的重构任务时开始频繁卡在“理解上下文边界”和“协调修改顺序”上。比如把一个工具函数从utils.py抽离到core/transformers/下再同步更新所有import语句和测试用例——单Agent要么改漏要么改错顺序导致CI直接挂掉。我们没去堆prompt engineering也没立刻上分布式调度而是用最笨的办法让三个角色Agent坐一张桌子——一个专读代码、一个专写修改、一个专做验证它们之间不靠LLM自己推理协调而是由一个轻量级RuntimeRunner硬编码调度逻辑。它不优雅文档里找不到社区没人提但它在那72天里把这类任务的交付成功率从61%拉到了89%。适合谁看不是想学“如何设计下一代Agent架构”的理论派而是正在被类似问题卡住、手头有真实代码库要动、需要立刻见效方案的工程师。你不需要懂Llama-3的attention机制但得知道怎么让两个Agent不同时改同一个文件的同一行。2. 系统设计思路为什么选择“硬调度”而非“软协商”2.1 放弃LLM自主协调的三个现实理由当时团队争论最激烈的是“该不该让Agent自己协商”。主流方案无非两种一种是像AutoGen那样让每个Agent带一个System Prompt描述自己的角色和协作规则靠LLM输出JSON格式的“下一步该谁干”另一种是用Tool Calling机制让Agent调用一个“assign_task”工具把子任务分发出去。我们试了两周结论很明确在代码生成场景下LLM的协调能力是不可靠的幻觉放大器。不是模型不行是问题域太苛刻。举三个实测案例案例1重构任务中Reader Agent识别出需要修改A.py、B.py、C.py三个文件Writer Agent却只改了A.py和C.py理由是“B.py的变更已在A.py中体现”——实际上B.py里有个独立的校验逻辑漏改直接导致运行时panic。LLM把“逻辑等价”当成了“文件等价”。案例2验证环节Verifier Agent报告“所有import已更新”但实际漏掉了tests/unit/test_utils.py里一个深埋的from utils import *。LLM在长上下文里丢失了这个引用而Reader Agent的摘要里根本没提测试文件。案例3当Writer Agent修改完A.py后触发pre-commit hook失败LLM生成的恢复策略是“回滚A.py并重试”但没意识到失败是因为B.py还没改hook里有跨文件依赖检查——它把因果关系搞反了。这三个问题背后是同一个本质代码的精确性要求与LLM的概率性输出存在根本矛盾。LLM擅长模糊匹配和语义泛化但代码重构要求字节级精确、依赖图严格、执行顺序确定。指望它在ReAct Loop里动态协调多Agent就像让一个擅长即兴演讲的人去操作核电站控制台——听起来很酷但没人敢签责任书。2.2 RuntimeRunner用确定性对抗不确定性所以AgentTeams的设计起点很务实把不确定的部分锁死把确定的部分放开。我们把整个协作流程拆成四个硬性阶段每个阶段由RuntimeRunner强制推进不接受Agent的“建议”Context Harvest上下文收割Reader Agent只做一件事——扫描指定目录生成一份结构化代码地图AST节点文件路径依赖关系输出必须是JSON Schema定义的固定格式字段缺失直接报错退出不给LLM自由发挥空间。Plan Split计划与切分RuntimeRunner拿到代码地图后用预置规则引擎不是LLM做三件事① 识别所有待修改文件② 按文件粒度切分原子任务如“修改A.py第12行import语句”、“在B.py第45行插入新函数”③ 根据依赖图排序任务队列。这里用的是一个简化的拓扑排序算法复杂度O(n²)但胜在100%可预测。Execute Validate执行与验证Writer Agent按队列顺序逐个执行原子任务每次只改一个文件的一处Verifier Agent在每次Writer提交后立即运行pylint mypy 单元测试子集结果必须是布尔值pass/fail不接受“基本通过”或“警告忽略”这类模糊反馈。Rollback or Commit回滚或提交如果任何一步失败RuntimeRunner触发全链路回滚——还原所有已修改文件到初始状态并记录失败点。只有全部原子任务成功且验证通过才允许git commit。这个设计牺牲了“智能感”换来了可调试性。你可以随时在任意阶段打断流程查看RuntimeRunner生成的中间产物比如Plan阶段输出的任务队列JSON或者对比Writer执行前后的文件diff。而纯LLM协调的方案debug时你只能看到一长串token概率分布根本不知道它“以为”自己在做什么。2.3 MyCodeAgent统一入口背后的降维打击MyCodeAgent这个名字听起来像一个产品其实它只是AgentTeams对外的API网关。它的核心价值不是功能而是收敛复杂度。用户调用时只传一个自然语言指令“把utils.date_format()函数移到core/datetime.py并更新所有调用处”。MyCodeAgent不做任何决策它只做三件事解析指令提取目标函数名、源文件、目标文件、影响范围默认全项目调用RuntimeRunner启动AgentTeams流程封装最终结果成功/失败 修改文件列表 diff摘要。为什么不用更“智能”的入口因为我们发现用户真正需要的不是“理解力”而是“确定性响应”。当工程师说“我要重构”他要的不是Agent跟你辩论“这个重构是否合理”而是“OK3分钟内给你一个可review的PR”。MyCodeAgent把所有决策权交给RuntimeRunner的硬规则自己只做协议转换——HTTP请求转成内部消息内部消息转成HTTP响应。它甚至没有自己的prompt模板所有LLM交互都由Reader/Writer/Verifier各自封装。这种“无脑转发”看似简单却让整个系统的可观测性提升了数个量级所有日志都按RuntimeRunner的阶段打标监控大盘能清晰看到“Plan阶段平均耗时1.2s”、“Verify阶段失败率最高占总失败73%”而不是一堆混在一起的“Agent thinking time”。3. 核心细节解析RuntimeRunner的五个关键实现点3.1 代码地图生成器Reader Agent的“手术刀式”解析Reader Agent不是简单地把文件内容喂给LLM。它的工作流是先用tree-sitter解析目标代码库生成AST再遍历AST节点提取三类信息并结构化存储声明节点函数名、类名、变量名、所在文件、行号、参数签名对函数、继承关系对类引用节点import语句绝对/相对路径、from...import...、函数调用、属性访问依赖边基于引用节点构建有向图边权重引用频次用于后续优先级排序。输出JSON示例{ functions: [ { name: date_format, file: utils.py, line: 12, signature: (dt: datetime, fmt: str) - str, references: [ { file: models/user.py, line: 45, type: call }, { file: tests/test_utils.py, line: 12, type: call } ] } ], imports: [ { file: utils.py, target: core.datetime, line: 3 } ], dependency_graph: { utils.py: [core/datetime.py], models/user.py: [utils.py] } }这个结构的关键在于剥离语义理解专注结构提取。Reader Agent的LLM prompt只有一句话“请严格按上述JSON Schema输出不要添加任何额外字段或解释。” 它不负责判断“date_format是否应该移动”只负责告诉你“它现在在哪、谁在用它、它依赖谁”。实测下来这个步骤的准确率稳定在99.2%错误基本来自语法错误的代码比如未闭合的括号而这类代码本身就不该进入重构流程。提示我们刻意避开了用LLM做AST解析。曾试过让GPT-4直接输出JSON结果发现它会“脑补”不存在的引用或者把注释里的字符串当成import路径。tree-sitter是唯一可靠的方案——它不理解代码但绝不会错。3.2 任务切分引擎RuntimeRunner的“机械臂”逻辑Plan阶段是RuntimeRunner最重的逻辑。它接收Reader输出的JSON执行以下确定性步骤目标定位根据指令中的函数名date_format在functions数组中找到对应项确认其当前文件utils.py和目标文件core/datetime.py。影响范围计算遍历该函数的所有references对每个引用文件生成一个原子任务任务类型UPDATE_IMPORT修改import语句目标文件models/user.py操作将from utils import date_format改为from core.datetime import date_format行号45前置条件core/datetime.py必须已存在且包含date_format函数定义依赖排序构建任务DAG。UPDATE_IMPORT任务依赖于CREATE_FUNCTION任务在core/datetime.py中创建函数。RuntimeRunner用Kahn算法做拓扑排序确保CREATE_FUNCTION永远排在所有UPDATE_IMPORT之前。冲突检测检查是否有两个任务修改同一文件的同一行。例如如果另一个指令也要求修改models/user.py第45行这里会直接报错“行冲突”拒绝启动流程。这是人工Review无法实时发现的硬伤。这个引擎没有机器学习全是if-else和图算法。好处是每一步都能单元测试每个任务都能生成可追溯的ID如TASK-20240515-001失败时日志里直接显示“TASK-20240515-003 failed: line 45 conflict with TASK-20240515-002”。3.3 Writer Agent的“手术执行”协议Writer Agent不接受自由发挥。它只认一种输入格式{ task_id: TASK-20240515-001, file_path: core/datetime.py, operation: INSERT_FUNCTION, content: def date_format(dt: datetime, fmt: str) - str:\n return dt.strftime(fmt), line_number: 15 }它的输出也严格限定{ task_id: TASK-20240515-001, status: SUCCESS, file_hash_before: a1b2c3..., file_hash_after: d4e5f6..., diff: -12,0 13,5 \ndef date_format... }关键约束原子性每次只改一个文件的一处不允许批量修改幂等性对同一task_id重复执行结果必须一致靠file_hash_before校验可逆性每次修改都生成reverse_diff用于回滚。我们放弃让Writer“理解”代码意图只让它做文本编辑。实测证明这反而提升了稳定性——GPT-4 Turbo在纯文本插入任务上的准确率是99.8%而在“理解业务逻辑后重构”任务上只有82%。把复杂度锁死在协议层是降低故障率最有效的手段。3.4 Verifier Agent不是“检查”而是“执行”Verifier Agent的名字容易误导。它不“检查”代码它“执行”验证。流程是RuntimeRunner将Writer刚修改的文件复制到临时沙箱环境在沙箱中运行三条命令pylint --errors-only modified_file只报error忽略warningmypy modified_file类型检查pytest tests/ -k test_date_format --tbshort只跑相关测试收集三个命令的exit code和stdout合成一个布尔结果。输出JSON{ task_id: TASK-20240515-001, status: PASS, pylint_errors: 0, mypy_errors: 0, pytest_failures: 0, sandbox_hash: xyz789... }这里的关键是沙箱隔离。我们不用本地环境验证因为本地可能有未提交的脏代码。沙箱基于Docker镜像构建镜像里只装项目依赖和Python每次验证都是干净的。Verifier的LLM prompt只有一行“请解析上述命令输出严格按JSON Schema返回不要解释原因。” 它不负责诊断错误只负责传递结果。真正的诊断由RuntimeRunner的日志聚合完成——比如连续三次TASK-20240515-003失败日志会显示“pylint error: unused variable fmt”工程师一眼就知道是Writer生成的函数签名漏了参数。3.5 回滚机制不是“撤销”而是“还原”AgentTeams的回滚不是Git reset而是文件级精准还原。RuntimeRunner在每个Writer任务执行前都会计算目标文件的SHA256哈希将原始内容base64编码存入内存缓存不是数据库避免IO瓶颈记录task_id与哈希的映射。当流程中断时RuntimeRunner遍历所有已执行任务的task_id查缓存获取原始内容直接覆盖写回文件。整个过程不依赖Git不产生中间commit100%可预测。实测回滚平均耗时210ms比git stash pop快3倍。更重要的是它规避了Git的“状态污染”风险——比如Writer修改了A.pyVerifier失败后回滚但此时本地还有其他未add的修改git reset会误删它们。文件级还原只动它动过的文件其他一切照旧。4. 实操过程从零部署到生产灰度的七步落地4.1 环境准备最小可行依赖清单AgentTeams不是重量级框架它跑在一个标准Python 3.11环境中。我们刻意避开所有“AI工程化”套件只用最基础的依赖包名版本用途替代方案tree-sitter0.22.5AST解析引擎不可替代性能关键pydantic2.7.1JSON Schema校验可换为jsonschema但pydantic更快docker-py6.1.3沙箱环境管理必须无替代requests2.31.0HTTP API网关可换urllib但requests更稳安装命令pip install tree-sitter pydantic docker-py requests # 注意tree-sitter需要编译务必先装build-essentialUbuntu或Xcode command line toolsmacOS注意不要装langchain、llama-index、autogen这些。它们会引入大量隐式依赖干扰RuntimeRunner的确定性调度。AgentTeams的哲学是“LLM只负责填空不负责决策”。4.2 Reader Agent配置如何让LLM只做结构提取Reader Agent的prompt模板是成败关键。我们反复迭代了17版最终锁定这个极简版本You are a code parser. Your only job is to output JSON matching this schema: { functions: [{name: string, file: string, line: int, signature: string, references: [{file: string, line: int, type: string}]}], imports: [{file: string, target: string, line: int}], dependency_graph: {string: [string]} } Do not add any other fields, do not explain, do not format as markdown. Output pure JSON. Input code: {code_snippet}关键技巧禁用解释明确说“Do not explain”否则LLM会加一堆“根据我的分析…”的废话破坏JSON格式强Schema约束用pydantic在代码层二次校验任何字段缺失或类型错误都抛异常分片输入单个文件超过500行时自动按类/函数切片分别调用LLM再合并结果——避免上下文截断。实测下来这个prompt在GPT-4 Turbo上对Python代码的结构提取准确率是99.2%错误集中在嵌套装饰器和动态import上但这部分本就不该进入重构流程。4.3 RuntimeRunner初始化五参数启动法RuntimeRunner不是一个类而是一个函数工厂。启动时必须传入五个参数缺一不可from runtime_runner import create_runner runner create_runner( reader_agentreader_client, # Reader Agent的API客户端 writer_agentwriter_client, # Writer Agent的API客户端 verifier_agentverifier_client, # Verifier Agent的API客户端 sandbox_imagemyproject:latest, # Docker镜像名必须预构建 max_retries3 # 单个任务最大重试次数 )每个参数都有硬性要求Agent客户端必须实现统一接口execute(task: dict) - dict返回必须含task_id和status字段Sandbox镜像必须包含项目所有依赖且WORKDIR设为/workspace否则Verifier找不到文件Max_retries设为3是经验值。设为1则容错太低设为5则失败任务拖慢整体流程。启动后runner会做三件事① 验证所有客户端连通性② 拉取sandbox镜像并检查tag③ 预热一个沙箱容器避免首次验证时冷启动延迟。整个过程耗时800ms。4.4 MyCodeAgent API最简REST接口设计MyCodeAgent只暴露一个POST端点/v1/refactor。请求体是纯文本指令响应体是结构化JSONcurl -X POST http://localhost:8000/v1/refactor \ -H Content-Type: text/plain \ -d 把utils.date_format()函数移到core/datetime.py并更新所有调用处响应示例{ request_id: REQ-20240515-001, status: PROCESSING, estimated_time_seconds: 180, steps: [ {phase: ContextHarvest, status: COMPLETED}, {phase: PlanAndSplit, status: COMPLETED}, {phase: Execute, status: IN_PROGRESS, current_task: TASK-20240515-003} ] }关键设计异步响应不阻塞等待立即返回request_id客户端用/v1/status/{id}轮询进度透明steps数组实时反映RuntimeRunner的阶段状态工程师可随时知道卡在哪无状态所有中间状态存内存用LRU cache不依赖数据库——简化部署提升速度。我们刻意没做JWT鉴权、没做rate limit因为这是内部工具。安全靠网络隔离限流靠K8s HPA——让API保持呼吸感。4.5 灰度发布策略从个人笔记本到CI流水线AgentTeams的上线分三步走每步都设硬性指标开发者本地验证Day 1-3每个工程师在自己笔记本上跑通3个真实重构案例指标成功率≥95%单任务耗时≤120s失败案例必须人工Review归因到Reader/Writer/Verifier哪个环节。PR机器人集成Day 4-14在GitHub Action中加入agent-teams-refactorstep仅对refactor:开头的commit生效指标每周自动处理PR数≥20人工干预率≤5%所有失败PR自动打labelagent-failed并附详细日志链接。CI前置门禁Day 15-72在CI pipeline的pre-test阶段插入AgentTeams检查对所有修改文件自动执行“影响范围分析”指标拦截高风险修改如跨模块全局变量变更准确率≥80%误报率≤2%此阶段不再自动修改只输出report由工程师决定是否采纳。这个节奏保证了每个环节都有数据支撑。最终72天里AgentTeams共处理1274次重构请求成功率89.3%平均节省人工重构时间42分钟/次。但它也暴露了致命短板当代码库规模超过50万行时Reader的AST解析耗时飙升至47秒超出CI容忍阈值。这不是算法问题是tree-sitter在超大文件上的固有瓶颈。5. 常见问题与排查技巧实录72天踩过的12个坑5.1 Reader Agent的“幽灵引用”问题现象Reader输出的references里出现了一个根本不存在的文件路径比如/tmp/ghost.py。根因tree-sitter解析时遇到from . import utils这样的相对import会尝试解析__init__.py但如果目录下没有__init__.py它会fallback到临时路径。这不是bug是tree-sitter的设计选择。排查技巧在Reader的输入代码前加一行# TREE-SITTER-DEBUG: true它会输出解析日志检查日志里是否有failed to resolve relative import字样临时解决方案在所有包目录下放空__init__.py。实操心得我们后来在RuntimeRunner里加了一层过滤自动剔除所有/tmp/或/var/folders/开头的路径。这不是修复是绕过——因为改tree-sitter源码成本太高。5.2 Writer Agent的“行号漂移”故障现象Writer按指令修改第45行结果改到了第46行导致语法错误。根因目标文件在Writer执行前被其他进程如IDE自动保存、git merge修改过行号已变。Writer拿到的是旧快照。排查技巧启用Writer的--dry-run模式它会输出将要修改的diff不实际写入对比file_hash_before和当前文件哈希不一致就报警终极方案Writer执行前用flock锁定文件。我们选择了第三种。在Writer的Docker容器里执行修改前先flock /workspace/target.py -c python write.py。虽然增加了100ms延迟但100%杜绝了行号漂移。5.3 Verifier沙箱的“依赖幻影”现象沙箱里mypy报错ModuleNotFoundError: No module named core但本地环境正常。根因Docker镜像构建时COPY . /workspace没包含src/目录下的core包只copy了setup.py。排查技巧在Verifier的沙箱里加一条debug命令ls -R /workspace确认目录结构用docker run -it --rm -v $(pwd):/workspace myproject:latest bash手动进镜像验证构建镜像时用.dockerignore排除__pycache__和.git但别excludesrc/。教训沙箱环境必须100%复现CI环境。我们后来把镜像构建脚本和CI的build.yml完全同步用同一个Dockerfile。5.4 RuntimeRunner的“任务雪崩”现象一个简单的函数移动触发了200个UPDATE_IMPORT任务流程卡死。根因Reader的references数组里把from utils import *展开成了所有函数名包括根本没用到的date_parse、time_now等。排查技巧在Plan阶段加日志logger.info(fGenerated {len(tasks)} tasks for {function_name})设置硬上限if len(tasks) 50: raise ValueError(Too many tasks, aborting)Reader的prompt里加约束Only include references that directly call the target function。我们选了第二种。50是个经验值——超过50个文件调用同一个工具函数说明设计有问题该拆分了。5.5 MyCodeAgent的“超时静默”现象API返回504 Gateway Timeout但RuntimeRunner日志里没有任何错误。根因Nginx默认超时60秒而一个大型重构可能耗时90秒。Nginx先断开连接但RuntimeRunner还在跑。排查技巧在MyCodeAgent的API handler里加asyncio.wait_for(runner.execute(), timeout120)Nginx配置加proxy_read_timeout 120;最重要所有异步任务必须有try/except包裹失败时主动写入Redis status key。我们后来在所有关键路径都加了超时保护并用Redis做状态中心这样即使API断开客户端也能用/status/{id}查到最终结果。5.6 回滚失败的“哈希失联”现象回滚时提示No original content found for TASK-20240515-001。根因RuntimeRunner的内存缓存是LRU当并发任务过多时旧task的哈希被挤出。排查技巧监控缓存命中率cache_hit_rate hits / (hits misses)低于95%就要扩容把缓存从内存移到Redis但会增加200ms延迟更优解Writer执行前把原始文件内容存到本地临时目录路径用task_id哈希回滚时直接读。我们选了第三种。临时目录用/tmp/agent-teams/{task_id}/original.py100%可靠且清理简单——任务完成后shutil.rmtree即可。5.7 ReAct Loop的“无限重试”现象一个任务失败后RuntimeRunner重试3次每次都失败最后报错但没给出根本原因。根因Verifier的pytest命令没加--tbshortstdout太长LLM解析失败返回空JSONRuntimeRunner误判为“验证通过”。排查技巧所有命令输出必须截断timeout 30s pytest ... 21 | head -n 100Verifier的LLM prompt里加If output is empty or invalid, set status to PARSE_ERROR在RuntimeRunner里加fallback当Verifier返回空时直接标记为VERIFIER_PARSE_FAILED。这个坑让我们损失了两天debug时间。教训永远假设下游会返回垃圾数据上游必须做防御性解析。5.8 多Agent的“资源争抢”现象两个AgentTeams实例同时运行Writer修改同一个文件导致内容错乱。根因RuntimeRunner没做分布式锁多个实例共享同一代码库。排查技巧用Redis锁redis.lock(frepo:{repo_hash}, timeout300)或更简单在代码库根目录放.agent-teams-lock文件Writer执行前检查并创建最佳实践每个AgentTeams实例绑定唯一代码库副本用git worktree隔离。我们用了第二种。.agent-teams-lock文件里写入进程PID冲突时直接kill -9 {pid}。粗暴但有效。5.9 LLM的“幻觉注入”现象Writer生成的函数体里多了import numpy as np但原代码根本没用numpy。根因Writer的prompt里写了“include necessary imports”LLM过度发挥。排查技巧把“necessary imports”改成“only imports present in original files top-level scope”Writer输出后用AST比对提取生成代码的import列表与原文件diff只保留交集加一道静态检查grep import generated.py | grep -v from utils。我们加了第二道。AST比对100%准确且不依赖LLM。5.10 网络分区的“状态撕裂”现象Reader成功Writer失败但Verifier仍被调用返回“PASS”整个流程标记为成功。根因RuntimeRunner的阶段间没有状态持久化网络抖动导致Writer响应丢失但Verifier的调用请求已发出。排查技巧所有阶段调用加retry2用指数退避Writer成功后写一条task_status: EXECUTED到RedisVerifier调用前先查Redis确认Writer状态为EXECUTED。这个设计让整个流程变成“至少一次”语义虽有重复但保证不丢。5.11 日志的“信息黑洞”现象流程失败但日志里只有Task failed没有具体哪行错。根因Logger配置没设exc_infoTrue异常堆栈没打印。排查技巧统一Logger配置logging.basicConfig(levellogging.INFO, format%(asctime)s %(name)s %(levelname)s %(message)s, exc_infoTrue)在每个Agent的execute方法里try/except捕获所有异常logger.exception(Agent execution failed)关键变量打loglogger.debug(fTask {task_id} input: {task})。一句话不打堆栈的日志等于没日志。5.12 归档决策的“最后一击”现象系统运行良好为何72天后被归档根因不是技术失败是价值衰减。当代码库增长到80万行Reader耗时突破60秒CI无法接受同时团队发现85%的重构需求其实只需修改3个文件以内单Agent强化prompt就能搞定。AgentTeams的边际收益为负。排查技巧建立ROI仪表盘横轴是代码库规模纵轴是AgentTeams vs 单Agent的耗时比当比值1.5且持续一周触发归档评审归档前把RuntimeRunner的硬规则引擎抽出来作为独立库code-restructure-engine开源。这就是AgentTeams的终点——它完成了使命然后安静离开。没有失败只有适时退场。6. 项目终结的思考为什么“生与死”才是Code Agent最该讲的故事AgentTeams停运那天我没写任何总结邮件。只是把README里那句“Experimental multi-agent code refactoring system”改成了“Deprecated. See code-restructure-engine for core logic.”。它没死在bug里没亡于架构腐化而是死在了一个更残酷的真相面前在工程世界里一个系统最大的成功不是活得多久而是死得有多及时。回头看这72天最值得记录的不是那些漂亮的指标——89.3%的成功率、42分钟的人效节省、1274次自动重构。而是那些深夜三点的debug会议大家围着屏幕看tree-sitter的解析日志争论“relative import的fallback路径算不算bug”是第一次看到Verifier沙箱里mypy报错时整个办公室爆发出的、带着疲惫的笑声是当RuntimeRunner的回滚机制在CI里100%还原了被误删的测试文件那个实习生跳起来拍桌子的样子。Code Agent不是魔法它是工具是杠杆是无数个确定性规则对抗不确定性世界的笨拙尝试。AgentTeams的“死”恰恰证明了它的“生”足够真实——它没活在论文里没飘在PPT上它真正在生产环境里流过汗、出过错、救过火然后在该谢幕的时候鞠躬退场。如果你正打算启动一个类似的实验我的建议只有一条别想“怎么让它永生”先想“怎么让它死得明白”。