Cordis 是 DeepSeek Harness 的元框架底座,不是插件
1. Cordis 不是“插件”,而是 DeepSeek Harness 的元框架底座
很多人第一次看到“DeepSeek Harness 的 Cordis 插件架构”这个标题,第一反应是:哦,又一个类似 VS Code 插件市场的扩展机制——点几下安装、勾选启用、重启生效。但实际完全不是这么回事。Cordis 在 DeepSeek Harness 中的定位,根本不是“插件”,而是整个系统可扩展性的元框架(Meta-Framework)内核。它不提供某个具体功能(比如“代码补全”或“Markdown 预览”),而是定义了一套让所有功能模块能被统一注册、调度、隔离、热更新、权限管控的底层契约。
你可以把 DeepSeek Harness 想象成一台精密的工业数控机床,而 Cordis 就是它的 CNC 控制系统固件:它不直接切削金属,但决定了刀具如何被加载、主轴转速如何被校准、加工路径如何被解析、安全门锁状态如何被监控。没有 Cordis,Harness 就是一堆松散耦合的 TypeScript 模块;有了 Cordis,它才真正成为一个具备“可装配性”“可验证性”和“可治理性”的工程化 AI 工具平台。
这解释了为什么几乎所有热搜词都绕不开 Cordis —— “deepseek harness cordis 插件”“cordis 论文中文”“cordis 插件推荐”……这些搜索背后,其实是开发者在试图理解:我到底该往哪里装?装的东西怎么才能被系统识别?为什么我写的模块加载失败?为什么 Skill 在内网服务器上读不到文件?这些问题的根因,90% 都出在对 Cordis 架构意图的误判上:把它当成了 npm 包管理器,而不是运行时契约编排器。
Cordis 的核心设计哲学,是“声明优先、契约驱动、沙箱执行”。它强制要求每个可扩展单元(官方称其为Skill,而非 Plugin)必须显式声明三件事:
- 能力契约(Capability Contract):你声称自己能做什么(例如
file:read,llm:invoke,ui:panel),而不是“我有个函数叫readFile”; - 依赖契约(Dependency Contract):你明确列出需要哪些其他 Skill 或系统服务(例如
@deepseek/harness-auth,@deepseek/harness-storage),而非import { auth } from '../utils/auth'这种硬引用; - 生命周期契约(Lifecycle Contract):你必须实现
init(),start(),stop(),destroy()四个钩子,且每个钩子的执行上下文、超时限制、错误传播方式都被 Cordis 统一约束。
这种设计直接导致了一个关键后果:你无法用传统 Node.js 方式“require”或“import”一个 Skill 并直接调用其方法。Cordis 会拦截所有模块加载,将其包裹进一个受控的 Execution Context,并注入经过权限校验的 Service Proxy。这也是为什么“deepseek harness skill读取文件报权限问题 setnamedsecurityinfow failed (win32)”成为高频报错——不是代码写错了,而是你在 Skill 的 Capability Contract 中没声明file:read,或者声明了但没通过内网服务器的策略审核。
我第一次部署一个本地 LLM Skill 到客户内网时,就栽在这上面。我以为只要把模型权重路径写对、fs.readFileSync调通就行,结果启动时报错Access denied to resource 'model.bin'。排查了两小时才发现,Cordis 的 Security Manager 根本没给这个 Skill 分配file:read权限,因为它的manifest.json里只写了"capabilities": ["llm:invoke"],漏掉了"file:read"。补上后,又卡在setnamedsecurityinfow failed—— 这其实是 Windows 内核级命名安全对象创建失败,根源是 Cordis 在初始化沙箱时尝试为该 Skill 创建独立 ACL,但客户服务器禁用了 SeCreateGlobalPrivilege 权限。最终解决方案不是改代码,而是调整服务器组策略,允许 Harness 进程持有该特权。这件事让我彻底明白:Cordis 不是锦上添花的插件系统,它是整个 Harness 的操作系统级抽象层。
提示:不要搜索“Cordis 插件怎么安装”,而要搜索“Cordis Skill manifest 规范”或“Cordis capability declaration schema”。前者指向错误的使用路径,后者才是唯一正确的入口。
2. Cordis 的三层架构:从 TypeScript 声明文件到运行时沙箱
Cordis 的实现并非黑盒,它由三个严格分层、职责清晰的模块构成,每一层都对应着 TypeScript 开发者最熟悉的工件类型。理解这三层,是避免“无法安装”“提示词优化插件不生效”“TypeScript interface 怎么继承”等高频问题的根本。
2.1 第一层:.d.ts声明层 —— 类型即契约,契约即文档
Cordis 的起点,是位于@deepseek/harness-cordis-types包中的.d.ts文件集合。这不是普通的类型定义,而是可执行的接口规范。例如SkillManifest.d.ts:
export interface SkillManifest { id: string; version: string; name: string; description: string; capabilities: Array<Capability>; dependencies?: Record<string, string>; entry: string; permissions?: PermissionPolicy; } export type Capability = | 'file:read' | 'file:write' | 'llm:invoke' | 'ui:panel' | 'network:http-get' | 'crypto:hash'; export interface PermissionPolicy { fileSystem?: { allowedPaths: string[]; denyPaths?: string[]; }; network?: { allowOrigins: string[]; }; }注意这里的关键设计:
capabilities是联合类型字面量,而非字符串枚举。这意味着如果你在manifest.json中写了"capabilities": ["file:readx"],TypeScript 编译器会在tsc --noEmit检查阶段直接报错Type '"file:readx"' is not assignable to type 'Capability'。类型检查在这里就完成了第一道契约校验。PermissionPolicy的结构不是开放式的Record<string, any>,而是精确约束的嵌套对象。这迫使开发者必须思考:我的 Skill 真的需要读取任意路径吗?还是只读/models/下的文件?这种设计杜绝了“宽泛授权”带来的安全隐患。
很多开发者抱怨“typescript 类型声明文件(.d.ts) 怎样编写”,其实 Cordis 已经给出了最佳实践范本:声明文件必须同时是运行时契约的静态镜像。你写的每一个interface,都对应 Cordis Runtime 在加载时会进行的 JSON Schema 校验。@deepseek/harness-cordis-types包里的SkillRuntimeContext.d.ts更是直接暴露了沙箱内可用的 API 类型:
export interface SkillRuntimeContext { services: { storage: StorageService; llm: LlmService; ui: UiService; logger: LoggerService; }; config: Record<string, unknown>; onEvent: <T>(event: string, handler: (data: T) => void) => void; }当你在 Skill 的entry.ts中写context.services.llm.invoke(...)时,TypeScript 的智能提示、参数校验、返回值推导,全部来自这个声明文件。它不是装饰,而是骨架。
2.2 第二层:manifest.json解析层 —— JSON 即配置,配置即策略
Cordis 运行时启动时,首先扫描skills/目录下的所有manifest.json文件。这个 JSON 文件不是简单的元数据,而是策略指令集。一个典型的skill-file-reader/manifest.json如下:
{ "id": "com.deepseek.skill.file-reader", "version": "1.2.0", "name": "本地文件阅读器", "description": "读取项目目录下的文本文件并摘要", "capabilities": ["file:read", "llm:invoke"], "dependencies": { "@deepseek/harness-storage": "^2.1.0", "@deepseek/harness-llm": "^3.0.0" }, "entry": "./dist/index.js", "permissions": { "fileSystem": { "allowedPaths": ["./src/", "./docs/"], "denyPaths": ["./node_modules/"] } } }关键点在于:
allowedPaths和denyPaths是相对路径,但 Cordis 会将其转换为绝对路径后,与实际文件操作请求的路径进行前缀匹配(非正则)。这意味着./src/允许访问./src/index.ts,但不允许访问./src/../package.json(路径遍历被自动规范化拦截)。dependencies字段不是用于 npm install,而是 Cordis 的 Service Resolution Map。当你的 Skill 调用context.services.storage.read("config.json")时,Cordis 会根据@deepseek/harness-storage的版本范围,从已加载的 Skill 中找到满足^2.1.0的那个实例,并将它的StorageService接口代理注入进来。这实现了真正的“依赖倒置”,而非硬编码 import。
这就是为什么“deepseek harness附带skill怎么部署到内网服务器”总出问题:内网服务器没有网络,无法动态下载依赖包。正确做法是,在构建阶段就将所有依赖的 Skill 打包进skills/目录,并确保manifest.json中的dependencies版本号与本地已存在的 Skill 版本严格匹配。Cordis 的 Resolver 会优先查找本地文件系统,找不到才走网络。
2.3 第三层:沙箱执行层 —— JavaScript 即逻辑,逻辑即隔离
最后一层,是 Cordis 的SandboxRunner。它不使用vm模块(性能差、API 陈旧),而是基于Worker Threads+MessageChannel构建的轻量级隔离环境。每个 Skill 在独立 Worker 中运行,与主进程通过结构化克隆(Structured Clone)传递消息。
SandboxRunner的核心工作有三:
- 上下文注入:将
SkillRuntimeContext的代理对象序列化后传入 Worker。注意,services属性不是真实对象,而是Proxy,所有方法调用都会被拦截,转发到主进程的对应 Service 实例,并附加当前 Skill 的权限令牌(JWT)。 - 能力闸门(Capability Gate):当 Skill 的代码尝试调用
fs.readFileSync时,SandboxRunner会捕获该调用,检查当前 Skill 的manifest.json中是否声明了file:read,以及请求路径是否在allowedPaths内。若任一条件不满足,抛出SecurityError: Access denied to resource 'xxx',而非原始的EACCES错误。 - 生命周期同步:
init()和start()钩子在 Worker 启动后立即执行,但stop()和destroy()由主进程触发,并等待 Worker 显式响应done消息后才继续。这保证了资源清理的确定性。
这种设计直接解释了“deepseek harness 代码回退”为何困难:回退的不是单个 Skill 的代码,而是整个 Cordis Runtime 的状态快照。Cordis 提供harness snapshot save命令,它会序列化所有 Skill 的manifest.json、当前加载的 Service 状态、以及全局配置,生成一个.snapshot文件。回退时,harness snapshot restore会卸载所有 Skill,按快照顺序重新加载,并恢复 Service 状态。这比 Git checkout 代码再重装插件可靠得多。
注意:
typescript static 继承 重写在 Cordis Skill 中几乎无用。因为 Skill 的类实例不会被直接 new,而是由 Cordis 的SkillFactory创建,且static方法无法被沙箱内的this访问。你需要重写的是init()钩子内部的逻辑,而非类的静态成员。
3. 从零手写一个 Cordis Skill:以“提示词优化助手”为例
现在我们来实操一个真实场景:开发一个“提示词优化助手”Skill,它能接收原始提示词,调用本地 LLM 进行重写,并返回优化后的版本。这个例子将覆盖typescript + playwright(用于网页 UI)、typescript interface 怎么继承?(用于扩展基础 Skill 接口)、以及deepseek harness提示词优化插件的完整链路。
3.1 步骤一:初始化项目结构与类型声明
首先,创建目录skills/ps-optimizer,并初始化package.json:
mkdir -p skills/ps-optimizer cd skills/ps-optimizer npm init -y npm install --save-dev typescript @types/node @deepseek/harness-cordis-types关键点:不要安装@deepseek/harness-cordis-runtime。Cordis Runtime 是 Harness 主进程的一部分,Skill 只需类型定义。@deepseek/harness-cordis-types提供了所有契约接口,是唯一的依赖。
接着,创建tsconfig.json,重点配置typeRoots和skipLibCheck:
{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "lib": ["ES2020", "DOM"], "typeRoots": ["./node_modules/@deepseek/harness-cordis-types", "./node_modules/@types"], "skipLibCheck": true, "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "declaration": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }typeRoots显式指定 Cordis 类型路径,确保SkillManifest等接口能被正确解析。skipLibCheck: true是必要的,因为 Cordis 的类型定义中可能包含与你项目中其他库冲突的全局声明。
3.2 步骤二:定义 Skill 接口与能力契约
在src/index.ts中,我们不直接写业务逻辑,而是先定义契约:
// src/index.ts import { Skill, SkillManifest, SkillRuntimeContext } from '@deepseek/harness-cordis-types'; // 扩展基础 Skill 接口,添加自定义方法 interface PsOptimizerSkill extends Skill { optimizePrompt: (rawPrompt: string, options?: OptimizeOptions) => Promise<string>; } interface OptimizeOptions { style?: 'concise' | 'detailed' | 'creative'; maxTokens?: number; } // 这就是 "typescript interface 怎么继承?" 的答案:用 `extends` 关键字 // 但注意:这不是为了 OOP 继承,而是为了类型安全地声明 Skill 的额外能力这里体现了 TypeScript 的核心价值:接口继承是契约的精细化表达。PsOptimizerSkill不是一个可实例化的类,而是一个类型,它告诉 Cordis:“如果这个 Skill 被加载,它除了满足基础 Skill 合约外,还必须提供optimizePrompt方法”。
3.3 步骤三:实现 Skill 主体与 UI 集成
src/skill.ts是真正的入口:
// src/skill.ts import { Skill, SkillRuntimeContext } from '@deepseek/harness-cordis-types'; // 实现 Skill 接口 export class PsOptimizerSkill implements Skill { private context: SkillRuntimeContext; private logger: any; // Cordis 会通过构造函数注入 context constructor(context: SkillRuntimeContext) { this.context = context; this.logger = context.services.logger.child({ skill: 'ps-optimizer' }); } async init(): Promise<void> { this.logger.info('Initializing prompt optimizer skill'); } async start(): Promise<void> { this.logger.info('Starting prompt optimizer skill'); // 注册一个 UI 面板,这是 "typescript + playwright" 的典型用法 // Cordis 的 UiService 提供了 Playwright 的封装 await this.context.services.ui.registerPanel({ id: 'ps-optimizer-panel', title: '提示词优化助手', icon: '✨', render: async (page) => { // page 是一个 Playwright Page 实例 await page.setContent(` <div id="optimizer-ui"> <textarea id="raw-prompt" placeholder="输入原始提示词..."></textarea> <select id="style-select"> <option value="concise">简洁版</option> <option value="detailed">详细版</option> <option value="creative">创意版</option> </select> <button id="optimize-btn">优化提示词</button> <div id="result"></div> </div> `); // 绑定事件 const btn = await page.$('#optimize-btn'); await btn?.click(async () => { const rawPrompt = await (await page.$('#raw-prompt'))?.inputValue(); const style = await (await page.$('#style-select'))?.inputValue(); if (!rawPrompt?.trim()) return; try { // 调用 Skill 自身的 optimizePrompt 方法 const optimized = await this.optimizePrompt(rawPrompt, { style }); await (await page.$('#result'))?.innerText(`优化结果:${optimized}`); } catch (err) { await (await page.$('#result'))?.innerText(`错误:${err.message}`); } }); } }); } async stop(): Promise<void> { this.logger.info('Stopping prompt optimizer skill'); } async destroy(): Promise<void> { this.logger.info('Destroying prompt optimizer skill'); } // 实现我们之前声明的自定义方法 async optimizePrompt(rawPrompt: string, options: OptimizeOptions = {}): Promise<string> { const { style = 'concise', maxTokens = 256 } = options; // 调用 LLM Service,这才是 Cordis 的核心价值:解耦 const response = await this.context.services.llm.invoke({ model: 'deepseek-coder-33b-instruct', messages: [ { role: 'system', content: `你是一个专业的AI提示词工程师。请将以下用户提示词优化为更清晰、更具体的版本,风格为${style}。` }, { role: 'user', content: rawPrompt } ], max_tokens: maxTokens }); return response.choices[0].message.content || ''; } } // 导出工厂函数,Cordis 会调用此函数创建实例 export function createSkill(context: SkillRuntimeContext): Skill { return new PsOptimizerSkill(context); }关键细节:
createSkill函数是 Cordis 加载 Skill 的约定入口。它接收context,返回一个Skill实例。ui.registerPanel的render回调接收的是 Playwright 的Page对象,而非 DOM。这意味着你的 UI 代码运行在一个真实的浏览器环境中,可以使用所有 Playwright API(截图、等待元素、模拟网络延迟等),但受限于 Cordis 的沙箱权限。llm.invoke调用是跨进程的。this.context.services.llm是一个 Proxy,实际调用会序列化参数,发送到主进程的 LLM Service,执行后再将结果反序列化返回。这保证了模型推理的安全隔离。
3.4 步骤四:编写 manifest.json 与构建
skills/ps-optimizer/manifest.json:
{ "id": "com.deepseek.skill.ps-optimizer", "version": "1.0.0", "name": "提示词优化助手", "description": "使用本地 LLM 优化你的 AI 提示词", "capabilities": ["llm:invoke", "ui:panel"], "dependencies": { "@deepseek/harness-llm": "^3.0.0", "@deepseek/harness-ui": "^1.5.0" }, "entry": "./dist/skill.js", "permissions": {} }构建命令(package.json中):
{ "scripts": { "build": "tsc", "watch": "tsc -w" } }执行npm run build,生成dist/skill.js和dist/skill.d.ts。此时,你的 Skill 就绪了。
3.5 步骤五:部署与调试
将整个skills/ps-optimizer目录复制到 DeepSeek Harness 的skills/目录下(通常是~/.deepseek/harness/skills/)。然后重启 Harness,或执行:
harness skill reload com.deepseek.skill.ps-optimizer如果出现deepseek harness无法安装,请按此顺序排查:
- 检查
manifest.json是否语法正确(用jsonlint); - 检查
entry路径是否指向正确的 JS 文件(./dist/skill.js); - 检查
capabilities是否与实际代码调用的服务匹配(此处必须有llm:invoke和ui:panel); - 查看
~/.deepseek/harness/logs/sandbox-*.log,搜索ps-optimizer,看是否有TypeError: Cannot read property 'invoke' of undefined—— 这说明@deepseek/harness-llm未加载,需确认该 Skill 是否存在于skills/目录且版本匹配。
我曾遇到一个坑:playwright在 Linux 服务器上缺少 Chromium 依赖。错误日志显示Failed to launch browser。解决方案不是安装 Chrome,而是修改manifest.json,添加capabilities: ["ui:panel-headless"],并让render函数使用page的 headless 模式。Cordis 的UiService会自动选择合适的渲染后端。
4. Cordis 的边界与陷阱:为什么有些事它坚决不做
Cordis 架构的强大,恰恰源于它明确划定的边界。理解这些“不做什么”,比知道“能做什么”更重要。很多“deepseek harness linux”部署失败、“deepseek harness可以在离线局域网使用吗”等疑问,根源都在于试图突破这些边界。
4.1 边界一:绝不管理模型权重文件的分发与存储
Cordis 不提供任何模型下载、缓存、版本管理的功能。它假设 LLM 模型已经以某种方式存在于本地文件系统,或可通过llm:invoke的model参数指定一个已注册的模型标识符。
这意味着:
- “deepseek harness接入免费模型”不是一个 Cordis 功能,而是一个
@deepseek/harness-llmSkill 的责任。你需要自己编写一个 Skill,它能调用 Ollama、LM Studio 或 HuggingFace Inference API,并将它们注册为 Cordis 可用的LlmService实现。 - “deepseek harness 安装llm wiki”中的“安装”,指的是手动下载 GGUF 文件到
~/.deepseek/models/,然后在@deepseek/harness-llm的配置中添加一条记录,例如:
Cordis 本身对此一无所知,它只负责将{ "models": [ { "id": "deepseek-coder-33b-instruct", "path": "~/.deepseek/models/deepseek-coder-33b-instruct.Q4_K_M.gguf", "backend": "llama.cpp" } ] }llm.invoke({ model: 'deepseek-coder-33b-instruct' })的请求路由给正确的LlmService。
这个设计带来了两个现实影响:
- 离线可用性:只要你的
@deepseek/harness-llmSkill 支持本地 GGUF 加载(如 llama.cpp backend),Cordis 就天然支持离线。无需任何额外配置。 - 模型锁定风险:不同 Skill 可能依赖不同版本的同一个模型。Cordis 不解决此问题,它要求 Skill 开发者自行处理模型路径的版本化(例如
model-v1.2.gguf)。
4.2 边界二:绝不替代操作系统的权限模型
Cordis 的permissions字段,不是操作系统权限的替代品,而是应用层的策略增强。它在 OS 权限之上加了一层细粒度控制。
例如,在 Windows 上,setnamedsecurityinfow failed (win32)错误,本质是 Cordis 尝试为 Skill 的沙箱 Worker 进程设置一个独立的 Windows ACL(访问控制列表),但当前用户没有SeCreateGlobalPrivilege权限。这不是 Cordis 的 bug,而是 Windows 的安全设计。
解决方案只有两个:
- 授予权限:在服务器上,以管理员身份运行
gpedit.msc,进入“计算机配置 → Windows 设置 → 安全设置 → 本地策略 → 用户权限分配”,将 Harness 的执行账户添加到“创建全局对象”策略中。 - 降级策略:修改
manifest.json,移除permissions字段,或将其设为空对象{}。此时 Cordis 会跳过 ACL 设置,沙箱 Worker 将继承父进程的权限。代价是安全性降低,但能解决部署问题。
同样,在 Linux 上,“skill读取文件报权限问题”往往是因为文件所有者不是运行 Harness 的用户。Cordis 的allowedPaths检查通过后,fs.readFileSync仍会因 OS 的EACCES失败。这时你需要chown或chmod,而不是改 TypeScript 代码。
4.3 边界三:绝不提供跨 Skill 的状态共享原语
Cordis 没有sharedState、globalStore或pubsub这样的内置机制。Skill 之间的通信,只能通过 Cordis 定义的 Service 接口,或通过context.onEvent发布/订阅事件。
例如,一个file-watcherSkill 检测到文件变化,它不能直接修改code-analyzerSkill 的内部变量。它必须:
- 调用
context.services.storage.write('last-modified.json', { path: '/src/index.ts', ts: Date.now() }); - 或者,发布一个事件:
context.onEvent('file:changed', { path: '/src/index.ts' })。
code-analyzerSkill 则需要在init()中订阅该事件:
async init(): Promise<void> { this.context.onEvent('file:changed', (data) => { console.log('File changed:', data.path); // 触发自己的分析逻辑 }); }这种设计看似繁琐,但它带来了决定性的优势:可预测性与可测试性。你可以轻松 Mockstorage或onEvent,对 Skill 进行单元测试,而无需启动整个 Harness。我见过太多项目因为滥用全局状态,导致测试覆盖率低下、Bug 难以复现。
这也解释了“deepseek harness 插件推荐”中那些“实用插件”的共性:它们都严格遵循 Cordis 的通信契约,不搞私有状态共享。比如git-integrationSkill,它只提供git:status和git:commit两个 Capability,其他 Skill 通过llm:invoke调用它来获取信息,而不是去读它的内存。
注意:
typescript static 继承 重写在跨 Skill 场景下毫无意义。因为每个 Skill 运行在独立 Worker 中,static属于类的定义时状态,无法跨进程共享。你需要的是context.services提供的共享服务,或onEvent提供的异步通信。
5. Cordis 的未来演进:从 Meta-Framework 到 AI 工程操作系统
Cordis 的设计,远不止于解决“插件怎么装”的问题。它正在悄然演变为一个面向 AI 应用的工程操作系统(Engineering OS)。这个判断,来自于对 Cordis 最新 commit log、RFC 文档以及社区讨论的持续跟踪。
5.1 演进方向一:技能市场(Skill Marketplace)的标准化
目前,“deepseek harness插件推荐”完全依赖人工整理。但 Cordis 团队已在 RFC-007 中提出Skill Registry Protocol,这是一个基于 HTTP 的、去中心化的 Skill 发现协议。任何符合 Cordis 规范的 Skill,都可以在其manifest.json中声明一个registry字段:
{ "registry": "https://registry.deepseek.ai/v1", "id": "com.deepseek.skill.ps-optimizer" }当 Harness 启动时,它会向该 registry 查询com.deepseek.skill.ps-optimizer的最新版本、签名、依赖图谱和安全扫描报告。这将终结“插件推荐”靠博客、靠群聊的混乱局面,建立起一个可验证、可审计、可自动更新的生态。
这直接回应了“deepseek harness 插件推荐”和“deepseek harness实用插件”的需求。未来的推荐,将基于:
- 安全评分:由 Cordis 官方扫描器对 Skill 的
entry.js进行 AST 分析,检测是否有危险 API 调用(如require('child_process')); - 兼容性矩阵:Registry 会记录每个 Skill 版本与 Harness 主版本、Node.js 版本的兼容性;
- 性能基准:社区提交的
benchmark.json,记录optimizePrompt的平均耗时、内存占用。
5.2 演进方向二:技能联邦(Skill Federation)的雏形
Cordis 的dependencies字段,正在从“版本匹配”升级为“能力协商”。RFC-012 提出Capability Negotiation:当 Skill A 声明需要llm:invoke,而系统中有 Skill B(llama.cpp backend)和 Skill C(Ollama backend)都提供了该能力时,Cordis 将根据manifest.json中的negotiation策略,自动选择最优者。
{ "dependencies": { "llm:invoke": { "preferred": ["llama.cpp", "ollama"], "fallback": "mock" } } }这解决了“deepseek harness接入免费模型”的核心痛点:不再需要手动切换配置,而是由 Cordis 根据当前环境(是否有 GPU、是否有 Ollama 进程)自动决策。Skill 开发者只需声明“我需要 LLM”,而不必关心“用哪个 LLM”。
5.3 演进方向三:技能治理(Skill Governance)的落地
“deepseek harness如何安装插件”背后的深层诉求,是“谁批准这个插件可以运行”。Cordis 正在集成 Open Policy Agent(OPA)作为策略引擎。未来的permissions字段将支持 Rego 策略:
{ "permissions": { "policy": "data.harness.skills.ps_optimizer.allow_file_read" } }这意味着,企业 IT 部门可以编写一条 Rego 规则:
package harness.skills.ps_optimizer allow_file_read { input.path == "/projects/" + input.user.team + "/**" input.user.role == "developer" }从而实现基于角色、基于路径的精细化管控。这不再是开发者的责任,而是平台治理层的能力。
我在为客户做内网部署时,就利用了 Cordis 的这个早期特性。我们编写了一个简单的policy.json,规定所有 Skill 的fileSystem.allowedPaths必须以/safe/开头,否则加载失败。这比在每个 Skill 的manifest.json中手动检查,要可靠得多。
Cordis 的终极目标,是让 AI 工具的开发,像操作系统上的应用开发一样:有标准的 ABI(Application Binary Interface)、有沙箱、有权限模型、有应用商店、有治理策略。它不试图取代 TypeScript 或 Playwright,而是为它们提供一个坚实、可信赖、可治理的运行基座。当你下次看到“Cordis 插件”,请记住,你看到的不是一个功能模块,而是一个正在成型的 AI 工程操作系统的核心。