DeepSeek Harness 桌面端来了!带你拆解核心机制

DeepSeek Harness 桌面端来了!带你拆解核心机制

 

DeepSeek Harness(简称 DSH)是 DeepSeek 开源的 AI Agent 框架,在 GitHub 上受到了广泛的关注。

DeepSeek Harness的核心机制,Everything is a Plugin,也就是把各种功能都做成插件,可以按需替换。我们也可以把自己的业务当成插件一样接入进来,比如查询订单、读取内部数据、调用企业服务等,这样就可以让 Agent 在对话中帮我们处理业务。

这篇文章我们先聊聊插件是怎么工作的,再用订单查询做一个例子,看看怎么把业务接入 DSH 里面。

官方最近也给出了桌面端的APP,可以直接下载安装使用。

DeepSeek Harness 桌面端来了!带你拆解核心机制

一、DeepSeek Harness 的插件能力

DeepSeek Harness 用插件组织 Agent 的各项能力,模型接入、工具、技能、会话、沙箱、存储、任务调度和 UI 都由插件提供,连负责驱动任务执行的 Agent Loop 本身也是一个插件。开发者可以沿用官方给出的默认组合,也可以根据需要调整其中的实现。

支撑这套架构的是 Cordis。它不规定模型该怎样调用,也不规定 Agent 该怎样执行任务,而是提供插件生命周期、服务依赖、事件通信和副作用管理机制。具体的 Agent 能力由插件实现,Cordis 负责协调这些插件的组合与运行。

DeepSeek Harness 桌面端来了!带你拆解核心机制

通过配置选择和替换能力:对于已有的兼容插件,开发者可以通过配置调整组合,无需修改 Harness 的主体代码。例如,保留会话和工具体系,换用另一个模型适配器,就可以测试不同模型的表现。自己开发替代插件时,也需要遵守相应的接口、事件和生命周期约定,才能与其他插件协作。

时间可组合性:插件卸载时,清理它注册的能力和资源。 插件运行后,可能注册服务、监听事件,也可能创建定时器或网络连接。Cordis 会在卸载时撤销纳入生命周期管理的注册,并执行相应的资源清理逻辑。插件作者需要把自行创建的资源也交给这套机制管理,才能避免插件移除后仍有监听器或后台任务残留。

空间可组合性:依赖变化时,自动调整相关插件的运行状态。 这里的“空间”指组件之间的依赖关系。插件声明自己需要哪些服务,Cordis 据此协调它的激活和停用:必需的服务尚未就绪时等待,服务就绪后激活,服务消失时停用并清理,服务恢复后重新加载。这为运行期间替换插件提供了基础,不过相关插件可能需要重新初始化,正在执行的任务也不一定能无缝继续。

这种插件化架构,也为自我进化 Agent提供了一种可能:Agent 可以围绕任务检查已有能力,编写所需的插件或配置,再通过插件管理工具将其安装到当前应用中。DeepSeek Harness 的“创造模式”正是这一理念的实验性落地,它试图让 Harness 的配置本身也成为 Agent 可以操作和改变的对象。

二、插件有哪些类型

了解插件如何组合之后,再来看它们分别承担什么工作。如果我们让Agent查订单,就需要工具插件;接入模型服务时,就需要模型适配插件;调整执行权限,可以使用策略插件。下面按主要职责介绍几类常见插件,同一个插件也可以承担多种职责。

类型 常见需求 主要职责
工具插件 查询订单、读取文件、执行命令 把操作提供给模型调用
模型适配插件 接入不同模型服务 对接模型请求、响应和流式输出
服务插件 文件访问、命令执行、会话存储 提供供其他插件调用的公共能力
策略插件 权限检查、超时控制、重试 在执行过程的相应位置施加规则
界面插件 增加面板、输入组件、结果展示 提供用户交互与展示能力
外部系统接入插件 接入 MCP 服务或自动化客户端 对接外部协议与 Harness 能力

DeepSeek Harness 桌面端来了!带你拆解核心机制

其中,服务插件把公共功能提供给其他插件调用。例如,订单查询工具和每日统计任务都要读取订单,可以共用一个订单服务。工具插件负责把查询操作提供给模型,执行时再调用这个服务,简单的查询也可以直接写在工具插件里。

