← 全部极客知识库

主流 Agent 入门教程 / DeepSeek Harness

11. 案例二-改造代码

原文备份 · 第 12 / 21 篇 · 查看极客时间原知识库 ↗

本篇目录 · 23 节

来源:DeepSeek Harness

本文属于《DeepSeek Harness 入门教程(实战版)》· 第四部分 · 沿着项目掌握核心能力

第 11 章 案例二:从需求到可运行的第一版

现在的 daily-report 还不是一个程序。它只有上一次实战创建的两个文件:

daily-report/
├── PROJECT.md
└── sources.json

这一章要让 DSH 把它变成能真实运行的 Node.js 日报助手:读取两个 GitHub Releases 数据源,生成 daily-report.md,同时留下不依赖网络的自动测试。

我们练的不是“请 AI 帮我写代码”这一句话,而是一条可以复用的工作流:

读取现状 → 先做计划 → 审批执行 → 查看差异
         → 跑聚焦测试 → 跑完整验证 → 亲自验收产物

章节结束时,你不仅会得到一版程序,还应该能判断 Agent 的改动是否合理。

11.1 先确认真实起点

请选中第 7 章使用的 daily-report 工作区,打开文件树确认:

  • PROJECT.md 中有“项目目标”“输入与输出”“技术约束”“首版验收标准”;
  • sources.json 顶层是数组,包含 DeepSeek Harness Releases 和 Node.js Releases 两项;
  • 目录中还没有 package.json、src/、test/ 和 daily-report.md。

如果你是从本章直接开始,请先回到第 7 章,按那里的提示创建这两个文件。不要让 Agent 在本章里凭空补写一份不同的需求,否则后面的验收基准会不一致。

继续使用:

  • 标准模式:这次需要读文件、搜索、编辑和运行命令;
  • Workspace Write(工作区内修改):允许写入当前项目,但不需要完全权限;
  • 与前几章相同的可用模型:先不换模型,避免同时改变太多变量。

11.2 这次为什么先用 Plan mode

写两个配置文件时,我们可以直接下达任务。现在要同时决定文件拆分、错误处理、测试边界和输出格式,先看计划更划算。

DSH 的 Plan mode 是一种协作状态:它引导 Agent 先探索和设计,再把完整计划交给你审查。它不是安全沙箱,也不会自动禁用写文件或 Shell 工具;真正的强制边界仍然由权限模式和审批策略提供。官方 Plan mode 说明

这个区别很重要:

  • Plan mode 回答“我们先怎么想清楚”;
  • Workspace Write 回答“实际执行时最多能写到哪里”;
  • 审批卡片回答“这一次具体操作是否允许”。

如果当前组合已加载 Plan 插件,在输入框中输入:

/plan

界面应该显示计划模式已开启。你也可以通过会话页面中与计划相关的控件进入;如果界面标签随版本改变,/plan 是更容易核对的入口。

11.3 先让 Agent 读需求并提交计划

在同一个任务中发送下面这段话:

请先读取当前工作区的 PROJECT.md 和 sources.json,为“日报助手”设计一个可运行的首版。目前只有这两个文件。

请遵守以下实现约定:

1. 使用 ES Modules 和 Node.js 内置 fetch,零第三方依赖;
2. 提供 npm start 和 npm test 两个脚本;
3. 从 sources.json 加载并校验数据源,请求每个 GitHub Releases API;
4. 请求 GitHub API 时带上能识别本工具的 User-Agent,检查 response.ok,再将每条 release 统一为标题、页面链接和发布时间;
5. 所有数据源都获取成功后,再一次性写入 daily-report.md;任一数据源失败时显示包含源名称的错误并以非零状态结束,不要用空报告冒充成功。每源请求及响应体读取最多 10 秒,全部数据源总预算 25 秒;本课不自动重试。使用 AbortController/AbortSignal 取消底层 fetch,清理定时器。用遵守 signal 的永不响应假 fetch 验证超时后能结束且不覆盖旧报告;
6. daily-report.md 至少包含生成时间、按数据源分组的二级标题,以及带链接的 release 列表;
7. 将配置解析、网络请求和 Markdown 渲染拆成可单独测试的模块;
8. 测试使用 node:test 和伪造的 fetch,不访问真实网络;
9. README.md 写清运行、测试、输出文件和常见失败;
10. 不要修改 sources.json 中现有的两个数据源,不要安装依赖,不要初始化 Git。

