Asterism

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug

内容摘要

本文用一个可复现的 Java Bug,完整演示 Pi 与 DeepSeek Harness 的安装、只读分析、最小修改和测试验收,并记录权限边界、Hash 校验、Diff 审查与实际踩坑,帮助新手建立一套可复核的 Agent 工作流程。

上一篇《Agent Harness 到底是什么?从 Pi 和 DeepSeek Harness 讲起》讲清了基本概念、两个工具的区别。这篇直接动手:从一个会报错的 Java 小项目开始,安装 Pi 和 DeepSeek Harness,再让它们分别完成一次任务。

在这次实测之前,我大概理解 Agent Harness 的概念,但还没有亲手走完整个过程:应该在哪个目录启动,怎样登录,怎样要求它先别改文件,任务结束后又该怎样验收。

这次我把这条路线完整跑了一遍:先在 IDEA 里复现一个 Java Bug,再让 Pi 和 DeepSeek Harness 分别读取项目、修改代码、运行检查,最后回到 IDEA 做人工验收。

这不是模型能力评测,也不预设哪个工具更好用。文中只写这次真实发生的操作、报错和结果。

这次要完成的路线

IDEA 跑出 Bug
  → 安装并启动 Pi
  → Pi 只读分析
  → Pi 修改并验证
  → 恢复 Bug
  → 启动 DSH,完成同一任务
  → 回到 IDEA 和 Diff 人工验收

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 1第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 1

除了按目录完成操作,过程中还要持续记录四件事:

  1. 它先读了哪些文件。
  2. 它有没有遵守只改一个文件的要求。
  3. 它有没有真的运行检查。
  4. 最后的代码和测试结果,能不能由我自己复核。

四项都有可检查的记录,这次练习才算跑通。

动手前,准备环境和安全边界

本文在 Windows 上实验,所有需要读者执行的命令都按 Windows PowerShell 编写。如果使用 IDEA 底部的 Terminal,也请先确认当前 Shell 是 PowerShell。开始前先检查环境。

node --version
npm --version
npx --version
java --version
javac --version
git --version

需要准备:

本次实测使用 Node.js 24.19.0。Pi 0.84.3 的本地安装包声明 Node.js 需要 >=22.19.0;DSH 官方快速开始只写明需要安装 Node.js,没有在页面上固定更细的版本区间。想尽量复现本文,可以先使用 24.19.0;如果 npm 报 Unsupported engine,按安装提示升级 Node,再把 PowerShell 和 IDEA Terminal 全部关掉重开,然后重新检查 nodenpmnpx

如果升级后显示的仍是旧版本,用下面两条确认命令来自哪个目录。

where.exe node
where.exe npm

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 2第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 2

第一次练习只在下面这些边界内操作:

本地终端和本地 Web 页面不代表代码一定只留在本机。只要连接外部模型服务,完成任务所需的上下文就可能发送给对应服务。第一次不要拿公司的支付、结算、对账项目练手。

第 1 步:先在 IDEA 里复现 Bug

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 3第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 3

这次使用的练习目录是:

D:\Documents\Agent\agent-harness-lab

你可以换成自己的路径。文末附有完整示例文件,没有现成项目也能自己创建。

项目结构很简单。

agent-harness-lab/
├─ AGENTS.md
├─ TASK.md
├─ README.md
├─ baseline/OrderService.java
├─ src/main/java/lab/OrderService.java
└─ src/test/java/lab/OrderServiceSelfTest.java

AGENTS.md 保存给 Agent 看的项目规则,TASK.md 写本次任务,README.md 保存检查命令,baseline 保存最初的故障代码。

OrderService 只有一个方法。

public String normalizeStatus(String status) {
    return status.trim().toUpperCase(Locale.ROOT);
}

它应该满足三个条件:

当前代码没有处理 null,空白字符串的返回结果也不对。先保留这个故障,交给 Agent 修。

在 IDEA 中运行基线

  1. 用 IDEA 打开 D:\Documents\Agent\agent-harness-lab
  2. 打开 File → Project Structure → Project
  3. Project SDK 选择本机已经安装的 JDK 21,具体路径以自己的电脑为准。
  4. 打开 src/test/java/lab/OrderServiceSelfTest.java
  5. 点击 main 方法左侧的绿色三角,选择 Run 'OrderServiceSelfTest.main()'

如果代码能正常编译,程序会在 normalizeStatus(null) 这里触发空指针。具体文件行号以 IDEA 的真实输出为准,跑完以后再记录。

