TeamPulse
装一个插件,让你的团队记忆留在自己手里。
TeamPulse 是一个 DeepSeek Harness(DSH)插件。它做一件很窄但很硬的事:
把团队的会议纪要、技术文档、群聊记录收进本地数据库,需要时按关键词召回,每条结果都带可回溯的引用。
【d783055c2438f#0】产品评审会 2026-10-14(meeting · 2026-10-14T14:00:00+08:00)
决议:十一月底前完成用户系统重构,由张三负责。
待办:张三 输出用户系统重构方案,截止 2026-10-20
为什么需要它
会议纪要这件事,已经不缺工具了:
- 腾讯会议有智能纪要、元宝纪要
- 飞书有妙记,企微、钉钉都有 AI 助手
- SkillHub 上搜「会议纪要」有一千多个 skill
它们都能把一场会总结得很好。但它们都缺三样东西:
| 缺什么 | 后果 |
|---|
| 跨源 | 会议定了什么、文档里写了什么、群里又改了什么,没人拼在一起 |
| 引用 | AI 给的结论无从核对,团队不敢真用 |
| 归属 | 数据在平台里,换个 AI 就没了 |
TeamPulse 只补这三样。不重复做大厂已经做好的事。
设计取舍
只做存储和检索,不做 LLM 提取
插件里没有一行 prompt。
决议、待办、摘要这些结构化提取,交给 DSH 里的模型自己做——它比任何内嵌模板都强,而且换模型不用改代码。
插件只负责模型做不到的事:落库、索引、给出可引用的原文。
零运行时依赖
DSH 版本迭代快。插件一旦 import @deepseek-ai/dsh-tools,宿主一升级就可能跑不起来。
所以这个插件:
- 不 import 任何 DSH 内部包
- 只要求
ctx.tools.register(definition) 这个最稳定的契约
- 所有包都用原生 JS + JSDoc,不用编译
数据在你自己的磁盘上
一个 SQLite 文件,默认 ~/.dsh/teampulse/team.db。
- 不上传,不同步
- 一条命令清空
- 换 AI(DSH / 豆包 / 自己的 agent)继续用同一份记忆
安装
# 从本地目录安装
dsh plugin --profile default add /path/to/dsh-teampulse
# 之后正常启动
dsh web --profile default
或者用 patch 覆盖层临时加载(开发时方便):
# cordis.yml
- insert:
- id: teampulse
name: '/absolute/path/to/dsh-teampulse/index.js'
config:
dbPath: '~/.dsh/teampulse/team.db'
可选配置项:
config:
dbPath: '~/.dsh/teampulse/team.db' # 库文件位置
chunkSize: 900 # 单片段字符数
chunkOverlap: 120 # 相邻片段重叠
maxHits: 12 # 单次检索默认返回条数
maxChunkChars: 4000 # 单片段硬上限
四个工具
team_remember — 入库
把这段产品评审会的纪要存起来,标题「产品评审会 2026-10-14」,
时间是 2026-10-14T14:00:00+08:00,标签 产品、权限
| 参数 | 必填 | 说明 |
|---|
content | 二选一 | 正文全文。会议纪要直接贴,不要先摘要 |
filePath | 二选一 | 从本地文件读取正文 |
title | ✅ | 标题 |
source | | meeting / doc / chat / note / text |
sourceRef | | 会议号、文档 URL、群名,便于回溯原处 |
author | | 作者/记录人 |
occurredAt | | ISO 8601,用于时间过滤 |
tags | | 标签数组 |
返回 docId(d + 内容哈希前 12 位)和片段数。
同一正文重复入库会自动去重,返回已有 docId——这样周报里不会出现三遍同一个决定。
team_recall — 检索
之前谁提过用户权限的方案?
| 参数 | 必填 | 说明 |
|---|
query | ✅ | 关键词或短句。中文建议 2~8 字 |
limit | | 返回条数,默认 12,上限 50 |
source | | 只看某类来源 |
since / until | | 时间范围过滤 |
每条结果都带 citation: "d783055c2438f#0" —— 指向库中具体片段。
team_docs — 看看有什么
我的团队记忆里都存了什么?
列出已入库的文档(按入库时间倒序),带 docId、来源、时间、片段数。
回答「存过哪些会议」这类问题时用它,比空转检索更直接。
team_forget — 删除
把 d783055c2438f 这份删掉
| 参数 | 说明 |
|---|
docId | 删单份。不传则清空全部 |
confirm | 清空全部时必须传 true |
这是「数据在你手里」的兑现——不是你信我,是你随时能删。
清空全部需要显式确认,防止模型自作主张把记忆清空。
典型用法
一场会开完
你:把这段会议纪要存起来,标题「产品评审会 10/14」,来源 meeting
Agent:[调 team_remember] 已入库:产品评审会 10/14 ...
一周结束了
你:这周定了什么?谁欠什么活?
Agent:[调 team_recall 查"决议""待办"]
基于检索结果整理:
- 用户系统重构 11 月底前完成(【d783...#0】)
- 张三欠一份重构方案,10/20 到期(【d783...#0】)
关键是那些方括号引用——每条结论都能点回原文。
同一件事跨了三处
你:用户权限这事到底怎么定的?
Agent:[多次 team_recall]
会议里说参考 RBAC(【d783...#0】)
文档里定的是 RBAC + ABAC 混合(【a1b2...#1】)
结论:会议提的方向,文档细化为混合模型
这是大厂工具做不到的——它们只看得见自己生态里的数据。
技术细节
中文全文检索
SQLite FTS5 + trigram 分词。
这是关键:默认的 unicode61 分词器切不了中文(会把整句当一个词)。trigram 按三字符窗口建索引,中文能正常匹配。
代价是 trigram 要求查询词 ≥ 3 字符。所以 team_recall 对 1~2 字的短查询自动降级为 LIKE 扫描。
切分策略
按字符数切,但在窗口后 40% 范围内优先找自然断点:
\n\n > \n > 。!?; > . ! ? ;
中文没有空格,纯按长度切会把句子拦腰截断,检索出来的片段读着别扭。
相邻片段保留 120 字重叠,避免关键信息正好落在切口上。
引用格式
docId#seq
docId = d + 正文 SHA-256 前 12 位 —— 内容相同则 ID 相同,天然幂等
seq = 片段在该文档内的序号
这个 ID 是稳定的:同样的内容,无论在谁的机器上入库,ID 都一样。
测试
# 纯逻辑测试(不依赖 DSH,直接跑)
node test/smoke.mjs
# 集成测试(真实 Cordis + 真实 tools 注册表加载插件)
# E2E(真实 dsh CLI 装进临时 profile → 配置合成 → 真实 dispatch → 查盘)
DSH_REPO=/path/to/deepseek-harness node test/integration.mjs
DSH_REPO=/path/to/deepseek-harness node test/e2e.mjs
DSH_REPO 指向你的 deepseek-harness 源码 checkout(需要已 pnpm install 并 build 过)。没设置时这两个测试会直接退出并提示。
当前状态:
| 测试 | 数量 | 结果 | 内容 |
|---|
| smoke | 27 | ✅ | 切分、FTS、去重、过滤,自带桩 |
| integration | 52 | ✅ | 真实 Cordis 加载 + 四工具全链路 |
| e2e | 14 | ✅ | CLI 安装 + dispatch 管道 + 落盘 |
不做什么
明确写下来,免得越做越散:
- ❌ 不做会议纪要生成 —— 腾讯会议/飞书/企微已有,且免费
- ❌ 不接腾讯会议 API —— 需要时用官方
@tencent-adm/tencent-meeting-mcp,插件不重复造
- ❌ 不内置 LLM prompt —— 交给宿主模型
- ❌ 不做向量检索 —— FTS5 trigram 对团队规模的语料足够,向量库是过度设计
- ❌ 不上云、不同步 —— 这是卖点不是缺陷
路线
v0.1(当前)
v0.2
v0.3
License
MIT