谁告诉你AI改自己的代码,改错了还能全身而退?
一个自演化Agent把代码改了,系统崩了,连回滚的程序都没了——这画面够不够惊悚。现实是,绝大多数AI Agent框架处理不了这个问题。
DeepSeek Harness是这个游戏里的破局者。它的底层机制叫Cordis,一套专门解决“插件装上能卸、卸了没残留”的编程框架。这跟VSCode插件卸不掉得重启那一套完全两回事。Cordis干的活是:Agent运行时里几十上百个插件互相依赖、随时热替换,替换完了系统状态还是对的,依赖关系还是通的。这种事,以前没人做到过。
这到底怎么实现的?七个认知翻转接着往下看。
自演化Agent拆自己的零件,拆完还能跑?
AI Agent在运行时自动生成和替换自己的组件,这不再是小论文里的想象。工具集、执行环境、权限控制、会话状态、记忆系统、子Agent调度——整个框架都在被动态修改。每个修改本质上是一次动态组件操作。如果一个Agent自己改了代码,改到一半挂了,或者改完了留下状态污染,谁来修?没有人类盯着。
每次自修改都强迫完整重启,会丢掉所有进程局部累积状态——缓存、连接、中间计算结果。频繁重启,累积不可用时间变长。正在执行的任务被反复打断。更糟的是,一次故障性自修改可能禁用了用来恢复的进程本身。
那为什么不能像普通程序那样“改完编译一下就行”?因为Agent是活的。它改了组件A,组件B依赖A的接口,A的接口变了,B得跟着重新解析依赖。这个依赖图在运行时动态变化,没法静态分析。现有软件工程里的模块热替换,要么要求开发者手写迁移函数,要么只支持函数级热补丁,不支持组件级接口变更。问题卡在这里了。
每个组件自带上卸开关,数学上怎么构造
一个组件修改了系统状态。要撤,就得记录这个修改的逆操作。数学上就是给一个函数f配一个g,让g∘f等于恒等映射。只要求左逆,不要求双逆。
为什么只要左逆?只关心撤销这次改动,不关心从任意状态都能撤。单个操作的逆有了,整个组件的逆就是所有原子操作逆的反序合成。先装A再装B,卸的时候先卸B再卸A。数学形式是(f1,g1)和(f2,g2)合成得(f1∘f2, g2∘g1)。
原子操作的逆是静态的。但同一个操作在不同状态下需要不同逆。所以升级一下:函数输入当前状态,输出新状态加动态生成的逆。整组操作序列作为一个迭代器来执行,每步输出新状态、逆、是否继续。全部跑完,逆就是所有已执行步骤逆的反序合成。
组件A依赖key k,组件B提供k。B要卸,A得先卸。B不能先撤k再让A卸,因为A的卸货逻辑可能还需要k。设计是两阶段撤回:B先停掉对k的提供,让A的依赖状态变成不满足,触发A开始卸载。等A彻底卸完,B才执行自己的逆操作回收资源。
依赖图有环怎么办?A要B的key,B要A的key,谁先起?看声明就知道。依赖图有环,环上的组件永远无法同时满足依赖条件,直接报错不让起。这跟运行时死锁不一样,编译时或加载时就堵死了。
效应和余效应合在一个上下文里跑
效应管怎么撤——每个操作记录逆。余效应管依赖谁——每个组件声明自己需要什么key。两个东西得放一个统一框架里。统一上下文长这样:Γ∞ = μΓ. Γ × (Γ → Γ) × Σ。三个部分:当前状态、累积逆、依赖表。递归结构让父组件的逆自动包含子组件的逆。卸父组件等于卸所有子组件。
两个效应独立意味着可以任意交换顺序。判断依据是两个效应函数生成的变换幺半群互相交换,一个效应不干扰另一个产生的逆。操作不同key自动独立。操作同一个key看代数结构:集合型增删独立,有序链表插入不独立。
依赖表发生变化,系统检查每个组件的依赖是否满足。变化被分类为激活、停用、中性三类,触发启动、关闭或无视。这就是响应式依赖解析。组件声明依赖哪些key,系统维护一张依赖表,每次表变化触发所有相关组件的target view重新计算,不匹配就触发状态转换。
target view记录的是provider的uid,不是值。provider被替换时,即使新provider提供了相同的值,uid不一样,target view也不匹配,触发重载。用uid比用值可靠——值相等但来源不同,行为可能完全不同。
Cordis把这套数学变成跑起来的代码
Cordis是DeepSeek Harness的底层核心机制,一套专门处理时空可组合性的元框架。核心是ctx.effect函数。所有通过上下文进行的操作——注册依赖、修改配置、启动子组件——都包在ctx.effect里。函数返回dispose闭包,调用就撤销这次操作的全部影响。ctx.effect内部维护累积逆,每执行一步把新逆前置到合成链上,形成LIFO撤销链。
组件生命周期由fiber承载。每个fiber有自己的状态机:INACTIVE、LOADING、ACTIVE、UNLOADING、FAILED。状态转换由refresh驱动。依赖表每次变化,所有相关fiber的target view重新计算。不匹配就触发状态转换。
声明式配置加热模块替换是独立层。配置文件变了,系统自动算出差集,只卸载受影响的组件再重装,其他保持运行。事务性保证:新模块加载失败,自动回滚到旧状态。热模块替换不需要开发者手写module.hot.accept那一套。组件级别的逆操作自动构成模块级别的回滚单元。
整个Cordis框架以vendor方式引入DeepSeek Harness仓库。Harness里所有具体组件——模型接入、工具集、会话管理、沙箱、权限控制——全都是不同的Cordis插件。Cordis负责插件的加载、卸载和依赖关系管理,不关心插件具体做什么。这就是元框架的含义。
四千个插件跑四年,拿什么验证了这套设计
Cordis最早服务于Koishi——一个跨平台聊天机器人框架,在开源社区跑了四年,积累了超过4000个插件。聊天机器人场景天然是几十个插件拼在一起、热插拔、随时改配置,跟Agent场景几乎相同,只是没有LLM。
插件日常热替换生效,不用重启服务。插件的清理是自动的,插件作者不写清理代码。依赖拓扑真正存在:IM适配器提供各平台接入,数据库驱动提供存储,功能插件声明这些为依赖并调用。运行中换存储后端或重连适配器,只有依赖被改动的那批插件重新激活。依赖暂时不可用,插件就安静停在那,等依赖出现再自动启动,不出错。
四千个独立作者写的插件,协调全靠中间那个共享上下文。语法对了,依赖声明对了,剩下的Cordis接管。这个规模不是实验室玩具——每天都有新插件发布、更新、卸载,系统持续跑了四年,没出过因为依赖解析错误导致的全局崩溃。
DeepSeek把它拿过来,适配到Agent运行时上。Harness中一个典型的场景:LLM生成一个新的工具插件并加载,旧版本的相同工具被卸载,所有依赖这个工具的技能自动更新它们的依赖引用。整个过程不停服。这不是理论推演,是已经在生产环境跑通的设计。
程序世界的物理学,终于写完了缺失的那一章。
元数据:
arXiv / 2026年8月14日 / Spatiotemporal Composability: A Calculus and Meta-Framework for Dynamic Composition / Peking University & DeepSeek-AI