上面按插件承担的工作分类。开发时,还需要考虑插件运行在哪里,因此又有 Host 插件和 Client 插件 的区分。以 Web 版为例,终端启动的 Harness 程序是 Host,负责调用模型、执行订单查询;浏览器里的页面程序是 Client,负责接收输入、显示结果。订单工具运行在 Host,订单详情界面运行在 Client。

MCP 和 Skill 也通过插件接入。已有 MCP 服务器提供订单查询时,MCP 客户端插件可以把它接成模型可用的工具。Skill 则是给 Agent 阅读的任务说明,例如查询前需要哪些信息,由相应插件查找和加载;实际查询仍由工具完成。

三、全部由插件构成,Agent 怎么运行起来

DSH 的 Agent 有一套明确的运行流程,默认由 agent-loop 插件负责。 主循环也和其他能力一样,通过插件机制加载,需要时可以在配置中替换。无论采用哪种实现,都要知道 Agent 是怎么创建、任务需要按什么顺序来执行,以及什么时候结束任务。

DSH 已经提供了一套默认的插件组合,模型调用、工具执行、会话记录和主循环都有各自的实现。我们可以直接使用这套组合,再加上自己的业务插件,不需要从头组装一个 Agent。

Agent Loop 负责把一次任务组织起来。 模型插件负责和模型通信,工具插件提供可以执行的操作,会话插件负责保存对话与执行记录。Agent Loop 按照主流程调用这些能力,让一次模型请求、一次工具执行和后续回答形成完整的链路。

比如用户让助手查订单,一次常见的执行过程是:

用户提出查询请求

↓

Agent Loop 整理上下文、系统提示词和可用工具,交给模型

↓

模型选择调用订单查询工具

↓

工具执行查询,执行流程记录结果,再把结果交给模型

↓

模型根据查询结果回答;如果还需要调用工具,就继续执行

↓

没有待继续的工作时,结束本轮

DeepSeek Harness 桌面端来了!带你拆解核心机制

我们如果想要开发一个订单插件,我们只需要提供查询能力,并遵守工具接口和资源清理的要求。什么时候把工具交给模型、怎样把查询结果传回去、是否还要继续下一步,这些由已有的主流程处理。

插件之间也有明确的协作要求。 每个插件要声明自己依赖哪些服务,Cordis 需要等这些依赖的服务就绪后才会激活它。启动时,DSH 会检查必需插件的激活结果。如果已启用的默认主循环等必需插件没能启动,应用会报错并清理已加载的资源,普通可选插件失败则会给出一些诊断信息,其他成功激活的插件可以继续运行。

所以,DSH 能作为 Agent 运行,靠的是默认组合提供所需能力、Agent Loop 组织执行,以及插件共同遵守的接口和生命周期约定。插件化让这些实现可以替换,但替换后仍要满足同样的协作要求。尤其是主循环,换成自己的实现后,任务执行、取消、会话恢复等工作也要一并完成,不能只写一个反复调用模型的循环就算完成。

四、插件的运行机制

知道 Agent 的主流程由谁负责之后,我们就可以具体看一个插件怎么加入其中了。从加载时注册能力,到运行时使用服务、通过事件参与任务,再到卸载时清理资源,下面按这个过程逐步介绍。

DeepSeek Harness 桌面端来了!带你拆解核心机制

加载插件时,先注册它提供的能力

前面说到,Agent Loop 会把可用工具交给模型。要让订单查询工具出现在其中,插件就需要先把它注册到 DSH 中。

这一步可以写在插件导出的 apply 函数里。插件激活时,Cordis 会调用这个函数,并传入上下文 ctx。插件通过 ctx 使用 DSH 已有的服务,也把自己提供的能力注册进去。先看一个最简单的插件结构:

import type { Context } from ‘@deepseek-ai/cordis’

export const name = ‘my-plugin’

export function apply(ctx: Context) {

// 在这里注册插件提供的能力。

}

这段代码还没有注册具体工具,后面我们的订单插件会在 apply 中注册 lookup_order。工具先注册,什么时候执行由模型决定。 插件激活时会先把查询能力准备好,等模型选择调用这个工具时,才执行工具的业务函数。

