DeepSeek Harness 本地聊天记忆:按来源保存聊天原文,关键词 + 向量检索,可选大模型重排与检索摘要。源码公开,仅限非商用
浏览文件
main
分支
corpus.js
97 行 · 8.9 KB历史下载| 1 | /** |
| 2 | * Retrieval evaluation corpus: QQ-style private and group chats a companion would see. |
| 3 | * Synthetic and deterministic. `facts` carry the answers; `filler` is everyday chatter that |
| 4 | * shares common words with the queries, so ranking has to work for its place. |
| 5 | * |
| 6 | * Query kinds: |
| 7 | * exact the query reuses words from the record |
| 8 | * paraphrase different wording, still sharing some characters |
| 9 | * context the record that matches the query lacks the answer; it is in the next turn |
| 10 | * update a fact changed; the newer record must outrank the older one |
| 11 | * noisy the question is buried in a long bridge-style prompt |
| 12 | * semantic no shared characters at all; lexical retrieval cannot find it (tracked, not gated) |
| 13 | */ |
| 14 | const DAY = 86400000; |
| 15 | const T0 = Date.UTC(2026, 8, 1, 2, 0, 0); |
| 16 | const at = (day, minute = 0) => T0 + day * DAY + minute * 60000; |
| 17 | |
| 18 | export const OWNER = 'owner'; |
| 19 | export const GROUP = 'group:73120001'; |
| 20 | export const GROUP2 = 'group:73120002'; |
| 21 | export const OTHER = 'private:20002'; |
| 22 | |
| 23 | export const facts = [ |
| 24 | { key: 'cat', scope: OWNER, time: at(1), content: '用户:我家那只橘猫叫团子,三岁了,特别能吃\n助手:团子听起来好可爱!' }, |
| 25 | { key: 'birthday', scope: OWNER, time: at(2), content: '用户:跟你说哦,我生日是3月15号\n助手:记住啦,3月15号!' }, |
| 26 | { key: 'allergy', scope: GROUP, time: at(3), content: '用户:【新消息】\n阿杰:我对花生过敏,上次吃了一口宫保鸡丁直接进医院\n助手:天哪,那以后点菜得注意' }, |
| 27 | { key: 'trip-ask', scope: OWNER, time: at(4, 0), content: '用户:这周末去哪玩比较好\n助手:天气不错的话,海边或者爬山都可以' }, |
| 28 | { key: 'trip-decide', scope: OWNER, time: at(4, 3), content: '用户:那就海边吧,周六早上八点在地铁站集合\n助手:好嘞,到时候提醒你带防晒' }, |
| 29 | { key: 'home-old', scope: OWNER, time: at(5), content: '用户:我住在杭州西湖边上,周末经常去断桥散步\n助手:西湖边真舒服' }, |
| 30 | { key: 'home-new', scope: OWNER, time: at(40), content: '用户:我现在住在上海浦东了,上个月刚搬过来\n助手:新家怎么样?' }, |
| 31 | { key: 'game', scope: GROUP, time: at(6), content: '用户:【新消息】\n小明:今晚LOL五排有人吗,我黄金二\n助手:我可以围观吗哈哈' }, |
| 32 | { key: 'bili', scope: OWNER, time: at(7), content: '用户:我的B站账号叫咸鱼不想翻身,你可以去关注一下\n助手:已经记住你的B站名字了' }, |
| 33 | { key: 'exam', scope: OWNER, time: at(8), content: '用户:下周三我要考驾照科目二,好紧张\n助手:倒车入库多练练,你可以的' }, |
| 34 | { key: 'promise', scope: GROUP, time: at(9), content: '用户:【新消息】\n小红:你答应过要给我们唱一首晴天的\n助手:好好好,等我练好了就唱' }, |
| 35 | { key: 'food', scope: OWNER, time: at(10), content: '用户:我不吃香菜,一点都不行,闻到就想吐\n助手:好的,以后推荐菜都避开香菜' }, |
| 36 | { key: 'work-ask', scope: OWNER, time: at(11, 0), content: '用户:今天面试的结果出来了\n助手:怎么样怎么样?' }, |
| 37 | { key: 'work-answer', scope: OWNER, time: at(11, 2), content: '用户:过了!下个月一号去字节报到,做前端\n助手:太棒了,恭喜!' }, |
| 38 | { key: 'medicine', scope: OWNER, time: at(12), content: '用户:医生让我每天晚上九点吃一次降压药\n助手:我到点提醒你' }, |
| 39 | { key: 'group-rule', scope: GROUP2, time: at(13), content: '用户:【新消息】\n群主:本群禁止发广告,发一次直接踢\n助手:收到,我会乖乖的' }, |
| 40 | { key: 'secret', scope: OTHER, time: at(14), content: '用户:别告诉别人,我其实在准备辞职\n助手:放心,我不会说出去的' }, |
| 41 | { key: 'plant', scope: OWNER, time: at(15), content: '用户:阳台那盆绿萝最近叶子发黄\n助手:可能是浇水太多了,等土干了再浇' }, |
| 42 | ]; |
| 43 | |
| 44 | export const queries = [ |
| 45 | { kind: 'exact', scope: OWNER, q: '团子最近还好吗', expect: ['cat'], answer: '橘猫' }, |
| 46 | { kind: 'exact', scope: OWNER, q: '还记得我生日是几号吗', expect: ['birthday'], answer: '3月15号' }, |
| 47 | { kind: 'exact', scope: GROUP, q: '阿杰能吃花生吗', expect: ['allergy'], answer: '过敏' }, |
| 48 | { kind: 'exact', scope: OWNER, q: '我B站叫什么来着', expect: ['bili'], answer: '咸鱼不想翻身' }, |
| 49 | { kind: 'exact', scope: GROUP, q: '小明LOL什么段位', expect: ['game'], answer: '黄金二' }, |
| 50 | { kind: 'exact', scope: OWNER, q: '降压药几点吃', expect: ['medicine'], answer: '九点' }, |
| 51 | { kind: 'paraphrase', scope: OWNER, q: '我的猫叫啥名字', expect: ['cat'], answer: '团子' }, |
| 52 | { kind: 'paraphrase', scope: OWNER, q: '科目二考得怎么样', expect: ['exam'], answer: '下周三' }, |
| 53 | { kind: 'paraphrase', scope: GROUP, q: '你是不是欠我们一首歌', expect: ['promise'], answer: '晴天' }, |
| 54 | { kind: 'paraphrase', scope: OWNER, q: '点外卖要注意我什么口味', expect: ['food'], answer: '香菜' }, |
| 55 | { kind: 'paraphrase', scope: OWNER, q: '绿萝怎么救', expect: ['plant'], answer: '浇水' }, |
| 56 | { kind: 'paraphrase', scope: GROUP, q: '群里能发广告吗', expect: ['group-rule'], answer: '踢' }, |
| 57 | { kind: 'context', scope: OWNER, q: '周末去哪玩来着', expect: ['trip-ask', 'trip-decide'], answer: '八点' }, |
| 58 | { kind: 'context', scope: OWNER, q: '面试结果怎么样了', expect: ['work-ask', 'work-answer'], answer: '字节' }, |
| 59 | { kind: 'update', scope: OWNER, q: '你记得我住在哪吗', expect: ['home-new'], answer: '上海', older: 'home-old', olderAnswer: '杭州' }, |
| 60 | { kind: 'noisy', scope: GROUP, q: '__BOILER__\n【新消息】\n小红:话说阿杰是不是有什么不能吃的\n__TAIL__', expect: ['allergy'], answer: '花生' }, |
| 61 | { kind: 'noisy', scope: OWNER, q: '__BOILER__\n【新消息】\n主人:我的猫最近不爱吃饭\n__TAIL__', expect: ['cat'], answer: '团子' }, |
| 62 | { kind: 'semantic', scope: OWNER, q: '宠物多大了', expect: ['cat'], answer: '三岁' }, |
| 63 | { kind: 'semantic', scope: OWNER, q: '新工作在哪家公司', expect: ['work-answer'], answer: '字节' }, |
| 64 | ]; |
| 65 | |
| 66 | /** Long fixed instructions a bridge prepends to every prompt; the same each turn. */ |
| 67 | export const BOILER = [ |
| 68 | '【当前角色】小鲸鱼(继续按角色卡说话)', |
| 69 | '【反AI味】你不是客服:不用有求必应,可以装傻、已读乱回、拒绝推荐;少用“一绝/真管用/保证/绝对”这类词。', |
| 70 | '【积极性】不要习惯性潜水:群里有你能接的话题就主动参与,偶尔插一句别人的话题也很正常;只有确实没话可说时才潜水。', |
| 71 | '【引用:只在必要时用】只有你这条消息指向的人或消息并非最新一条别人的消息时,才引用具体那条;其他情况不要引用。', |
| 72 | '【表情包】可以用表情包回复,但不要每句都发,一般三四句话里最多一个。吃饭睡觉上班这种日常话题随便聊。', |
| 73 | ].join('\n'); |
| 74 | export const TAIL = '请根据情况决定是否回复。如果不需要回应、想潜水/不接话,请只输出 [SILENT];否则正常回复。今天也要开开心心的哦。'; |
| 75 | |
| 76 | const fillerLines = [ |
| 77 | ['今天吃什么好呢', '要不点个外卖吧'], ['好困啊想睡觉', '那就早点睡'], ['上班好累', '摸摸头,辛苦了'], |
| 78 | ['哈哈哈哈笑死我了', '什么这么好笑'], ['周末有什么安排', '还没想好呢'], ['下雨了没带伞', '找个地方躲躲雨吧'], |
| 79 | ['刚吃完火锅好撑', '火锅永远的神'], ['你在干嘛呢', '在等你说话呀'], ['我最近在追一部剧', '什么剧呀好看吗'], |
| 80 | ['好想放假', '快了快了再坚持一下'], ['今天地铁好挤', '早高峰就是这样'], ['晚饭吃了面条', '面条也挺好的'], |
| 81 | ['我的猫粮快没了', '记得去买呀'], ['明天要早起', '那今晚别熬夜了'], ['这个月工资还没发', '再等等吧'], |
| 82 | ['周六好像要下雨', '那就在家休息'], ['我朋友今天生日', '记得说生日快乐'], ['医院排队排了好久', '辛苦啦'], |
| 83 | ['刚打完一把游戏', '赢了吗'], ['考试终于结束了', '恭喜解放'], ['在看B站视频', '看什么呢'], |
| 84 | ['想去海边看日落', '听起来好浪漫'], ['我住的地方好吵', '戴个耳塞试试'], ['晚上九点有个会', '会开完早点休息'], |
| 85 | ]; |
| 86 | /** Deterministic everyday chatter across all scopes, spread over the same weeks as the facts. */ |
| 87 | export function filler() { |
| 88 | const scopes = [OWNER, GROUP, GROUP2, OWNER, GROUP]; |
| 89 | const out = []; |
| 90 | for (let i = 0; i < 240; i++) { |
| 91 | const [user, reply] = fillerLines[i % fillerLines.length]; |
| 92 | const scope = scopes[i % scopes.length]; |
| 93 | const speaker = scope.startsWith('group:') ? `【新消息】\n${['小明', '小红', '阿杰', '路人甲'][i % 4]}:` : ''; |
| 94 | out.push({ key: 'filler-' + i, scope, time: at(1 + (i % 45), 30 + (i % 300)), content: `用户:${speaker}${user}\n助手:${reply}` }); |
| 95 | } |
| 96 | return out; |
| 97 | } |

