ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

DeepSeek Harness 零基础入门:从 dsh 命令到 Python SDK 批量自动化

DeepSeek Harness 零基础入门:从 dsh 命令到 Python SDK 批量自动化

摘要:本文面向零基础读者,系统讲解 DeepSeek Harness(dsh)的两层用法。第一层是命令行:搞清 launcher 与应用的参数分界,用 headless 无头模式跑一次性任务,用--patch临时加载配置,用dsh plugin管理插件,并把 dsh 接进 CI。第二层是 Python SDK:在自己的代码里创建 Harness、跑任务、拿结果,最终用独立 session id 驱动多仓库批量自动化。全文代码逐词注释,笔记去重保留,读完即可上手。
注意:本文非百分百原创,本人经学习后,重新梳理了学习思路,依据个人学习习惯添加红笔笔记,为代码添加相关注释,如有误请各位同仁批评指正。


一、学习路线:先“跑一次”,再“编程序”

Web UI 适合人机交互,但真正让 dsh 值钱的,是它可以被脚本和 CI 调用。
命令行适合“跑一次”,Python SDK 适合“在程序里编排”。

建议按以下顺序推进:

  1. 第 1 章:dsh 命令行——无头模式、patch、plugin、CI。
  2. 第 2 章:Python SDK——环境、安装、示例、批量任务。

二、dsh 命令行:把 Harness 变成可脚本化工具

2.1 命令语法:先分清“谁的参数”

dsh是启动器(launcher),它只解析自己的 flag,把不认识的参数交给 profile 里的应用插件解析。

一句话:launcher 的参数在前,应用的参数在后;遇到第一个启动器不认识的参数,就开始算应用的。

📝笔记:launcher /ˈlɔːntʃər/ n. 启动器、加载器,用来启动程序的工具。如:game launcher 游戏启动器,app launcher 应用程序启动器。
flag 在这里指标记位,用来记录某个状态的开启或关闭。

dsh--profileweb--port8080# dsh:启动器命令# --profile web:启动器参数,选择 web 配置档# --port 8080:启动器不认识,交给 web 应用解析,端口 8080dsh--profileheadless"run the tests"# --profile headless:选择无头模式# "run the tests":任务文本,作为应用参数传入dsh--profileweb--help# --help 出现在 profile 之后,打印的是 web 应用帮助dsh--help# --help 直接跟在 dsh 后,打印启动器自身帮助

2.2 入口模式一览

📝笔记:plugin n. 插件(插到主程序里增加额外功能,主程序本身不包含),如:browser plugin 浏览器插件。

命令作用
dsh web启动 Web UI(--profile web的别名)
dsh --profile headless "任务"无头模式:跑一次性会话,打印最终回复后退出
dsh --profile <name>启动任意命名 profile
dsh plugin --profile <name> <pnpm 参数...>管理 profile 插件(转发给 pnpm)
dsh --profile web --dump-config打印组合后的配置树(不启动)
dsh --dump-default-config打印默认配置

📝笔记:dump v. 导出、转储,如:dump memory 转储内存。

2.3 无头模式:一行命令跑一个任务

无头模式是脚本化的核心:接受任务文本,创建并持久化一个全新会话,跑完后打印最终回复并退出。

dsh--profileheadless"fix the failing test in this workspace"# --profile headless:无头模式# fix the failing test:修复失败的测试# in this workspace:在当前工作区中

注意:

  • 调用目录是默认工作区根;
  • web和headless首次使用会自动初始化;
  • 会话是持久化的,跑过的任务会留下日志,对批量任务和审计有价值。

2.4 用patch临时加载自己的配置

你写了一个插件和对应的 patch 文件,不想装进 profile,只想临时试一下:

dsh web--patch./scratch-plugin/cordis.yml# dsh web:启动 Web UI(--profile web 的别名)# --patch:临时加载 patch 配置# ./scratch-plugin/cordis.yml:patch 文件路径# . = 当前目录,/ = 路径分隔符

📝笔记:patch n. 补丁、修补程序。
scratch 在 IT 里常见于from scratch,意为“从零开始、从头搭建”。

多个 patch 可以叠加,按参数顺序应用。

2.5dsh plugin:管理 Profile 的插件

