新文章设计方案:如何为自己的工程项目设计并实现 DSH 预设

新文章设计方案:如何为自己的工程项目设计并实现 DSH 预设

Date: 2026-09-13 Owner: aone2233 状态: 待评审(未开始写作)

一、文章定位

决定
拟用标题如何为自己的工程项目设计并实现 DSH 预设
副标题从一个真实科研仿真工作区到可复用的 agent preset
categories[工具, AI](与 Claude Code / Codex / ThuThesis 三篇一致)
目标篇幅约 12000–16000 字(与 thuthesis-ai-latex-guide 同量级)
素材来源开源仓库 dsh-router-sci + 本地工程 Gra_thesis + DSH 预设机制
核心立场预设不是”更长的提示词”,而是把项目约定升级为运行时装配

目标读者

已经用 dsh / Claude Code / Codex 做过真实项目,但每次开新会话都要重新解释一遍项目约定的人。 读者不需要读过 dsh 源码,但需要知道”agent 预设”大概是什么。

本文要回答的三个问题

  1. 项目里那么多约定,哪些该进预设、进预设的哪个位置
  2. 一个预设最少需要什么才能跑起来,怎么验证它真的装配了?
  3. 想开源出去,怎么把一个装满个人路径的预设变成模板

二、叙事主线

全篇是一条”从项目到产品”的路径,而不是 dsh 功能罗列:

真实项目(Gra_thesis)
   ↓ 抽取约定(四类素材 → 四个落点)
预设设计(agent.cordis.yml 的行怎么分)
   ↓ 实现
最小预设 → persona → 工具行 → 渐进披露路由
   ↓ 验证
selftest + 真实挂载
   ↓ 脱敏与开源
router-sci(占位符模板 + NOTICE 合规)

三、章节设计

开篇引言块(blockquote)

沿用本站长文的体例:目标读者 / 推荐路线 / 前置知识 / “本文核查时间”。明确说明:示例基于真实开源仓库,机器相关路径已占位符化。

一、问题:为什么 AGENTS.md 不够

  • 现状:项目里有 AGENTS.md / CLAUDE.md,agent 每次自己去读
  • 三个失效点:
    1. 环境事实靠”读”:读了仍可能在错误的一侧执行(Linux 侧 / Windows 侧)
    2. 纪律靠”提醒”:写进文件也只是建议,工具该用还是能用
    3. 常驻成本:每轮都在上下文里占位,或者每次重新读一遍
  • 结论:预设 = 把”文件里的约定”变成”会话装配的一部分”

二、先分清两个平面:host 与 agent

这是全文的判断基准,后面所有取舍都由它推导。

  • host 平面拥有:注册表本身(tools / systemPrompt / agents / sessions)、 沙箱与审批栈、模型路由、subagent 注册表与其后端、持久化
  • agent 预设拥有:一个会话贡献给这些注册表的东西 —— 工具插件、persona、prompt 段、compaction 策略
  • 判定规则有 agent 平面之外的消费者 → 必须留在 host
  • 反例(讲透一个就够):subagents 注册表为什么不能搬进预设 —— api-proxy 要跨会话查询它,搬进去既饿死 host 那一行, 又会在第二个会话上撞名(provider name 只能注册一次)
  • 带出下一章的结论:预设的”工具行”和 host 的”服务行”不是一回事

三、素材提取:从一个真实工程工作区说起

Gra_thesis 为例,先描述这类工作区的形状(脱敏后):

  • 四个工作区:微观仿真(LAMMPS)/ 宏观仿真(Fluent DPM)/ 过程报告(LaTeX)/ 最终论文(LaTeX)
  • 环境分裂:Linux 侧跑计算与脚本,Windows 侧跑商业软件
  • 已有的约定载体:AGENTS.mdCLAUDE.md.claude/skills/ 下的技能、 task_plan.md / findings.md / progress.md

然后给出核心素材提取表(全文最有复用价值的一张表):

项目里的东西性质落到预设的哪里理由
领域术语、研究对象、物理模型事实背景persona每轮都需要,必须常驻
哪台机器跑什么、路径怎么对应环境事实persona(工具路由约定)同上
参数不能编造、编译必须通过纪律persona + 硬门控需要”拒绝”的部分下沉到工具行
批量跑工况的操作步骤流程知识skills按需加载,不常驻
能读不能写、能跑不能装能力边界agent.cordis.yml 工具行只有工具行能真正约束
开工先读什么、收工回写什么续接约定persona属于行为习惯

