我把 Roam Planner 重写成了 DeepSeek Harness(DSH)插件:在现有对话里规划旅行,把结果落到日程和地图,继续对话修订,满意后采用。
宿主提供运行环境,我保留旅行规则。
一、用户少部署一套系统
| 对比项 | 原独立应用 | DSH 插件 |
|---|---|---|
| 运行环境 | Docker,默认四个服务 | 复用已有 DSH |
| 模型与会话 | 单独配置和运行 | 使用宿主配置 |
| 旅行界面 | 独立网站 | 工作台+对话地图抽屉 |
| 基础地点与路线 | 配置来源服务 | Nominatim+OSRM 可用 |
| 铁路、小红书 | 外部来源接入 | 可选 MCP,仍需配置 |
原版四个服务是 trek、agent、sources、铁路 MCP;前后端同在 trek 容器中。Compose 配置
已有 DSH 环境的用户:
- 在插件管理器安装
dsh-roam-planner。 - 重启 DSH,加载旅行工具与界面。
- 开始对话:中国地址可按需配置高德 Web 服务 Key。
前提: DSH ^0.2.1-rc.2,且模型连接可用。完整步骤见安装说明。
二、哪些交出去,哪些留下来
Pi Durable 已承担原应用的持久会话与子任务运行。迁入 DSH 后,我进一步复用了界面、配置和服务入口。
| 接入点 | 宿主提供 | 插件保留 |
|---|---|---|
| 界面槽位 | 页面入口、生命周期 | 日程与地图交互 |
| 存储域 | 数据读写 | 状态机、修订号、保存逻辑 |
| 凭据服务 | 敏感值保存 | Key 配置和服务端调用 |
| 工具注册 | 模型调度 | 旅行操作与参数校验 |
| 通用搜索 | 已启用的搜索能力 | 来源适配、MCP 桥、铁路查询收窄 |
接口速查
- 工作台:
main+sidebar.panellist - 对话地图抽屉:
shell.overlay - 设置区:
settings.section - 前端产物:包内
client.bundle.js
当前地图抽屉会覆盖部分对话区域,尚未实现挤窄聊天栏的真正分栏。原应用已能同时显示地图和聊天,这次改变的是接入宿主的方式。
三、对话如何变成可采用的行程
12 个注册项 = 8 个旅行工具+3 个 MCP 工具+1 个诊断工具。
旅行工具覆盖读取、改稿、单日更新、保存候选、采用、路线、天气和地点查询。宿主负责调度,插件负责执行与保存。
- 存储: 优先使用宿主存储域,不可用时退回 JSON 文件。
- 凭据: 高德 Key 写入凭据服务;状态查询仅返回是否配置。
- 路线: 有轨迹就画路网,暂缺轨迹时用虚线连线示意。
四、三次翻车
01 · Cookie 跟着源码进了仓库
sidecar 继承仓库
cwd→ 写入cookies.json→ 批量暂存、提交。
| 问题 | 处理与边界 |
|---|---|
| 登录产物混进源码 | 固定 sidecar 工作目录,忽略 Cookie 与二维码文件 |
| 文件进入提交 | 删除跟踪文件,改写相关提交并推送 |
| 旧凭据是否失效 | 必须单独核验,清理仓库不能代替作废会话 |
教训:外部进程的数据目录,需要显式约定。 凭据泄露还应先撤销旧凭据,再处理历史副本。GitHub 处理建议
02 · 有坐标,不等于地点正确
山东行程里曾出现:趵突泉 → 西安附近,芙蓉街 → 云南,大明湖 → 新疆。
原因:名称解析缺少城市约束。高德 city 为空时全国检索,且该参数不支持县级市。接口说明
工具前置约束: 需要解析地点名称却没传城市,直接拒绝。有城市参考点时,再检查异常偏离:
80 km 只是粗筛。 它拦不住偏移 35 km 的同名地点;参考点缺失时也无法检查。POI 重查结果仍须结合名称、地址与行政区核对。
批量查询的另一道坎:限频。
- 高德地理编码:当前间隔 450 ms;配额错误时尝试 Nominatim。
- Nominatim:单独使用 1100 ms 间隔。
- 这些是本次实现参数;备用来源的结果同样需要校验。
03 · 顺着缺包报错,补装出多套宿主依赖
为了接入博客 MCP,我尝试在 profile 中引用宿主的 dsh-mcp-client,随后一路补装缺失依赖,连带引入多组宿主包和另一份 Cordis,最后回退修复。
| 当时的假设 | 后来确认的边界 |
|---|---|
| 应用内置了,就能直接引用 | profile 的包解析路径需要确认 |
| 缺什么就补什么 | 还要确认宿主版本、加载入口与依赖关系 |
| 这次失败说明不支持外部 MCP | 只能说明这次接入方式出了问题 |
插件自己的 MCP 桥已支持 stdio、Streamable HTTP、自定义请求头;它与宿主级 MCP 配置是不同的接入路径。
另外两个契约坑:
type: ['number', 'null']超出当时宿主接受的 schema 子集,导致插件激活失败、路由不可用。后来用测试遍历实际工具定义;JSON Schema 本身支持多类型。- 包内放了
SKILL.md,仍需显式调用ctx.skills.register注册。
五、最后交付了什么
版本 0.2.3 · 23 个文件 · 压缩约 355 KiB · 解包约 1.30 MiB
- 对话改稿、候选与采用
- 日程、地图、路线、天气
- 可选铁路与小红书 MCP 接入
- 原独立应用的预算、预订、文件、协作页面——本次未重写
对应 CI 已通过类型检查与 13 个测试文件,通过 npm Trusted Publishing 发布,产物带 provenance。模型规划质量与来源稳定性,仍要靠真实场景检验。
| 得到 | 付出 |
|---|---|
| 复用对话、配置和界面入口 | 依赖宿主版本与槽位约束 |
| 少维护一套通用运行环境 | 旅行规则、适配与外部服务继续维护 |
用一部分控制权,换掉一整类重复劳动。
记录基于 2026-10-21 · 0.2.3 · 提交 a449dd1。后续变化以项目仓库为准。
评论 0
还没有评论,欢迎留下第一个想法。