如果 IDEA 提示找不到 OrderService

这个问题来自练习项目的模块依赖,不是要交给 Agent 修的业务 Bug。

当前本地项目把生产代码和测试代码拆成了 maintest 两个模块,test 需要依赖 main

  1. 打开 File → Project Structure → Modules
  2. 选择 test → Dependencies
  3. 点击 + → Module Dependency
  4. 只选择 mainScope 保持 Compile
  5. 点击 Apply → OK,再运行测试类的 main 方法。

不要再给 test 添加 root 依赖。root 里放着用于恢复现场的 baseline/OrderService.java,它和生产代码同名,同时引入会出现重复类。

如果暂时不想调整 IDEA 模块,也可以打开 IDEA 底部的 Terminal,确认当前 Shell 是 PowerShell,再运行下面两条命令作为保底。

javac -encoding UTF-8 -d out src/main/java/lab/OrderService.java src/test/java/lab/OrderServiceSelfTest.java
java -ea -cp out lab.OrderServiceSelfTest

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 4第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 4

给不允许修改的文件留一个指纹

Agent 动手前,先给四个受保护文件计算 SHA-256。它相当于文件内容的指纹,只要内容变化一个字符,Hash 就会变化。

在 Windows PowerShell 中运行下面这段,并保持窗口不要关闭。如果使用 IDEA Terminal,先确认其 Shell 已切换为 PowerShell。

$guardedFiles = @(
    'AGENTS.md',
    'TASK.md',
    'README.md',
    'src/test/java/lab/OrderServiceSelfTest.java'
)

$guardedBefore = Get-FileHash -Algorithm SHA256 -LiteralPath $guardedFiles
$guardedBefore | Select-Object Path, Hash

Pi 和 DSH 每完成一次任务,都用这份指纹复查。这样既能通过 Diff 查看 OrderService.java 的变化,也能确认规则、任务、README 和测试有没有被改过。

先跑出失败基线很重要。Agent 稍后会报告它已经修好;有了修复前的失败记录,再从同一个入口重跑,结果才不只是听它自己汇报。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 5第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 5

第 2 步:安装并第一次打开 Pi

Pi 当前的官方安装命令是:

npm install -g --ignore-scripts @earendil-works/pi-coding-agent
pi --version

包名要看清。旧教程里常见的 @mariozechner/pi-coding-agent 已经不是当前官方包,本文使用 @earendil-works/pi-coding-agent

如果安装完成后提示无法识别 pi,先关闭并重新打开 Windows PowerShell,或已切换到 PowerShell 的 IDEA Terminal,不要立刻重复安装。仍然找不到时运行下面三条,确认它们来自当前使用的 Node 目录。

where.exe node
where.exe npm
where.exe pi

第一轮先尝试通过启动参数只提供读取工具,不把写入和命令工具交给 Pi。

$labRoot = 'D:\Documents\Agent\agent-harness-lab'
Set-Location $labRoot
pi --tools 'read,grep,find,ls'

--tools 后面的逗号列表要整体加引号。本次最初实测漏掉了这对引号;Pi 虽然仍能进入交互界面,但这不代表四个工具已经加载成功。

本次实测中,pi --version 返回 0.84.3。启动页列出了当前目录的 AGENTS.md 和 4 个 Skills。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 6第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 6

启动页还出现了两类黄色提示,含义不同:

接下来完成两项配置:

  1. 输入 /login,选择模型服务并完成登录。
  2. 输入 /model,确认本次实际使用的模型。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 7第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 7

登录并确认模型后,在 Pi 里输入 /quit,退出第一次打开的会话。看到 PowerShell 的 PS ...> 提示符后,第 2 步结束。

第 3 步:让 Pi 先做只读分析

第 3 步从退出 Pi 后的 PowerShell 开始。先运行下面的启动命令,不要急着发送任务提示词。

Set-Location 'D:\Documents\Agent\agent-harness-lab'
pi --tools 'read,grep,find,ls'

/quit 要在 Pi 里输入,pi --tools 'read,grep,find,ls' 要在 PowerShell 里运行。单引号不能省略。等新的 Pi 界面打开后,再继续下面的只读分析。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 8第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 8

把下面这段提示词发给 Pi。

先只读分析当前目录,不要修改文件,也不要运行命令。