两条设计原则(本节的落点):

  1. 能落到工具行或 skill 的,不要写进 persona —— persona 是每轮都付的 token 成本,skill 是按需加载的
  2. 需要”拒绝”的用工具行,只需要”提醒”的用 persona —— 软引导会被无视,硬门控不会

四、最小可运行预设:目录与两个文件

  • 预设根:${DSH_HOME:-~/.dsh}/.agent-presets/<id>/
  • 只扫一级子目录(所以不要把预设嵌套进子目录)
  • preset.yml:显示用元数据 name / description / order —— 不写就会在选单里显示成裸目录名
  • agent.cordis.yml:一组插件行
  • 给一个最小可用示例(persona + 一个工具 + 一个技能根)
  • 生效条件:新会话才挂载;composition 文件的改动靠时间戳触发新一代
  • 引出 ?v=N 缓存问题(详述放在第九章)

五、写 persona:把项目约定写成可执行的约束

  • 推荐结构:身份 → 语言约定 → 领域背景 → 工具路由 → 写作纪律 → 续接工作流 (按 dsh-router-sci 的真实顺序讲)
  • 反例 vs 正例对照
    • 反例:「注意 Fluent 在 Windows 上」
    • 正例:给出三侧路径对应 + 明确”重 IO 必须留在原生目录”的理由
  • 重点讲双环境工具路由怎么写清楚
    • 三侧路径对应(原生 / UNC / 符号链接)
    • 9P 路径的性能坑:轻量读写可以,批量与重 IO 不行
    • 为什么要把”理由”也写进去(agent 才能在边界情况下自己判断)
  • 运行时占位符:/ 由 dsh 解析,保持原样
  • 常见错误:把 persona 写成项目 README 的副本

六、能力边界用工具行表达

  • agent.cordis.yml 的字面含义:这个会话装配哪些插件
  • 平台条件:disabled: !!js process.platform !== 'win32'
  • isolate realm:服务行必须放进 group 且带 isolate, 否则会发布到 root realm(进程级)→ 第二个会话撞名
    • 讲清 true(每会话私有实例)与共享标签的区别
  • 举例:Windows 上要真正的 Git Bash,需要私有 shell 服务(gitbash-executor) —— 以及它的诚实边界:不绕过沙箱,MSYS 在受限令牌下可能启动失败, 按正常审批做单次升级,而不是篡改策略

七、把”流程”做成渐进披露(进阶机制)

全文技术含量最高的一节,也是 router-sci 真正的原创贡献所在。

  • 动机:一次性给出全部工具 = 注意力税 + 模型会”大跃进”
  • 四阶段模型(真实定义):

    阶段名称解锁工具
    0了解/对齐read glob grep web_search ask_user_question
    1拟合方案todo_write exit_plan_mode
    2开发write edit str_replace_editor
    3验证bash pwsh read_image job_list job_output job_kill
  • 硬门控实现tools.restrict({ allow })交集语义
    • per-session disposer,释放旧再设新(否则 restrict 会叠加)
    • 跨 generation 用 globalThis[Symbol.for(...)] 共享,避免新一代提不起旧一代的 restrict
    • 平台性缺失的工具名会让 restrict 整体抛错 → 先按平台可用集过滤
  • 只暴露当前档windowFor(stage) = stage + 1 —— 模型看不到后续工具,消除”知道后面有工具”的焦虑与跃进入口
  • 自动推进:完成信号(todo_write / exit_plan_mode)触发, 避免模型手动调 phase_advance 而跳阶段
  • 二级披露tools_catalog / tools_help 让”未解锁但想查”成为可能 —— 拒绝调用,但允许查阅
  • 常驻指引:阶段目标写进 prompt 段,经上下文压缩不丢
  • 收尾给一句设计哲学:这不是”限制模型”,而是把”该想清楚再做”变成结构

