DeepSeek Harness SDK 集成:把 Agent 嵌进你的应用

DeepSeek Harness SDK 集成:把 Agent 嵌进你的应用

上一篇讲清楚了 dsh 的三种运行形态,最后预告说「最值得深挖的是 sdk」。这一篇就兑现它------怎么把 DeepSeek Harness 当成一个库,嵌进你自己写的程序里。

Harness 的 SDK 分两条线:Python SDK 走一个开箱即用的 DeepSeekHarness 上下文管理器;TypeScript SDK 走一套叫 Typert 的 API Gateway,用 @Remote 装饰器把业务服务暴露成可远程调用的方法。两条线面向不同的人,但底层共享同一个「sdk profile + JSON-RPC 服务器」的运行时。

一、Python SDK:一个上下文管理器搞定

Python 这边做得很顺滑。先装:

sh 复制代码
python -m venv .venv
. .venv/bin/activate
python -m pip install deepseek-harness-sdk

装完自带一个匹配的原生 runtime wheel 和 dsh 命令,正常运行 SDK 不需要系统里装 Node.js(只有仓库贡献者构建产物时才需要)。

在你自己的程序里,核心就一个 DeepSeekHarness 上下文管理器:

python 复制代码
from pathlib import Path
from deepseek_harness import DeepSeekHarness

workspace = Path("/absolute/path/to/disposable-workspace").resolve()
dsh_home = Path("/absolute/path/to/example-dsh-home").resolve()

with DeepSeekHarness(
    provider="deepseek-official",
    model="deepseek-v4-flash",
    max_tokens=49_152,
    cwd=str(workspace),
    dsh_home=str(dsh_home),
    profile="sdk-minimal",
) as harness:
    result = harness.run(
        "Inspect the repository and fix the failing tests.",
        session_id="example-001",
    )

print(result.final_response)

几个关键点:

  • SDK 会惰性启动 dsh --profile sdk-minimal 这个子进程,并在上下文管理器退出前一直复用它;
  • profile、它的持久 patch、home 级 patch,以及 patches 元组里传入的有序 patch,共同构成应用配置;
  • 没有单独的 Python runtime bin,也没有「完整配置」这一说------一切还是走 profile 那套。

二、sdk-minimal:一个「极简到极致」的 profile

SDK 默认或例子常选的 sdk-minimal 值得单独看一眼,因为它清楚展示了「最小可用」长什么样:

项目 值
系统提示词 DSH_SYSTEM_PROMPT,兜底 You are a helpful software engineer assistant.
模型 --model → DSH_MODEL → deepseek-v4-flash
面向模型的工具 持久 bash(Linux/macOS)或 pwsh(Windows),加 str_replace_editor
Shell 超时 300 秒
编辑器输出上限 16000 字符
运行时上下文与压缩 无
会话持久化 <dsh_home>/sessions 下的未压缩 JSONL

它只有一个 bundle,把整棵树插在空 root 上,不包含 dsh-base ,所以后面 base-profile 的工具不会隐式出现。settings、托管凭据、遥测、Web 工具、子 agent、本地指令发现、压缩------这些统统不在里面。它 pin 了 danger-full-access,意味着持久 shell 和编辑器能改运行时可见的任何路径------所以官方反复强调:用一次性 checkout 或容器跑。

三、TypeScript SDK:Typert 的 @Remote 编程模型

TS 这边不是「start 一个进程」,而是声明式地把业务服务暴露成 Remote 方法 。核心是 @Remote / @RemoteScope 两个装饰器:

ts 复制代码
import type { Agent } from '@deepseek-ai/dsh-agent'
import { TypertRemoteService, Remote, RemoteScope } from '@deepseek-ai/dsh-typert-protocol'
import type { Context } from '@deepseek-ai/cordis'

export interface CreateGoalRequest { objective: string }
export interface CreateGoalResult { accepted: boolean }

export class GoalService extends TypertRemoteService {
  constructor(ctx: Context) {
    super(ctx, 'goals')            // 绑定 cordis service key + Remote namespace
  }

  @Remote('create')
  createForClient(agent: Agent, request: CreateGoalRequest, signal: AbortSignal): CreateGoalResult {
    signal.throwIfAborted()
    return this.create(agent, request)
  }

  @RemoteScope('agent', 'current')
  currentForClient(): CreateGoalResult {
    return { accepted: true }
  }

  private create(_agent: Agent, request: CreateGoalRequest): CreateGoalResult {
    return { accepted: request.objective.length > 0 }
  }
}
  • @Remote 表示调用 root Host Context 上的 cordis service;@RemoteScope 先把身份解析成 scoped Context 再拿 service 调用;
  • 复杂对象(比如 Agent)不能直接过线,要用 TypertLookupMap 声明「wire 身份」→ Host 对象的映射,Gateway 会按 agentId 这种 wire 字段去解析回真实对象;
  • 方法最后一个参数必须是 signal: AbortSignal,用于协作式取消。

