# dsh-paper 设计文档 - 版本:v2.0(四仓库合并版) - 状态:**合并实施完成,M1-M5 与四块新能力落地** - 前身:`dsh-thesis` v1.0.0(论文流水线,M1-M5 全部交付)、`dsh-mem`、`dsh-socrates`、`dsh-ai-learning` --- ## 1. 目标 **一句话**:让一个对流程不了解的本科生,把「学校模板 + 论文要求 + 实验数据 + 代码 + 参考文献」这堆材料, 在 AI 的带教下变成**一篇真实系统与真实数据背书、符合学校规范、经得起查重与答辩的论文**, 外加**一个能在答辩席上讲清自己系统的作者**。 ### 1.1 五个可验收的标准(不是功能数量) 1. **零假文献**:每条参考文献都来自真实学术检索,工具层强制(`thesis_lit_save` 只接受检索缓存 id)。 2. **零假成果**:每个实验数据、截图都来自真实运行;降重工具明文禁止为降重改动数据与结论。 3. **人是作者**:关键决策有用户书面拍板(G1-G4 闸门 + 决定日志),答辩能讲清"为什么"。 4. **规范驱动**:格式/引用/字数/模板以学校真实文件为准;缺失时显式标注"通用过渡模板"。 5. **真的能跑**:所有工具可执行、可失败、有测试;文档描述与实现一一对应。 ### 1.2 合并的动机 四个插件各自解决了一段真实痛点,但分开装意味着四份配置、四套技能、四个互不知情的上下文: | 分开时的断点 | 合并后的解法 | |---|---| | 材料要人工读给 AI 听(`dsh-mem` 只会 import 文本) | `thesis_ingest` 直接读 docx/xlsx/pptx/pdf | | 要求散落在对话里,模型凭记忆开工 | `thesis_intake` 把要求问成 `意图规格.md`,全流程引用它 | | 降重靠"换词",AI 味自查与降重各说各话 | `thesis_dedup` 本地度量 + 处方 + 复测,与 `thesis_ai_selfcheck` 同源 | | 答辩 PPT 只有大纲(`thesis_defense_prep`) | `thesis_ppt` 出 Marp Markdown 并可转 pptx | | 学习训练与论文流程无关 | `code-learning` 收敛为「答辩前搞懂自己的系统」 | | 每次新会话都要重新解释学校规范 | `memory_*` 长期记忆跨会话保留 | --- ## 2. 总体架构 ``` ┌──────────────────────────────────────────────────────────────────────┐ │ DSH Web 界面(127.0.0.1:3080):自然语言 + /thesis-*、/learn 命令 │ ├──────────────────────────────────────────────────────────────────────┤ │ 单一插件 dsh-paper(Cordis 插件,纯 TypeScript,一行 cordis.patch.yml)│ │ │ │ 入口层 ingest/(Office 摄取) intake/(苏格拉底追问 → 意图规格) │ │ 流水线 paper/(11 工具 + 5 命令 + 7 技能:台账/关卡/文献/评审/构建) │ │ 合规层 dedup/(本地相似度 + 改写处方 + 复测) paper/lib/aicheck │ │ 答辩层 ppt/(Marp Markdown + 外部转换器) paper/lib/defense │ │ 横切层 memory/(SQLite 长期记忆 + 相关时自动回灌) learn/(代码理解训练)│ │ 闸门层 socratic/(agent/pre-step 提示闸门 + tools/pre-execute 高危) │ ├──────────────────────────────────────────────────────────────────────┤ │ 技能包 skills/**(11 个方法论技能,`thesis_init` 复制到论文仓库 │ │ .dsh/skills/,项目级 rank 100 最高优先级,随论文 git 版本化) │ ├──────────────────────────────────────────────────────────────────────┤ │ 论文工作区(git 仓库,唯一数据真相):00-管理 … 08-合规 + 意图规格 │ └──────────────────────────────────────────────────────────────────────┘ ``` ### 2.1 目录与模块职责 | 路径 | 来源 | 职责 | 对外表面 | |---|---|---|---| | `src/index.ts` | 新 | 唯一装配层:`apply()` 调各模块 register | `name`/`inject`/`Config`/`apply` | | `src/config.ts` | 新 | 统一配置 schema + 默认值单一来源 + `resolveConfig` | `Config`/`PaperConfig`/`PAPER_DEFAULTS` | | `src/shared/**` | 新 | 工具胶水(输出/会话定位/二进制落盘)+ 双模工具定义器 | `definePaperTool` 等 | | `src/paper/**` | dsh-thesis | 论文流水线(纯逻辑 + 工具 + 命令) | `registerPaper` | | `src/memory/**` | dsh-mem | `MemoryStore`(纯 SQLite)+ provider + 3 工具 | `registerMemory` | | `src/socratic/**` | dsh-socrates | 两个闸门 + 启发式 + 消息模板 | `installPromptGate`/`installDestructiveGate` | | `src/learn/**` | dsh-ai-learning | 引擎 + gate + 3 工具 + `/learn` + 进度注入 + 技能 | `registerLearn` | | `src/ingest/**` | 新 | ZIP/OOXML/PDF 解析 → 文本;源码目录 → 代码结构摘要(不贴正文) | `registerIngest` | | `src/intake/**` | 新 | 问题库 + 状态机 + 意图规格渲染 | `registerIntake` | | `src/dedup/**` | 新 | 归一化 + 相似度 + 处方 + 报告 | `registerDedup` | | `src/ppt/**` | 新 | 幻灯计划 + Marp 渲染 + 转换器探测 | `registerPpt` | ### 2.2 分层规则(全仓库唯一的硬性架构约束) > **纯逻辑不依赖宿主,宿主胶水不含业务判断。** 每个模块都拆成「零宿主依赖的纯函数层」(可 `node --test` 直接跑)+「很薄的 register 层」。 收益是可测性与可替换性:记忆的 SQL 语义、降重的相似度、幻灯的渲染、追问的排序, 全都能在没有 DSH 运行时的环境里被完整验证。 --- ## 3. 关键设计决策(ADR) ### ADR-1 单一包、单一插件行(而非 monorepo 多行) `dsh plugin add` 一次装完,一个 `Config`,一套技能,模块间共享上下文(intake 写规格、writing 读规格、 dedup 读章节、ppt 读答辩素材)。代价是包变大;用「目录即模块 + 无跨模块反向依赖」控制耦合。 ### ADR-2 材料先追问、后动手(intake 前置) 写错方向的返工成本远高于问清楚的十分钟。`thesis_intake` 的硬约束:**一次只返回一个问题**、 每问必带「为什么问 / 影响哪个产出 / 合格答案形态」、材料里能读出来的不重复问、`required` 齐了才允许 `done`。 意图规格 `00-管理/意图规格.md` 成为后续所有产出的验收依据。 ### ADR-3 零第三方运行时依赖(含 Office 解析) - ZIP 读取器自实现(EOCD + 中央目录 + STORE/DEFLATE,DEFLATE 用内置 `node:zlib`); - docx/xlsx/pptx 走 OOXML 文本抽取,不引入 mammoth/xlsx/jszip; - PDF 用内置能力**尽力而为**,抽不出来就诚实报错(见 §6); - 记忆用内置 `node:sqlite`; - 唯一非内置依赖是 `@deepseek-ai/schemastery`(Config schema 的 `z` 双重语义无法伪造)。 收益:离线可构建、可评审、供应链风险为零、插件体积小。 ### ADR-3b 代码走「结构摘要」而不是「正文倒出」 用户材料里的「代码结构」若按文本摄取,一个上万行的仓库会挤爆上下文且对写作无益。 `src/ingest/code.ts` 只提取**结构信号**:语言、文件/行数/代码行/注释行、顶层声明 (函数/类/接口/结构体/路由/表)与行号、依赖清单推断的技术栈指纹、以及被跳过的大文件清单。 产物是 `00-管理/材料/<目录>-代码结构.md`,直接服务「系统实现」章的骨架、工作量证据与答辩索引。 ### ADR-4 只在运行时依赖宿主的两处能力 运行期 import 宿主包只有两处:`schemastery`(schema)与 `dsh-tools` 的 `defineTool`(离线退回本地等价实现)。 其余宿主能力(`ctx.fs`/`ctx.tools`/`ctx.commands`/`ctx.on`/`ctx.provide`/`ctx.effect`)都经 `ctx` 注入, 类型由 `src/types/shims.d.ts` 声明。**理由**:DSH 的 rc 阶段包树不稳定, 把编译期的类型耦合压到最小,可以让仓库在只有 `typescript` 的环境里 `tsc` 全绿、`node --test` 全绿。 ### ADR-5 降重只做「诚实度量 + 改写处方」 - 本地、确定性、可复现(shingle 指纹 + 倒排剪枝 + 最长公共片段定位),报告写明估算口径; - **不接入**知网/维普等收费系统(无账号,也不该绕过学校流程);用户自行送检后可回填结果形成对照; - 处方明确「必须保留」:数字、单位、术语、公式、引用标记、代码标识符——为降重改数据是学术不端; - 与 `thesis_ai_selfcheck` 同源:两者同时命中的段落优先**整段重写**(用真实实验细节),而不是逐句换词。 ### ADR-6 答辩幻灯以 Markdown 为唯一真相 `07-答辩/PPT.md`(Marp 兼容)可 git diff、可复用、不依赖 Office;`.pptx` 是派生产物。 转换链路沿用 `thesis_build` 已验证的模式:探测外部引擎(marp → npx marp-cli → pandoc)→ 成功则产出 → 失败/缺失则写「转换说明」给出可复制命令与兜底路径,**绝不假装成功**。不自研 pptx 生成器(用户拍板)。 ### ADR-7 记忆用全局库 + key 命名空间,而非每篇论文一个库 装配发生在进程启动、拿不到会话 cwd;而记忆里跨课题复用的内容(写作风格偏好、导师沟通习惯、 学校通用规范)本就该跨项目活着。约定 `user.*` / `school.*` / `thesis..*`,技能明文规定 "不要把进度与一次性实验数字写进记忆"。 ### ADR-8 技能随插件发布并复制进论文仓库 项目级技能目录 `<论文仓库>/.dsh/skills`(rank 100)优先级高于用户级(400); `thesis_init` 把 `skills/**` 复制过去,使方法论与论文同版本、同 git 历史、可离线迁移。 ### ADR-9 目录结构只在 paper 模块内成形 论文工作区的九阶段目录(`00-管理` … `08-合规`)由 `paper/lib/layout.ts` 唯一产生; 新模块只往既有目录写产物(`00-管理/材料清单.md`、`00-管理/材料/`、`08-合规/降重报告.md`、 `07-答辩/PPT.md`),**不新增顶层阶段目录**,保证老工作区向后兼容。 --- ## 4. 数据与产物 | 产物 | 位置 | 产生者 | |---|---|---| | 意图规格(唯一真相) | `00-管理/意图规格.md` | `thesis_intake` | | 材料清单 + 逐文件摘要 | `00-管理/材料清单.md`、`00-管理/材料/*.md` | `thesis_ingest` | | 进度台账 / 决定日志 / 时间线 | `00-管理/` | `thesis_init` / `thesis_progress` / `thesis_decision` | | 文献库与检索审计 | `02-文献/refs.bib`、`检索记录.md`、`笔记/` | `thesis_lit_*` | | 章节与产出 | `06-论文/章节/*.md`、`产出/论文.docx` | 写作 + `thesis_build` | | 合规报告 | `08-合规/`(引用/格式/AI 味/降重/复测) | `thesis_check` / `thesis_ai_selfcheck` / `thesis_dedup` | | 答辩材料 | `07-答辩/答辩素材.md`、`预答辩问题库.md`、`PPT.md` | `thesis_defense_prep` / `thesis_ppt` | | 插件状态 | `/.paper/`(学习训练 state.json、追问状态) | `learn/` / `intake/` | | 长期记忆 | `$DSH_HOME/paper-memory.db` | `memory_*` | --- ## 5. 质量与测试策略 | 层 | 手段 | |---|---| | 纯逻辑 | `node --test`(Node 24 直接跑 `.ts`):相似度、归一化、处方、问题排序、状态机、幻灯渲染、OOXML/PDF 解析、记忆 SQL、代码结构摘要 | | 装配 | `tests/composition.test.ts` 用假宿主跑 `apply()`,断言 21 个工具 / 10 个命令 / 2 个服务 / 4 个 pre-step 与 1 个 pre-execute 监听,并逐个校验工具的注册形态 schema 与描述长度 | | 工具定义 | `tests/shared-define-tool.test.ts` 断言 DSL→JSON Schema 编译产物与 `INVALID_ARGS` 行为 | | **跨模块契约** | `tests/intake-convergence.test.ts`:追问收敛后入口闸门必须放行(字面量契约漂移会立刻红) | | 闸门行为 | `tests/intake-gate.test.ts`、`tests/memory-recall.test.ts`、`tests/socratic-heuristics.test.mjs`:该拦的拦住、不该拦的一个字节都不注入、异常不抛进 agent 循环 | | 真实磁盘 | `tests/e2e/paper-real-disk.mjs`:真实建目录、写文件、构建 docx、`git init` | | 真实网络 | `tests/e2e/paper-lit-real.mjs`:真实学术 API 检索 → 收录 → 笔记 | | 真实宿主 | `scripts/host-smoke.mjs`:把编译产物装进真实 DSH 依赖树,注册并执行工具,验证卸载注销 | - 负路径是必测项:未过 G1 拒绝推进阶段、缓存外的文献 id 被拒、必答项未齐拒绝 `done`、 损坏的 PDF/状态文件返回可读错误、幻灯缺引擎时不得报成功。 --- ## 6. 已知边界(诚实清单) 1. **PDF 抽取是尽力而为**:扫描版(无文本层)、对象流/加密 PDF 可能抽不到文字;工具返回 `ok:false` + 原因, 绝不编造内容;低抽取率会带 `lowConfidence` 标记。 2. **旧二进制 Office 格式(.doc/.xls/.ppt)不支持**,明确提示另存为新格式。 3. **查重不接收费系统**:报告里的重复率是本地估算,与学校检测结果不可等同;口径与参数写进报告。 4. **PPT 依赖外部转换器**:本机无 marp/pandoc 时只能拿到 Markdown + 转换指引(幻灯文字已是最终稿)。 5. **学习训练内置 gate 表只覆盖 Go/TS/Python/Rust**,其余语言需在配置里补。 6. **宿主契约以本地 shim 声明**:真实签名核对见 `docs/host-api.md`;shim 宽松(工具参数/渲染值取 `any`), 由装配测试、真实端到端与 `scripts/host-smoke.mjs` 兜底。 7. **意图规格是"一次到位"的努力而非保证**:它把已知的返工源问完;未知风险仍会在阶段推进中暴露, 此时应回到 `thesis_intake` 补问并把答案写回规格。 --- ## 7. 与四个前身仓库的差异总览 | 维度 | 合并前 | 合并后 | |---|---|---| | 安装 | 4 次 `dsh plugin add`,4 个 profile 行 | 1 次,1 行 | | 配置 | 4 个 Config schema | 1 个 `PaperConfig`(嵌套块) | | 技能 | 分散在 4 个仓库 | `skills/**` 11 个,`thesis_init` 统一分发 | | 记忆 | Go CLI + MCP + TS bundle 两套实现 | 单一 TS `MemoryStore`(Go 引擎移除) | | 追问 | 无(只靠 prompts) | `thesis_intake` 状态机 + 意图规格 | | 降重 | 无(只有 AI 味自查) | `thesis_dedup` 度量 + 处方 + 复测 | | PPT | 只有大纲 | Marp Markdown + 转换链路 | | 测试 | 分散(vitest/node --test 混用) | 统一 `node --test`,含装配测试与双模工具定义测试 |