八、验证:怎么知道预设真的装配了

  • 观察面:dev_router_status 看当前阶段与可调工具
  • 源码级回归自测*.selftest.mjs):对插件源码做字符串断言
    • 给 2–3 条真实断言示例(如”引导文案必须完整拼接”、 “配置必须指向新一代”、”restrict disposer 必须在场”)
    • 讲清这种自测的价值与边界:它守的是机制不被误删,不是功能正确
  • 真实挂载验证:新会话才是最终判据
  • 失败排查顺序:composition 能否解析 → 模块能否加载 → 行是否在等一个没人提供的服务

九、迭代循环

  • 改 persona / 工具行 → 直接改 agent.cordis.yml,新会话生效
  • 改插件 .mjs必须递增 ?v=N
    • 原因:generation 只以 composition 文件的 stamp(mtime + size)为指纹, 旁挂的 .mjs 改动不会让指纹变化,ESM 缓存仍返回旧模块
    • 这是一条很容易踩、且症状是”改了没生效”的坑
  • 备份策略:改动前把预设目录整体复制一份(带日期后缀)
  • 热更新工具的存在与边界:能让新会话挂载新一代,已运行会话保持旧代

十、脱敏与开源:把”我的项目”变成”任何同类项目”

  • 三层脱敏(明确区分,不能混为一谈):
    1. 机器事实 → 占位符:发行版名、项目根、软件安装路径、符号链接路径
    2. 研究对象 → 通用化:具体物料名 → “粉体颗粒”;这是语义脱敏, 不是字符串替换
    3. 个人标识 → 移除:用户名、绝对路径、内网 git 地址
  • 占位符对照表<PROJECT_NAME> <WSL_DISTRO> <WSL_PROJECT_ROOT> <WIN_PROJECT_LINK> <ANSYS_INSTALL>),并注明 / 不在此列
  • 为什么不能只做字符串替换:把路径变量收敛成占位符的过程, 会强迫你回答”这个预设到底依赖哪几个环境事实”——这一步本身就是设计
  • 版权合规NOTICE 文件怎么写
    • 逐项列出上游来源、许可证、具体哪些文件是派生
    • 明确划分”原创部分”与”派生部分”(如本仓库:persona 与元数据原创, 路由代码来自上游 MIT)
    • 商标与背书的免责声明

十一、常见坑清单

按”症状 → 原因 → 处理”组织:

  1. 预设不出现 → 目录嵌套了(只扫一级)
  2. 改了代码没生效 → 忘递增 ?v=N
  3. 第二个会话崩 → 服务行没放进 isolate realm
  4. persona 越写越长 → 该下沉到 skill 的内容没下沉
  5. 约束被无视 → 用 persona 做了本该工具行做的硬门控
  6. 升级后改动丢失 → 直接改了随部署发布的预设
  7. 在错误平台注册工具 → 忘了 disabled 的平台条件
  8. 路径硬编码 → 换机器就废(占位符化没做完)

十二、参考资料

  • dsh 与 dsh-agent-presets 文档
  • dsh-router-sci 仓库
  • 上游 dsh-routing-suite
  • 本站相关文章互链:Claude Code 指南、Codex 指南、ThuThesis 指南

四、脱敏策略(待确认)

建议处理备注
用户名 / 家目录绝对路径移除,改 <WSL_PROJECT_ROOT>必做
WSL 发行版名<WSL_DISTRO>必做
商业软件安装路径<ANSYS_INSTALL>必做
Windows 侧符号链接路径<WIN_PROJECT_LINK>必做
项目名<PROJECT_NAME>(正文叙述可称”该科研工作区”)待确认
研究对象具体物料通用化为”粉体颗粒”待确认
领域描述是否保留”核工程粉体/多相流”待确认(开源仓库已公开此描述)
内网 git 地址移除必做
真实数值/结论只作机制示例,不引用未发表数据必做

五、写作纪律(沿用本站体例)

  • 中文正文;代码、公式、技术名词保持英文
  • 命令行代码块给可复制的最短路径,不堆砌选项
  • 关键判断给理由,不写”应该可以”
  • 表格用于对比与选型;每章末尾有落点句
  • 不确定处标注”核查时间”,避免读者照抄过期信息

六、待办

  • 确认脱敏策略(见第四节三个”待确认”)
  • 确认是否需要为文章新增配图(当前仓库长文均为纯文本 + 表格)
  • 确认是否顺带修复 comment/comments 键不一致(新文章会用到评论开关)
  • 写作 → 本地预览验证 → 提交