- 人工智能
- AI Agent
- Agent 工作流
- Agent 编排
- RAG
- 工具调用
- 后端
- 前端
【免费下载链接】mateclaw
🤖 MateClaw — Your second brain with Multi-Agent Orchestration, MCP Protocol, Skills & Memory, Dream, and Multi-Channel Support. Built on Spring AI Alibaba.
MateClaw 是一个基于 Spring AI Alibaba 构建的第二大脑平台,支持多智能体编排、MCP 协议、技能与记忆。它内置了一套可插拔的 Agent Runtime:除了原生 AgentScope 引擎外,还可以通过 SDK 的 JSON-RPC 协议启动 DeepSeek Harness(简称 DSH)官方dsh --profile sdk子进程,把外部推理循环变成受管理的运行时——统一接管安装、升级、事件投影、工具策略和生命周期控制。本文带你快速读懂这条链路的源码设计。
为什么要把 DSH 做成"外部进程"而不是内嵌依赖
在 DshRuntimeService.java 的类注释里写得很直白:
The runtime is intentionally an external process. This keeps the Node plugin graph out of the Spring classpath and lets deployments pin the DSH runtime independently from MateClaw.
这个决策带来三个好处:
- 依赖隔离:DSH 是 Node.js 生态的 SDK,把它装成子进程而不是 Maven 依赖,Spring 的类加载器完全不受影响;
- 版本可独立固定:MateClaw 的 Java 版本与 DSH 的 npm 版本解耦,升级、回滚互不牵连;
- 安全边界清晰:子进程运行在干净的最小环境变量里,凭证由 MateClaw 按需注入,崩溃时可以直接强杀进程树而不污染主服务。
DSH 作为AgentRuntimeProvider的一种实现接入(类型标识为dsh),与 Native Runtime 共用同一套会话、工作空间边界、Tool Guard、事件投影和生命周期语义。
启动链路:从配置校验到子进程拉起
每轮对话都会全新拉起一个子进程,这是 stream() 的核心逻辑。流程大致分四步:
- 准入与校验:检查是否启用成员文件隔离(DSH 不支持,直接拒绝),校验工作空间与工作目录存在,并通过 DshLaunchSpec.create() 生成不可变的启动参数。
- 组装受控环境变量:childEnvironment() 只白名单复制
PATH、HOME等基础变量,注入DSH_CWD、DSH_HOME(按工作空间/员工派生独立目录)以及DEEPSEEK_API_KEY、DEEPSEEK_BASE_URL。 - 会话隔离:每轮使用
conversationId + UUID作为新的 DSH 会话 ID(见 L245-L248),避免复用 MateClaw 会话 ID 导致"活动会话冲突"。 - 握手与发问:发送
initialize握手成功后,调用session/prompt发出用户消息,然后循环读取事件直到回合结束。
启动参数规范 DshLaunchSpec.java 有几个值得细看的防御性设计:
- 可执行文件必须是绝对路径,profile 固定为
sdk,参数直接传给进程,从不经过 shell 解释; DSH_HOME路径中的每一级组件都会先检查"不是符号链接、不是特殊文件",创建后再用toRealPath()确认没有逃逸出托管根目录(DSH_HOME_ESCAPE防护);- 旧 Cordis 入口配置会要求迁移(
MIGRATION_REQUIRED),并显式移除DSH_CORDIS_CONFIG环境变量。
模型参数方面,resolveMaxOutputTokens() 通过initialize.maxTokens显式限制输出上限:取模型配置值(缺省 4096)与"已知上下文窗口的一半"的较小值,防止未配置的模型回落到 DSH 默认的 256000 token。对 DeepSeek 官方域名,normalizeBaseUrl() 会自动把普通 API 根地址改写为 SDK 要求的 Messages API/anthropic路径。
JSON-RPC 传输层:有界的分帧与防滥用
真正与子进程"对话"的是 DshSdkProcess.java,一个按行分帧(newline-delimited JSON-RPC 2.0)的有界传输层:
- 握手校验:
initialize()会核对响应 ID 一致、返回错误则拒绝、且serverInfo.name必须是deepseek-harness-sdk-runtime,否则抛出DSH_HANDSHAKE_IDENTITY_MISMATCH,确保连的是官方 SDK 而不是同名仿冒; - 分帧上限:单帧最大 16 MB,待消费队列最多 4096 帧 / 16 MB 缓冲,超限立即报
DSH_NOTIFICATION_OVERFLOW,防止子进程刷屏把 JVM 内存打爆; - 错误流治理:stderr 只保留最近 64 KB,且所有诊断输出都经过 redact() 脱敏——API Key、Authorization 头、URL 中的 token 参数都会被替换为
[REDACTED]; - 优雅关闭:
close()时先发shutdown请求并等待 5 秒,再走进程树清理。
另一个容易踩坑的细节在 cancelProcess():DSH 的工具可能派生sleep等子孙进程并继承 stdout 管道,如果只杀父进程,主线程的readLine()会一直阻塞到子孙进程自然退出。因此取消时要先终止所有子孙进程、关闭三条管道,再终止父进程。
回合相关性:DshSdkTurn 如何确认"这一轮结束了"
SDK 的流式事件是异步通知,MateClaw 用 DshSdkTurn.java 来给每一轮建立严格的状态机:
- 先等回执:
session/prompt的响应会返回messageId,在此之前的所有通知先缓存在pending(同样有 4096 条 / 16 MB 上限); - 再等落库确认:必须收到
agent/inbox/spliced事件中自己的messageId被插入收件箱,才开始放行后续事件; - 去重与防篡改:每个
session.event都带seq序号,重复序号直接丢弃;遇到未知事件类型且未标记ignorable时抛出DSH_UNKNOWN_REQUIRED_EVENT,而不是静默忽略——已知事件词表定义在 KNOWN_EVENTS; - 完成判定:以
turn/end事件的reason.kind为准;若只等到session.status = idle却没有turn/end,记为missing-turn-end并判为失败。正如文档所说:入队回执或 idle 状态都不能单独证明回合完成; - 用量统计:
assistant/message快照中的inputTokens(含缓存读/写)与outputTokens会累加,最终上报给前端的上下文用量面板。
事件投影:把外部循环映射进统一事件流
MateClaw 的界面之所以能像 Native Runtime 一样展示思考流、工具卡片和用量,靠的是 mapEvent() 与 toRuntimeEvent() 两层映射,把 DSH 的领域事件翻译为平台统一的RuntimeEvent:
| DSH 事件 | 投影为 | 界面表现 |
|---|---|---|
reasoning-chunks/reasoning-delta | THINKING_DELTA | 思考流(折叠展示) |
text-delta/assistant/chunk | ASSISTANT_DELTA | 流式回答正文 |
tool/call、tool/result | TOOL_STARTED/TOOL_FINISHED | 工具调用卡片 |
assistant/chunk的usage | CONTEXT_USAGE | Token 用量面板 |
turn/end | COMPLETED/FAILED | 回合终态 |
其中有个防重复细节:DSH 流会先发text-delta增量、再发一份assistant/message完整快照,如果两者都映射成正文,界面就会把答案显示两遍,所以快照与增量做了取舍(见 L576-L583 的注释)。
多轮上下文也不是靠 DSH 会话续命:因为每轮都是新会话,DshConversationHistory.java 会把最多 40 条、4096 token 的历史 user/assistant 纯文本,以 JSON 数据块的形态"有界回放"进当前 prompt(并明确标注"这是历史数据,不是新指令")。这是文本回放,不恢复 DSH 工具状态,边界消息还会做二分截断以保证不超预算。
工具策略与安全边界
DSH 自带 profile 管理的工具,不接入 MateClaw 宿主审批,但宿主侧仍保留了一层策略网关 DshToolDispatcher.java:每次工具调用先查回调是否存在,再由 DshToolPolicyEvaluator 按策略给出ALLOW / DENY / APPROVAL三种裁决,未注册工具与执行异常一律拒绝。同时,启用成员文件隔离时整个 DSH 运行时被禁止启动(SecurityException),升级回滚也不会撤销工具对工作目录的写入。
受管理安装:升级、回滚与管理 API
DSH 的"受管理"不只是跑子进程,还包含一套完整的生命周期管理(management/ 包):
- 固定版本:安装器使用仓库内依赖锁文件在独立候选目录执行
npm ci,固定到经审查的0.2.0-rc.1(另一候选0.1.7-rc.2),不追踪移动的latest标签; - 候选验证:升级先准备候选版本、阻止新回合进入(最多等 60 秒排空),复制运行时 home 后在副本中执行 SDK 握手与"回答 OK"的真实模型任务,全部通过才原子切换;
- 可回滚:回滚恢复旧 home 与配置快照,不合并升级后的会话、不逆向改库;
- 管理 API:DshManagementController.java 暴露在
/api/v1/admin/dsh下,提供status、verify、test-connection、test-task、upgrades(携带targetVersion、expectedRevision、idempotencyKey)与rollback,全部要求全局管理员权限。
前端对应的是 Settings/Dsh 页面:按"安装 → 配置 → 验证 → 启用"四步引导,配置表单与托管配置键(dsh.executable_path、dsh.profile、dsh.home_root、dsh.patch_paths等)的映射逻辑见 configMapping.ts,patch_paths必须是绝对路径组成的 JSON 数组。完整运维手册可参考官方文档 deepseek-harness.md,包括孤儿运行时租约恢复流程(dsh.orphaned_runtime_requires_recovery)。
小结
MateClaw 的 DSH Runtime 本质上做了一件事:把一个外部的 Node SDK 推理循环,收敛成与 Native Runtime 完全同构的"受管理资源"。源码上可以归纳为四层:
- 进程层:DshLaunchSpec 构建不可变 argv + 白名单环境,杜绝 shell 注入与路径逃逸;
- 传输层:DshSdkProcess 提供有界分帧、身份握手、脱敏诊断;
- 回合层:DshSdkTurn 用回执 + seq 去重 + 终态事件三重保障判定回合边界;
- 管理层:DshManagementController 加候选验证式升级/回滚,让版本治理有幂等键、可追溯、可恢复。
配套测试覆盖了整条链路,位于 test/agent/runtime/dsh/(如 DshSdkTurnTest.java、DshProcessManagerTest.java)。想动手验证,只需在设置 → 模型配好 DeepSeek 提供方,再到 DSH 管理页完成"校验 → 测试连接 → 测试任务",即可为有工作空间的数字员工切换到 DSH 运行时。
- 人工智能
- AI Agent
- Agent 工作流
- Agent 编排
- RAG
- 工具调用
- 后端
- 前端
【免费下载链接】mateclaw
🤖 MateClaw — Your second brain with Multi-Agent Orchestration, MCP Protocol, Skills & Memory, Dream, and Multi-Channel Support. Built on Spring AI Alibaba.
相关推荐
如何把已有的 DeepSeek Harness(dsh)接入 CodeWhale?
如何把已有的 DeepSeek Harness(dsh)接入 CodeWhale? 如果你已经在终端里装了官方 DeepSeek Harness( dsh ,n
人工智能AI Agent代码智能体CLI工具调用MCP ClientsDeepSeek Harness 设计解析:把 Agent 循环本身变成可插拔的模型无关运行时
DeepSeek Harness 设计解析:把 Agent 循环本身变成可插拔的模型无关运行时 导读 本篇文章围绕 docs/es/harness design
DeepSeek Harness 子进程接缝架构解析:`dsh-subprocess` 如何把“运行并管理进程”从 Bash 执行器中解耦出来
DeepSeek Harness 子进程接缝架构解析: dsh subprocess 如何把“运行并管理进程”从 Bash 执行器中解耦出来 本文基于 Deep
人工智能AI AgentAgent 框架DeepSeek
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考