DeepSeek Harness Hub
← 返回列表

yxie2/dsh-petrinet

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

一个面向 DeepSeek Harness…

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/24 · 已提供中文文档

DeepSeek Harness 的 Workflow-net 运行时:资源感知并发、原生循环与扇出、在计划变为持久化之前进行静态健全性检查,以及对其自身事件日志进行流程挖掘。

综合分
28.2
GitHub 分
28.2
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add yxie2/dsh-petrinet
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-attachment@deepseek-ai/dsh-commands@deepseek-ai/dsh-invariants@deepseek-ai/dsh-llm@deepseek-ai/dsh-scope@deepseek-ai/dsh-session@deepseek-ai/dsh-session-projection@deepseek-ai/dsh-subagent@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-timeout
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-petrinet

一个面向 DeepSeek Harness 的工作流网运行时。它将长周期计划建模为状态——令牌驻留在库所中,变迁消耗并产生它们——这赋予了它三个特性:

1. 资源感知的并发。 一个信号量、一个互斥锁、一个 API 配额、一条“同一时间只允许一个 agent 触碰仓库”的规则——全都只需一次声明,由驱动其他一切的同一触发规则来强制执行。
2. 原生循环与运行时扇出。 重试直到成功、轮询直到就绪,以及“对你发现的每个条目各运行一次”都是普通结构。
3. 在计划变为持久化之前进行静态健全性检查。 一个可能死锁的计划会在提交时被拒绝,并附带一个具体的反例——在任何工作开始之前。

除此之外,它还会挖掘自身的执行日志,以提出有证据支撑的计划改进建议。

dsh plugin add @yxie2/petrinet

初次接触?阅读简介——从问题的形态到运行时对此的应对,阐述该设计背后的理由。本 README 是参考文档。中文读者请看中文简介。

工作流网建模什么

库所持有令牌。变迁从其输入库所消耗令牌,并将其产生到输出库所中。一个变迁只有在每个输入库所都持有足够令牌时才能触发。这一条规则承载了很多东西:

| | 如何表达 |
|---|---|
| 并发限制 | 一个持有 k 个令牌的库所就是一个 k 路信号量 |
| 循环 | 结构中的一个环 |
| 运行时扇出宽度 | 一个库所中的 n 个令牌 = n 个并行工作项 |
| AND 汇合 vs XOR 汇合 | 结构上截然不同 |

而且因为它是 Petri 网,六十年的分析成果随之而来:可达性、有界性、守恒律,以及一个可判定的健全性概念。

健全性门禁

这是值得整个设计的特性。

每个计划在进入持久化日志之前都会被静态分析。在探索预算之内,判定结果是证明,而非启发式——van der Aalst 的三个条件在具体枚举出的可达图上进行检查:

1. 可完成选项——每个可达状态仍能到达终点。
2. 正确完成——到达终点意味着没有任何东西被遗留。
3. 无死变迁——每一步都在某处可达。

这里有一个看起来完全合理的计划。两个分支,每个都需要两把锁:

{
"resources": [{ "id": "A", "capacity": 1 }, { "id": "B", "capacity": 1 }],
"flow": { "parallel": [
{ "guard": { "resource": "A", "body": { "guard": { "resource": "B", "body": { "task": { "id": "w1" } } } } } },
{ "guard": { "resource": "B", "body": { "guard": { "resource": "A", "body": { "task": { "id": "w2" } } } } } }
] }
}

petri_plan 会拒绝它:

PETRI_UNSOUND_PLAN: net is unsound: 2 deadlock marking(s) reachable;
1 reachable marking(s) can no longer reach the final marking
而 petri_analyze 会返回它本应死锁的状态:

{ "deadlockExample": { "p.guard.g1.body": 1, "p.guard.g3.body": 1 } }

两个分支各持有一把锁,彼此等待对方。经典的锁反转,在花费任何一个 token 之前就被捕获。放宽任一资源,或按一致的顺序获取,同一个计划就能验证为 SOUND。