profile 的 manifest 不需要手写,dsh plugin帮你维护:

📝笔记:manifest n. 清单、配置文件清单,记录包里包含哪些文件、版本、权限、依赖信息等。

dsh plugin--profiledemoadd./hello-plugin# dsh plugin:插件管理入口# --profile demo:操作 demo 这个 profile# add:添加/安装# ./hello-plugin:本地插件目录dsh plugin--profiledemoaddgithub:you/hello-plugin# github:you/hello-plugin:从 GitHub 的 you/hello-plugin 仓库安装dsh plugin--profiledemo remove dsh-hello-plugin# remove:移除插件# dsh-hello-plugin:要移除的插件名

dsh plugin本质上是在 profile 目录里转发 pnpm 命令,所以add、remove、install等 pnpm 子命令都可用。

2.6 实际场景:把 dsh 接进 CI

无头模式 + 退出码 + 会话日志,三者组合就是一条完整的 agent 流水线。

# 示例:在 CI 中让 dsh 跑测试并留档DEEPSEEK_API_KEY=${ secrets.DEEPSEEK_API_KEY }# 从 CI secrets 中取 API 密钥,赋给环境变量dsh--profileheadless"inspect this repo, run the tests, fix failures, report what you"# inspect:仔细检查、检视;repo = repository,代码仓库# run the tests:运行测试# fix failures:修复失败项# report:报告、汇报

📝笔记:repository n. 仓库、代码仓库(error report 错误报告)。

📝拓展:CI = Continuous Integration,译为“持续集成”。
大白话:每次有人提交代码,机器就自动帮你把代码拉下来、装好环境、跑测试、做检查,然后把结果告诉你,就像一个“自动质检员”,专门守在代码仓库门口,防止坏代码混进去。
用两个词概况就是"持续"(每次提交代码都自动检查)和"集成"(大家写的代码要合到一起,机器自动验证“合起来还能不能正常跑”)
回到文中的场景,理解CI的工作流就是:1.拉代码;2.让 dsh 在无头模式里检查仓库;3.让 dsh 跑测试、修复失败项;4.dsh 打印最终回复;5.CI 根据 dsh 的退出码判断成功还是失败;6.会话日志留下来,方便事后查。

进阶玩法:

  • 用 Python SDK 在代码里编排多任务。

📝笔记:SDK = Software Development Kit 译为:软件开发工具包,一整套为开发者提供的工具合集,一般包含 API 接口、代码示例、文档、库文件、调试工具,不用从零写底层代码,直接调用SDK提供的能力即可。

三、Python SDK:把 Harness 嵌进自己的程序

3.1 环境要求

  • Python 3.10 或更高;
  • Git;
  • Linux x64 / Linux arm64,或 macOS 14+(arm64);
  • 一个 DeepSeek 兼容的 API 端点与凭据;
  • 一个隔离的工作区。

关于 Windows:原文所依据的版本说明 Python SDK 暂不支持 Windows agent,因为持久化 PTY 后端需要 POSIX 终端环境,建议用 WSL、Linux 服务器或容器运行。官方 Python SDK 文档目前列出了 Windows x64,但本文涉及的 minimal 示例路径与 PTY 行为仍以 POSIX 环境为最稳妥。

📝笔记:POSIX = Portable Operating System Interface,可移植操作系统接口,一套操作系统 API 规范,规定进程、文件、终端怎么工作。
PTY = Pseudo Terminal,伪终端,模拟出来的虚拟终端设备,不是物理终端,更像一对主(master)、从(slave)设备,用来转交命令行输入输出。

3.2 安装

gitclone https://github.com/deepseek-ai/deepseek-harness.git# git clone:克隆仓库# 地址:deepseek-ai/deepseek-harness.gitcddeepseek-harness# 进入克隆下来的仓库目录python-mvenv .venv# python -m:以模块方式运行# venv:Python 虚拟环境模块# .venv:虚拟环境目录名..venv/bin/activate# source 激活脚本,在当前 shell 中生效python-mpipinstalldeepseek-harness-sdk# 用当前解释器的 pip 安装 SDK

安装内容包括匹配的原生运行时 wheel 和dsh命令;普通 SDK 运行不需要系统再装 Node.js。

3.3 设置环境变量

