Cordis 深度拆解:DeepSeek Harness 的"可逆副作用"插件内核——如何让 AI Agent 的每个模块都能安全热拔插
写在前面
2026年8月13日,DeepSeek 在发布 V4 Pro 正式版的同时,开源了旗下首款 Agent 产品——DeepSeek Harness(DSH)。这个框架的核心不是模型,而是插件架构:模型、工具、技能、会话、存储、主循环,全都可以替换、升级、热拔插。
但真正让我停下来多看了两眼的设计,是驱动这一切的底层内核——Cordis。它的核心设计哲学只有一句话:每个副作用都附带逆操作。这不是简单的"注册/注销"机制,而是一套用依赖注入 + 可逆副作用构建的插件图管理方案。
这篇文章,我们把 Cordis 从里到外拆一遍:它解决了什么问题、核心抽象是什么、代码怎么写、与 LangChain/AutoGen 的插件系统有什么本质区别,以及你在生产环境中怎么用它。
一、背景:为什么 AI Agent 框架需要"可逆副作用"
1.1 AI Agent 的插件困境
在传统的 AI Agent 框架里,"插件"(或叫 Tool、Extension、Skill)通常长这样:
注册一个工具 → 框架持有引用 → 卸载时只能等 GC
问题在哪?当一个 Agent 插件做了以下任何一件事,卸载它就会变成一场灾难:
- 启动了一个后台进程(比如一个长期运行的评估任务)
- 修改了全局状态(比如注册了一个全局 HTTP handler)
- 打开了文件句柄或网络连接
- 修改了环境变量
- 写入了一个持久化存储
更复杂的是,AI Agent 的插件通常工作在嵌套调用链里:A 插件调用了 B 服务,B 服务调用了 C 工具链。当你要卸载 A,理论上应该按依赖图的逆序清理——但谁来维护这张图?框架?还是插件自己?
如果插件自己维护,那就等于每个插件都要写一整套"自己的清理逻辑",而且还得知道谁依赖了自己。这是灾难级的耦合。
1.2 现有方案的局限
来看看目前主流 AI Agent 框架是怎么处理这个问题的:
LangChain:插件(Tools)基本上是无状态的函数,注册和卸载就是加到/移除列表。状态全靠外部管理。这意味着 LangChain 的工具集基本不支持有副作用的长期任务。
AutoGen:会话管理器负责生命周期,但插件卸载时的清理逻辑由插件自己负责。没有统一的可逆性保证。
CrewAI:类似地,工具是附加到 Agent 上的,卸载 = 列表删除。没有跨插件依赖追踪。
这些方案有一个共同点:它们假设插件是无状态的或自包含的。一旦你的插件需要管理外部资源(比如沙箱环境、数据库连接),就束手无策。
1.3 Cordis 的设计起源
Cordis 的设计动机就来自于这个真实的工程痛点。DeepSeek 在构建 Harness 的过程中发现:
如果每个插件都能声明自己的副作用,同时声明"如何撤销这些副作用",那么框架就能在插件卸载时自动执行清理,而不需要插件之间相互知道对方的存在。
这个想法不是 Cordis 首创的——它本质上来自事务性编程和函数式编程的副作用管理思想(类似 Monad 的 bracket、ZIO 的 acquireRelease、或 C++ 的 RAII)。但 Cordis 把这个思想落实到了 AI Agent 插件系统 这个场景,并且做得相当工程化。
二、核心抽象:Context、Service、Plugin 三层模型
Cordis 的整个架构建立在这三个核心抽象上:
Context(上下文)
└── Plugin(插件)
├── Service(服务)
├── Event Handler(事件处理器)
└── Dependency(依赖声明)
2.1 Context:全局插件容器
Context 是 Cordis 的顶层容器,类似于依赖注入框架中的 IoC Container。它负责:
- 加载和卸载插件
- 维护插件之间的依赖关系图
- 在卸载时自动触发逆操作
- 提供服务查询接口
# Cordis Python SDK 核心接口(参考 GitHub: deepseek-ai/deepseek-harness)
from cordis import Context, Plugin, Service
# 创建根上下文
ctx = Context()
# 向上下文注册一个服务
ctx.register("vector_store", MyVectorStore())
# 在上下文中查询服务
store = ctx.get("vector_store")
Context 的关键设计点在于:它是一个树形结构。可以创建子上下文(ctx.child()),子上下文卸载时只清理自己的插件,不影响父上下文。这对 AI Agent 场景特别重要——比如你想在一个隔离的子上下文中运行一个临时任务,任务结束后直接销毁子上下文,所有副作用自动回滚。
# 创建子上下文,运行临时任务
with ctx.child() as subctx:
subctx.load(temporary_plugin)
# ... 运行任务,所有资源由 subctx 管理
# 退出 with 块时,subctx 自动卸载,逆操作全部执行
2.2 Plugin:带生命周期声明的单元
一个 Cordis 插件不是简单的函数集合,而是一个带生命周期声明的包:
from cordis import Plugin, hook
class SandboxPlugin(Plugin):
name = "sandbox"
version = "1.0.0"
# 定义依赖的其他服务
requires = ["llm_adapter", "logger"]
# 提供给其他插件的服务
provides = ["sandbox_runtime"]
@hook("on_load")
def on_load(self, ctx: Context):
"""插件加载时执行"""
# 启动沙箱进程
self.process = subprocess.Popen(
["firecracker", "--config", self.config_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# 注册逆操作:在卸载时杀死进程
ctx.register_reversible(
action=lambda: self.process.terminate(),
reversal=lambda: None, # 进程终止不需要逆操作
description="terminate_firecracker"
)
# 注册服务
ctx.register("sandbox_runtime", SandboxRuntime(self.process))
@hook("on_unload")
def on_unload(self, ctx: Context):
"""插件卸载时执行——通常不需要手动写,
Cordis 会自动执行通过 register_reversible 注册的逆操作"""
pass
这里的关键是 ctx.register_reversible() ——这是 Cordis 的核心机制。插件不是通过"记住自己做了什么"来回滚,而是通过声明式地向 Context 注册"正操作+逆操作"对来实现可逆性。卸载时,Cordis 自动按逆序执行所有已注册的逆操作。
2.3 Service:带接口的服务对象
Service 是一个标记性抽象,代表"其他插件可以依赖的服务"。它本质上就是一个 Python 对象,但通过 Cordis 的类型系统,带上了依赖关系和生命周期语义:
from cordis import Service, implements
class LLMAdapter(Service):
"""LLM 适配器服务接口"""
async def complete(self, prompt: str) -> str:
raise NotImplementedError
@implements(LLMAdapter)
class DeepSeekAdapter(LLMAdapter):
def __init__(self, api_key: str, model: str = "deepseek-chat"):
self.api_key = api_key
self.model = model
async def complete(self, prompt: str) -> str:
# 调用 DeepSeek API
...
通过接口抽象,插件之间的依赖就变成了接口依赖而不是具体类依赖。这意味着你可以:
- 开发时用 mock 服务,上线时换真实服务
- 同时运行多个实现(比如同时用 DeepSeek 和 OpenAI 做对比)
- 在测试时注入桩服务
三、可逆副作用机制:从原理到实现
这是 Cordis 最核心、也是最有技术含量的部分。
3.1 为什么要"可逆"而不是"清理"
常规的资源管理思路是"清理"(Cleanup):
# 传统思路:插件自己管理自己的清理
class OldStylePlugin:
def setup(self):
self.file = open("/tmp/output.txt", "w")
self.process = subprocess.Popen(["daemon"])
os.environ["PLUGIN_ACTIVE"] = "1"
def teardown(self):
self.file.close() # 关闭文件
self.process.terminate() # 终止进程
del os.environ["PLUGIN_ACTIVE"] # 恢复环境变量
问题在于:teardown() 方法必须精确知道 setup() 做了什么,并且顺序要对。如果插件在运行过程中动态创建了额外资源(比如插件本身又调用了其他服务),那么 teardown() 需要知道这些依赖的资源链才能正确清理。
Cordis 的思路是每次做副作用操作时立即注册逆操作:
class CordisStylePlugin:
def setup(self, ctx: Context):
# 打开文件 → 同时注册"关闭文件"作为逆操作
ctx.register_reversible(
action=lambda: open("/tmp/output.txt", "w"),
reversal=lambda f: f.close(), # 逆操作接收 action 的返回值
description="open_output_file"
)
# 修改环境变量 → 同时注册"恢复旧值"作为逆操作
old_val = os.environ.get("PLUGIN_ACTIVE")
ctx.register_reversible(
action=lambda: os.environ.__setitem__("PLUGIN_ACTIVE", "1"),
reversal=lambda _: os.environ.__setitem__("PLUGIN_ACTIVE", old_val),
description="set_env_PLUGIN_ACTIVE"
)
# 启动进程 → 逆操作是终止它
ctx.register_reversible(
action=lambda: subprocess.Popen(["daemon"]),
reversal=lambda p: p.terminate(),
description="spawn_daemon"
)
这样,setup() 中的每行代码都同时记录了"如何撤销"。当 Cordis 执行卸载时,它只需要按逆序执行所有已注册的 reversal 就行了——不需要插件自己维护清理逻辑,也不需要框架知道具体操作是什么。
3.2 实现原理:撤销栈(Undo Stack)
Cordis 内部维护一个撤销栈(Undo Stack),每个 register_reversible 调用就是往栈上压一条记录:
撤销栈(后进先出)
┌─────────────────────────┐
│ reversal_4: p.terminate() │ ← 最后注册,最后执行
├─────────────────────────┤
│ reversal_3: env恢复 │
├─────────────────────────┤
│ reversal_2: f.close() │
├─────────────────────────┤
│ reversal_1: (无逆操作) │
└─────────────────────────┘
卸载时,从栈顶向下依次执行逆操作。如果某个逆操作本身也产生了副作用(这在实际中很常见),Cordis 会继续为这个"逆操作的副作用"注册新的撤销记录——形成嵌套撤销栈。
这和数据库事务的 UNDO 日志非常像,区别在于:
- 数据库的 UNDO 记录的是"旧数据",恢复时直接覆盖
- Cordis 记录的是"可调用函数",恢复时执行任意清理逻辑
3.3 跨插件依赖的清理:依赖图 + 拓扑排序
现在考虑一个更复杂的场景:
┌─────────────┐ requires ┌──────────────┐
│ Sandbox │ ──────────────▶ │ LLM Adapter │
│ Plugin │ │ Plugin │
└─────────────┘ └──────────────┘
│ ▲
│ provides │
└────────────────────────────────┘
Sandbox 插件依赖 LLM Adapter 插件。如果要卸载 LLM Adapter,Cordis 需要:
- 检测到 Sandbox 依赖它
- 先卸载 Sandbox(或拒绝卸载 LLM Adapter)
- 再卸载 LLM Adapter
Cordis 的依赖管理基于 声明式依赖:
class SandboxPlugin(Plugin):
requires = ["llm_adapter"] # 声明依赖
@hook("on_load")
def on_load(self, ctx: Context):
# Cordis 保证:在 on_load 执行时,llm_adapter 已加载
# 可以直接使用
llm = ctx.get("llm_adapter")
在加载时,Cordis 执行拓扑排序,保证依赖的插件先加载。在卸载时,Cordis 执行逆拓扑排序——先卸载没有其他插件依赖的叶子节点,再层层向上。
# Cordis 卸载时的依赖处理伪代码
def unload_with_deps(ctx: Context, plugin_name: str):
# 1. 构建依赖图
dependents = ctx.get_dependents(plugin_name)
if dependents and not force:
raise PluginInUseError(
f"Plugin '{plugin_name}' is still required by: {dependents}"
)
# 2. 递归卸载依赖它的插件(自身不算)
for dep in dependents:
unload_with_deps(ctx, dep)
# 3. 执行本插件的撤销栈(后进先出)
ctx.undo_plugin(plugin_name)
3.4 子上下文隔离:嵌套撤销栈
子上下文机制是 Cordis 处理"临时任务隔离"的方案:
# 主上下文:包含基础服务
main_ctx = Context()
main_ctx.load(core_plugin) # 全局共享,不会被临时任务影响
main_ctx.load(llm_adapter)
# 临时任务:在子上下文中运行
async def run_temp_agent(task: str):
async with main_ctx.child() as task_ctx:
# 临时任务只在这个子上下文中加载自己的插件
await task_ctx.load(sandbox_plugin) # 独立沙箱
await task_ctx.load(custom_tool_plugin)
# 运行 Agent
agent = Agent(runtime=task_ctx.get("sandbox_runtime"))
result = await agent.run(task)
return result
# with 块结束时:
# 1. 触发 task_ctx 的撤销栈(按逆序执行所有注册的 reversal)
# 2. 关闭所有临时资源
# 3. 主上下文的插件完全不受影响
这在 AI Agent 场景中非常有价值。比如你要并发运行多个 Agent 任务,每个任务需要自己的沙箱环境、自己的工具集、自己的临时存储——子上下文让这一切变得干干净净。
四、DeepSeek Harness 如何使用 Cordis
4.1 Harness 的插件体系
DeepSeek Harness 基于 Cordis 构建,官方定义的插件类型包括:
| 插件类型 | 说明 | 示例 |
|---|---|---|
llm | LLM 模型适配器 | DeepSeek 适配器、OpenAI 适配器 |
tool | 工具注册表 | 搜索工具、代码执行工具 |
skill | 技能包 | 某个垂直领域的工具集合 |
session | 会话管理 | 内存会话、持久化会话 |
sandbox | 隔离执行环境 | Firecracker microVM、Docker |
storage | 持久化存储 | 文件系统、向量数据库 |
loop | Agent 主循环 | ReAct 循环、Plan-Execute 循环 |
scheduler | 任务调度器 | 优先级调度、并发控制 |
ui | 用户界面 | CLI、Web UI |
所有这些插件都遵循 Cordis 的 Plugin 接口,通过 requires/provides 声明依赖关系。
4.2 用 Harness 配置一个多模型路由 Agent
以下是 Harness 的典型配置文件(YAML 格式),展示如何用 Cordis 插件系统组合出一个具有多模型路由能力的 Agent:
# harness.yaml
name: "multi-model-router"
version: "1.0"
plugins:
# LLM 适配器:同时接入多个模型
- name: llm/deepseek
package: cordis-llm-deepseek
config:
api_key: ${DEEPSEEK_API_KEY}
model: deepseek-chat
max_tokens: 8192
- name: llm/openai
package: cordis-llm-openai
config:
api_key: ${OPENAI_API_KEY}
model: gpt-4.6-turbo
- name: llm/claude
package: cordis-llm-anthropic
config:
api_key: ${ANTHROPIC_API_KEY}
model: claude-sonnet-4-20250514
# 工具集
- name: tools/search
package: cordis-tools-websearch
config:
engine: brave
api_key: ${BRAVE_API_KEY}
- name: tools/code_exec
package: cordis-tools-code
requires: [sandbox/default]
config:
timeout_seconds: 30
max_memory_mb: 512
# 沙箱
- name: sandbox/default
package: cordis-sandbox-firecracker
config:
snapshot_path: /opt/harness/base-snapshot.bin
network_bridge: harness-br0
# Agent 主循环:多模型路由循环
- name: loop/router
package: cordis-loop-model-router
requires: [llm/deepseek, llm/openai, llm/claude]
config:
routing_policy: "cost-quality-balance" # 或 "fastest", "highest-quality"
fallback_order: [deepseek, openai, claude]
thresholds:
coding: { model: claude, min_quality: 0.85 }
fast_response: { model: deepseek, max_latency_ms: 2000 }
default: { model: openai }
这份配置不需要写一行 Python 代码。Cordis 会自动:
- 按拓扑序加载所有插件
- 验证依赖完整性
- 启动各插件的副作用
- 注册所有逆操作
4.3 代码级插件开发
如果要开发自己的 Cordis 插件,完整流程如下:
# cordis_my_tool/__init__.py
from cordis import Plugin, hook, Service, contextproperty
import httpx
class MyWebSearchService(Service):
"""自定义搜索服务"""
def __init__(self, api_key: str, engine: str = "brave"):
self.client = httpx.AsyncClient(
headers={"Authorization": f"Bearer {api_key}"},
timeout=10.0
)
self.engine = engine
async def search(self, query: str, top_k: int = 5) -> list[dict]:
response = await self.client.post(
f"https://api.search.{self.engine}.com/v1/search",
json={"q": query, "count": top_k}
)
return response.json()["results"]
class MyToolPlugin(Plugin):
name = "my-web-search"
version = "1.0.0"
# 声明插件元数据
provides = ["web_search"]
requires = []
@hook("on_load")
async def on_load(self, ctx, config: dict):
# 初始化服务
service = MyWebSearchService(
api_key=config["api_key"],
engine=config.get("engine", "brave")
)
# 注册服务(其他插件可以通过 ctx.get("web_search") 使用)
ctx.register("web_search", service)
# 注册可逆副作用:异步客户端需要在卸载时关闭
ctx.register_reversible(
action=lambda: None, # action 是空操作,客户端已在 service.__init__ 创建
reversal=lambda _: self._close_client(service),
description="close_httpx_client"
)
# 注册事件处理器
ctx.on("agent.before_tool_call", self._log_tool_call)
@hook("on_unload")
async def on_unload(self, ctx):
# 注销事件处理器
ctx.off("agent.before_tool_call", self._log_tool_call)
async def _close_client(self, service: MyWebSearchService):
await service.client.aclose()
async def _log_tool_call(self, event):
print(f"[MyTool] Agent calling tool: {event['tool_name']}")
五、与 LangChain/AutoGen 插件系统的本质区别
| 维度 | LangChain | AutoGen | Cordis (Harness) |
|---|---|---|---|
| 插件形态 | Python 函数(@tool 装饰器) | ConversationGroup + Handler | 声明式插件包(Plugin 类) |
| 状态管理 | 无内置机制,靠外部 | 有限的状态清理钩子 | 可逆副作用 + 撤销栈 |
| 依赖声明 | 无 | 无 | requires/provides 声明 |
| 卸载安全性 | 不可靠(有资源泄漏风险) | 部分可靠 | 可靠(自动撤销栈执行) |
| 子上下文 | 不支持 | 不支持 | 支持(嵌套隔离) |
| 事件系统 | 有限(回调钩子) | 会话级别回调 | 统一事件总线(ctx.on/off) |
| 插件隔离 | 无 | 无 | 有(子上下文级别) |
| 配置方式 | 代码 | 代码 | YAML 配置(声明式) |
Cordis 的本质区别在于:它把"副作用管理"从插件的手动实现中抽离出来,变成了框架层的保证。在 LangChain 里,插件作者需要自己记得在 teardown 中清理资源;在 Cordis 里,插件作者在 on_load 中就声明了清理方式,框架保证执行。
六、生产环境部署实战
6.1 Docker Compose 部署 Harness
以下是生产级部署配置,包含持久化存储、监控、健康检查:
# docker-compose.yml
version: "3.9"
services:
harness:
image: deepseek/harness:latest
container_name: dsh-agent
ports:
- "8080:8080"
- "8081:8081" # metrics 端口
environment:
- HARNESS_CONFIG=/etc/harness/config.yaml
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
- LOG_LEVEL=info
volumes:
- ./config:/etc/harness:ro
- hns_data:/var/lib/harness # 持久化数据卷
deploy:
resources:
limits:
cpus: "4"
memory: 8G
reservations:
cpus: "2"
memory: 4G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
cap_add:
- NET_ADMIN # Firecracker 需要,用于网络配置
devices:
- /dev/kvm:/dev/kvm # 硬件虚拟化支持
# 可选:持久化向量存储插件
qdrant:
image: qdrant/qdrant:v1.7.0
container_name: dsh-vector-store
ports:
- "6333:6333"
- "6334:6334"
volumes:
- qdrant_storage:/qdrant/storage
profiles:
- with-vector-store
# Prometheus 监控
prometheus:
image: prom/prometheus:latest
container_name: dsh-prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
profiles:
- with-monitoring
volumes:
hns_data:
qdrant_storage:
prometheus_data:
6.2 Harness 配置文件
# config/harness.yaml
harness:
name: production-agent
log_level: info
plugins:
- name: llm/deepseek
package: cordis-llm-deepseek
enabled: true
config:
api_key: ${DEEPSEEK_API_KEY}
model: deepseek-chat
temperature: 0.7
max_tokens: 8192
retry:
max_attempts: 3
backoff_ms: 1000
- name: sandbox/firecracker
package: cordis-sandbox-firecracker
enabled: true
config:
snapshot: /opt/harness/snapshots/base-snapshot.bin
max_instances: 4 # 最大并发沙箱数量
memory_mb: 512
vcpus: 2
timeout_seconds: 60
- name: storage/qdrant
package: cordis-storage-qdrant
enabled: true
requires: [llm/deepseek]
config:
url: http://qdrant:6333
collection: agent_memory
vector_dim: 1536
- name: loop/react
package: cordis-loop-react
enabled: true
requires: [llm/deepseek, tools/*]
config:
max_iterations: 20
timeout_seconds: 300
reflection_enabled: true
tools:
enabled:
- web_search
- code_execution
- file_read
- web_page_fetch
web_search:
engine: brave
api_key: ${BRAVE_API_KEY}
top_k: 5
code_execution:
sandbox: firecracker
allowed_languages:
- python
- bash
- javascript
max_output_chars: 10000
monitoring:
enabled: true
port: 8081
metrics:
- agent_iterations
- tool_call_count
- llm_token_usage
- sandbox_startup_time
- plugin_load_time
6.3 性能基准测试
在生产环境中,Cordis 插件系统的开销实测数据(DeepSeek 官方 benchmark,2026-08-13):
| 操作 | 平均耗时 | P99 |
|---|---|---|
| 插件加载(无依赖) | 45ms | 80ms |
| 插件加载(含5个依赖) | 180ms | 320ms |
| 插件卸载(含全部逆操作) | 25ms | 60ms |
| 子上下文创建 | 8ms | 15ms |
| 子上下文销毁(触发全部撤销) | 120ms | 250ms |
服务查询(ctx.get) | 0.02ms | 0.05ms |
关键观察:子上下文的撤销操作是最慢的环节,因为它需要按逆序执行所有注册的副作用。这个开销与注册的副作用数量成正比——如果你在一个子上下文中打开了100个文件,关闭这100个文件描述符就是撤销栈的执行时间。
优化建议:
- 对长时间运行的任务,尽量把有副作用的操作提前注册,减少运行时的撤销栈深度
- 对高频临时任务,考虑复用子上下文而不是每次新建(但要注意状态隔离)
- 使用异步 I/O 包装文件和网络操作,让逆操作的执行更快
七、总结与展望
7.1 Cordis 的核心价值
Cordis 解决了一个非常具体但被长期忽视的问题:AI Agent 插件的生命周期管理。它的贡献不是发明了什么全新的概念,而是把"可逆副作用"这个函数式编程中的思想,成功地产品化、工程化,并应用到了 AI Agent 这个新兴领域。
三大核心价值:
- 可靠性:通过撤销栈和依赖图,保证插件卸载时不会留下资源泄漏
- 可组合性:声明式依赖 + 服务接口,让插件之间以最小耦合度协作
- 隔离性:子上下文机制,使得临时任务可以安全地运行在隔离环境中
7.2 局限性
Cordis 也不是银弹,以下场景它目前处理得不够好:
- 跨进程副作用:如果插件 fork 了子进程,Cordis 的撤销栈无法追踪子进程的退出(需要手动处理
SIGCHLD) - 分布式事务:当插件通过网络调用触发了远程状态变更,Cordis 的撤销是本地的,无法回滚远程状态
- 插件图循环依赖:虽然 Cordis 在加载时会检测循环依赖,但某些合法的循环依赖场景目前会直接拒绝加载
- 动态副作用:运行时动态创建的资源(比如根据请求动态创建文件),需要在运行时不断注册撤销记录,增加了开发负担
7.3 未来方向
根据 DeepSeek 官方路线图,Cordis 的未来发展方向包括:
- Rust 重写核心:当前 Cordis SDK 有 Python 和 TypeScript 两个版本,性能关键路径(撤销栈执行引擎)将迁移到 Rust,以支持更低延迟的插件切换
- WASM 插件支持:允许用 WASM 编译的插件作为隔离单元运行,进一步提升安全性和性能
- 分布式 Cordis:支持跨多台机器的插件协调,通过 Raft 共识保证分布式撤销的一致性
- 可视化调试工具:展示插件依赖图、撤销栈状态,帮助开发者理解复杂插件系统的运行机制
Cordis 是一个值得关注的技术方向。无论你最终是否使用 DeepSeek Harness,理解它背后的可逆副作用 + 依赖注入设计哲学,对构建任何需要精细生命周期管理的系统,都会有启发。
Tags: Cordis | DeepSeek Harness | AI Agent | 插件架构 | 可逆副作用 | 依赖注入 | Python | Firecracker | 沙箱隔离 | 生命周期管理
字数:约 9600 字