当答案未知时,它会如实说明。 超过探索上限后,判定结果是 UNKNOWN,绝不会是乐观的 SOUND。通过具体反例发现的违规即使在有上限的情况下也依然确定,因为死锁标记无论还有什么未被探索,都没有可触发的变迁。

模型编写结构,而非弧

模型擅长嵌套的任务结构,却不擅长输出库所、变迁和弧权重。因此 Petri 网是中间表示,绝不是表层语法。模型编写一个小型模式 DSL:

{
"resources": [{ "id": "repo_lock", "capacity": 1 }, { "id": "ci_slots", "capacity": 3 }],
"flow": { "seq": [
{ "task": { "id": "survey", "name": "Survey the codebase" } },
{ "foreach": { "id": "each_pkg", "over": "packages needing migration",
"body": { "guard": { "resource": "ci_slots",
"body": { "task": { "id": "migrate" } } } } } },
{ "guard": { "resource": "repo_lock",
"body": { "loop": { "id": "green", "maxIterations": 5,
"body": { "task": { "id": "fix_tests" } } } } } }
] }
}

| 节点 | 含义 |
|---|---|
| task | 一个真实工作单元,分派给子代理 |
| seq | 按顺序运行 |
| parallel | AND 分支,并发运行,全部完成后汇合 |
| choice | XOR 分支,恰好选择一条分支 |
| loop | 重复直到走退出分支(由 maxIterations 限定) |
| foreach | 在运行时发现 n 个条目,对每个条目运行一次主体,然后收集 |
| guard | 在主体持续期间持有一个信号量 |

每个模式都降级为一个恰好有一个入口库所和一个出口库所的片段,并且此类片段的组合在工作流网形态下是封闭的。因此,控制流模式在构造上就是可靠的。 分析器的存在是为了捕获组合无法保证的东西:资源引发的死锁——而这正是真实的长时运行计划实际失败的地方。

Token 仅在验证时移动

每次触发都是两阶段的,而这两个阶段由裁决分隔:

claim    在租约下消耗输入 token   (保留,而非销毁)
|
execute  分派一个子代理
|
report   工作者关于环境的声明    产生输出 token
+-- failed  -> 归还消耗的 token,消耗一次尝试

一个自信但错误的子代理无法推进网络。没有任何东西能自我认证。
标记是派生的,从不存储——重新折叠会话日志即可重建精确的运行时状态,因此崩溃恢复、重放和时间旅行调试都是免费的。一个静默死亡的 worker 会使其租约过期,其令牌被归还,其转换被重新启用。

并发来自网络

驱动器不进行调度。它触发网络所启用的一切,而网络的资源位置决定了一次可以发生多少:

resources: [{ id: 'slots', capacity: 2 }]

这就是双向并发上限的完整实现。来自测试套件:

capacity 1 -> peak concurrency 1
capacity 2 -> peak concurrency 2
capacity 3 -> peak concurrency 3

驱动器上的 maxConcurrency 是在此之上的第二层、更粗粒度的上限——一个安全限制,而非机制本身。

从日志中学习

事件流无需任何额外插桩,就是一个流程挖掘事件日志:案例 id(网络修订版)、活动(转换)、顺序、结果。这是一个领域的规范输入,而该领域的规范输出是 Petri 网。这个循环自我闭合。

petri_insights 报告两件事:

一致性。 候选计划与实际发生情况之间的令牌重放适应度。这就是如何依据历史而非模型自身的乐观来评判所提议的修复——一个得分比它所替代的计划更差的修复不是修复。

适配。 具体数字,每个都由一次计数的观察作为支撑:

[
{ "kind": "maxAttempts", "target": "t.flaky", "current": 3, "suggested": 4,
"rationale": "hit its budget of 3 yet committed elsewhere in history (worst streak 3); the failures are transient" },
{ "kind": "resourceCapacity", "target": "ci_slots", "current": 3, "suggested": 4,
"rationale": "drained to zero while 18 further acquisition(s) were otherwise ready; widening it raises real concurrency" }
]

alphaMine 还会从观察到的行为中重新发现一个网络,因此你可以将你计划的内容与实际发生的情况进行对比。

自我修复,从最廉价开始

当一个网络死亡时,驱动器分层修复它:

1. adaptive——免费。从会话自身的历史中推导出参数变更。不调用模型,每个变更都由一次观察作为支撑。
2. llm——模型编写一个替代的工作流规范,它经过与人类路径相同的编译器,并继承相同的构造即正确的模式。它被逐字地交给分析报告,包括具体的死锁标记,因为“这是你陷入的确切状态”远比“你的计划失败了”更具可操作性。

两个提议在提交前都要通过健全性门禁。 一个提出死锁的模型会得到拒绝,而不是一个卡住的网络。这道门禁正是将这与无界自我修改区分开来的东西。
结构变更绝不会从挖掘中自动应用——死锁转移的观察结果只会被报告,绝不会被据以行动。放宽预算是可逆的算术;重写计划则是一项决策。

诚实的局限,事先说明:
- 重试探测是有上限的(RETRY_PROBE_CEILING)。一个从未成功过的步骤只会再获得一次尝试机会,仅此一次——超过之后,更多的耐心并不是答案,代码在其输出的理由中也是这样说的。
- alpha 算法无法看到长度为 1 或 2 的循环、重复活动或不可见的路由步骤。请把低适应度分数当作一个问题,而不是一个判决。

工具

| 工具 | 用途 |
|---|---|
| petri_create | 为长周期目标打开一个网 |
| petri_analyze | 编译并检查候选计划,而不提交它 |
| petri_plan | 将计划提交为下一个修订版(CAS;若不健全则拒绝) |
| petri_status | 标记、已启用的转移、选择点、每一次触发 |
| petri_insights | 针对历史的一致性 + 有证据支持的适配 |
| petri_cancel | 中止当前网 |

外加一个 /petri 斜杠命令(status / analyze / cancel / )。

petri_analyze 是值得鼓励使用的那个:它把死锁从四十小时的损失变成规划阶段的一次免费修正。

配置

默认值不产生任何成本——确定性选择,无需修复:

- id: petri-driver
name: '@yxie2/petrinet/driver-host'
config:
decider: llm          # deterministic (default) | llm — only consulted at real choice points
repair: both          # off (default) | adaptive | llm | both
maxConcurrency: 4
approveRepairs: false

repair: adaptive 同样免费——它读取的是历史,而不是模型——所以它是首先值得开启的东西。

llm 决策器只在转移真正竞争相同令牌的地方被咨询。无竞争的进展和控制转移完全不产生模型调用。

架构

compile.ts     workflow DSL  ->  workflow net        (sound by construction)
soundness.ts   structural | invariants | reachability (the gate)
net.ts         the firing rule: enabling, conflict, marking algebra
fold.ts        events -> state (the marking is derived, never stored)
validate.ts    admissibility, incl. the soundness gate on every revision
mining.ts      traces, alpha algorithm, conformance, adaptations
|
+-- zero runtime dependencies; runs under node --experimental-strip-types
|
driver.ts      the concurrent firing loop
service.ts     ctx.petri  — event-sourced, CAS revisions
tools.ts / trigger.ts / driver-host.ts / invariant.ts / projection.ts

整个引擎——语义、降级、分析、折叠、挖掘——都刻意不依赖任何 harness。它的测试套件无需安装,也无需构建:

node --experimental-strip-types tests/net.test.mjs

那里的回归是数学上的回归,而不是集成上的回归。

npm test         # all suites
npm run build    # typecheck + emit lib/

先前技术

这是应用性工作,而非凭空发明的理论。它依赖于:

- W.M.P. van der Aalst,The Application of Petri Nets to Workflow Management(1998)——工作流网与健全性。
- van der Aalst、ter Hofstede 等,Workflow Patterns(2003)以及 YAWL——该 DSL 所实现的模式集合。
- van der Aalst,Process Mining——alpha 算法与令牌重放一致性。
- Rozinat & van der Aalst,Conformance Checking of Processes Based on Monitoring Real Behavior(2008)——适应度指标。
- dsh-mission——本包全盘采纳的原则(智能体提议,环境裁定,运行时提交),以及其针对持久化规划状态所采用的事件溯源、比较并交换方法。两者可并排安装。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群