← 返回列表
未验证
面向 DeepSeek Harness 的通用诊断导师
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/25 · 已提供中文文档
面向 DeepSeek Harness 的诊断优先 AI 学习运行时——梳理你所需的内容,进行交互式学习,并迈向下一个最佳步骤。
综合分
30.8
GitHub 分
30.8
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add SenmuuuuW/dsh-diagnostic-tutor该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:需留意实装验证未通过
- 是什么
- dsh 原生插件 · chat
- 装得上吗
- 实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 0 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/9/25) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
数据截至 2026/9/25(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-client-ui-layout@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-sidebar@deepseek-ai/dsh-client-ui-sidebar-right@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-skill@deepseek-ai/dsh-skill-filesystem@deepseek-ai/dsh-storage用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成面向 DeepSeek Harness 的通用诊断导师
从导师技能到学习运行时。
面向 DeepSeek Harness 的诊断优先 AI 学习运行时——梳理你需要什么,
交互式学习,并迈向下一个最佳步骤。
DeepSeek Harness 中的学习运行时:对话位于中间,诊断地图和课程停靠在旁边
学习界面停靠在右侧边栏,紧邻对话。地图、课程和聊天同时显示在屏幕上,因此回答检查题时无需离开课程。
早期开发
v0.0.x。学习循环已端到端可用——一个真实目标、一张真实诊断地图、一节由导师编写的课程、在聊天中回答的检查题、记录下来的证据,以及导师选择的下一步——但这还不是成品。预计会有破坏性变更,也预计缺口会被记录下来,而不是被掩盖。以下尚未构建,且下文任何地方均未声称已具备:PDF 或文档摄取、RAG、抽认卡、资源库、分析或课程生成。
两半,一个系统
这个项目的特别之处在于,教学与运行时是两个独立的程序,并且只有其中一个做决策。
| | 负责 | 位置 |
| --- | --- | --- |
| 通用诊断导师技能= 教学大脑 | 接下来教什么:诊断、教学动作、节奏、检查题何时算通过、下一步是什么 | 该仓库(v2.1,MIT) |
| dsh-diagnostic-tutor= 学习运行时 | 它保存在哪里:持久化学习者状态、诊断地图、结构化课程、UI | 这里 |
这种拆分不是打包细节。本仓库不包含任何教学逻辑:没有“如果卡住,就解释先修知识”这样的规则,也没有“如果答错,就给一个更简单的例子”这样的规则。那些都在技能里。运行时存储导师决定的内容,将其展示出来,并且从不自行决定。
循环
目标 → 诊断 → 地图 → 学习 → 检查 → 决定 → 下一课
│ │ │ │ │ │
│ │ │ │ │ └ 导师指定
│ │ │ │ │ 下一个节点,并给出理由
│ │ │ │ └ 学习者在聊天中回答
│ │ │ └ 导师将课程写入侧边面板
│ │ └ 节点只有在诊断揭示它们时才出现
│ └ 导师询问你实际掌握的内容
└ 用你自己的话在聊天中陈述
从左到右阅读,这也是保证:运行时从不自行推进。 一个决定会连同导师的理由一起被存储,展示给学习者,并等待被按下。
演示场景
以下截图来自一个场景,针对真实 DeepSeek Harness 运行
有了真正的技能:
我想学习机器学习。我懂一些 Python,但我的数学很薄弱。
导师在教任何东西之前会先问目标是什么,然后一次一个诊断地逐步构建地图。
这些图片中没有任何内容是固定装置或模拟——它们是运行中应用的截图。demo-1 是从空存储冷启动;其余的是同一场景的恢复,因为澄清-然后-诊断阶段需要多次模型轮次,而从冷启动到完整课程大约需要十五分钟。
| | |
| --- | --- |
| 首次使用:面板问一个问题 | 首次使用。 还没有目标。一个问题,以及回答它的那句话——没有向导,没有空仪表盘。 |
| 诊断地图 | 诊断地图。 六个节点,每个都可追溯到证据,按深度嵌套。blocked 和 checked 一目了然;没有检查支撑,任何节点都不会是 confirmed。 |
| 带检查的课程 | 一节课程。 真实的标题和列表,一个单独展示的示例,一个在独立框架中的图表,以及一个将轮次交还给学习者的检查。 |
| 带进度线的停靠界面 | 停靠界面。 右侧边栏中的同一循环,带有交接进度线(Lesson ready 7s),这样缓慢的模型轮次读起来是正在工作而不是坏了。 |
为什么这不仅仅是另一个 AI 导师
大多数“AI 导师”项目是围绕聊天框包装的提示词:模型教学,而关于学习者的一切在对话结束后都不复存在。这里有三点不同。
教学大脑是一个真实的、独立的产物。 诊断、教学动作、节奏和掌握判断都存在于一个书面技能中,带有自己的协议——而不是这个仓库发明的系统提示词。这个插件依赖它,并拒绝复制它。
状态是真实的,而且是学习者的。 一个目标、一张你实际知道什么的地图,以及每个状态背后证据的记录。没有检查支撑,任何东西都不会是 confirmed,没有评分,而且全部可见且可导出。
运行时不做决定。 导师说出下一步并说明原因;运行时存储它并显示它;学习者按下继续。没有任何路径可以让进度自行推进。
它的状态词汇也不是在这里发明的:节点携带技能自己的七个状态术语,检查携带它的六个准备结果。
为什么地图不违背诊断优先
该技能明确指出,一个宽泛的目标绝不能变成预先展开的课程或课程大纲。这个插件不会产生这样的东西。节点只在诊断揭示它们时出现,每个节点在检查产生证据之前都是 unconfirmed,而且地图是可逆的——新证据会移动它。你看到的是诊断地图,不是教学大纲。
兼容性
一个 DSH 配置文件可以同时解析多个 harness 版本(运行中的
宿主、共享 profile 回退,以及每个插件自己的存储)。把这个矩阵当作承重结构,而不是装饰。
| 本插件 | 已验证兼容的 DSH | Node |
| --- | --- | --- |
| 0.0.10 | 0.1.7-alpha.2(也在 0.1.5-rc.1 下组合通过) | ^22.19.0 \|\| >=24.0.0 |
本仓库机械强制执行的规则:
- 仅使用具名导出。 一个 export default 插件会让 Cordis 的加载器优先选择
.default,并静默丢弃 inject——这是一个有文档记录的 DSH 故障。由
一个测试固定:一旦引入默认导出,该测试就会失败。
- @deepseek-ai/ 仅以 type 方式导入,因此编译器会将其擦除,不会解析出
第二份运行时副本。由 verbatimModuleSyntax 强制执行,并在构建产物上验证
(其中包含零个导入)。
- 不跨包边界使用 instanceof。 从 ctx 获取运行时对象。
- peer 范围很宽( 目前还没有 npm 发布版本。 请从仓库安装;在 v0.1.0 之前,这是唯一的
途径。
要求
| | |
| --- | --- |
| DeepSeek Harness | 已验证兼容 0.1.7-alpha.2 |
| Node | ^22.19.0 \|\| >=24.0.0 |
| pnpm | 用于构建,也因为 dsh plugin 会转发给它 |
| Universal Diagnostic Tutor 技能 | 教学大脑。没有它,运行时仍会加载并记录状态,但永远不会写出任何课程——而且它会在日志和面板中说明这一点 |
安装
git clone https://github.com/SenmuuuuW/dsh-diagnostic-tutor
cd dsh-diagnostic-tutor
pnpm install
pnpm build
--profile 是必需的:不带它运行 dsh plugin 会以非零状态退出,因为它是一个
轻量的 pnpm 转发器,需要一个 profile 才能转发进去。
#
请使用绝对路径。dsh plugin 会在 profile 目录内运行 pnpm,因此相对路径会
相对于 profile 解析,而不是你的检出目录。
dsh plugin --profile add "$PWD"
验证它已挂载
该插件应作为一条 insert 行出现在合并后的树中。
dsh --profile --dump-config | grep -A2 dsh-diagnostic-tutor
然后以 web 界面启动该 profile,并在侧边栏中寻找 Learn:
dsh --port 8399 --no-open
--dump-config 中的条目只能证明存在一条加载器行——并不能证明插件在运行。
要证明这一点,请打开面板:首次运行会显示 What do you want to learn?,而没有
技能的 profile 则会显示无导师提示。
已知安装限制。 通过 github: 安装还需要在 profile 的
pnpm-workspace.yaml 中批准该包的构建脚本,这相当于允许该代码在安装时在你的
机器上运行。预构建产物可以省去这一步,这也是从 v0.1.0 起的意图。
学习者状态与诊断映射
状态存在于一个 Cordis 存储域(udt,版本 1)中,覆盖
官方的 storageDomain 接缝。配置文件选择介质——标准配置文件通过 dshHomePath('storages') 下的 dsh-storage-json 路由它——因此这个插件从不硬编码路径。
使用 json 后端时,你会得到恰好一个文档,/udt.json(默认安装下为 ~/.dsh/storages/udt.json):
{
"unit": { "name": "udt", "version": 1 },
"global": { "initializedAt": "…", "updatedAt": "…", "activeCourseId": "…" },
"tables": { "courses": { "…": {} }, "nodes": { "…": {} } }
}
| 槽位 | 存放内容 |
| --- | --- |
| global | 学习者单例——偏好、活跃目标、initializedAt |
| tables.courses | 每个学习目标一条记录,用学习者自己的话表述 |
| tables.nodes | 诊断图:id、courseId、title、parentId?、relation、state、evidence[] |
两条刻意的规则:
- zod 就是契约。 每条记录都在持久化边界处进行校验,因此手工编辑或损坏的文档会大声失败,而不是进入内存。
- 永远没有分数。 没有用于分数、等级或百分比的字段——该技能禁止将掌握程度变成分数,并且有一项测试断言持久化文档中任何地方都不存在此类键。
记录从不就地修改;写入通过单一按域写入链上的 put/set 进行,因此并发写入者无法交错。
如何防止地图变成教学大纲
这些规则在 src/diagnosis.ts 中作为纯函数强制执行,因此没有任何工具可以绕过它们:
- 一个节点出生时是 unconfirmed,并且在没有证据的情况下保持该状态;
- confirmed 需要一条 check 或 transfer 证据条目。仅凭解释或练习永远不能确认——该技能明确指出“仅凭解释和一次侥幸答对永远不能确认已准备好”;
- 目标节点永远不能被确认:它是地图的框架,而不是关于学习者的断言;
- 每个非目标节点都必须附着到同一课程中已经存在的父节点,并且没有环——因此地图从已经诊断出的内容向外生长,一次一步;
- 每次调用最多 8 个节点,每门课程最多 40 个。 单次调用不能种下一学期的材料;
- relation 为 goal | part-of | prerequisite | related。这里刻意没有 next-in-course,因为这个运行时中没有任何东西知道教学顺序。
工具
五个,并且它们都不对教学做任何决定。
| 工具 | 作用 |
| --- | --- |
| udt_status | 报告运行时:域、版本、目标、地图,以及当前焦点 |
| udt_goal_create | 记录一个目标并种下地图根——仅此而已 |
| udt_map_get | 读取地图,包含每个节点的关系、状态和证据 |
| udt_map_update | add-nodes · set-state · add-evidence |
| udt_lesson_update | 将教学作为块写入学习界面 |
| udt_decide_next | 记录学习者接下来应该去哪里,以及为什么 |
分工即架构:导师决定教什么、何时检查、以及一个回答说明了什么;运行时决定什么可以被存储并渲染它。这个仓库中没有任何分支写着“如果被阻塞就解释先修内容”——那是技能在聊天中做出的判断。
循环
按下 Start learning
→ 记录焦点(courseId、nodeId、startedAt、status)
→ 在该对话中唤醒导师,并指明节点
→ 导师通过 udt_lesson_update 将教学内容写入界面
→ 学习者在聊天中回答检查
→ 导师评判,通过 udt_map_update 记录证据,决定下一步动作
→ 面板随之更新
→ 导师通过 udt_decide_next 决定下一步
→ 面板显示推荐及其原因
→ 学习者按下 Continue,下一个节点开始
决策
action 是技能的六种就绪结果,被复用而非重新发明:“这个概念的展示说明了什么”和“这将学习者引向何处”用的是同一套词汇。运行时只需要关于每个结果的一个结构性事实——它是否指定了一个目标:
| 结果 | 目标 | 含义 |
| --- | --- | --- |
| advance / advance-with-caution | 必需 | 前往那里 |
| step-down | 必需 | 阻塞点;通常是先修内容 |
| review-first | 可选 | 返回,或在此复习 |
| more-practice / diagnose-again | 禁止 | 留在这里 |
移动会结束焦点并盖上 endedAt;停留则让它保持打开。没有任何东西会自行移动——学习者阅读原因并按下 Continue。
等待,被测量
移动到某个节点并非瞬时完成,因此等待是一个持久化记录,以目标节点为键——这使其具备幂等性、抗刷新、抗重启且可重试——并且每个阶段都带有一个时间戳:
requestedAt → focusRecordedAt → promptedAt → firstActivityAt → lessonAt → observedAt
同一条记录既是进度线(focus recorded → tutor requested → tutor working → lesson ready,附带已用秒数),也是测量结果。一次针对 DSH 0.1.6-alpha.2 和真实技能的实际运行:
| 阶段 | 时间 |
| --- | --- |
| 焦点已持久化 | 0.0s |
| 后续请求已接受 | 0.0s |
| 导师首次活动 | 1.0s |
| 课程已写入 | 26.1s |
| UI 已观察到 | 26.1s |
插件大约花费一秒;其余是模型在写作。 停滞是从记录中推导出来的,而非存储的,重试永远不会触碰焦点——超时是关于等待的陈述,而不是关于学习者所在位置的陈述。
Start learning 是一个归属于此插件的用户角色回合,而非注入的上下文:agent.inject() 会添加模型可见的上下文,但不会唤醒空闲的 agent,因此在学习者输入之前什么都不会发生。开启一个回合才是这个按钮的含义。
两个界面,一种状态
| 界面 | 位置 | 用途 |
| --- | --- | --- |
| Learning 标签页 | 右侧边栏,聊天旁边 | 日常工作——在你交谈时查看地图、节点和课程 |
| 学习面板 | 主列(main) | 专注模式——整个运行时同时呈现 |
该标签页是让这个循环可用的原因:完整面板填满主列,而主列也是对话所在之处,因此如果只有该面板在应答,检查就意味着要离开课程。右侧边栏是单独的一列。
两者运行在同一个共享的 useLearning 状态上,因此它们不可能在聚焦于什么或导师写了什么上产生分歧。面板的 在聊天中回答 按钮会返回对话,并在同一步中将标签页停靠。
右侧边栏承载会话作用域的标签页,因此当会话表面挂载时,它只能接受一个——这就是为什么停靠发生在返回对话的途中,而不是在加载时。
教学大脑检测
加载时,插件会询问平台自己的技能注册表,以确认是否安装了 Universal Diagnostic Tutor 技能——没有硬编码路径,没有假定技能根目录,也没有复制任何内容。缺失的目录、缺失的技能和不可读的主体,每一种都会降级为报告状态,而不是错误。
兼容性是通过能力来探测的,而不是通过版本字符串:该技能的维护契约只允许 frontmatter 中包含 name 和 description,因此它无法声明版本。结果会携带一个简短的内容摘要作为版本提示。
检测结果保持内部——以 debug 级别记录,不出现在任何工具输出中。该技能禁止在学习者可见文本中提及其文件、版本或仓库,而这个运行时不会成为泄露它们的那一个。
两半如何达成一致
该技能的护栏说,掌握度跟踪绝不能变成“分数、数据库、隐藏记忆或课程路线图”,而这个运行时则有意持久化状态并渲染地图。
直到 v0.0.8,这种张力都是从这一侧弥合的:一段简短的系统提示词部分向教学大脑解释了运行时的存储语义。UDT v2.1 的 learning_runtime_contract.md 现在用技能自己的话陈述了这一切——运行时可以保存什么、决策何时被记录,以及一个对答案作出判断的回合在下一步被记录之前并未完成——因此这座桥被删除,而不是作为第二种声音保留。插件在这方面变得更好了,这正是它本应属于上游的证据。
面板
浏览器这一半只注册两样东西,别无其他:一个侧边栏图标(sidebar.panellist,一个 list)以及它打开的页面(main,一个 keyed 槽位)。侧边栏的 id 和面板的 key 来自同一个常量——它们之间的漂移会让图标打开不了任何东西。
它从左到右读起来像一句话:
[ Course + Diagnosis Map ] → [ Selected node ] → [ Learning surface ]
没有仪表盘:三个窗格,而地图就是导航。
学习块
一个块是 { id, type, content, metadata? }。模式在宿主侧(在持久边界处经 zod 验证),而渲染器在浏览器侧,按 type 键控:
| 类型 | 内容 |
| --- | --- |
| text | md —— markdown,采用该技能的 \(...\) 数学约定 |
| example | title、steps[]、takeaway? |
| diagram | format(ascii \| mermaid)、spec、caption? |
| check | prompt、expect?、hint? —— 即停即等的交互界面 |
之后添加 Formula、Code、Comparison、Practice 或 Resource,只需添加一条注册表条目,而无需重写课程渲染器。未知类型会渲染为可读的占位符,而不是抛出异常,因此由更新版本宿主编写的课程仍可在此处渲染。
浏览器 API
三个调用,位于 /diagnostic-tutor/api:
| 路由 | 返回 |
| --- | --- |
| GET /overview | 当前课程及其完整地图(首次运行时为 course: null) |
| GET /node?id= | 一个节点及其证据、父节点和子节点 |
| POST /lesson {nodeId} | 原型课程,构建一次后复用 |
每个请求都经过一道信任围栏:裸的 ctx.webServer.register() 路由不继承任何身份验证,因此该路由会检查请求是否到达回环 Host、来自回环 Origin,且未被标记为跨站。其他任何情况都会得到 403 且无响应体。浏览器仅接收视图——没有存储路径、没有域句柄、没有原始记录。
预览
面板将 API 作为 prop 接收,因此 UI 无需 DSH 和 agent 即可运行:
pnpm build && pnpm preview # then open the printed URL
preview/index.html 通过 preview/fixture.js 上的 __ModuleLoader__ 垫片加载真实构建产物,该 fixture 模拟了一位说“我想学习机器学习”但数学基础薄弱的学习者:
Machine Learning [goal, unconfirmed]
├─ Math Foundations [prerequisite, blocked]
│ ├─ Linear Algebra [part-of, unconfirmed]
│ ├─ Calculus [part-of, unconfirmed]
│ └─ Probability [part-of, unconfirmed]
└─ Python [prerequisite, unconfirmed]
若要从实时配置文件捕获面板:
pnpm screenshot "" preview/dsh-ui.png
开发
pnpm install
pnpm typecheck # tsc --noEmit (host and client)
pnpm test # 250 tests: unit, guard, DOM, render, real composition
pnpm build # tsc -> lib/ (host) + tsdown -> lib/client.js
tests/harness.ts 在临时根目录上挂载标准配置文件所用的同一套存储栈(systemPrompt → tools,以及 storage → storage-json → storage-domain)。因此,持久化测试会执行真实的序列化 → 文件 → 重新解析 → 验证往返流程,而非使用伪造实现;并且 --dump-config 绝不会被误认为插件加载成功的证据:它只能表明存在一行加载器记录。
路线图
| 版本 | 交付内容 |
| --- | --- |
| v0.0.1 | 可安装的 bundle、插件加载、guard + composition 测试 |
| v0.0.2 | udt 存储域、学习者往返、udt_status 工具 |
| v0.0.3 | 教学大脑检测、udt_goal_create、诊断地图(udt_map_get / udt_map_update) |
| v0.0.4 | 客户端部分:槽位挂载面板、可点击地图、节点详情、学习块、浏览器 API |
| v0.0.5 | 循环:学习焦点、导师编写的课程、检查 → 证据 → 状态、实时面板 |
| v0.0.6 | 学习界面停靠在聊天旁边;两个界面共享同一状态 |
| v0.0.7 | 导师决定下一步;焦点生命周期;NEXT BEST STEP 卡片 |
| v0.0.8 | 交接记录、进度线、重试,以及测得的延迟 |
| v0.0.9 | DSH 0.1.7 兼容性、第一个真正的 A → B,以及产品打磨 |
| v0.0.10 | 当前 — 导出和删除你的数据 |
| v0.1.0 | 首个可玩 MVP — 状态导出/重置、设置、i18n、数学排版 |
信任
DSH 不会对插件代码进行沙箱隔离:已安装的插件以你的权限在进程内运行,而一个裸的 ctx.webServer.register() 路由不会继承任何身份验证。本插件的承诺:
- 只读写自己的存储域;
- 仅通过它自行检查的 loopback 防护路由提供其浏览器部分;
- 不发起任何出站网络请求;
- 不在 harness 自身存储之外写入任何文件;
- 让学习者状态保持可见、可导出、可删除——绝不隐藏记忆。
导出我的数据会写入一个自描述的 JSON 文件;删除一切会在第二次点击后将其移除,且不可逆。撤销就意味着保留一份正是被要求删除的内容的副本。
如果存储已损坏
运行时声明了 invalidRecords: 'backup-and-skip',这是平台的恢复路径:未通过其 schema 的记录会被移到一旁,域会在没有它的情况下打开。它目前在这里不会生效,因为平台只有在单元能够将逐记录*文档移到一旁时才会遵循它,而此域使用默认的 single 布局——一个 udt.json 容纳所有内容。因此,一条格式错误的记录仍会导致打开被拒绝,插件会报告它并保持惰性,而不是使配置文件失败,并且不会销毁任何东西:手动移除有问题的记录即可恢复其余部分。
修复方法是将 layout: 'per-record' 改一行,JSON 后端会从现有的单个文件播种。目前尚未完成,因为它会改变磁盘上的格式,而这是一个值得慎重做出的决定,而不是作为副作用。在那之前,编辑前先导出。
许可证
MIT。Universal Diagnostic Tutor 技能是同一作者的一个独立 MIT 项目,并未在此处 vendored。
本项目的规划与架构研究位于
docs/planning/。