主流 Agent 入门教程 / DeepSeek Harness
11. 案例二-改造代码
原文备份 · 第 12 / 21 篇 · 查看极客时间原知识库 ↗
本篇目录 · 23 节
本文属于《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 前,单独告诉我。
标准模式中,你通常会看到这样的轨迹:
- 用
read、glob或grep核对现有文件; - 用
write创建新文件,或用edit做针对性修改; - 运行某个聚焦测试,例如
node --test test/report.test.js; - 修复聚焦测试暴露的问题;
- 运行
npm test做完整回归验证; - 总结新增文件、验证结果和尚未执行的联网验收。
具体的文件工具名和调用次数会因实现结构而不同,不用求它完全一致。DSH 当前的文件能力会把读取、精准编辑、原子写入和搜索分开,读前编辑策略还会防止 Agent 基于过时内容盲改。官方文件系统包说明
审批时只看实际请求
这一章合理的操作边界是:
| 请求 | 是否符合本章任务 |
|---|---|
读写 daily-report 工作区内的源码、测试和 README |
符合 |
运行 node --test ... 或 npm test |
符合,不应联网 |
运行 npm start |
符合,但会访问 GitHub API 并写入报告 |
运行 npm install |
不符合,本项目零第三方依赖 |
| 读取工作区外的密钥、主目录或其他项目 | 不符合 |
| 删除旧文件、修改全局 npm 配置、用管理员权限执行 | 不符合 |
遇到审批卡片时,核对完整命令、工作目录、联网行为和写入目标。对本章任务,选择“允许一次”已经足够;不需要为省一次点击而扩大后续全部权限。
11.6 先审差异,再看总结
Agent 说“完成”之后,打开会话页面的“代码更改”或差异审查区域。当前版本由“代码工作工具”统一控制工作过程、代码差异和新任务模式;差异可在卡片和侧边栏审阅。官方 v0.1.7-rc.2 更新说明
请逐项检查:
sources.json中的两个对象没有被改名或替换 URL;package.json声明了"type": "module",start和test不依赖额外包;- 请求代码检查
response.ok,错误信息能指出失败的数据源; - 网络请求函数可接收注入的
fetch实现,或用等价方式避免测试联网; - 程序在所有数据都准备好之后才写
daily-report.md; - 测试至少覆盖配置、HTTP 失败和 Markdown 渲染,而不是只断言“函数存在”;
- README 中的命令与
package.json实际脚本一致; - 没有新增 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,并继续用同一套权限和验收方法判断它们是否生效。
← 上一章:插件系统:配置、启停与验证 | 回目录 | 下一章:案例三:接入外部工具 →