现在只做读取和设计。请提交一份可审查的计划,说明:
- 打算新建或修改哪些文件,每个文件负责什么;
- 数据从配置到 Markdown 的流转过程;
- 会测试哪些正常与失败路径;
- 会运行哪些验证命令,哪一步会真实访问网络。

未经我批准计划前,不要写文件、不要运行网络请求。

要求“伪造的 fetch”有一个很实际的理由:测试应该在断网时也能稳定重现,不能把 GitHub 网络、限流或上游数据变化当成本地代码的测试结果。Node.js 的 fetch 和 node:test 都是内置能力,这个项目不需要为 HTTP 或测试安装额外包;GitHub REST API 则要求请求包含有效的 User-Agent。Node.js fetch 文档 · Node.js Test runner 文档 · GitHub REST API 入门

11.4 怎样审一份实现计划

Agent 读取两个文件后,应该通过计划审查界面提交完整方案。不要因为“看起来很专业”就直接批准,先核对下面五点。

一、文件边界是否清楚

具体文件名可以有小幅差异,但职责应该至少覆盖:

package.json       项目类型与 start/test 脚本
src/               配置、请求、报告渲染和 CLI 入口
test/              不依赖真实网络的测试
README.md          用法与排错
daily-report.md    只在真实运行后生成

不要强求每个人都得到完全相同的 src 文件名。判断标准是模块边界是否让配置、请求和渲染能被独立测试,而不是文件越多越好。

二、测试是否覆盖真正的边界

首版至少要验证:

  • 正确配置能通过,空数组或缺少 name / url 会失败;
  • HTTP 成功响应能被解析为统一 release 结构;
  • HTTP 404/500 会被当成失败,不是继续解析 JSON;
  • Markdown 中有生成时间、两个数据源标题和 release 链接;
  • 测试不请求 GitHub API,也不留下 daily-report.md。

fetch() 在收到 404 或 500 时会返回一个 HTTP 响应,而不是仅因状态码就自动抛出异常;因此计划中应该明确检查 response.ok。这正是上一章网页搜索得到的结论在代码中的落点。

三、失败时是否“明确失败”

不要接受“某个源错了就用空数组,依然输出成功”的计划。对学习项目来说,这会把网络错误伪装成“今天没有内容”。

更合理的首版是:先在内存中拿到所有数据、组装 Markdown,全部成功后才写文件。这也为后面接入新数据源和工具留出稳定的处理接口。

四、是否偷偷增加了额外复杂度

首版不需要 TypeScript 编译、Web 界面、数据库、测试框架、日志库或 GitHub SDK。如果计划中出现 npm install,先让 Agent 说明为什么 Node.js 内置能力不够。本章的约束已经说明零依赖,通常应直接删掉这部分。

五、验证顺序是否合理

一份合格计划应该先运行不联网的测试,再运行一次真实网络验收。这样即使 GitHub 不可访问,也能判断本地逻辑是否正常。

如果计划还不具体,在评审界面选择继续规划,并补充反馈,例如:

请把计划补充到文件级,并明确列出 HTTP 失败、非法 sources.json 和 Markdown 渲染的测试方式。测试不得访问网络。

当计划能回答“改哪里、为什么、怎么证明成功”时,再选择批准。

11.5 批准后,让 Agent 完成最小实现

批准计划后,Agent 会离开 Plan mode 并进入执行。如果界面在评审后停在等待输入状态,发送:

按刚才批准的计划执行。请先完成实现和无网络测试;在运行会访问 GitHub 的 npm start 前,单独告诉我。