请阅读 AGENTS.md、TASK.md、README.md 和 Java 源码,然后告诉我
1. 当前失败的根因是什么
2. 哪个文件允许修改
3. 应该运行什么检查
4. 如果允许修改,你准备怎样做最小修复

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 9第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 9

这一次只读分析成功。会话日志显示,Pi 实际调用 read 读取了 AGENTS.mdTASK.mdREADME.md、生产代码、测试代码和 baseline,并用 ls 查看了项目目录。没有出现 writeeditbashpowershell 调用。

要看什么本次实测结果
当前失败的根因找对了。null 会在 status.trim() 处触发空指针;空白字符串会变成 "",而不是期望的 "UNKNOWN"
哪个文件允许修改只允许修改 src/main/java/lab/OrderService.java
应该运行什么检查准确复述了 README.md 中的 javac 编译、自测和 git diff --no-index 命令
最小修复方案在方法入口统一处理 null 和空白字符串并返回 "UNKNOWN",其余转换逻辑保持不变
是否修改文件或运行命令没有。本轮只调用了读取类工具,修改与测试要等下一步授权

Pi 根据源码和测试用例判断:" paid " 这条正常路径会通过,null 和空白字符串两条会失败。这里是静态分析结论,不是测试执行结果。当前目录已经有 out/;如果在全新目录复现且还没有它,应先运行 New-Item -ItemType Directory -Force out,再执行 README.md 中的编译命令。

pi --tools 'read,grep,find,ls' 在本机正确启用了四个读取类工具,同时没有提供 writeeditbashpowershell。这能限制 Pi 本轮可调用的内置工具,但不等于系统隔离;Pi 仍以当前 Windows 用户的权限读取文件,练习目录里不能放敏感内容。

记录完成后,在 Pi 中输入 /quit 或连续按两次 Ctrl+C 退出。

实测记录 03|完成。deepseek-v4-pro 实际读取了项目规则、任务、README、生产代码、测试和 baseline,正确给出了失败根因、唯一可修改文件、检查命令和最小修复方案。本轮没有修改文件,也没有运行编译或测试。

第 4 步:让 Pi 修改代码并验证

第 3 步已经确认 Pi 实际读取了项目文件并给出四项结论。退出只读会话后,用默认模式重新启动 Pi。

Set-Location 'D:\Documents\Agent\agent-harness-lab'
pi

下面的任务提示词会原样交给 Pi 和 DSH。两边面对同一份代码、同一套规则,后面的观察才有参考价值。

请先阅读 AGENTS.md、TASK.md、README.md 和相关 Java 源码。

目标
修复 TASK.md 描述的问题,并运行 README.md 中的检查。

要求
1. 修改前先解释根因和最小修复计划
2. 只允许修改 src/main/java/lab/OrderService.java
3. 不修改测试、任务说明和 README
4. 不访问网络,不安装依赖,不提交 Git
5. 修改后实际运行编译和自测命令
6. 使用下面的命令展示生产代码与基线的差异
   git diff --no-index -- baseline/OrderService.java src/main/java/lab/OrderService.java
7. 最后报告根因、修改内容、测试结果、是否触碰边界和剩余风险

Agent 工作时留在旁边观察:

如果第一次没有成功,就把报错、补充提示和第二次尝试一起记下来,不为文章效果删掉失败过程。

Pi 的实际执行记录

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 10第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 10

本次会话最初选中 deepseek-v4-pro,在发送任务前切换为 deepseek-v4-flash,推理档位为 high。后续读取、修改、验证和最终报告都发生在切换之后。

会话日志里的真实工具轨迹是:

  1. read 读取 AGENTS.mdTASK.mdREADME.md、当前生产代码、baseline 和自测代码。
  2. 只对 src/main/java/lab/OrderService.java 发起一次 edit
  3. bash 编译并运行自测,得到 All self-tests passed.
  4. 再用 bash 执行 git diff --no-index,结果只新增下面 3 行,退出码为预期的 1
+        if (status == null || status.trim().isEmpty()) {
+            return "UNKNOWN";
+        }
检查项Pi 本轮实测
根因null 会触发空指针;空白字符串处理后得到 "",不符合返回 "UNKNOWN" 的要求
修改范围方法签名和原有大写转换逻辑不变,只新增 3 行入口守卫
编译与自测已实际执行并输出 All self-tests passed.
Diff只有 OrderService.java 的 3 行新增;退出码 1 表示发现预期差异
网络、安装、提交Pi 的工具轨迹中没有相关命令
受保护文件没有针对它们的 edit 调用;是否保持原 Hash 仍由下面的人工检查确认

