deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
让 Agent 的记忆能力向人类靠拢:人脑可以在不同任务间随时切换,靠的是对事件建立多维触点(关键词、视角、触发物…),触点被当前情境激活后,从长期记忆快速拉取事件细节。本插件把这一机制在 dsh(DeepSeek Harness)上落地。
人脑记忆模型 本插件实现
───────────────── ─────────────────────────────
事件经历 触点库中的 topic(带摘要+关键词+时间)
事件触点(关键词/视角/触发物) topic.keywords + dimensions
情境激活触点 → 唤醒事件 用户新消息关键词 → 扫描触点库
话题切换 → 快速拉取细节 重合度低于阈值 → 注入记忆唤醒上下文
记忆渐进完善 每次触碰更新 lastTouchedAt / 合并关键词
┌─ 写入侧(建库,每轮 turn 结束时)─────────────────────┐
│ agent/status=idle → 读本 turn 文本 │
│ ├─ 对话级触点:本轮关键词(2~4 字中文 gram + 英文词)│
│ ├─ 任务级触点:session 聚合关键词(合并更新) │
│ └─ 用户惯用词:近 N 轮窗口的高频个人用词(第二类) │
│ → upsert 进全局触点库(原子写 JSON) │
└───────────────────────────────────────────────────────┘
┌─ 唤醒侧(话题切换时,每步组装前)─────────────────────┐
│ systemPrompt.context() provider(同步契约) │
│ → 提取新消息关键词 → 与上轮关键词算重合度 │
│ → 重合度 < 阈值 = 话题切换 │
│ → 扫描触点库(关键词 TF 加权 / 向量余弦) │
│ → 命中 top-N → 注入 <system-reminder> 记忆唤醒块 │
│ → 命中用户惯用词 → 追加「用户惯用词」提示行 │
└───────────────────────────────────────────────────────┘
使用 systemPrompt.context() 注册动态上下文:每次 prompt 组装时求值 provider,生成带来源的 runtime-context 快照,随请求发送但不写入持久 session 历史。话题不切换时不注入,保持上下文干净。这正是与 agent-instructions(持久注入)的关键区别。
| 配置 | 默认 | 说明 |
|---|---|---|
topic.switchDetection |
true |
开启话题切换检测 |
topic.switchThreshold |
0.25 |
关键词重合度低于此值视为切换(0~1) |
topic.scanEveryTurn |
false |
每轮都扫描(灵敏但开销大);false 时只在切换时扫描 |
| 模式 | 成本/次唤醒 | 效果 | 适用 |
|---|---|---|---|
keyword(TF 加权穷举) |
0(纯本地) | 词面重合准确,语义弱 | 无外部 key |
vector(向量余弦) |
≈ ¥0.000025(见下) | 语义匹配强 | 有 embedding key |
auto(默认) |
— | 有 key 用向量,否则降级关键词 | 推荐 |
⚠️ DeepSeek 官方 API 不提供 embedding 端点(见 issue #806),向量模式走 OpenAI 兼容接口(默认 SiliconFlow
BAAI/bge-m3)。库向量在写入时预计算并缓存,唤醒时只编码 1 条 query,不重复计费。
成本估算(bge-m3 / SiliconFlow,2026-08 行情):
监听全局 agent/created,对每个 agent 挂载唤醒/写入钩子,不限于飞书。userId 从 session id 提取(feishu:ou_xxx → ou_xxx;其他 session 用完整 id),按用户分片存储。
触点库存于 $DSH_HOME/storages/cue-bank/users/<userId>.json(默认),跨 profile、跨会话共享;可用 storageRoot 覆盖。单用户触点上限 200 条(LRU 淘汰),惯用词上限 50 条。
/home/ubuntu/dsh-cue-bank)在 profile 的 package.json 加依赖:
"dependencies": {
"@local/dsh-cue-bank": "file:/home/ubuntu/dsh-cue-bank"
}
在 profile 的 cordis.patch.yml 插入:
- insert:
- id: cue-bank
name: '@local/dsh-cue-bank'
config:
storageRoot: ''
matchMode: 'auto'
embedding:
provider: 'openai-compatible'
baseURL: 'https://api.siliconflow.cn/v1'
apiKeyEnv: 'SILICONFLOW_API_KEY'
model: 'BAAI/bge-m3'
dimensions: 1024
topic:
switchDetection: true
switchThreshold: 0.25
scanEveryTurn: false
inject:
enabled: true
maxCues: 3
maxDetailChars: 400
dbg: false
cd ~/.dsh/profiles/web && pnpm install
# 重启 dsh web 后生效(插件在启动时加载)
| 键 | 默认 | 说明 |
|---|---|---|
storageRoot |
'' |
空 = $DSH_HOME/storages/cue-bank |
matchMode |
auto |
auto | keyword | vector |
embedding.baseURL |
https://api.siliconflow.cn/v1 |
OpenAI 兼容端点 |
embedding.apiKeyEnv |
SILICONFLOW_API_KEY |
API key 环境变量名 |
embedding.model |
BAAI/bge-m3 |
嵌入模型 |
embedding.dimensions |
1024 |
向量维度 |
embedding.timeoutMs |
5000 |
嵌入超时 |
topic.switchDetection |
true |
话题切换检测开关 |
topic.switchThreshold |
0.25 |
切换阈值(关键词重合度) |
topic.scanEveryTurn |
false |
每轮扫描 |
topic.maxKeywords |
10 |
每轮提取关键词数 |
inject.enabled |
true |
唤醒注入开关 |
inject.maxCues |
3 |
最多注入几条记忆 |
inject.maxDetailChars |
400 |
单条细节截断长度 |
extract.enabled |
true |
建库开关 |
extract.maxKeywordsPerTurn |
12 |
每轮入库关键词数 |
extract.keywordMinLen |
2 |
关键词最小长度 |
extract.userIdiomWindowTurns |
10 |
惯用词统计窗口(轮) |
extract.maxIdiomHints |
5 |
唤醒时最多提示几个惯用词 |
dbg |
false |
调试日志 |
{
"version": 1,
"userId": "ou_xxx",
"idiosyncrasies": [ // 第二类触点:用户用词偏好
{ "word": "闭环", "score": 0.2, "firstSeen": "...", "lastSeen": "..." }
],
"topics": [ // 第一类触点:事件
{
"id": "t-...",
"level": "task" | "conversation",
"keywords": [ { "word": "飞书插件", "score": 0.035 } ],
"summary": "对话: 讨论飞书插件…",
"dimensions": { "trigger": "keywords", "perspective": "task" },
"embedding": [0.1, 0.2, ...] | null, // 向量模式缓存
"refSessions": ["feishu:ou_xxx"],
"createdAt": "...", "lastTouchedAt": "...", "hitCount": 3
}
]
}
<system-reminder>
📌 记忆唤醒(cue-bank): 检测到话题切换,以下为与该话题相关的历史记忆,可作为参考:
- [conversation] 对话: 我想做一个飞书插件,用来管理跨会话记忆…
触点命中: 飞书插件、插件
最近提及: 2026-08-15
细节: 对话: 我想做一个飞书插件…
- [task] 任务: 我想做一个飞书插件…
用户惯用词: 形成闭环、闭环(用户习惯的表述,回复可顺应)
</system-reminder>
调研日期:2026-08,基于 dsh-base 实际装配的插件清单逐一核验源码/README。
结论:核心能力几乎不重复(估计重复度 10-15%),方向相反——官方是「被动查询」,cue-bank 是「自动记忆 + 主动唤醒」。
| 官方插件(dsh-base 已装配) | 做什么 | 与 cue-bank 重复度 |
|---|---|---|
dsh-session-query + sqlite |
会话历史 FTS5 全文检索、关系追踪(被动查询 API,需有人调用) | ⚠️ 低——管"查",不管"自动记+自动唤醒" |
dsh-session-reference |
显式 @ 引用跨会话快照注入(需用户主动提及,dsh-base 默认未启用) |
⚠️ 低——被动触发 vs 话题切换主动触发 |
dsh-compaction(-basic) |
同会话内 token 压力摘要压缩(管理当前窗口) | ✅ 无——不跨会话 |
dsh-agent-instructions |
AGENTS.md/CLAUDE.md 静态指令文件加载 | ✅ 无——静态文件 |
dsh-spill |
超大工具输出暂存+取回定位 | ✅ 无——存储优化 |
cue-bank 独有能力(官方全部缺失):
systemPrompt.context() 动态组装,无需用户提及(官方 session-reference 必须显式 @)$DSH_HOME/storages/cue-bank/(官方是 SQLite/JSONL 原始日志)协同方向(可选,不影响当前设计):未来可用 session-query 的 FTS 作为 cue-bank 的补充召回通道——关键词穷举漏掉的记忆用全文搜索兜底,互补而非竞争。
cd dsh-cue-bank && node test/integration.test.js # 13/13 通过
覆盖:写入建库、话题切换唤醒、同话题抑制、无关话题抑制、惯用词提取、惯用词参与唤醒(第二类触点闭环)。
真实环境验证(headless profile,真实 dsh 进程):插件加载无报错、turn 结束自动写入全局触点库(conversation+task 两级)、emoji 过滤生效。
用本地 mock OpenAI 兼容 embedding 服务器验证代码路径,未调用任何真实 API:
/embeddings、Bearer auth、OpenAI 兼容格式)available=false → matchMode: auto 自动降级 keyword启用向量模式只需设置 SILICONFLOW_API_KEY 环境变量(或配置 embedding.apiKey),无需改代码或配置。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。