标准模式中,你通常会看到这样的轨迹:

  1. 用 read、glob 或 grep 核对现有文件;
  2. 用 write 创建新文件,或用 edit 做针对性修改;
  3. 运行某个聚焦测试,例如 node --test test/report.test.js;
  4. 修复聚焦测试暴露的问题;
  5. 运行 npm test 做完整回归验证;
  6. 总结新增文件、验证结果和尚未执行的联网验收。

具体的文件工具名和调用次数会因实现结构而不同,不用求它完全一致。DSH 当前的文件能力会把读取、精准编辑、原子写入和搜索分开,读前编辑策略还会防止 Agent 基于过时内容盲改。官方文件系统包说明

审批时只看实际请求

这一章合理的操作边界是:

请求 是否符合本章任务
读写 daily-report 工作区内的源码、测试和 README 符合
运行 node --test ... 或 npm test 符合,不应联网
运行 npm start 符合,但会访问 GitHub API 并写入报告
运行 npm install 不符合,本项目零第三方依赖
读取工作区外的密钥、主目录或其他项目 不符合
删除旧文件、修改全局 npm 配置、用管理员权限执行 不符合

遇到审批卡片时,核对完整命令、工作目录、联网行为和写入目标。对本章任务,选择“允许一次”已经足够;不需要为省一次点击而扩大后续全部权限。

11.6 先审差异,再看总结

Agent 说“完成”之后,打开会话页面的“代码更改”或差异审查区域。当前版本由“代码工作工具”统一控制工作过程、代码差异和新任务模式;差异可在卡片和侧边栏审阅。官方 v0.1.7-rc.2 更新说明

请逐项检查:

  1. sources.json 中的两个对象没有被改名或替换 URL;
  2. package.json 声明了 "type": "module",start 和 test 不依赖额外包;
  3. 请求代码检查 response.ok,错误信息能指出失败的数据源;
  4. 网络请求函数可接收注入的 fetch 实现,或用等价方式避免测试联网;
  5. 程序在所有数据都准备好之后才写 daily-report.md;
  6. 测试至少覆盖配置、HTTP 失败和 Markdown 渲染,而不是只断言“函数存在”;
  7. README 中的命令与 package.json 实际脚本一致;
  8. 没有新增 API Key、.env 真实密钥、node_modules 或不必要的锁文件。

看差异时,不要把“整个文件都是绿色”当成问题:新文件本来就是全量新增。更值得警惕的是未约定的删除、工作区外路径、不必要依赖和测试中真实联网。

如果发现偏差,不要只说“重写一遍”。指出具体事实,例如:

测试轨迹显示请求了 api.github.com,这与“测试不访问真实网络”的约定不符。
请只调整网络模块和相关测试,通过注入假 fetch 覆盖成功、500 和响应格式错误,不要改动其他文件。

这类反馈比“还是不对”有效,因为它给了 Agent 新的、可验证的信息。

11.7 分三层验证

差异没有明显越界后,不要直接跳到“报告生成了”。按下面三层逐步验证,问题会更容易定位。

第一层:聚焦测试

Agent 在实现过程中应该已经运行过某个直接相关的测试文件。例如渲染模块的测试文件是 test/report.test.js,你可以在系统终端中进入 daily-report 目录后执行:

node --test test/report.test.js

如果 Agent 采用了其他文件名,用它实际创建的测试路径替换命令。成功时应看到通过数为正数、失败数为 0。

第二层:完整回归测试

继续执行:

npm test

这一步应运行 test/ 下全部测试,且不需要网络。结果格式会随 Node.js 版本有差异,核心验收点是:

pass > 0
fail 0

如果测试在 GitHub 不可访问时失败,说明它们仍然依赖真实网络,还不符合本章要求。

第三层:真实运行

最后才执行:

npm start

这条命令会访问 sources.json 中的两个 GitHub API URL,并在当前工作区写入 daily-report.md。如果由 Agent 代为执行,审批时应能看到正是这条命令;如果你在自己的系统终端执行,则不经过 DSH 的 Agent 审批。

