DeepSeek Harness · 猫狗识别框架研究学习与实践指南
学习型项目 · 研究 · 实践
从一句话需求,到一套能跑、可验证、可复盘的 Cordis 插件系统 —— 用"搭建一个真实系统"的方式,彻底理解 dsh 框架「一切皆插件」的架构思想。
- 交付物:web 系统 + dsh 插件 + ds-v4-flash API
- 运行地址:http://127.0.0.1:3080
- 插件:cat-dog-classify-plugin
- 数据:50 猫图 + 50 狗图,批量识别 100% 正确,24 用例全过
目录
1. 项目定位:为什么要做这个系统
DeepSeek Harness(dsh)是 DeepSeek AI 开源的 Agent 编排框架,核心口号只有五个字——一切皆插件:模型适配器、工具注册表、会话日志、HTTP 服务、Agent 主循环,都是插件。
本项目(猫狗识别)正是为理解这套思想而设计的:功能足够简单(上传图片 → 输出"猫"/“狗”),却要求你亲手走完插件开发的完整闭环——注册模型工具、注册 HTTP 路由、装配进 profile、验证插件树,并用真实 API 完成全链路联调。
📌 框架知识点(贯穿全程的核心概念)
插件(Plugin)→ 上下文(Context)→ 服务(Service)→ 可逆注册(Effect)→ 装配层(Patch)。 理解这五个概念,就理解了 dsh 插件化设计的骨架。
两条学习入口(同一份能力,两个入口)
| HTTP 接口 /api/cat-dog-classify | 浏览器页面 | 裸 node:http 处理器,插件自解析 multipart |
| 模型工具 classify_pet_image | harness 会话中的 Agent | dsh 工具管道(校验/权限/执行/日志由框架统一处理) |
关键设计决策:两个入口复用同一个 ClassifierService 业务实例,业务逻辑只写一遍,互不复刻。
2. 制作过程:8 个阶段的完整旅程
这条旅程把"需求 → 设计 → UE → 规则 → 测试 → 插件 → 联调 → 验证"串成一条可复制的学习路线,每一步都产出可检验的文档或代码。
第 0 步:先想清楚,你要学什么
- 产出:明确的目标与学习对象
- 明确 dsh 是什么、为什么学它;项目定位为"通过构建一个小系统来理解插件框架"。此阶段没有文件,却决定了后续所有技术选型的基调。
第 1 步:把一句话需求变成规格
- 产出:doc/req-001-spec.md
- FR-1~FR-7 | NFR-1~NFR-5 | AC-1~AC-7
- 需求原文仅一句:“web 系统 + dsh 插件连接 ds-v4-flash API,识别猫狗图片”。学习型项目的第一课是先文档后代码:把模糊想法拆成功能需求、非功能需求、可检验的验收标准,并约定三条约束(插件优先 / 指令源唯一 / 以官方文档为准)。
📌 框架知识点
dsh 处于开发者预览阶段,API 可能变动。规格里预留"以安装版本官方文档为准"的兜底条款,并把 dsh –profile web –dump-config 的插件树输出作为最终验收依据 —— 这比任何文档都真实。
第 2 步:技术设计:搭建系统骨架
- 产出:doc/tech-design-spec.md
- 分层架构 | 双入口复用 | 错误码表
- 设计文档回答三个关键问题:分层架构(表现层/能力层/服务层/接入层)、双入口复用(工具与路由共享同一份 ClassifierService)、错误码表(INVALID_IMAGE(400)、FILE_TOO_LARGE(413)、MODEL_TIMEOUT(504)、MODEL_AUTH_ERROR(502)、RESULT_PARSE_ERROR(502))。这张错误码表后来被"一处定义、处处引用"——设计文档、规则、前端、路由、测试用例全部一致。
第 3 步:UE 设计先行,原型即页面
- 产出:doc/ue-design-spec.md → web/index.html
- 单页 5 区域 | 状态机 5 态 | 错误映射
- 流程值得学习:先出 UE 设计文档,人工确认后,才动手生成原型。单页 5 区域(标题→上传→操作→结果→页脚),视觉规范主色 #4D6BFE 呼应 DeepSeek 品牌,emoji 图标、零外部依赖(符合最小实现)。交互状态机 idle → preview → loading → success/error,5 个错误码逐一映射为友好中文提示。
web/index.html 单文件(HTML + 内联 CSS + 原生 JS):fetch POST /api/cat-dog-classify、FormData 字段 image、AbortController 60s 超时、所有动态文本 textContent 渲染(零 innerHTML 拼接模型输出)、loading 中换图会中止旧请求。
📌 框架知识点
页面是纯静态文件,最终由 dsh web 服务的 HTTP 层承载(插件注册路由把它挂出来)。所以前端不用自己起服务,接口与页面天然同源 —— 这正是"web 系统 + 插件"一体化的含义。
第 4 步:给 AI 协作者立规矩
- 产出:AGENTS.md + .qoder/rules/
- 行为规范 | 权限清单 | 规则索引
- 学习型项目里 AI 是最主要的协作者。AGENTS.md 定义行为规范(插件优先、最小实现、验证优先)、工具使用权限、插件加载策略、工作流约束与"关键事实速查表";.qoder/rules/ 提供四个按场景分工的规则(coding-standards、plugin-rules、api-contract、service-workflow),AGENTS.md 维护规则索引。
📌 框架知识点
配置文件也是学习框架的窗口 —— AGENTS.md 会被 dsh 加载这件事,本身就是"一切皆插件"的体现:指令加载是插件、技能发现是插件、规则消费也是插件。
第 5 步:测试用例先行
- 产出:test/test-cases.md + 100 张测试图
- TC-01~TC-24 | LLM 可自动执行 | PASS/FAIL/BLOCKED
- 在写插件之前先把验收合同定下来,并把它升级成 LLM 可自动执行的规格:每条用例结构化(编号/依赖/执行方式/可复制命令/精确断言/判定规则),判定仅三种输出 PASS / FAIL / BLOCKED(前提不满足不算失败)。测试数据:50 张猫图 + 50 张狗图,另加非法格式/超限文件的现场构造指令。写用例的过程就是反向梳理设计的过程。
第 6 步:插件开发:本旅程的核心
- 产出:plugins/cat-dog-classify-plugin/(四文件)+ 装配层
- classifier.ts | tool.ts | route.ts | index.ts
先调研 API 再动手写码。 三个可靠信息源:官方文档与社区教程、npm 包的类型定义(.d.ts 就是最精确的 API 文档)、运行时验证(dsh –dump-config 看真实插件树)。
四个源文件的分工
| classifier.ts | 纯业务,零框架依赖 | 校验 → base64 编码 → 提示词组装 → OpenAI 兼容调用(temperature=0、60s 超时)→ 归一化为"猫/狗"(歧义不猜测 → 抛 RESULT_PARSE_ERROR)。零依赖便于直接单测 |
| tool.ts | 模型工具 classify_pet_image | defineTool 声明 schema;required 是每属性的 required: true,不是 JSON Schema 的数组;工具只写业务 |
| route.ts | HTTP 路由 | 裸 node:http 语义,手工解析 multipart(boundary 切分 + Content-Disposition 提取 + 大小上限);错误码 → HTTP 状态映射(400/413/504/502) |
| index.ts | 装配入口 apply(ctx) | inject = ['tools'] 必需依赖;ctx.effect 可逆注册工具;ctx.inject(['webServer']) 声明可选路由依赖 |
装配:让插件进入插件树
dsh 的插件树由多层 patch 叠加:bundle 层 → profile 的 cordis.patch.yml → –patch 覆盖层。本项目把装配写进项目根 dsh-patch.yml:
# dsh-patch.yml
– insert:
– id: cat–dog–classify
name: 'file:///D:/szp/work/deepseek-harness/plugins/cat-dog-classify-plugin/index.ts'
并更新唯一指令源 command/start-web-command.md;用 dsh –profile web –dump-config 验证插件树中可见 id: cat-dog-classify。
⚠️ 联调必踩的两个坑
① 模型名坑:设计文档里的占位名 ds-v4-flash-version 会 400。需先用密钥调 GET /models 探测真实模型列表,得到 deepseek-v4-flash-vision-exp(vision 多模态版)。
② 推理预算坑:该模型是推理模型,max_tokens=32 会让推理 token 吃光预算、content 为空,实测需 max_tokens=1024。→ 通过环境变量 DS_MODEL 覆盖模型名,密钥只走 DS_API_KEY。
第 7 步:全链路验证:24 用例全过
- 产出:验证报告(API 批量 / UI 自动化 / 异常注入 / Agent 工具调用)
- 100% 正确 | 单张 ~2s | 异常可构造
API 批量验证:100 张测试图逐张过 POST /api/cat-dog-classify,猫 50/50、狗 50/50,100% 正确,单张延迟约 2 秒。UI 浏览器自动化:逐条断言空态→预览→非法类型/超限拒绝→"识别中…“→成功展示。异常注入:把 DS_API_BASE 指向不可路由地址→504;去掉 DS_API_KEY→502;停服→前端"无法连接识别服务”。
📌 框架能力的最终证明
在 headless profile 会话中给 Agent 下达任务"识别 test/images/cat/cat_001.jpg 是猫还是狗",Agent 自主完成:读文件 → base64 编码 → 调用 classify_pet_image → 得到"识别结果:猫" → 回答"猫"。你写的工具,被另一个 AI 当成了它的手。
第 8 步:复盘:框架知识地图
- 产出:概念全景与进阶方向(详见第 5 部分)
- 把整个旅程对照框架概念做一次收束,形成可迁移到任何 dsh 插件开发任务的方法论,并指出进阶方向(事件钩子、自定义服务、正式发布为 npm 包、MCP 接入、多 Agent)。
3. 工程结构:目录、架构与分工
一份可导航的代码库地图,从总目录到文件分工,看懂"哪个文件负责什么"。
3.1 总目录结构
deepseek-harness/
├── AGENTS.md # Agent 行为准则(dsh 指令插件自动加载)
├── dsh-patch.yml # 装配层:把插件插入 dsh web profile 插件树
├── command/
│ └── start-web-command.md # 启动命令唯一指令源
├── doc/ # 文档区
│ ├── readme.md # 代码库导航入口
│ ├── ds-harness-doc.md # 框架官方文档链接
│ ├── req-001.md # 原始需求(一句话需求)
│ ├── req-001-spec.md # 需求规格说明书 REQ-001
│ ├── tech-design-spec.md # 技术详细设计 TECH-DESIGN-001
│ ├── ue-design-spec.md # 用户体验设计 UE-DESIGN-001
│ └── coach/ # 教练式指南
│ ├── guide.md # 从 0 构建的学习指南(步骤式)
│ └── ds-harness-framework-dogcatclassify-research-study-practice.md # 本文档
├── plugins/
│ └── cat-dog-classify-plugin/ # 核心交付物:猫狗识别 dsh 插件
│ ├── index.ts # 插件入口:apply(ctx) 注册服务
│ ├── classifier.ts # ClassifierService 识别核心(零依赖)
│ ├── tool.ts # classify_pet_image 模型工具定义
│ ├── route.ts # /api/cat-dog-classify + 页面路由
│ ├── cordis.patch.yml # 插件装配描述(bundle patch)
│ ├── package.json # 包元信息(dsh.bundle 声明)
│ └── tsconfig.json # TypeScript 配置
├── web/
│ └── index.html # 前端单页(原生 HTML+JS,无构建链)
├── test/
│ ├── test-cases.md # 测试用例集 TEST-001(LLM 可执行)
│ └── images/{cat,dog}/ # 各 50 张测试图片
├── .qoder/
│ ├── rules/ # 项目规则(改代码前必读)
│ └── skills/start-web-service/ # 启停服务项目级技能
└── .test-loop/ # 文档驱动测试的循环记录(产物)
3.2 分层架构
识别能力的分层设计,从浏览器到模型 API 一共四层,各层职责清晰、边界明确:
表现层 Web 页面(上传 / 预览 / 结果展示)
│ HTTP POST /api/cat-dog-classify
▼
能力层 dsh 插件 cat-dog-classify-plugin
├─ 模型工具 classify_pet_image
└─ HTTP 路由 /api/cat-dog-classify
│ 复用同一实例
▼
服务层 识别核心 ClassifierService
├─ 图片校验/编码
└─ 提示词组装/结果解析
│ OpenAI 兼容接口(图片 base64)
▼
接入层 ds-v4-flash 系列多模态 API(deepseek-v4-flash-vision-exp)
3.3 端到端数据流
web/index.html ──POST /api/cat-dog-classify──▶ cat-dog-classify-plugin ──▶ ds-v4-flash API
▲ │
└────────── 识别结果 {"result":"猫"|"狗"} ────────┘
同时:Agent 会话 ──ctx.tools──▶ classify_pet_image 工具(复用同一识别逻辑)
3.4 装配层(插件如何"插进"框架)
| dsh-patch.yml | 顶层装配:–patch overlay 把本地插件插入 web profile 插件树(用 file:///D:/… URL) |
| cordis.patch.yml | 插件自带 bundle patch,声明插件 id 与依赖服务(webServer、tools) |
| package.json | dsh.bundle.patch 字段关联装配文件;依赖 @deepseek-ai/cordis、dsh-tools、dsh-host-webserver |
4. 项目构建结果:验收、测试与踩坑
用可验证的数字与清单,说明"这套系统确实做成了、做对了"。
4.1 结果总览
| 批量识别正确率(50 猫 + 50 狗) | 100% |
| 测试用例 PASS(TC-01~TC-24) | 24/24 |
| 单张识别延迟 | ~2s |
| 验收标准(AC-1~AC-7) | 全部满足 |
4.2 验收标准(AC-1~AC-7)对照
| AC-1 | 服务启动 | 执行启动命令后 dsh web 可用(http://127.0.0.1:3080) | ✅ 通过 |
| AC-2 | 插件加载 | 插件树中可见 cat-dog-classify-plugin | ✅ 通过 |
| AC-3 | 图片识别-猫 | 上传猫图输出"猫" | ✅ 通过 |
| AC-4 | 图片识别-狗 | 上传狗图输出"狗" | ✅ 通过 |
| AC-5 | Agent 工具调用 | Agent 可发现并调用"猫狗识别"工具 | ✅ 通过 |
| AC-6 | 服务关闭 | 可按技能流程干净关闭服务 | ✅ 通过 |
| AC-7 | 文档交付 | 需求规格文档交付完成 | ✅ 通过 |
4.3 测试覆盖(TC-01~TC-24)
| 服务类 | TC-01 / TC-02 / TC-13 / TC-14 | 启动就绪、插件树可见、干净关闭、重复启动防护 |
| API 类 | TC-03 ~ TC-09 | 猫/狗批量识别、非法格式 400、超限 413、缺字段 400、超时 504、密钥缺失 502 |
| 单元类 | TC-10 / TC-12 | parseResult 归一化与歧义不猜测(8 项样例) |
| UI 类 | TC-15 ~ TC-21 | 空态、预览、非法/超限拒绝、加载反馈、成功展示、服务不可达提示 |
| 静态检查 | TC-22 ~ TC-24 | 无 innerHTML、5 错误码齐全、接口路径正确 |
| Agent 类 | TC-11 | 会话中出现 classify_pet_image 调用且回答含结论 |
4.4 关键事实速查表
| 启动命令 | npx @deepseek-ai/dsh –profile web –patch dsh-patch.yml |
| Web 地址 | http://127.0.0.1:3080 |
| 插件名 | cat-dog-classify-plugin |
| 模型工具 | classify_pet_image(入参 {"image": string},出参 {"result": string}) |
| HTTP 接口 | POST /api/cat-dog-classify(multipart/form-data,字段 image) |
| 模型标识 | deepseek-v4-flash-vision-exp(环境变量 DS_MODEL 可覆盖) |
| 密钥环境变量 | DS_API_KEY |
| 环境要求 | Node.js ^22.19.0 或 >=24.0.0 |
4.5 踩坑清单(完整记录)
这些坑是这趟旅程最宝贵的经验积累,每一个都有具体后果与解法:
| Node 24 type-stripping 不支持 TS 参数属性(constructor(public x)) | 运行时 SyntaxError | 构造函数内显式赋值 |
| 占位模型名 ds-v4-flash-version | API 400 invalid_request_error | GET /models 探测,改 deepseek-v4-flash-vision-exp |
| 推理模型 max_tokens=32 | 推理吃光预算,content 为空 | max_tokens=1024 |
| Windows 绝对路径装配 | ERR_UNSUPPORTED_ESM_URL_SCHEME | 用 file:///D:/… URL |
| dsh web 子命令不接受父级 –patch | boot 报错 | 用 –profile web –patch … 形式 |
| PowerShell 5.1 读 UTF-8 无 BOM 脚本 | 中文注释乱码/匹配失败 | 脚本存 BOM;响应断言用 UTF-8 hex 比对 |
| npm –no-save 单包安装 | 剪掉此前全部未记录包 | 一次安装全部所需包(含可选原生依赖) |
| dsh Web UI 与业务页争抢 / | UI 不可达 | 按测试合同业务页占用 /;Agent 会话改用 headless 验证 |
5. 框架知识地图:概念全景
把工程动作翻译成框架概念,是这趟旅程真正的"学习成果"。
| Plugin | 能力单元,用 apply(ctx) 描述贡献 | index.ts 四文件 |
| Context | 服务仓库,按 key 找服务而不 import 实现 | ctx.tools / ctx.webServer |
| Service | 具名能力,可被替换 | ToolRegistry、WebServer |
| Effect | 可逆注册,卸载自动回滚 | 工具/路由注册的 disposer |
| inject | 声明依赖,服务就绪才执行 | ['tools'] 必需、['webServer'] 按需 |
| Profile/Bundle/Patch | 组合层,后层覆盖前层 | dsh-patch.yml overlay |
| dump-config | 真实插件树的"照妖镜" | 装配验收 |
✅ 你现在能做什么了
写一个模型工具、写一个 HTTP 路由、把插件装配进 web profile、验证插件树、用 headless 会话驱动 Agent、按 24 条用例做全量回归。这套流程可以迁移到任何 dsh 插件开发任务上。
6. 进阶方向与学习闭环
进阶方向
- 事件钩子:tools/pre-execute(权限门)、tools/post-execute(结果改写);
- 自定义服务:Service 子类对外提供 ctx.<key>;
- 正式发布:把插件做成 npm 包 + "dsh": {"bundle": {"patch": …}},dsh plugin add 安装;
- MCP 接入、多 Agent(spawn / fork / workflow)。
🔁 学习闭环
读文档 → 写规格 → 写设计 → 写测试 → 写插件 → 装配验证 → 注入异常 → 全量回归。每一步都留下可检验的产物,这就是"从 0 构建一个系统来学习框架"的正确姿势。
附录:命令速查
# 启动(唯一指令源 command/start-web-command.md)
npx @deepseek-ai/dsh —profile web —patch dsh-patch.yml
# 验证插件树
npx @deepseek-ai/dsh —profile web —patch dsh-patch.yml —dump-config
# 停止(Windows:定位 PID → 终止 → 复查端口释放)
netstat –ano | findstr :3080
Stop-Process –Id <PID> –Force
# 单张识别
curl.exe –s –F "image=@test\\images\\cat\\cat_001.jpg" http://127.0.0.1:3080/api/cat–dog-classify
# headless 会话驱动 Agent
npx @deepseek-ai/dsh —profile headless —patch dsh-patch.yml "识别 test/images/cat/cat_001.jpg 是猫还是狗"
# 插件类型检查
npx tsc —noEmit –p plugins\\cat–dog-classify-plugin\\tsconfig.json
本文档基于 deepseek-harness 工程的真实交付物整理,供研究学习与实践复盘使用。
源码仓库:github.com/leo21cn/sharing-dsharness-dogcatclassify