客户端这边,调用是具体函数,不是 JS Proxy:

ts 复制代码
await ctx.remote.goals.create(agentId, { objective: 'ship it' })
await agentCtx.remote.goals.create({ objective: 'ship it' })

每个 namespace 是一个 trace 过的 cordis child service,注册成 remote.<namespace>;装配通过 ctx.remote.$mount() 挂载贡献,namespace 最后一个方法卸载后自动回收。

四、调用链:JSON-RPC 承载在 /api 路由上

Remote 调用走 Connection 的 /api 路由:客户端 connection.rpc.call('/api', '<namespace>/<method>', { args }, signal),HTTP 层映射成 POST /api/<namespace>/<method>,payload 只带一个命名的 args 对象。

Gateway 对每一次调用都会:解析描述符和「当前注册表里的 live service」(不缓存业务对象)、用 codec 校验 wire 值、通过 lookup/Context provider 解析对象、调用目标方法、再校验返回值。缺 provider、身份未知、参数对不上、schema 失败、方法不存在,都在进业务代码前或出业务代码后失败------这套严格校验是 TS SDK 比「裸 RPC」更值钱的地方。

五、插件持久化安装

不管哪条线,想把插件 bundle 持久装进 SDK profile,都用运行时自带的 dsh CLI:

sh 复制代码
export DSH_HOME=/absolute/path/to/isolated-dsh-home
dsh --profile sdk --dump-default-config     # 先初始化 profile
dsh plugin --profile sdk add file:/absolute/path/to/my-plugin-bundle

第一条初始化 profile,第二条把包管理转发给 pnpm 并记录下所有导出 dsh.bundle 层的包。只有这个管理命令需要 pnpm,启动已装好的 SDK 不需要。

六、避坑清单

  1. Python SDK 别默认它会读 ~/.dsh 。例子和 SDK 从不静默读取 ~/.dsh,workspace 和 home 都要显式给绝对路径,否则它不知道去哪找。
  2. sdk-minimal 是全访问,隔离优先 。它 pin danger-full-access,用一次性 checkout 或容器跑,别拿它直接啃你的真实仓库。
  3. TS SDK 换传输不改契约。Remote 描述符和客户端接口独立于 Connection 载体,换 carrier 不需要动 Remote 定义------但反过来,别把 Remote 方法和流式/增量数据混为一谈,那些得走单独的数据协议。
  4. 改了 @Remote 签名要重建 。增删装饰器、改导出名/namespace/参数/返回值/lookup,都得 pnpm run build:lib 让 Host 先生成严格契约,客户端才能编译到新贡献;只改方法体不用重建。
  5. web 是独立 CLI,不能服务 Python SDK 客户端 。想浏览器界面就单独 dsh web,别指望同一个进程又当 web 又当 Python SDK server。

小结

SDK 集成的本质,是把前八篇反复强调的「seam」再往外推一层:对内,插件是 seam;对外,SDK 本身也是 seam 。Python 用 DeepSeekHarness 一个对象包住整个 agent 进程,TS 用 @Remote 装饰器把业务服务暴露成可远程调用的方法------两条路殊途同归,都是「把 Agent 变成你程序里的一个能力」。

下一篇我们往里收一步,讲怎么改行为而不碰源码------这就是 Harness 的配置与 Patch 体系。


参考:deepseek-ai/deepseek-harness 官方仓库 docs/user/guide/python-sdk.md、docs/api-gateway.md。

相关推荐
杨杨杨大侠4 小时前
RAG、记忆、上下文,这几个东西到底怎么串起来?
人工智能·agent
system_error_x6 小时前
MCP协议开发实战:从零搭建AI Agent工具链
人工智能
Sayai6 小时前
ComfyUI+混元视频实战:12G 显存跑 13G 模型,5 分钟出片(国产开源,附模型与工作流)
人工智能·aigc·音视频·comfyui·hunyuanvideo·混元视频
燧机科技SuiJi6 小时前
山体坍塌落石滑坡泥石流监测系统 落石泥石流监控摄像机
大数据·人工智能·深度学习·yolo
国科安芯6 小时前
立方星与微纳卫星综合电子微型化趋势下的抗辐射MCU选型综述
人工智能·单片机·嵌入式硬件·mcu·risc-v·抗辐射
诸神缄默不语7 小时前
小春学习日刊 2026年第4期:2026.10.16
人工智能
draracle7 小时前
为什么 AI 无法胜任系统架构
人工智能·系统架构
未来和明天7 小时前
iLeadE-3403边缘计算网关10.4 TOPS数据采集、视频接入与外设扩展等多元化应用需求
人工智能·边缘计算
youngfengying7 小时前
集成学习及置信度
人工智能·机器学习