新文章设计方案:如何为自己的工程项目设计并实现 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 预设”大概是什么。
本文要回答的三个问题
- 项目里那么多约定,哪些该进预设、进预设的哪个位置?
- 一个预设最少需要什么才能跑起来,怎么验证它真的装配了?
- 想开源出去,怎么把一个装满个人路径的预设变成模板?
二、叙事主线
全篇是一条”从项目到产品”的路径,而不是 dsh 功能罗列:
真实项目(Gra_thesis)
↓ 抽取约定(四类素材 → 四个落点)
预设设计(agent.cordis.yml 的行怎么分)
↓ 实现
最小预设 → persona → 工具行 → 渐进披露路由
↓ 验证
selftest + 真实挂载
↓ 脱敏与开源
router-sci(占位符模板 + NOTICE 合规)
三、章节设计
开篇引言块(blockquote)
沿用本站长文的体例:目标读者 / 推荐路线 / 前置知识 / “本文核查时间”。明确说明:示例基于真实开源仓库,机器相关路径已占位符化。
一、问题:为什么 AGENTS.md 不够
- 现状:项目里有
AGENTS.md/CLAUDE.md,agent 每次自己去读 - 三个失效点:
- 环境事实靠”读”:读了仍可能在错误的一侧执行(Linux 侧 / Windows 侧)
- 纪律靠”提醒”:写进文件也只是建议,工具该用还是能用
- 常驻成本:每轮都在上下文里占位,或者每次重新读一遍
- 结论:预设 = 把”文件里的约定”变成”会话装配的一部分”
二、先分清两个平面: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.md、CLAUDE.md、.claude/skills/下的技能、task_plan.md/findings.md/progress.md
然后给出核心素材提取表(全文最有复用价值的一张表):
| 项目里的东西 | 性质 | 落到预设的哪里 | 理由 |
|---|---|---|---|
| 领域术语、研究对象、物理模型 | 事实背景 | persona | 每轮都需要,必须常驻 |
| 哪台机器跑什么、路径怎么对应 | 环境事实 | persona(工具路由约定) | 同上 |
| 参数不能编造、编译必须通过 | 纪律 | persona + 硬门控 | 需要”拒绝”的部分下沉到工具行 |
| 批量跑工况的操作步骤 | 流程知识 | skills | 按需加载,不常驻 |
| 能读不能写、能跑不能装 | 能力边界 | agent.cordis.yml 工具行 | 只有工具行能真正约束 |
| 开工先读什么、收工回写什么 | 续接约定 | persona | 属于行为习惯 |
两条设计原则(本节的落点):
- 能落到工具行或 skill 的,不要写进 persona —— persona 是每轮都付的 token 成本,skill 是按需加载的
- 需要”拒绝”的用工具行,只需要”提醒”的用 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' isolaterealm:服务行必须放进 group 且带isolate, 否则会发布到 root realm(进程级)→ 第二个会话撞名- 讲清
true(每会话私有实例)与共享标签的区别
- 讲清
- 举例:Windows 上要真正的 Git Bash,需要私有
shell服务(gitbash-executor) —— 以及它的诚实边界:不绕过沙箱,MSYS 在受限令牌下可能启动失败, 按正常审批做单次升级,而不是篡改策略
七、把”流程”做成渐进披露(进阶机制)
全文技术含量最高的一节,也是 router-sci 真正的原创贡献所在。
- 动机:一次性给出全部工具 = 注意力税 + 模型会”大跃进”
四阶段模型(真实定义):
阶段 名称 解锁工具 0 了解/对齐 readglobgrepweb_searchask_user_question1 拟合方案 todo_writeexit_plan_mode2 开发 writeeditstr_replace_editor3 验证 bashpwshread_imagejob_listjob_outputjob_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 缓存仍返回旧模块 - 这是一条很容易踩、且症状是”改了没生效”的坑
- 原因:generation 只以 composition 文件的 stamp(mtime + size)为指纹, 旁挂的
- 备份策略:改动前把预设目录整体复制一份(带日期后缀)
- 热更新工具的存在与边界:能让新会话挂载新一代,已运行会话保持旧代
十、脱敏与开源:把”我的项目”变成”任何同类项目”
- 三层脱敏(明确区分,不能混为一谈):
- 机器事实 → 占位符:发行版名、项目根、软件安装路径、符号链接路径
- 研究对象 → 通用化:具体物料名 → “粉体颗粒”;这是语义脱敏, 不是字符串替换
- 个人标识 → 移除:用户名、绝对路径、内网 git 地址
- 给占位符对照表(
<PROJECT_NAME><WSL_DISTRO><WSL_PROJECT_ROOT><WIN_PROJECT_LINK><ANSYS_INSTALL>),并注明/不在此列 - 为什么不能只做字符串替换:把路径变量收敛成占位符的过程, 会强迫你回答”这个预设到底依赖哪几个环境事实”——这一步本身就是设计
- 版权合规:
NOTICE文件怎么写- 逐项列出上游来源、许可证、具体哪些文件是派生
- 明确划分”原创部分”与”派生部分”(如本仓库:persona 与元数据原创, 路由代码来自上游 MIT)
- 商标与背书的免责声明
十一、常见坑清单
按”症状 → 原因 → 处理”组织:
- 预设不出现 → 目录嵌套了(只扫一级)
- 改了代码没生效 → 忘递增
?v=N - 第二个会话崩 → 服务行没放进
isolaterealm - persona 越写越长 → 该下沉到 skill 的内容没下沉
- 约束被无视 → 用 persona 做了本该工具行做的硬门控
- 升级后改动丢失 → 直接改了随部署发布的预设
- 在错误平台注册工具 → 忘了
disabled的平台条件 - 路径硬编码 → 换机器就废(占位符化没做完)
十二、参考资料
- 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键不一致(新文章会用到评论开关) - 写作 → 本地预览验证 → 提交