这个修复延续了项目原有的 trim() 行为,覆盖当前三个自测用例。Unicode 空白字符等更宽泛场景不在本次测试范围内,是否扩展语义要另行确认,不能为了“更通用”擅自扩大改动。

回到 IDEA 验收 Pi

Pi 报告完成后,先自己验收。

  1. 回到 OrderServiceSelfTest.java
  2. 点击 IDEA 的 Rerun,或按 Shift+F10
  3. 正确结果应该是 All self-tests passed.
  4. 再到 IDEA 的 PowerShell Terminal 查看修改前后的差异。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 11第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 11

本次人工复跑已经通过。IDEA 的运行窗口输出 All self-tests passed.,随后显示“进程已结束,退出代码为 0”。画面同时显示了三个自测用例和 OrderService.java 中新增的 3 行守卫,因此 Pi 终端里的成功结果在 IDEA 中得到了再次验证。

git diff --no-index -- baseline/OrderService.java src/main/java/lab/OrderService.java

git diff --no-index 发现两个文件不同时会返回退出码 1。这里的 1 表示确实存在差异,不是命令执行失败。

Diff 只说明 OrderService.java 改了什么。受保护文件还要用之前保存的 Hash 检查。

$guardedAfter = Get-FileHash -Algorithm SHA256 -LiteralPath $guardedFiles
Compare-Object $guardedBefore $guardedAfter -Property Path, Hash

没有任何输出,表示这四个文件的内容没变,前提是 $guardedBefore 确实保存于 Pi 修改之前。如果出现结果,先查清 Agent 改了什么,不要直接进入下一步。最后再检查项目树,确认没有新增与任务无关的文件。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 12第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 12

本次截图里重新计算了 $guardedBefore,因此仅凭紧接着的 Compare-Object 空输出,不能单独证明 Pi 修改前后没有变化。继续与第 1 步的 011-sha256.png 逐项核对后,AGENTS.mdTASK.mdREADME.mdOrderServiceSelfTest.java 的四个当前 Hash 与原始 Hash 完全一致。结合会话中唯一的 edit 目标是 OrderService.java,可以确认这四个受保护文件未被修改。

实测记录 04|完成。Pi 使用 deepseek-v4-flash 只对 OrderService.java 发起修改,真实执行编译与自测并输出 All self-tests passed.;IDEA 人工复跑再次输出相同结果,退出码为 0git diff --no-index 只显示 3 行入口守卫;四个受保护文件的当前 SHA-256 与第 1 步保存的原始值完全一致。

第 5 步:恢复 Bug

Pi 验收结束后,把生产代码恢复成最初的故障版本。

Set-Location 'D:\Documents\Agent\agent-harness-lab'
Copy-Item -LiteralPath baseline/OrderService.java -Destination src/main/java/lab/OrderService.java -Force

回到 IDEA,再运行一次 OrderServiceSelfTest.main()

只有空指针重新出现,才能确认 DSH 接下来拿到的是同一个起点。两边面对的代码不同,比较就失去了意义。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 13第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 13

本次恢复验证符合预期。IDEA 显示 normalizeStatus 已回到没有入口守卫的单行实现;运行自测时,normalizeStatus(null)OrderService.java:8 再次触发 NullPointerException,调用位置是 OrderServiceSelfTest.java:9,进程退出码为 1

随后计算当前生产文件与 baseline 的 SHA-256,两者都是 D8C2F3DEB9D5FFC938C8DE010101DD369A800C0BBA8791CE8C53DA7096E3C208。这说明 OrderService.java 已经字节级恢复,DSH 将面对与 Pi 修改前相同的故障代码。

向 DSH 发送第 7 步任务前,再执行一次下面这条,为 DSH 单独保存受保护文件的指纹。只启动本地页面不会修改练习代码,因此即使服务已经打开,现在补做仍然有效。

$guardedBefore = Get-FileHash -Algorithm SHA256 -LiteralPath $guardedFiles

实测记录 05|完成。当前 OrderService.java 与 baseline 的 SHA-256 完全一致;IDEA 复跑重新出现预期的 NullPointerException,退出码为 1。第 7 步继续用第 1 步保存的原始 Hash 核对四个受保护文件。

第 6 步:启动并配置 DeepSeek Harness

下文把 DeepSeek Harness 简称为 DSH。