exportDEEPSEEK_API_KEY=sk-your-key-here# export:导出为环境变量,让变量在当前环境生效# DEEPSEEK_API_KEY:变量名# sk-your-key-here:API 密钥占位符,将其替换为你的真是API

3.4 运行官方内置示例

仓库自带的examples/jsonrpc-agent/minimal.py是对 SDK 的轻量包装,针对隔离工作区和会话目录执行一个任务。

📝笔记:JSON-RPC = JSON Remote Procedure Call,一种轻量级调用协议,远端服务器收到后执行函数。
minimal adj. 极小的、极简的,如:minimal code 极简代码。

python examples/jsonrpc-agent/minimal.py\--workspace/absolute/path/to/workspace\--session-root /absolute/path/to/sessions\--session-id example-001\"Inspect the repository and fix the failing tests."# python:解释器# examples/jsonrpc-agent/minimal.py:示例脚本路径# \:续行符,下一行仍是同一条命令# --workspace:工作区路径# /absolute/path/to/workspace:工作区绝对路径占位# --session-root:会话日志根目录# --session-id:会话 ID# example-001:本次会话标识# "Inspect...tests.":任务文本

📝笔记:absolute adj. 绝对的、无条件的,如:absolute path 绝对路径,relative path 相对路径。

脚本会打印 agent 最终回复。会话目录会收到 JSONL 格式日志,完整记录组装后的模型请求和工具调用,对调试和审计有用。

3.5 在自己的代码里用 SDK

frompathlibimportPath# 从 pathlib 导入 Path 类,用来表示和操作文件路径fromdeepseek_harnessimportDeepSeekHarness# 从 SDK 包导入 DeepSeekHarness 类config=Path("examples/jsonrpc-agent/minimal.cordis.yml").resolve()# 创建配置路径对象,.resolve() 转为绝对路径workspace=Path("/absolute/path/to/workspace").resolve()# 工作区路径,同样解析为绝对路径sessions=Path("/absolute/path/to/sessions").resolve()# 会话日志根目录withDeepSeekHarness(provider="deepseek-official",# 服务提供商:官方 DeepSeekmodel="deepseek-v4-flash",# 模型:快速响应模型max_tokens=49_152,# 最大 token 数cwd=str(workspace),# current working directory,当前工作目录session_root=str(sessions),# 会话日志根目录cordis=str(config),# 配置框架文件)asharness:# with...as:上下文管理器,自动开启和释放资源result=harness.run("Inspect the repository and fix the failing tests.",session_id="example-001",)print(result.final_response)# final_response:agent 的最终文本回复

📝笔记:cwd= current working directory,当前工作目录。
str(...)是因为部分 API 只接受字符串。
sessionn. 会话。
resolvev. 解析路径,也有“解决”义,如:resolve bug 修复 bug,resolve conflict 解决冲突,把相对路径解析成完整的绝对路径。
responsen. 响应、返回数据(in response to 作为对……的回应)。
pathlib是 Python 内置路径处理模块,Path 是核心类,大写首字母为类名。
result执行结果,返回结构。
shell命令解释器,终端壳程序,就是操作系统的命令交互程序,接收你输入的命令,交给系统内核执行。

注意:

  • DeepSeekHarness会延迟启动内置运行时并持续复用,直到退出上下文管理器;
  • 复用同一个 harness 和 session id,会保留该会话的 Bash 进程(工作目录、导出的变量、shell 函数都在);
  • 独立任务用新的 session id;只有确定要延续同一段对话和 shell 状态时,才复用原有 id;
  • cwd决定 agent 可访问的工作区,session_root决定会话日志存哪。

3.6 最小 harness 的“配方”

属性值
系统提示词DSH_SYSTEM_PROMPT,缺省 “You are a helpful software engineer assistant.”
模型--model→DSH_MODEL→ 默认deepseek-v4-flash
面向模型的工具仅持久 bash 与str_replace_editor
Bash 超时300 秒
编辑器输出上限16,000 字符
上下文压缩关闭
文件系统裸本地后端(编辑器用绝对路径)
会话持久化session_root下未压缩的 JSONL
沙箱danger-full-access,只能在可丢弃的 checkout 或容器里跑

