给 DeepSeek Harness 开发功能:别急着写 Tool,先找对扩展层
ç» DeepSeek Harness å¼ååè½ï¼å«æ¥çå Toolï¼å æ¾å¯¹æ©å±å±
çº¯ç±æé¨äºº 2026-08-14 0 é 读7åéå¨å¾å¤ Agent æ¡æ¶éï¼å¼ååè½å ä¹çåäºâ注åä¸ä¸ª Toolâã
DeepSeek Harness 䏿¯è¿æ ·ã
Tool åªæ¯æ¨¡åä¾§ç Consumerãä¸ä¸ªå®æ´åè½è¿å¯è½æ¶å ServiceãProviderãäºä»¶ãæä¹ åãæéå UIã妿ä¸ä¸æ¥å°±æææé»è¾å¡è¿ Toolï¼æåå¾å°çä»ç¶æ¯ä¸ä¸ªæ æ³æ¿æ¢çå使¨¡åã
è¿ç¯ä»ä¸ä¸ªæå° Tool å¼å§ï¼éæ¥è®²æ¸ åè½åºè¯¥æä¹è½å¨ Harness éã
å ååè½å½å±å¤æ
å代ç åï¼å ç¡®è®¤éæ±å±äºåªä¸å±ï¼
| éæ± | æ©å±ä½ç½® |
|---|---|
| å¢å 模å | ctx.llm Adapter |
| å¢å 模åå·¥å · | ctx.tools |
| å¢å ç¨æ·å½ä»¤ | ctx.commands |
| å¢å åå°ä»»å¡ | ctx.jobs |
| æ¿æ¢æä»¶ç³»ç» | ctx.fs Provider |
| æ¿æ¢è¿ç¨æ§è¡ | ctx.subprocess Provider |
| å¢å æ§è¡çç¥ | tools/* æ fs/* äºä»¶ |
| æ³¨å ¥æ¨¡åä¸ä¸æ | agent.inject() |
| ä¿åä¼è¯äºå® | SessionEventMap |
| å¢å è天 UI èç¹ | Conversation Node ä¸ Renderer |
妿åè½å·²ç»ææç¡®æ©å±ç¹ï¼å°±ä¸è¦ä¿®æ¹ Agent Loopã
仿尿件å¼å§
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export function apply(ctx: Context) {
console.log('my plugin loaded')
}
è¿ä¸ªæ¨¡åå·²ç»æ¯åæ³æä»¶ã
æ¬å°è°è¯æ¶ï¼ç¨ Patch å è½½ï¼
- insert:
- id: my-plugin
name: '/absolute/path/to/my-plugin.ts'
pnpm dsh web --patch ./scratch-plugin/cordis.yml
ä¸è¦ä¸ºäºéªè¯ä¸ä¸ªæ³æ³å°±å åå»ºå®æ´ npm å ãPatch æ´éåååé¶æ®µï¼ç¡®è®¤æ©å±ç¹æ£ç¡®ååæå ã
ä¾èµä¸è¦é å 载顺åº
æä»¶éè¦ Tool Registry æ¶ï¼åºå£°æ injectï¼
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(/* ... */)
}
Cordis ä¼å¨ tools æå¡å°±ç»ªåè°ç¨ applyã
ä¸é¢è¿ç§æ¹å¼ä¸å¯é ï¼
import { globalToolRegistry } from 'some-provider'
å®è®©æä»¶ä¾èµå ·ä½ Providerï¼ä¹ç»è¿äº Profile çç»åè½åãæ¢ä¸ä¸ª Tool Provider æé离 Realm åï¼ä»£ç å¾å¯è½ç´æ¥å¤±æã
åå¯ä½ç¨æ¶é¡ºæåæ¸ çé»è¾
æä»¶å¯è½è¢«å¸è½½ï¼ä¹å¯è½å 为é ç½®åæ´èçæ¿æ¢ã
宿¶å¨ãè¿æ¥åå¤é¨è¿ç¨å¿ 须坿¸ çï¼
export function apply(ctx: Context) {
ctx.effect(() => {
const timer = setInterval(runTask, 5000)
return () => {
clearInterval(timer)
}
})
}
妿æä»¶æ³¨åäºä¸ä¸ªè½åï¼è¿åºè¯¥è¡¥ä¸ä¸ªçå½å¨ææµè¯ï¼
æè½½æä»¶
â æè¨æ³¨ååå¨
â Dispose Fiber
â æè¨æ³¨åæ¶å¤±
è¿ç±»æµè¯æ¯å纯éªè¯â注åæåâæ´éè¦ï¼å 为æ®ç注åé常åªä¼å¨çæ´æ°æå¤æ¬¡æµè¯åæ´é²ã
é ç½®ä¸è¦åæ»å¨å¸¸éé
ä¸åç¯å¢å¯è½ååçåæ°ï¼é½åºè¯¥è¿å ¥é ç½® Schemaï¼
import Schema from '@deepseek-ai/schemastery'
export interface Config {
endpoint: string
timeoutMs: number
}
export const Config: Schema<Config> = Schema.object({
endpoint: Schema.string().required(),
timeoutMs: Schema.number().default(30_000),
})
export function apply(ctx: Context, config: Config) {
// config å·²ç»è¿è¿è¡æ¶æ ¡éª
}
ä¸ä¸ªç®åå¤ææ¹æ³æ¯ï¼
ä¿®æ¹è¿ä¸ªå¼æ¶ï¼è¿ç»´æç¨æ·æ¯å¦åºè¯¥éæ°ç¼è¯ä»£ç ï¼
å¦æçæ¡æ¯å¦å®çï¼å®å°±ä¸è¯¥æ¯ç¡¬ç¼ç 常éã
Schema åæ¶æ¿æ é»è®¤å¼åå è½½ææ ¡éªãé ç½®é误åºè¯¥è®©æä»¶æç¡®å 载失败ï¼è䏿¯ææåéå°ä¸ä¸ªæå¤å¼ã
ä¸ä¸ªåæ ¼ç Tool è³å°æä¸å±
ä¸é¢æ¯å®æ¹æç¨ä¸çé®å Toolï¼
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet',
description: 'Greet someone by name.',
parameters: {
name: {
type: 'string',
required: true,
description: 'The name to greet',
},
},
output: {
schema: { type: 'string' },
render: (_args, value) => [
{ type: 'text', text: value },
],
},
async execute(args) {
return `Hello, ${args.name}!`
},
}))
}
è¿éæ æåå¼äºä¸ä»¶äºï¼
parameters å®ä¹å¹¶æ ¡éªæ¨¡åè¾å
¥
execute è¿åè§èä¸å¡å¼
output.render è½¬æ¢ææ¨¡åå¯è§å
容
ä¸è¦è®© execute ç´æ¥è¿å䏿®µå¸¦ UI å«ä¹çæ¼æ¥ææ¬ãä¸å¡å¼ä¸å±ç¤ºå离åï¼åä¸ä¸ªç»ææè½è¢«æ¥å¿ãæµè¯ã模åå Web UI å嫿¶è´¹ã
ä»ä¹æ¶åéè¦ Capability Seam
å设è¦å¢å ä»£ç æç´¢è½åã
å¦ææ°¸è¿åªè°ç¨ä¸ä¸ªåºå® SDKï¼å¯ä»¥å ååæä»¶ã
ä½å¦ææªæ¥éè¦æ¬å°æç´¢ãè¿ç¨æç´¢åæ²ç®±æç´¢ï¼å°±åºè¯¥æåï¼
code-search Service Definition
code-search-local Local Provider
code-search-remote Remote Provider
tool-code-search Model Consumer
Tool åªä¾èµ code-search æ¥å£ï¼ä¸å
³å¿æç´¢åçå¨åªéã
å»ºç« Seam ååºç¡®è®¤è³å°æ»¡è¶³ä¸é¡¹ï¼
- åå¨å¤ç§ Provider
- å¤ä¸ª Consumer å ±äº«åä¸è½å
- éè¦ç¬ç«å®å ¨è¾¹ç
- éè¦æ¿æ¢è¿è¡ç¯å¢
- éè¦åç¬æµè¯æåå¸
å¦åæå ææ¬å¯è½é«äºæ¶çã
模åè½çå°çå å®¹å¿ é¡»è¿å ¥æ¥å¿
å设æä»¶è¦æé¡¹ç®è§åæ³¨å ¥ä¸ä¸æ¬¡æ¨¡å请æ±ã
ç´æ¥çå¬ agent/request å¹¶ä¿®æ¹æ¶æ¯ï¼çèµ·æ¥è½å·¥ä½ï¼ä½æ¢å¤ä¼è¯æ¶æ æ³éå»ºè¿æ®µå
容ã
Harness è¦æ±æ¨¡åå¯è§å 容è½å¤ä» Session Event æ¥å¿éæ¾ã
æ£ç¡®è®¾è®¡è³å°è¦åçï¼
- è¿æ¯ä»ä¹æä¹ äºå®ï¼
- 对åºåªä¸ç§ Session Eventï¼
- å¦ä½ä»æ¥å¿æå½±ææ¨¡åæ¶æ¯ï¼
- Fork æ¶æ¯å¦ç»§æ¿ï¼
- UI æ¯å¦éè¦å±ç¤ºï¼
- Snapshot å¦ä½åºå®è¡ä¸ºï¼
è¿ä¸æ¥ä¼å¢å 代ç éï¼ä½è½é¿å âå½åè¿è¡æ£å¸¸ï¼æ¢å¤åè¡ä¸ºæ¹åâçé®é¢ã
æ¦æªäºä»¶æ¶ä¸è¦å¿è®° next()
Waterfall äºä»¶å 许æä»¶å è£ åç»è¡ä¸ºï¼
ctx.on('tools/pre-execute', async (request, next) => {
checkPermission(request)
return next()
})
妿çç¥å³å®æç»ï¼å¯ä»¥æ¾å¼è¿åé误ææç»ç»æã
妿å
许继ç»ï¼å°±å¿
é¡»è°ç¨ next()ãæ¼æå®ä¼è®©åç»æ§è¡é¾ç´æ¥åæ¢ï¼è¿æ¯ Harness æä»¶å¼åä¸é常å
¸åçé®é¢ã
æµè¯è¦è¦ççå®ç»å
åªåä¸ä¸ª ctx.plugin() åå
æµè¯ï¼ä¸è¶³ä»¥è¯ææä»¶è½å¨äº§åä¸è¿è¡ã
Harness 宿¹æµè¯å¤§è´å为ï¼
pnpm run test # Unit
pnpm run test:coverage # éæä»¶è¦ççé¨ç¦
pnpm run test:snapshot # Keyless è¡ä¸ºä¸æ¥å¿å¿«ç
§
pnpm run test:web # æµè§å¨å¿«ç
§
pnpm run test:e2e # ç宿¨¡å API
pnpm run build # æå»ºåå¸äº§ç©
pnpm run typecheck
pnpm run lint
产åå¯è§æä»¶è³å°éè¦ä¸æ¬¡çå® Loader ç»åæµè¯ãæµè¯åºä» cordis.yml å¯å¨æä»¶ï¼è䏿¯åªæå·¥ç»è£
Contextã
妿åè½ä¿®æ¹äºæ¨¡åãåè®®æç¨æ·å¯è§è¾åºï¼è¿éè¦å¢å Keyless Snapshotã
çå® API E2E ä¸åºè¯¥æ£æ¥ Agent åç䏿¯å¦å å«âæåâ两个åãæä»¶ä»»å¡è¦éæ°è¯»åæä»¶ï¼å½ä»¤ä»»å¡è¦éæ°æ§è¡éªè¯ã
éªè¯ä¸çæ¯å¦æ¹åï¼ä¸è¦éªè¯ Agent æ¯å¦å£°ç§°èªå·±æ¹åäºä¸çã
ææä»¶å叿 Bundle
Bundle æ¯å¸¦æ Cordis Patch ç npm å ï¼
{
"name": "dsh-hello-plugin",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": {
"bundle": {
"patch": "./cordis.patch.yml"
}
}
}
cordis.patch.ymlï¼
- insert:
- id: hello
name: dsh-hello-plugin
æ¬å°å®è£ ï¼
dsh plugin --profile demo add ./hello-plugin
dsh --profile demo --dump-config
dsh --profile demo
没æ dsh.bundle çæ®é npm å
ä¹è½æä¸º Profile ä¾èµï¼ä½ä¸ä¼èªå¨è´¡ç®é
ç½®å±ã
ä» GitHub å®è£ æä»¶ææ§è¡é£é©
å¯ä»¥ç´æ¥å®è£ Git ä»åºï¼
dsh plugin --profile demo add \
github:you/hello-plugin#<commit-sha>
ä½ Git ä¾èµæ¿å°çæ¯æºç ï¼ä¸æ¯é¢æå»ºäº§ç©ãTypeScript æä»¶éè¦æä¾ prepare èæ¬ï¼å¨å®è£
åæå»º lib/ã
pnpm 10 ä¹åï¼å®è£
èæ¬é»è®¤éè¦éè¿ allowBuilds æ¾å¼ææã
è¿ä¸æ¯ä¸ä¸ªæ®éé ç½®é¡¹ãæææå³çå 许æä»¶ä»£ç å¨å®è£ é¶æ®µç´æ¥è¿è¡å¨å®¿ä¸»æºä¸ï¼èä¸ä¸å Agent Sandbox ä¿æ¤ã
å æ¤è³å°è¦åå°ï¼
- å®¡æ¥æºç
- éå® Commit SHA
- åªææç¡®åå å
- é¿å è·éå¯å忝
- è½å npm å æ¶ä¼å åå¸é¢æå»ºäº§ç©
- æéè¿
pnpm packäº¤ä» Tarball
æçå¼å顺åº
å®é å¼åä¸ä¸ª Harness åè½æ¶ï¼æä¼æä¸é¢çé¡ºåºæ¨è¿ï¼
确认åè½å½å±
â 夿æ¯å¦éè¦ Capability Seam
â å®ä¹ Service æäºä»¶
â å®ç° Provider
â å®ç° Tool æå
¶ä» Consumer
â æ¥å
¥ Patch
â æµè¯å¸è½½ä¸é误路å¾
â æµè¯çå® Loader ç»å
â å¢å Snapshot
â æå»ºå¹¶éªè¯ lib åå¸å
¥å£
â æå
æ Bundle
è¿ä¸ªé¡ºåºå»ææ Tool æ¾å¨ Provider ä¹åã
å 为 Tool åªæ¯æ¨¡åçå°çå ¥å£ï¼çæ£å³å®ç³»ç»æ¯å¦å¯æ¿æ¢ã坿µè¯å坿¢å¤çï¼æ¯å®èåçè½åè¾¹çã
Aitishiku.com