← 返回列表
✓ 可直接安装
DeepSeek HarnessDSH的 graph 运行时能力集,以独立 Cordis 插件/bundle 形式发布。
自动检查通过:npm 包已发布且 engines 声明满足基线(声明 Node >=22.5);该结论来自程序自动检查,未经人工实机验证。 · 最近上游提交 2026/9/17 · 已提供中文文档
DeepSeek Harness 的图运行时能力:将 LangGraph 编译后的图注册为 DSH 工具,并提供一个由图驱动的路由代理。
综合分
30.4
GitHub 分
30.4
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add dsh-graph-runtimenpm 包 dsh-graph-runtime 已校验归属本仓库,走 npm 安装最省事
信任档位:已验证本站已于 2 天前真实安装成功(L4 · 真实安装)
- 是什么
- dsh 原生插件 · chat
- 装得上吗
- 本站已真实安装成功(L4 · 真实安装,非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 8 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/24
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/20(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查✓ 自动检查通过
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-graph-runtime @ 0.2.0
✓Node 引擎要求 >=22.5 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/21 06:03:15
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools@deepseek-ai/dsh-util-values用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-graph-runtime
DeepSeek Harness(DSH)的 graph 运行时能力集,以独立 Cordis 插件/bundle 形式发布。
当前能力:
- 图定义与自动挂载:以 defineGraph 定义"扩展 StateGraph"——图工厂 +
注册声明(是否成为 DSH tool、是否登记注册表)+ 工具入参校验钩子。模块被
加载即完成注册:插件启动时自动挂载已定义的图,其后定义的即时挂载,开发者
无需任何 service 调用。工具名/描述自动发现(compile({ name, description })
或结构合成),编译惰性且记忆化(注册路径零编译副作用),参数校验、取消转发
与结果渲染都由本插件承担。
- GraphRoutingAgent:graph 驱动的路由 Agent。把 graphTools 注册表(可
过滤)交给 LLM,要求必须选择一个工具;对返回的工具调用做存在性、JSON、
schema 与作者 validate 校验,不通过带原因重试(默认 3 次,可配置),
通过后执行对应 graph。每次被选中工具的执行前后有 graphTools/pre-execute /
graphTools/post-execute 两个 waterfall 扩展点(门禁、审计、结果加工)。
安装与接入
发布后
npm install dsh-graph-runtime
或本地路径(例如在 yolo-agent 仓库内)
npm install file:../dsh-graph-runtime
接入方式与其他 DSH bundle 一致,二选一或同时:
- 根组合 cordis.yml 增加一行(本包自带 cordis.patch.yml,web profile 的
dsh.profile.bundles 加入包名后同样自动挂载):
- id: graph-runtime
name: dsh-graph-runtime
用法
图作者只需 defineGraph——定义即注册,不需要任何 mount 或 service 调用:
// graphs/echo.ts
import { defineGraph } from 'dsh-graph-runtime'
import { Annotation, END, START, StateGraph } from '@langchain/langgraph'
const State = Annotation.Root({
topic: Annotation,
log: Annotation({
reducer: (left, right) => [...left, ...right],
default: () => [],
}),
})
export const echoGraph = defineGraph({
name: 'echo_graph',
description: 'Echo the given topic.',
build: () =>
new StateGraph(State)
.addNode('echo', async (state) => ({ log: [seen:${state.topic}] }))
.addEdge(START, 'echo')
.addEdge('echo', END),
asTool: true, // 声明为模型可见的 DSH tool;默认 false
// asGraphTool: true, // 登记进 graphTools 注册表供发现;默认 true,可省
// validate: (input) => Boolean((input as { topic?: string }).topic), // 入参校验钩子,缺省恒通过
})
唯一的接线要求:graph 模块需要在某个 bundle 入口被 import(barrel 一行
import './graphs' 即可)。插件 apply 时自动挂载已定义的全部图,其后
定义的即时挂载;单个图挂载失败(重名、非法声明)告警跳过,不阻断启动。
asTool: true 的工具注册在插件的全局层:所有 agent(含默认 agent)可见。
需要 scope 私有或运行时动态构造的场景,使用下述命令式入口。
GraphRoutingAgent
参考 dsh ReactLoopAgent 裁剪为单步:一次路由 = LLM 选工具 → 校验 →
(可选重试)→ 执行 graph。
import { GraphRoutingAgent } from 'dsh-graph-runtime'
const router = new GraphRoutingAgent(ctx, {
provider: 'deepseek',
model: 'deepseek-chat',
filter: { allow: ['echo_graph', 'search_graph'] }, // 同 tools.restrict 的 allow/deny
maxRetries: 3, // 校验不通过时重新调用 LLM 的最大次数,默认 3
// fallback: myFallbackTool, // 可选:覆盖内置兜底 tool
})
const outcome = await router.route({ input: '帮我回显一下 hello' })
// outcome: { tool: 'echo_graph', args: {...}, result: }
行为细节:
- 必须选工具:dsh-llm 的 GenerateOptions 没有 toolChoice 字段,
"required" 语义由循环兜底——模型未选择任何工具(纯文本回复)时不重试,
直接执行兜底 tool 并在结果上标记 fallback: true。缺省兜底是内置的
graph_routing_fallback(什么都不做:空入参、返回 {});可通过
fallback 传入 ToolDefinition 或 GraphDefinition 覆盖,覆盖者自行
保证空入参 {} 能通过其 schema(如 parameters: {})。
- 校验链(任一不通过即带原因重试):工具存在于(过滤后的)注册表;
参数是合法 JSON;执行期 schema 校验(ToolArgsError);作者 validate
钩子(GraphValidationError,经路由时携带 context.request 可做语义
拒绝)。graph 自身的运行失败不是路由失败,原样上抛。
- 过滤:filter 的 allow/deny 语义同 tools.restrict(可同给取交集);
名单含未知工具或过滤后为空视为配置错误。
- 重试用尽后以最后一次失败原因收场。
路由扩展点
被路由的执行不走 dsh 的 ctx.tools 管线(那是另一套注册面),管线
形态的扩展点因此落在路由循环自身:以 cordis waterfall 事件提供,每个
被选中工具的尝试在 graph 执行前经过 graphTools/pre-execute、在执行
落定后经过 graphTools/post-execute。审计日志、指标、策略门禁、结果
加工都挂在这两个事件上:
// 执行前门禁:deny 的原因会反馈给模型重试,与 validate 拒绝完全一致。
ctx.on('graphTools/pre-execute', async (execution, next) => {
if (disabledTools.has(execution.tool)) {
return { kind: 'deny', reason: "${execution.tool}" 已被策略禁用 }
}
return next()
})
// 观察或改写落定结果;成功与失败都会经过。
ctx.on('graphTools/post-execute', async (execution, outcome, next) => {
if (execution.tool === 'search_graph' && !('error' in outcome)) {
return { kind: 'accept', result: redact(outcome.result) } // 替换返回值
}
return next()
})
语义:
- execution 携带 tool / args / request(原始路由文本)/
signal;同一次尝试的两个事件收到同一个 execution 对象。
- waterfall 顺序:监听器按注册顺序执行;next() 表示放行并委托后续,
不调 next() 直接作答则否决余下监听器——第一个决策生效。
- deny(pre)与 block(post)并入常规重试循环:原因反馈给模型,
重试用尽后抛标准错误。block 拒绝的是任何已落定的结果——也可以把
本会上抛的 graph 错误转化为一次带原因的重试。
- accept 维持落定结果;携带 result 时替换返回给调用方的值(各监听
器观察到的仍是原值)。
- 兜底路径(模型未选工具)不经过这两个事件;如需在兜底上加钩子,请
自行包装 fallback 工具的 execute。监听器抛错会原样上抛。监听器用
普通 ctx.on 注册(与任何 cordis 事件一致);监听器内 this 是
Agent 所在的 ctx。
注册声明
| 字段 | 说明 |
| --- | --- |
| asTool | 是否注册为模型可见的 DSH tool(ctx.tools)。默认 false;自动挂载路径注册在插件全局层(所有 agent 可见),命令式 mount 路径注册在传入 ctx 的层。 |
| asGraphTool | 是否登记进 graphTools 注册表供发现(get/list、GraphRoutingAgent)。默认 true。 |
defineGraph 字段
| 字段 | 说明 |
| --- | --- |
| name | 图名,即注册后的 tool 名;全局唯一,禁用保留名 run_code。 |
| description | 可选。面向模型的工具描述;缺省时取 build() 产物上 compile({ description }) 写入的描述(作者自行编译时),或由节点与 state 键合成的结构描述。 |
| build | 图工厂:返回未编译 builder(插件在首次调用时 plain compile(),不传任何选项),或作者自行编译的实例。checkpointer 等编译选项完全归作者所有——要 state 记忆就返回 builder.compile({ checkpointer: new MemorySaver() })。 |
| validate | 可选的工具入参校验钩子:graph 执行前收到 (input, context),context.tool 是工具名,经 GraphRoutingAgent 路由时 context.request 携带原始请求文本(直连调用时无此字段)。返回 false 或抛错即拒绝(抛错 message 进入拒绝原因);缺省恒通过。据此可实现"这个请求不属于我"的语义拒绝,路由循环会带原因重试。 |
| parameters | 可选的 DSH ParameterSchemaSpec。提供时整个参数对象作为 graph 输入;缺省时工具暴露唯一的必填 input JSON 参数(其描述会拼上结构发现的 state 键名,但值本身不透明)。模型可见的图应始终声明,见下节。 |
| threadId | 可选的线程键;仅透传为 graph config 的 thread_id。是否形成 state 记忆由 graph 自带的 checkpointer 决定(插件不代管)。 |
| configurable | 可选的 configurable 附加键透传(thread_id 以 threadId 为准)。 |
| timeoutMs | 可选的协作式超时预算;graph 必须响应取消信号并收敛。 |
参数 schema 质量(模型可见的图必读)
parameters 原样透传为 DSH ParameterSchemaSpec 并在执行前强制校验
(越界枚举、类型不符、缺 required 都会被 ToolArgsError 拦下)。给模型
看的图,请保证每个参数类型明确、描述具体、枚举列全:
defineGraph({
name: 'greet_graph',
build: () => buildGreetGraph(),
parameters: {
name: { type: 'string', required: true, description: 'The name to greet.' },
style: {
type: 'string',
required: true,
enum: ['formal', 'casual'],
description: 'Greeting style.',
},
times: { type: 'integer', description: 'Repeat count.', default: 1 },
tags: { type: 'array', items: { type: 'string' }, description: 'Extra tags.' },
},
})
支持的能力:type 取 string / number / integer / boolean / null / array /
object / json,联合用 oneOf;每个键可带 description / title / default /
examples;枚举用与类型匹配的 enum(如字符串数组),单值约束用 const;
嵌套对象用 object + properties + additionalProperties,数组用 items;
逐键 required: true 标注必填。
为什么不自动派生:langgraph 在编译时即丢弃 Annotation 的类型信息,
运行时结构只剩键名与聚合语义——伪造类型或 required 的 schema 会误导模型
拼出被校验层拒绝的参数,比诚实的 input 更糟。因此未声明 parameters
的兜底是单一必填 input(json),结构发现的 state 键会拼进它的描述
(如 Expected state keys: topic, log (accumulated).);asTool: true
且未声明参数时,挂载路径会经 ctx.logger 打一条 warn 提醒作者。
命令式入口(动态/低层场景)
// 运行时动态构造的图:createGraphDefinition 只构造不发布(defineGraph
// 会自动挂载,插件活跃时再显式 mount 会双重注册),配合显式 mount;
// ctx 是 fiber 归属与 tools 注册落点。
const dynamicGraph = createGraphDefinition({
name: 'dynamic_flow',
build: () => buildDynamicGraph(),
asTool: true,
})
const mounted = ctx.graphTools.mount(dynamicGraph, ctx)
// 发现侧:ctx.graphTools.get('echo_graph') / ctx.graphTools.list()
// 手里已是编译产物、或只想一次性转换:
const entry = ctx.graphTools.register(compiledGraph, ctx)
const tool = ctx.graphTools.create(compiledGraph)
也可以直接 import { createGraphTool } from 'dsh-graph-runtime' 做纯转换,
效果等价。向 register 传图定义会得到指向 mount 的错误——图定义自带
注册声明。defineGraph 面向图作者(声明即发布、自动挂载);
createGraphDefinition 面向运行时动态场景(构造归构造,挂载归挂载)。
行为契约
- 定义即注册:defineGraph 把图定义发布到包级静态队列;插件 apply 时
接管并清空积压,其后定义的图即时挂载。单个图挂载失败(重名、非法声明)
经 ctx.logger 告警跳过,不阻断启动;插件释放后 defineGraph 重新入队,
可随插件重载再次挂载。
- 注册只是注册:defineGraph/mount/register 全程不调用 langgraph 的
compile();未编译 builder 在该 tool 首次实际调用时才 plain compile()
一次并记忆化(结构发现只读取 builder 的 nodes/channels,同样不触发编译)。
- checkpointer 归 graph:插件从不注入或代管编译选项;threadId 仅是
thread_id 透传,记忆是否生效取决于作者在 build() 里返回的实例。
- 每次工具调用即一次 graph.invoke;工具入参先经 DSH 参数 schema 校验与
作者 validate 钩子,再进入 graph;调用方的 AbortSignal 原样转发。
- graph 最终 state 必须是 lossless JSON,否则以明确错误拒绝;工具结果以
pretty JSON 文本块返回给模型。
- 与 ctx.tools 的交互只发生在声明 asTool: true 时:自动挂载路径注册在
插件的全局层(所有 agent 含默认 agent 可见);命令式 mount(definition,
ctx) 注册在传入 ctx 的层(agent scoped ctx 上则仅该 agent 可见并 shadow
全局同名工具)。graphTools 注册表是独立状态:登记名唯一、unregister
幂等、随挂载路径的 fiber 释放自动移出。
- 自动发现的边界:Annotation 的类型信息与 addNode 的 description 在
langgraph 编译时即被丢弃,参数 schema 无法自动派生。自定义 GraphInvocable
缺少运行时字段时发现安全降级,但名字必须显式提供。