服务:通过上下文使用已有能力

上面的 ctx 提供了访问服务的入口,每项服务都有自己的名字。例如,ctx.tools 管理工具,订单插件通过它注册查询工具,ctx.llm 提供模型调用能力,ctx.agents 提供 Agent 相关接口。

插件通过 inject 声明必需的服务:

export const inject = [‘tools’]

Cordis 会等待工具服务就绪,再激活这个插件。

当一项能力需要复用或替换底层实现时,还可以进一步区分服务定义、服务提供方和消费方。以命令执行为例,dsh-shell 定义接口,dsh-bash-local 提供本地执行实现,dsh-tool-bash 将能力暴露给模型。

消费方和提供方都依赖服务定义。只要实现满足相同约定,替换提供方就不需要同步改写消费方。对于本文这样简单的订单查询,一个插件已经足够,以后出现多个数据来源或多个调用者,再考虑提取服务。

事件:在执行过程的合适位置介入

假设我们已经有了一个删除订单的工具,现在要加一条规定,只允许在营业时间内删单。这个检查可以放在工具执行前,通过监听 tools/pre-execute 来完成,不需要改动删除订单的代码。

插件用 ctx.on() 注册监听器。模型选中工具后,DSH 会先运行这里的检查,再决定是否执行删除操作。

ctx.on(‘tools/pre-execute’, async (exec, next) => {

const hour = new Date().getHours()

if (exec.name === ‘delete_order’ && (hour < 9 || hour >= 18)) {

return { kind: ‘deny’, reason: ‘非营业时间,禁止删单。’ }

}

return next()

})

这段代码检查的是运行程序所在机器的时间。早上 9 点之前、下午 6 点及以后,删单请求会收到 deny,模型也会从工具结果中读到拒绝原因。如果在允许的时间内,或者调用的是其他工具,就执行 next(),继续后面的检查。

这里的 next() 不能漏掉。一个事件可能有多个插件监听,当前监听器调用它,后面的监听器才有机会处理。这种方式在 Cordis 中叫瀑布式事件。如果插件要拒绝调用,可以像上面一样直接返回决定,如果只是观察或附加信息,处理完就要调用 next()。否则,后续处理也会被中断。

除了执行前的检查,DSH 还提供了 tools/execute 和 tools/post-execute,它们也采用瀑布式调用。要给工具加上超时或重试处理,可以监听 tools/execute,要修改、补充工具返回的结果,则用 tools/post-execute。超时处理还需要工具配合,插件会传入带截止时间的取消信号,工具发起的网络请求或子进程必须响应这个信号,到了时间才会停下来。

如果我们只想记录查询结果,或者统计工具的使用情况,监听 tools/result 就够了。这个事件在最终结果确定后发出,属于广播式事件。监听器拿到的是冻结的结果快照,可以读取,不能修改,也不需要调用 next()。

后面的订单查询示例暂时没有这些额外要求,直接注册工具即可。以后要增加执行前的检查或查询后的统计,再加相应的监听器。

生命周期:注册的能力要能撤销

假如订单插件启动了一个定时器,每隔一分钟查询一次订单,那么卸载插件时,也需要清理这个定时器。否则,即使订单查询工具已经从可用工具列表中移除,定时器仍可能继续发起查询。

通过 ctx.tools.register() 注册的工具、通过 ctx.on() 注册的监听器,Cordis 会在插件卸载时自动移除。插件自己创建的定时器、网络连接,则需要自己写好清理方法,交给 ctx.effect() 管理。定时查询可以这样写。

ctx.effect(() => {

const timer = setInterval(pollOrders, 60000)

return () => clearInterval(timer)

})

ctx.effect() 会先执行传入的函数,创建定时器,并保存它返回的清理函数。之后无论是配置重载、停用插件,还是退出应用,只要卸载这个插件,Cordis 就会调用清理函数,停止这次定时查询。

写插件时还要考虑会话恢复。比如助手已经查过一次订单,恢复会话后,这次查询的参数和结果也需要能找回来。DSH 会在正常的工具执行过程中记录这些内容,本文的订单插件可以直接使用。如果插件另外向对话添加信息,或保存会影响后续回答的业务状态,就要把相应的记录和恢复逻辑一并做好,让模型读到过的信息都能从 Session 日志中重建。