📝笔记:str_replace_editor中的 replace 意为“替换、取代、更换”,在字符串/文件处理中很常用。
danger-full-access中的 danger 意为“危险、风险”;
Full access是完整访问权限,可读取、修改、删除所有资源。
checkout在这里指把远程仓库或本地分支的代码提取到当前工作目录。
沙箱:沙箱 = 给 AI 圈出来的一块“隔离试验田”,AI 只能在这块地里挖土、改东西、跑命令;就算它把地挖坏了,也不会影响到你真正的房子、文件和系统。总之,沙箱不是“一个软件”,而是“一圈围栏 + 一套权限规则”,它主要限制 AI 能碰什么:能看哪些文件?能改哪些目录?能不能联网?能不能执行危险命令?跑坏了会不会影响真实系统?等。

3.7 批量任务小例子

把上面的模式套进循环,就是最简单的批量自动化。每个 repo 用独立 session id,状态互不污染。

frompathlibimportPathfromdeepseek_harnessimportDeepSeekHarness# tasks:字典,键是仓库名,值是对应的任务文本tasks={"repo-a":"Run the test suite and fix failures.",# test suite:一整套测试用例,不是单个测试"repo-b":"Find TODO comments and turn them into issues.",# comments 代码注释,查找 TODO 注释,转成 issues"repo-c":"Update the dependency versions in package.json.",# dependency:依赖包(项目需要的第三方库)# package.json:记录项目名称、脚本、依赖及版本的核心配置文件}withDeepSeekHarness(provider="deepseek-official",model="deepseek-v4-flash",cwd="/work",# 当前工作目录session_root="/sessions",# 会话存放根目录cordis=Path("minimal.cordis.yml").resolve(),# minimal.cordis.yml 配置框架文件,定义运行规则、权限、沙箱;resolve() 取绝对路径)asharness:forrepo,taskintasks.items():# 遍历所有仓库和对应任务,实现批量执行result=harness.run(task,session_id=repo)# session_id=repo:每个仓库独立会话,实现隔离print(f"---{repo}:{result.final_response[:200]}")# 只打印最终回复的前 200 个字符,避免输出过长

/sessions下会留下每次任务的完整 JSONL 日志,方便事后排查。

四、FAQ

Q1:dsh --profile web --help和dsh --help有什么区别?

前者打印的是web应用的帮助,后者打印的是启动器自身的帮助。判断依据是--help出现在--profile之前还是之后。

Q2:无头模式跑完任务后,日志存在哪?

会话是持久化的,跑过的任务会留下 JSONL 格式日志。Python SDK 中由session_root决定日志根目录;命令行 headless 模式会使用默认位置。

Q3:--patch和dsh plugin add有什么区别?

--patch是临时加载配置文件,不装进 profile,适合开发和试验。dsh plugin add会把插件真正装进 profile 的依赖和 bundle 层。

Q4:批量任务为什么每个 repo 要用独立的 session id?

独立 session id 意味着独立的对话状态和 shell 状态,仓库之间不会互相污染。只有当确定要延续同一段对话和 Bash 进程时,才复用同一个 id。

Q5:最小 harness 的danger-full-access能直接上生产吗?

不能。这个配置没有任何沙箱限制,Bash 和编辑器可以改运行时进程可见的任何路径。只能在可丢弃的 checkout 或容器里跑;生产环境必须替换为更严格的沙箱策略。

Q6:Python SDK 在 Windows 上到底能不能跑?

原文依据的版本说明 SDK 暂不支持 Windows agent,原因是持久化 PTY 后端需要 POSIX 终端环境,建议用 WSL、Linux 服务器或容器。官方 Python SDK 文档目前列出了 Windows x64,但 minimal 示例和 PTY 相关行为仍建议在 POSIX 环境下验证。

五、零基础自查清单

学完后,试着回答:

  1. dsh从哪个参数开始把控制权交给应用?
  2. dsh --profile headless "任务"和dsh web分别做什么?
  3. --patch与--dump-config各自适合什么场景?
  4. dsh plugin本质上在转发什么命令?会不会动全局环境?
  5. cwd、session_root、session_id分别控制什么?
  6. 为什么批量任务要给每个 repo 用独立 session id?
  7. 最小 harness 的沙箱为什么是danger-full-access?生产环境要注意什么?
返回列表