成功时,终端应该明确提示写入了 daily-report.md,而且进程返回成功状态。现在文件树中才应该出现这个报告。

11.8 独立验收生成的报告

即使 npm start 返回成功,也还要检查产物。先在 DSH 的文件侧边栏打开 daily-report.md,确认:

  • 第一行是日报的一级标题;
  • 页面上有生成时间;
  • 存在 DeepSeek Harness Releases 和 Node.js Releases 两个二级标题;
  • 两个分组下都有可读标题和 GitHub 页面链接,不是原始 JSON;
  • 文件中没有 undefined、[object Object] 或错误堆栈。

再在系统终端中执行一条独立检查:

node -e "const fs=require('node:fs'); const s=fs.readFileSync('daily-report.md','utf8'); const ok=['DeepSeek Harness Releases','Node.js Releases'].every(x=>s.includes(x)) && s.includes('https://github.com/'); if(!ok) process.exit(1); console.log('daily-report.md OK')"

成功时应看到:

daily-report.md OK

这条命令不证明所有文字都完美,但它独立证明了两个必要分组和至少一条 GitHub 页面链接确实落在文件中。

项目应该处于什么状态

你的具体 src 和 test 文件名可能略有不同,但项目应该大致是:

daily-report/
├── PROJECT.md
├── README.md
├── package.json
├── sources.json
├── daily-report.md
├── src/
│   └── ...
└── test/
    └── ...

不应该出现 node_modules/,因为本项目没有第三方依赖;也不要因为平时的 npm 习惯就先运行 npm install。

11.9 三个最容易卡住的地方

npm test 提示找不到模块

先打开 package.json,确认它有 "type": "module",再检查源码中的相对导入路径是否包含 .js 扩展名。不要通过安装一个新包来解决本地文件路径错误。

可以把原始错误交回同一任务:

npm test 失败了,下面是完整输出:

(粘贴输出)

请先定位是 package.json 的 ES Modules 配置还是相对导入路径问题,只做最小修改,不要安装依赖。

npm start 返回 403 或 API rate limit

这通常不是 Markdown 渲染问题,而是 GitHub API 访问受限。先确认代码有明确的 User-Agent 请求头,然后等限流窗口恢复或换一个可以访问 GitHub API 的网络再试。

不要把真实 GitHub Token 直接写进 sources.json、源码、README 或聊天消息。首版练习不要求 Token;如果你所在网络必须认证,先保留已通过的无网络测试,把凭证注入放到后续的专门改造中。

Agent 说已完成,但看不到新文件

先确认会话仍属于正确的 daily-report 工作区,然后展开工具卡片检查实际路径。如果计划被批准后没有进入执行,发送“按已批准的计划执行”即可。

若工具报告“成功”但文件树没刷新,用系统终端的 ls 或 PowerShell 的 Get-ChildItem 直接查看磁盘;界面显示与实际磁盘结果冲突时,以磁盘为准并重新打开预览。

11.10 本章验收

进入下一章前,请确认:

  • 你是从 PROJECT.md 和 sources.json 两个文件开始,没有假设项目早已存在;
  • 使用 Plan mode 审查过文件级实现计划,并理解它不等于安全沙箱;
  • 新程序使用 Node.js 内置能力,没有第三方依赖;
  • 测试使用假 fetch,npm test 在不联网时也能通过;
  • 已在差异界面核对真实改动和权限范围;
  • npm start 成功生成 daily-report.md;
  • 亲自打开报告,并用独立命令确认两个数据源和链接都存在;
  • 能分清聚焦测试、完整回归和真实联网验收各在证明什么。

现在,日报助手已经有了稳定的配置、请求、渲染和测试边界。下一章会在这个可运行基线上,把一份真实 Skill 和一个可验证的 MCP 工具接入 DSH,并继续用同一套权限和验收方法判断它们是否生效。


← 上一章:插件系统:配置、启停与验证 | 回目录 | 下一章:案例三:接入外部工具 →