在练习目录运行官方启动命令。

Set-Location 'D:\Documents\Agent\agent-harness-lab'
npx @deepseek-ai/dsh web

第一次运行时,npx 可能需要下载所需内容。如果它询问是否安装,先核对包名确实是 @deepseek-ai/dsh,再确认继续。

本次首次运行提示安装 @deepseek-ai/dsh@0.1.1-rc.2,确认后终端长时间只显示旋转符。进程和 npm 日志显示它仍在解析较大的依赖树,并非立即卡死;与此同时,本机已有同版本 DSH 服务监听 3080,页面返回 200 OK。后来重复的 npx 进程自行退出,只剩一个服务进程。

遇到类似情况时,先直接访问下面的地址。页面能打开就不要重复执行 npx,否则可能同时启动多个安装或服务进程。

默认页面地址是:

http://127.0.0.1:3080

如果只想启动服务,不让它自动打开浏览器,可以使用下面的命令。

npx @deepseek-ai/dsh web --no-open

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 14第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 14

打开页面后,按下面的顺序配置。

  1. 进入 Settings → Models
  2. 配置要使用的模型服务。
  3. 点击 Choose workspace。Workspace 就是这次允许 DSH 使用的工作目录。
  4. 只选择 D:\Documents\Agent\agent-harness-lab
  5. 权限预设选择 workspace-write。它内部对应文件沙箱 workspace-write 和审批策略 ask,不要为了少点确认就切到 danger-full-access

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 15第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 15

本次页面配置为:

配置项实测值
页面地址http://127.0.0.1:3080
Workspaceagent-harness-lab
ProviderDeepSeek,状态正常
模型DeepSeek-V4-FlashHigh
Agent 模式标准模式
权限Workspace Write
界面语言中文

这个预设也不是完整隔离。它主要约束文件写入,不限制文件读取、网络和进程可见性;官方还标明 Windows ACL 后端可能只有 partial,也就是部分生效。练习目录之外仍然不要放希望它绝对看不到的敏感内容。

如果想尽量比较 Harness,而不是比较模型,就让 Pi 和 DSH 使用同一个模型。做不到也没关系,只要在实测记录里写清两边的模型,不把结果包装成严格评测。

实测记录 06|完成。DSH 0.1.1-rc.2 已在 127.0.0.1:3080 打开,Workspace 为 agent-harness-lab,使用 DeepSeek-V4-Flash High、标准模式、中文界面和 Workspace Write;截图没有暴露 API Key。Workspace Write 允许修改练习目录,第 7 步的“只读分析”仍只是提示词约束。

第 7 步:把同一个任务交给 DSH

先把第 3 步那段要求不修改文件的提示词发给 DSH,观察它能不能找到项目规则、任务和测试入口。

这里有一个需要单独说明的差别:Pi 第一轮通过 --tools 去掉了写入和命令工具;DSH 这一轮主要依靠提示词要求它只读观察。两者不是同一种技术限制。发出任务后仍要看真实工具轨迹,不能只看它口头答应了什么。

DSH 的只读分析记录

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 16第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 16

