Repository navigation
dsh-team-models:给 Agent Teams 补上「每个队友自选模型」(Host 插件,MIT) #13305
QinLuza
started this conversation in
Show Your Plugins!
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
给 DeepSeek Harness 的 Agent Teams 补上「每个队友自选模型」
一、问题:队友被「钉死」在一条模型路由上
DeepSeek Harness(下称 DSH)的 Agent Teams 允许多个智能体组队协作:一个 Lead 负责编排,若干 teammate 各司其职。用起来很顺,直到你遇到这两类场景:
直觉上「给队友换个模型」应该是个配置项。但翻源码会发现,这件事在现有机制下做不到:
subagent/descriptor(版本化、首事件权威)。之后每次唤醒——收消息、恢复运行、冷恢复——都从这份快照重建路由,不会重新解析当前默认模型。spawn_teammate工具到 roster 再到运行时创建,整条链没有模型参数的入口。origin === "subagent"的会话一律返回session/agent-busy;桌面端的模型选择器对队友会话直接隐藏。三层叠起来,队友的模型座位是空的。唯一的「换模型」办法是拆掉队友重建——而 roster 的名字不可复用、失败成员永久占槽,拆队成本很高。
二、思路:不改 base,在请求期改写路由
DSH 是「万物皆插件」的架构,模型选择本身有一个公开导出:
installModelSelection(agentCtx, selection)。它把一份可变的选择耦到三个 waterfall 上:system-prompt/assemble:进入提示组装时快照当前选择;agent/request:在next()之后用快照覆盖最终请求路由;agent/pre-step:路由变化时追加一条[model changed: ...]提示。关键观察:这个函数作用于任意
agent.ctx。官方只在它会话管理的入口安装它,队友会话没人装——那我们就给每个 teammate 的agent.ctx装一份自己的选择引用。于是路由解析变成请求期的事:descriptor 快照一个字都不用改,spawn 链一个字都不用改,base 零改动。未配置任何值时,三个 waterfall 全部直通——行为与没装插件完全一致。
三、设计要点
四个 agent 工具,让模型自己就能管理路由,而不是只有人类点 UI:
team_model_listteam_model_setteam_model_resetteam_model_default身份取自执行上下文,不取自参数。工具 handler 里的
exec.agent是 loop 注入的精确调用者,配合团队的 membership 判定角色:Lead 可以指向任意队友,队友只能点名自己。参数里写别人的名字会被直接拒绝——越权不靠提示词约束,靠执行点校验。持久化与一致性。覆盖和团队默认落在
$DSH_HOME/storages/team-models/state.json:先写副本、原子 rename、落盘成功才换入内存状态;读取时做字段级校验,坏条目丢弃并告警,JSON 损坏则隔离原文件后空状态启动。跨重启存活。三条不变量(都有单测断言):
model/selection作为尽力而为的回显。四、踩过的坑(挑几个有代表性的)
listMembers(agent),不是list(membership)——后者在私有 roster 上。第一版按直觉写,一调用就 TypeError。教训:外置插件对接宿主服务,签名要逐个对着源码核。null原样放行,文档示例里写defaultModel: null会让插件在启动时崩。修法:种子只认非空字符串,文档示例改成「不配即不设」。team_model_reset不传 target 时,第一版会清空全表——包括别的成员。复核时被抓出来,改成「队友必须显式点名自己,清全部是 Lead 专属」。这类「省略参数 = 全局操作」的默认行为,是多智能体工具里特别容易踩的雷。model/selection事件的追加在某些时序下会落空(目标不在 live 列表里),但路由本身不受影响。把它当「锦上添花」而非「正确性依赖」,设计上就松了。五、怎么验证它真的生效
模型自述「我用的是 X 模型」不算证据。硬证据在会话日志里:
request/header路由等于 override,且不等于subagent/descriptor里的派发路由;离线侧用 vitest 直接对着真实的
installModelSelection跑 waterfall:无配置时断言请求逐字段直通,有配置时断言覆盖与等级清理。加上路由优先级真值表、身份/越权矩阵、存储损坏恢复,共 49 个用例。真机侧在桌面与 Android(arm64)两端都跑通了上述行为门。一个有意思的副产品:给队友设一个 provider 不支持的等级,请求期会明确报「不支持该推理等级」——这反而成了「override 确实写进了请求」的最硬证据。
六、用法
npm install && npm run build把包加进 profile 的
dependencies与dsh.profile.bundles(dsh-team-models),重启宿主。配置全可选:之后在对话里直接让 Lead 调工具即可:
{ "tool": "team_model_set", "target": "grader", "model": "provider-b/model-b" }改动在队友的下一个 step 生效,不打断进行中的请求。
七、局限与退役
如实说清楚边界:只覆盖 teammate(Lead 自己的模型仍走官方路径);这一版没有客户端 UI;状态按成员名索引、没有 team 维度,两个同名成员的团队会串覆盖(单团队场景适用);清除覆盖后的回落不带
[model changed]提示(上游在无选择时早退)。更重要的是退役条件:这个插件存在的理由,是上游还没提供 per-teammate 模型选择。社区里相关的 feature request 已经不少,一旦官方支持(或允许
model/selection覆盖 descriptor),它就该退役,而不是和官方能力并行维护。外置补丁的宿命是被收编——这是好事。八、链接
>=0.2.1-rc.5 <0.3.0)如果你也在用 Agent Teams 并被「队友换不了模型」卡过,欢迎试用、提 issue。
英文版讨论:#13303
All reactions