用 DeepSeek Harness 搭建自己的大肥鱼:从插件到桌面运行

作者
DeepSeekAgent.io 编辑部
发布
更新

搭建自己的“大肥鱼”不应从复制一个大型桌宠仓库开始。先做出一个能被 DSH 安装、能显示真实状态、能安全退出的最小插件,再逐步加入角色素材、原生窗口、派活、记忆和养成,后续升级会稳定得多。

本教程给出一条可落地的开发顺序。具体 API 会随 DSH 版本变化,插件清单和事件接口应以当前 DSH 仓库及参考项目为准。

第一步:确定产品边界

先回答四个问题:

  1. 角色显示在 DSH Web 内,还是系统桌面原生窗口?
  2. 它只显示状态,还是允许用户从气泡派活?
  3. 动作由本地规则驱动,还是需要模型生成台词?
  4. 是否保存名字、关系、喂食和长期记忆?

第一次实现建议选择:Web 内角色 + 结构化状态 + 本地动作 + 无长期记忆。这条路径不需要独立进程、固定端口或额外 API Key,最容易验证插件契约。

第二步:建立最小 bundle

一个完整桌宠通常包含 Host 与 Client 两部分:

my-dafeiyu/
├── package.json
├── cordis.patch.yml
├── src/
│   ├── index.ts          # Host:事件、配置、Remote
│   ├── client.tsx        # Client:渲染、交互、设置
│   └── shared.ts         # 状态类型与协议
├── assets/
│   ├── pet.json
│   └── animations/
└── README.md

package.json 需要声明 DSH bundle/patch 入口,cordis.patch.yml 把插件行插入 Profile。不要手工修改 DSH 核心文件,也不要依赖用户每次升级后重新打补丁。

最小版本只需实现:插件启用、角色显示、空闲动画、设置中的显示开关、卸载后不影响 DSH 启动。

第三步:把 Host 作为状态真相源

Host 负责订阅 DSH 的 Session 与 Tool 事件,并把不同事件归一化成少量 UI 状态:

IDLE → THINKING → WORKING → WAITING
                  ├→ SUCCESS
                  └→ ERROR

Client 不应扫描聊天 DOM 或根据气泡文字猜状态。Host 应输出一个最小快照,例如当前 Session、状态、工具类别、开始时间和是否需要用户输入。

同时处理插件销毁:取消事件订阅、停止计时器、关闭原生 Helper、刷写必要配置。桌宠不能在 DSH 退出后留下孤儿进程。

第四步:先在 Web 内完成角色

Web 版本是最小可行产品。把角色挂在不会遮挡输入框和主要内容的 Overlay 区域,至少提供:

  • 拖动与位置保存;
  • 大小和不透明度;
  • 显示/隐藏;
  • 减少动态;
  • 状态气泡;
  • 键盘与屏幕阅读器不会被无意义动画干扰。

交互动画结束后必须回到最新的真实 Agent 状态,而不是固定回到 IDLE。这是桌宠状态机最常见的错误之一。

第五步:需要桌面常驻时再加原生 Helper

只有当用户需要在 VS Code、浏览器和文件管理器上方持续看到角色时,才需要原生透明窗口。Helper 应由 DSH Host 启动和回收,通过宿主通信获取最小状态,不应重新保存一套 API Key 或会话数据库。

原生窗口至少要处理:

  • 透明、无边框、置顶与多显示器;
  • 拖动、边缘与任务栏约束;
  • 穿透模式的恢复入口;
  • DPI、缩放与不同平台坐标;
  • DSH 异常退出后的进程清理;
  • Helper 不可用时回退到 Web 角色。

第六步:选择正确 Profile 测试

WebUI 通常使用 web Profile,官方 Desktop 使用 desktop Profile。它们的插件配置彼此独立。测试时要覆盖:

dsh plugin --profile web add ./my-dafeiyu.tgz
dsh plugin --profile desktop add ./my-dafeiyu.tgz

不要假设在 Web 安装后 Desktop 会自动出现。两边都启用原生窗口时,也要避免重复启动两个角色。

第七步:再加入派活入口

气泡输入框可以把文本发送给用户明确选择的 Session。第一版不要自动创建完全访问 Session,也不要在后台切换权限。

派活 UI 至少显示:目标 Session、工作区、运行/空闲状态和权限模式。发送失败保留草稿,Session 忙碌时说明是追加、排队还是打断。

第八步:最后加入记忆和养成

角色名字、位置、音量属于设置;亲密度、食物、事件历史属于养成状态;用户告诉角色的事实、人物关系和日记属于私密记忆。三类数据应分开保存和导出。

给存档加入版本号和迁移函数,写入时采用临时文件加原子替换,并保留上一份备份。不要把用户记忆写进插件安装目录,因为升级和卸载可能替换它。

最小验收标准

  • 安装、启用、禁用、升级和卸载不破坏 DSH;
  • 空闲、思考、工具、等待、成功、失败状态可复现;
  • 多 Session 时角色不会频繁抢状态;
  • 交互结束回到最新真实状态;
  • Web 与 Desktop Profile 行为清楚;
  • 不读取屏幕,不泄露 API Key;
  • 断开 Helper 或损坏配置时有安全回退;
  • 代码授权与角色素材授权分别列出。

下一步可分别完成角色素材与透明动画、Session 与 Tool Call 状态联动、记忆与养成系统以及权限边界检查。

参考资料