本轮使用 DeepSeek-V4-Flash High。页面展示的真实轨迹是:先注入 Workspace 下的 AGENTS.md、DSH 系统提示和 Skill Catalog,再进入 Think;随后用 Glob 查找 **/*.java,依次读取 AGENTS.mdTASK.mdREADME.md、当前生产代码、baseline 和自测代码。没有出现编辑工具,也没有执行编译、测试或 Diff 命令。

它给出的四项结论与项目内容一致。

检查项DSH 本轮分析
根因null 会在 status.trim() 处触发空指针;空白字符串处理后得到 "",不符合返回 "UNKNOWN" 的要求
修改边界只允许修改 src/main/java/lab/OrderService.java,禁止改任务、README 和测试
验证办法正确列出了 README 中的 javacjavagit diff --no-index 命令
最小修复保持方法签名和原有大写逻辑,只在入口增加 null、空白字符串守卫

DSH 最后问“需要我继续执行这个最小修复吗?”,说明它在分析阶段后停下来等待确认。到这里能确认的是:它完成了只读静态分析,结论正确,且可见轨迹中没有修改或执行命令。这里还不能写“修复成功”,因为代码、编译、自测和 IDEA 复跑都没有发生。

截图之后再次核对,当前 OrderService.java 仍与 baseline 的 SHA-256 一致,四个受保护文件的 Hash 也没有变化。不过,页面底部仍是 Workspace Write,所以这次没有写文件是它遵守了提示词,不是系统撤掉了写入能力。

现在先回到此前保持打开的 PowerShell,为 DSH 的修改阶段单独保存一次受保护文件指纹。

$guardedBefore = Get-FileHash -Algorithm SHA256 -LiteralPath $guardedFiles
$guardedBefore | Select-Object Path, Hash

保存完成后,不要只回复“是”。把第 4 步的完整任务提示词原样发送给 DSH,其中包含允许修改的文件、禁止事项、验证命令和最终报告要求。这样 Pi 与 DSH 接到的是同一份修改任务,也方便事后检查它有没有越界。

DSH 的修改与自测记录

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 17第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 17

本次发送的是第 4 步的完整提示词。DSH 没有直接跳到修改,而是先复述根因和最小修复计划,然后按下面的顺序执行:

  1. Edit 修改 src/main/java/lab/OrderService.java
  2. 用 PowerShell 运行 javac 编译生产代码和自测代码。
  3. 用 PowerShell 运行 git diff --no-index,展示生产代码与 baseline 的差异。
  4. 用 PowerShell 运行 java -ea -cp out lab.OrderServiceSelfTest
  5. 汇总根因、修改内容、测试结果、边界和剩余风险。

页面中的最终报告显示,唯一的源码变化是下面 3 行入口守卫。

+        if (status == null || status.trim().isEmpty()) {
+            return "UNKNOWN";
+        }
检查项DSH 本轮实测
修改范围只修改 src/main/java/lab/OrderService.java,方法签名、Locale import 和原有大写逻辑不变
编译javac 成功,退出码为 0
自测输出 All self-tests passed.,退出码为 0
Diff只有 3 行新增;git diff --no-index 退出码为预期的 1
边界可见轨迹中没有网络访问、依赖安装或 Git 提交
剩余风险当前判断基于 trim(),没有把更宽泛的 Unicode 空白字符扩展进任务语义

随后又在项目根目录独立运行相同的编译、自测和 Diff 命令,得到相同结果。Diff 同时出现了 LF/CRLF 提示,它表示 Git 以后接触这些文件时可能转换行尾,不影响本次 3 行逻辑差异。接下来回到 IDEA,从同一个入口再做一次不依赖 DSH 报告的人工复跑。

回到 IDEA 验收 DSH

验收办法和 Pi 相同。

  1. 回到 IDEA 运行 OrderServiceSelfTest.main()
  2. 确认实际输出,不只看 DSH 的总结。
  3. 在 IDEA 的 PowerShell Terminal 运行同一条 Diff 命令。
  4. 检查 TASK.mdREADME.md 和测试文件有没有被改动。

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 18第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 18

本次 IDEA 人工复跑通过。运行窗口输出 All self-tests passed.,随后显示“进程已结束,退出代码为 0”;画面同时显示三个自测用例和 OrderService.java 中新增的入口守卫。这说明 DSH 页面里的成功结果已经从 IDEA 的同一测试入口得到复核。

git diff --no-index -- baseline/OrderService.java src/main/java/lab/OrderService.java

再检查受保护文件的 Hash。

$guardedAfter = Get-FileHash -Algorithm SHA256 -LiteralPath $guardedFiles
Compare-Object $guardedBefore $guardedAfter -Property Path, Hash

本次当前 Hash 与第 1 步保存的四个原始值逐项一致:

受保护文件当前 SHA-256
AGENTS.md3411EFBABAB2C5E54F1F19C88EAC6A1B8922658D277249D019441755A4D8AF67
TASK.md10102B6A31479A6E289C0045A73E0895921232E7958703AFD44A5E6440E43295
README.md21E72787FED95437AFC82258CC5EA8BDA6FC83161BDCCA880889BBC1F4CC5B54
OrderServiceSelfTest.javaF418BE36AE30EE90D1E0B8C9329845ACF022821A203D6EAB2E9839141CD9325B

截图中的最后一次 Compare-Object 没有输出,但画面里又重新计算了 $guardedBefore,所以不能只凭这次空输出证明 DSH 修改前后没有变化。有效依据是:上表四个当前 Hash 与第 1 步保留的原始 Hash 逐项一致。结合 DSH 的唯一 Edit 目标和真实 Diff,可以确认这四个受保护文件没有被修改。

完成后,关闭浏览器标签并不会停止 DSH。回到启动 npx 的 PowerShell 窗口,按 Ctrl+C 停止服务。

实测记录 07|完成。DSH 先完成只读分析,再只修改 OrderService.java;页面记录和项目根目录独立复核都显示编译成功、自测输出 All self-tests passed.,Diff 只有预期的 3 行入口守卫;IDEA 人工复跑再次通过,退出码为 0;四个受保护文件的当前 SHA-256 与第 1 步原始值一致。

用同一套证据记录两个 Harness

第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 19第一次上手 Agent Harness:用 Pi 和 DeepSeek Harness 修一个 Java Bug image 19

第一次体验先不急着打分,把实际记录填齐。

观察项Pi 实际记录DSH 实际记录
安装和第一次启动0.84.3 ,在 PowerShell 中进入终端界面0.1.1-rc.2 ,在 127.0.0.1:3080 打开本地工作台
实际使用的模型只读分析为 deepseek-v4-pro;修改阶段为 deepseek-v4-flash highDeepSeek-V4-Flash High
是否找到项目规则是,读取了 AGENTS.md、任务、README、生产代码、baseline 和自测是,读取范围与 Pi 相同
第一个读取的文件AGENTS.mdAGENTS.md
工具调用怎样展示终端中按时间顺序显示 readeditbash页面同时展示 Think、任务进度、ReadEdit 和 PowerShell 调用
是否尊重文件边界是,真实 Diff 和原始 Hash 复核均通过是,真实 Diff 和原始 Hash 复核均通过
是否主动运行检查是,实际编译、自测并展示 Diff是,实际编译、自测并展示 Diff
IDEA 人工验收结果All self-tests passed. ,退出码 0All self-tests passed. ,退出码 0
中途遇到的问题首次 --tools 参数漏加引号;fdripgrep 自动下载遇到 GitHub API 403首次 npx 长时间显示旋转符;确认 3080 页面可用后没有重复启动服务
本次主观感受命令行里的工具轨迹集中,但第一次使用没有图形页面直观模型、计划、任务和工具调用都在图形页面里,第一次操作更直观

这次两边最终都新增了相同的 3 行守卫,编译、自测和 IDEA 人工复跑也都通过。差别主要出现在交互方式:Pi 把过程集中显示在终端里,DSH 把模型、计划、任务和工具调用放在同一个图形页面中。

这份记录可以回答开始时的三个问题:

问题本次答案
它做过什么,我看得见吗?能。Pi 和 DSH 都留下了读取、编辑和命令调用轨迹
它有没有越过我给出的边界?没有发现。真实 Diff 只有生产代码的 3 行新增,四个受保护文件的 Hash 与原始值一致
它说完成以后,我能独立验证吗?能。两次都在 IDEA 从同一个测试入口复跑成功,退出码为 0

这仍然不是严格对比评测:只跑了一个小任务、每个 Harness 只有一次修改记录,而且 Pi 的只读阶段和修改阶段使用了不同模型。上面的结论只描述这次操作,不能据此判断谁的能力更强。

走完七步之后

七步走完,我留下了一套可以复用的验收顺序:先复现问题,保存受保护文件的 Hash,让 Agent 读取、修改和运行检查,再回到 IDEA 复跑并审 Diff。插件、子 Agent 和复杂工作流不在这次练习范围内,这次也没有测试它们。

下一步,尝试做一个 DSH 插件

下一步,我打算参考 Russell 的《万字长文,DeepSeek Harness 一文全看懂!!》,亲手做一个 DSH 插件。

不过现在只定了方向,具体做什么展示还没定。它最后是一个新工具、一块 Web 界面,还是另一种更适合演示的能力,要等选题确定以后再说。我不想为了让文章结尾显得完整,先编一个插件名,再把还没做过的功能和结果写上去。

选题时我会看三件事。读者能不能一眼看出装插件前后的变化,结果能不能独立验证,实验范围能不能控制在一个小目录里。等展示内容真正定下来,再补功能边界、权限、操作步骤和验收记录。

所以这里先留一个预告。下一篇从选题、搭插件骨架、加载运行,到失败、修改和最终验证,重新完整走一遍。现在能确认的只有一件事,下一站是 DSH 插件,具体做什么,尚未决定。

DSH 仍处于 Developer Preview,真正动手前还要重新核对官方仓库里的 web-cordis 示例和插件配置文档。

附录|没有练习项目时,自己创建一份

先建立目录。

$labRoot = 'D:\Documents\Agent\agent-harness-lab'
New-Item -ItemType Directory -Path "$labRoot\src\main\java\lab" -Force | Out-Null
New-Item -ItemType Directory -Path "$labRoot\src\test\java\lab" -Force | Out-Null
New-Item -ItemType Directory -Path "$labRoot\baseline" -Force | Out-Null
New-Item -ItemType Directory -Path "$labRoot\out" -Force | Out-Null
Set-Location $labRoot

src/main/java/lab/OrderService.java

package lab;

import java.util.Locale;

public final class OrderService {

    public String normalizeStatus(String status) {
        return status.trim().toUpperCase(Locale.ROOT);
    }
}

src/test/java/lab/OrderServiceSelfTest.java

package lab;

public final class OrderServiceSelfTest {

    public static void main(String[] args) {
        OrderService service = new OrderService();

        assertEquals("PAID", service.normalizeStatus(" paid "), "normal value");
        assertEquals("UNKNOWN", service.normalizeStatus(null), "null value");
        assertEquals("UNKNOWN", service.normalizeStatus("   "), "blank value");

        System.out.println("All self-tests passed.");
    }

    private static void assertEquals(String expected, String actual, String scenario) {
        if (!expected.equals(actual)) {
            throw new AssertionError(
                    scenario + ": expected <" + expected + "> but was <" + actual + ">"
            );
        }
    }
}

AGENTS.md

# Agent Harness Lab Rules

- 只允许修改 src/main/java/lab/OrderService.java
- 不修改测试、TASK.md 和 README.md
- 不安装依赖,不访问网络,不操作练习目录之外的文件
- 修改后必须运行编译和自测命令
- 最后报告原因、改动、测试结果和剩余风险

TASK.md

# Task

OrderService.normalizeStatus 需要满足下面三条

- " paid " 返回 "PAID"
- null 返回 "UNKNOWN"
- 空白字符串返回 "UNKNOWN"

保持现有 public 方法签名,只做最小、可读的生产代码修改,不要改测试。

README.md

# Agent Harness First Lab

在 Windows PowerShell 中运行

```powershell
javac -encoding UTF-8 -d out src/main/java/lab/OrderService.java src/test/java/lab/OrderServiceSelfTest.java
java -ea -cp out lab.OrderServiceSelfTest

正确结果是 All self-tests passed.


最后保存一份故障基线。

```powershell
Copy-Item -LiteralPath src/main/java/lab/OrderService.java -Destination baseline/OrderService.java -Force

手工创建项目后,再让 IDEA 认识源码目录。

  1. 用 IDEA 打开 agent-harness-lab
  2. 在项目树中右键 src/main/java,选择 Mark Directory as → Sources Root
  3. 右键 src/test/java,选择 Mark Directory as → Test Sources Root
  4. baseline 保持普通目录;如果 IDEA 把它识别成源码,改成 Mark Directory as → Excluded
  5. Project Structure → Project 中选择 JDK 21。

这条是自行创建项目的路线,不会沿用前文随附项目里的 rootmaintest 三模块结构,也不用添加模块依赖。

官方资料

延伸阅读(非官方):

资料核对时间为 2026 年 8 月 27 日。DSH 目前仍处于 Developer Preview,官方明确提醒可能发生破坏兼容性的变化。Pi 与 DSH 的安装命令、版本和界面也可能更新,实际使用前请再查看上面的官方文档。

引用链接

[1] 《万字长文,DeepSeek Harness 一文全看懂!!》: https://x.com/Russell3402/status/2092535898034630816 [2] `web-cordis` 示例: https://github.com/deepseek-ai/deepseek-harness/tree/master/examples/web-cordis [3] 插件配置文档: https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/config.md [4] Pi Quickstart: https://pi.dev/docs/latest/quickstart [5] Pi Windows 使用说明: https://pi.dev/docs/latest/windows [6] Pi Security: https://pi.dev/docs/latest/security [7] DeepSeek Harness 官方介绍: https://www.deepseek.com/harness/en/ [8] DSH Web UI 快速开始: https://deepseek-harness.github.io/deepseek-harness/en/guide/quickstart [9] DSH 模型配置: https://deepseek-harness.github.io/deepseek-harness/en/guide/providers [10] DSH 权限预设: https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/permission-presets [11] DSH Sandbox 边界: https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/sandbox [12] DeepSeek Harness 官方仓库: https://github.com/deepseek-ai/deepseek-harness