五、实践:开发一个订单查询插件

现在把前面的概念落实到代码,准备一个订单查询的插件,我们要做的事情是,接收订单号,查询三条模拟记录,返回商品、订单状态和物流单号。

准备开发环境

我们当前使用的是 0.1.7-rc.1 这个版本的源码,Deepseek Harness 的源码仍在迭代,使用其他版本时,需要对照该版本的开发要求。

该项目示例采用 Node.js 24,以及项目清单指定的 pnpm 11.7.0。检查当前软件的版本,版本过低则需要升级:

node –version

pnpm –version

确认版本符合要求后,先在终端进入 DeepSeek Harness 源码仓库的根目录,也就是包含 package.json、pnpm-workspace.yaml 和 packages 文件夹的那一层。将下面的路径换成你保存源码的实际位置:

cd “/你保存源码的位置/deepseek-harness”

然后安装依赖并构建项目:

pnpm install –frozen-lockfile

pnpm run build

等两条命令成功结束,再继续插件部分。

接下来,继续在仓库根目录执行以下命令,创建插件目录,并设置本次练习的数据目录:

mkdir -p scratch-order-plugin/src

export DSH_HOME=”$PWD/tmp/order-tutorial-home”

执行后,插件代码目录是仓库下的 scratch-order-plugin/src。后面的命令仍在仓库根目录执行,不需要进入这个新目录。

DSH_HOME 是告诉 DSH 把运行数据放在哪里的环境变量。上面的 $PWD 表示执行命令时所在的目录,因此这里指定的数据目录是仓库下的 tmp/order-tutorial-home。从这个终端启动 DSH 后,本次练习使用的应用配置、会话记录等数据会存放在那里,与日常使用的数据分开。插件代码仍放在 scratch-order-plugin 中。

这条 export 命令只对当前终端及从它启动的程序生效,关闭终端后,目录里的文件仍会保留。如果换了一个终端继续练习,需要重新进入同一个仓库,再设置一次变量,然后执行后面的启动命令:

cd “/你保存源码的位置/deepseek-harness”

export DSH_HOME=”$PWD/tmp/order-tutorial-home”

示例最终包含三个文件:

scratch-order-plugin/

├── src/

│   ├── orders.ts

│   └── index.ts

└── cordis.patch.yml

准备模拟订单

创建 scratch-order-plugin/src/orders.ts:

/** Tutorial-only orders. All products and tracking numbers are fictional. */

/** Fields returned by the tutorial’s in-memory order lookup. */

exportinterface Order {

orderId: string

product: string

status: ‘待发货’ | ‘已发货’ | ‘已取消’

trackingNumber: string | null

}

/** Fixed sample records; restarting the plugin restores these values. */

exportconst orders: readonly Order[] = [

{

orderId: ‘DS1001’,

product: ‘机械键盘’,

status: ‘已发货’,

trackingNumber: ‘DEMO-SF1001’,

},

{

orderId: ‘DS1002’,

product: ‘无线鼠标’,

status: ‘待发货’,

trackingNumber: null,

},

{

orderId: ‘DS1003’,

product: ‘显示器支架’,

status: ‘已取消’,

trackingNumber: null,

},

]

trackingNumber 为 null 表示没有物流单号。这个结果与“查询失败”含义不同,应当保留。三条记录分别覆盖已发货、待发货和已取消,后面可以逐一核对。

如果订单数据来自外部 API

上面的三条模拟订单,也可以由一个接口以 JSON 数组的形式返回。假设接口地址是 https://example.com/api/orders,获取数据的写法就像这样:

const response = await fetch(‘https://example.com/api/orders’)

const orders: Order[] = await response.json()

const order = orders.find(item => item.orderId === ‘DS1001’) ?? null

拿到的 orders 与前面的模拟数组一样,仍然可以按订单号查询。这里的地址只是示意,实际使用时换成自己的接口;后面的完整示例继续使用本地模拟数据。

实现完整的查询插件

创建 scratch-order-plugin/src/index.ts,写入以下代码:

/** Read-only order lookup using fictional tutorial data. */

importtype { Context } from’@deepseek-ai/cordis’

import Schema from’@deepseek-ai/schemastery’

import { defineTool } from’@deepseek-ai/dsh-tools’

import { orders } from’./orders.ts’

/** Cordis diagnostic name. */

exportconst name = ‘order-demo’

/** Required services before activation. */

exportconst inject = [‘tools’]

/** Deployment settings for the sample shop. */

exportinterface Config {

storeName: string

}

/** Validate settings and provide the sample shop’s default name. */

exportconst Config: Schema<Config> = Schema.object({

storeName: Schema.string().default(‘演示商店’),

})

/**

* Register the order lookup for this plugin’s lifetime.

* @param ctx – Plugin context with the tools service.

* @param config – Validated shop settings.

*/

exportfunction apply(ctx: Context, config: Config) {

ctx.tools.register(defineTool({

name: ‘lookup_order’,

description: ‘按订单号查询演示商店的模拟订单。只读,不修改订单;查不到时请说明未找到。’,

parameters: {

orderId: {

type: ‘string’,

required: true,

description: ‘订单号,例如 DS1001。’,

},

},

output: {

schema: {

type: ‘object’,

additionalProperties: false,

properties: {

storeName: { type: ‘string’, required: true },

orderId: { type: ‘string’, required: true },

order: {

required: true,

oneOf: [

{ type: ‘null’ },

{

type: ‘object’,

additionalProperties: false,

properties: {

orderId: { type: ‘string’, required: true },

product: { type: ‘string’, required: true },

status: {

type: ‘string’,

enum: [‘待发货’, ‘已发货’, ‘已取消’],

required: true,

},

trackingNumber: {

required: true,

oneOf: [{ type: ‘string’ }, { type: ‘null’ }],

},

},

},

],

},

},

},

render: (_args, value) => [{

type: ‘text’,

text: value.order === null

? `【模拟数据】${value.storeName}:未找到订单 ${value.orderId},请核对订单号。`

: [

`【模拟数据】${value.storeName}`,

`订单号:${value.order.orderId}`,

`商品:${value.order.product}`,

`状态:${value.order.status}`,

`物流单号:${value.order.trackingNumber ?? ‘暂无’}`,

].join(‘\n’),

}],

},

async execute(args) {

const orderId = args.orderId.trim().toUpperCase()

if (orderId.length === 0) {

thrownewError(‘订单号不能为空,请提供 DS1001 这样的订单号。’)

}

return {

storeName: config.storeName,

orderId,

order: orders.find(order => order.orderId === orderId) ?? null,

}

},

}))

console.log(`[order-demo] 已注册 lookup_order,店铺:${config.storeName}`)

}

代码中占篇幅最多的是返回字段声明。实际查询集中在 execute:整理订单号,从数组查找,再返回订单对象或 null。

前面讲过的几个机制,在这里都有了具体对应:apply 注册工具,inject 声明对工具服务的依赖,Config 校验部署配置。还需要仔细区分两组内容。

部署配置与调用参数

storeName 属于 Config,由部署者设置;orderId 属于 parameters,由模型在每次调用时传入。

例如,“演示商店”是插件配置,“DS1001”是这次查询的输入。以后接入真实服务时,服务地址也适合放在部署配置中,查询对象则继续作为调用参数。

defineTool 根据参数声明推导类型并校验输入。这里要求 orderId 是必填字符串,但字符串是否为空还需要业务代码判断,所以 execute 中保留了非空检查。

程序结果与模型内容

execute 返回结构化数据,output.schema 声明它应该包含的字段。order 可以是订单对象,也可以是 null;代码中的 oneOf 表示结果必须匹配所列分支中的一个。

output.render 把同一次执行的结果转换为模型可读的文字,不再查询一次订单。程序可以读取结构化字段,模型可以阅读包含“状态”“物流单号”的说明。

这里让错误含义更加明确:DS9999 这个订单不存在,是一次正常完成工具调用、结果为“未找到”的查询;订单号为空,则是不满足输入要求。接入真实 API 后,网络不可达或认证失败这是另外一类的错误问题。

加载插件,并让模型调用它

编写加载配置

在仓库根目录的 scratch-order-plugin 文件夹中,新建 cordis.patch.yml,写入以下完整内容:

– insert:

– id: order-demo

name: “/你的仓库绝对路径/scratch-order-plugin/src/index.ts”

config:

storeName: ‘演示商店’

将 name 中的 /你的仓库绝对路径 替换为本机 DeepSeek Harness 仓库的实际位置,保留后面的 /scratch-order-plugin/src/index.ts。例如,仓库位于 /home/lin/deepseek-harness,这一行就写成 name: “/home/lin/deepseek-harness/scratch-order-plugin/src/index.ts”。这里需要使用绝对路径,不能直接保留示例占位文字。

id 是配置条目标识,name 是插件模块路径,上面源码中定义的lookup_order 才是模型调用的工具名。保存时保留 YAML 的缩进,使用空格,不要使用 Tab。如果以后移动了仓库,也要更新 name 中的路径。

启动测试应用

在设置过 DSH_HOME 的终端执行,这里我们配置的源码的根目录:

pnpm dsh web –patch ./scratch-order-plugin/cordis.patch.yml –port 3088 –no-open

示例使用 3088 端口,并关闭自动打开浏览器。插件完成注册时,会输出:

[order-demo] 已注册 lookup_order,店铺:演示商店

DeepSeek Harness 桌面端来了!带你拆解核心机制

这条信息表示 apply 已运行并完成工具注册,还需要继续验证模型能否调用。

保持终端运行,在浏览器中打开终端打印的完整访问地址。地址以 http://127.0.0.1:3088/ 开头;如果带有 token 参数,访问时需要保留。

如果页面提示尚未配置模型,在“设置 → 模型”中设置可用凭据。独立测试目录可能需要重新配置。在插件里面搜索order就可以看到我们刚刚配置的插件了

DeepSeek Harness 桌面端来了!带你拆解核心机制

在界面中打开一个工作目录并新建会话,选择已配置的模型。先发送一条普通消息,确认模型能够回复,再测试插件,便于区分模型连接问题与插件问题。

DeepSeek Harness 桌面端来了!带你拆解核心机制
DeepSeek Harness 桌面端来了!带你拆解核心机制

让插件随 DSH 启动自动加载

–patch 只对本次启动生效,DSH 不会记住这个命令行参数。如果希望以后自动加载,可以把刚才的插件配置保存到 Web Profile 的配置文件中:

$DSH_HOME/profiles/web/cordis.patch.yml

DeepSeek Harness 桌面端来了!带你拆解核心机制

按照前面设置的 DSH_HOME,它就在仓库的 tmp/order-tutorial-home/profiles/web/cordis.patch.yml。首次启动 Web 后,这个文件会自动创建。停止服务,打开它,将 scratch-order-plugin/cordis.patch.yml 中的 – insert: 整段内容加入文件,如下图所示

DeepSeek Harness 桌面端来了!带你拆解核心机制

保存后,每次启动只需:

pnpm dsh web –port 3088 –no-open

DSH 会自动读取该 Profile 中的订单插件配置,不必再传 –patch。–port 3088 和 –no-open 只是指定端口、关闭自动打开浏览器,如果接受默认行为时,也可以直接执行 pnpm dsh web。

后续启动要使用同一个 DSH_HOME。如果没有设置它,默认读取的是 ~/.dsh/profiles/web/cordis.patch.yml。自动加载后,修改店铺名称等配置也应编辑 Profile 中的这份文件。

八、在创造模式里让 DSH 帮你开发插件

前面的订单插件,我们自己准备文件、编写代码,再通过配置加载。这些工作也可以交给 DeepSeek Harness 的创造模式。它带有插件开发指引、运行时 API 检查和插件管理工具,可以根据需求编写插件,并尝试安装到当前应用中。

这次我们不使用本地运行的web端,而是使用官方的桌面端来开发,这里继续使用同样的三条模拟订单,目标也一样,让助手收到订单号后调用查询工具,再根据结果回答。这样我们就能对照前面的源码示例,看清楚 Agent 代替我们完成了哪些工作,以及哪些地方仍然需要人工检查。

选好模式和工作目录。 打开桌面端,选择工作空间,打开一个新的会话,在聊天窗口左上角选择创造模式

把需求一次说清楚。 在新的会话中发送下面这段提示词。桌面端的案例使用 lookup_demo_order 作为工具名称,方便与前面的源码示例区分。

请帮我开发并安装一个 DSH 订单查询插件,让我能在当前桌面 App 的对话里查询模拟订单。

数据直接保存在本地插件中,不连接外部 API、不使用数据库。准备以下三条虚构数据:

– DS1001:机械键盘,已发货,物流单号 DEMO-SF1001。

– DS1002:无线鼠标,待发货,暂无物流单号。

– DS1003:显示器支架,已取消,暂无物流单号。

提供一个名为 lookup_demo_order 的工具,接收订单号,返回商品、状态和物流单号,并标明是模拟数据。忽略订单号两端的空格和字母大小写;查不到就说明未找到,不编造发货或到货时间。

把这段提示词发送给 DeepSeek Harness,接下来就可以观察它的开发过程。

DeepSeek Harness 桌面端来了!带你拆解核心机制

Agent 会根据当前版本选择实现方式,所以生成的文件可能与源码示例不完全相同。我们主要看它有没有完成工具定义、订单查询和插件安装。如果过程中弹出授权,先看清要执行的操作,再决定是否允许。

这次开发并没有一次成功。 中间出现报错时,我最初以为只是生成的代码有问题,让 Agent 根据错误提示继续修改就行。但后面发现,新开会话、换工作区,仍然会遇到同样的错误,连正常对话都受到了影响。

DeepSeek Harness 桌面端来了!带你拆解核心机制

后来检查生成的代码,发现问题出在工具注册时的 parameters,Agent 使用了不符合 DSH 要求的参数声明格式。前面的源码示例中,parameters 直接按 orderId 这样的参数名组织,每个参数再声明类型、说明和是否必填。让模型写出一段查询数组的代码并不难,但把这段代码接到 DSH 里,还需要它正确使用当前版本的工具接口。

创造模式能省下手动编写和安装插件的工作,但使用者仍然需要能看懂报错、找到生成的文件,并在必要时修改代码。尤其是刚开始尝试时,适合先用这里的模拟订单练习。如果完全没有排查代码和配置的经验,目前直接用它改动日常工作的应用,遇到这种问题会比较难处理。

修正参数声明后,应用恢复了正常,在插件列表中也可以看到新开发的订单查询工具。

DeepSeek Harness 桌面端来了!带你拆解核心机制

看到插件之后,还要实际查一次订单。 在聊天窗口发送下面这段话,检查执行记录里是否调用了 lookup_demo_order,再核对返回内容。

查询 DS1002,告诉我商品、订单状态和物流单号

DeepSeek Harness 桌面端来了!带你拆解核心机制

按照前面准备的数据,DS1002 对应无线鼠标,状态是待发货,暂无物流单号。这里要把工具调用记录和最终回答放在一起看,因为开发提示词里已经给出了全部模拟订单,模型只靠聊天上下文也能复述这些信息。看到回答正确,还不足以确认插件已经工作,这里可以查看一下轨迹的运行记录

DeepSeek Harness 桌面端来了!带你拆解核心机制

从运行轨迹可以看出,工具插件正常运行。通过查询指定编号的订单或者数据。

这次尝试里,DSH 根据一段需求,给自己增加了一个订单查询工具,修正代码后也确实调用成功了。以后需要查别的业务数据,也可以按这个方式,让它开发相应的插件,接入数据,再在对话里调用。

不过,中间那个参数格式错误也给我留下了更深的印象。创造模式已经能帮我们做不少开发工作,但出错之后,仍然可能需要人来接手。这次订单查询这个插件能用起来,靠的也是最后把参数声明改对了。想尝试这种开发方式,除了想好要加什么功能,也得考虑出了问题后,自己能不能把应用恢复到正常状态。

作者:叶小钗

来源:叶小钗

扫一扫 微信咨询

联系我们 青瓜传媒 服务项目

商务合作 联系我们

本文经授权 由青瓜传媒发布,转载联系作者并注明出处:https://www.opp2.com/386719.html

《免责声明》如对文章、图片、字体等版权有疑问,请联系我们 。 广告投放 找客户 找服务 蘑菇跨境
企业微信
运营大叔公众号
运营宝库
运营宝库H5