fix(memory): add bounded hybrid recall
Memind CI / Test, build, and release guards (push) Successful in 3m52s
Memind CI / Test, build, and release guards (push) Successful in 3m52s
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { createMemoryV2 } from './memory-v2.mjs';
|
||||
import { createPgvectorMemoryBackend } from './memory-v2-pgvector.mjs';
|
||||
import {
|
||||
createPgvectorMemoryBackend,
|
||||
pgvectorMemoryBackendInternals,
|
||||
} from './memory-v2-pgvector.mjs';
|
||||
|
||||
test('pgvector backend is disabled by default and does not query storage', async () => {
|
||||
let queried = false;
|
||||
@@ -85,7 +88,9 @@ test('pgvector backend performs parameterized vector lookup when explicitly enab
|
||||
|
||||
assert.equal(queries.length, 1);
|
||||
assert.match(queries[0].sql, /FROM memory_embeddings/);
|
||||
assert.deepEqual(queries[0].params, ['user-1', '[0.25,0.5,0.75]', 5]);
|
||||
assert.match(queries[0].sql, /WITH vector_candidates/);
|
||||
assert.match(queries[0].sql, /recent_candidates/);
|
||||
assert.deepEqual(queries[0].params, ['user-1', '[0.25,0.5,0.75]', 50]);
|
||||
assert.deepEqual(result.semanticMemories, ['用户关注 Memory V2 的 facade 边界']);
|
||||
assert.deepEqual(result.memories, [
|
||||
{
|
||||
@@ -94,10 +99,68 @@ test('pgvector backend performs parameterized vector lookup when explicitly enab
|
||||
text: '用户关注 Memory V2 的 facade 边界',
|
||||
score: 0.87,
|
||||
createdAt: '2026-07-02T00:00:00.000Z',
|
||||
updatedAt: '2026-07-02T00:00:00.000Z',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('pgvector hybrid ranking recovers a recent Chinese memory missed by vector top-k', async () => {
|
||||
const marker = 'MEM-RECALL-NEW';
|
||||
const backend = createPgvectorMemoryBackend({
|
||||
enabled: true,
|
||||
pool: {
|
||||
async query() {
|
||||
return {
|
||||
rows: [
|
||||
{
|
||||
id: 1,
|
||||
content: '用户以前关注贵州旅游攻略',
|
||||
type: 'interest',
|
||||
score: 0.91,
|
||||
created_at: '2026-06-01T00:00:00.000Z',
|
||||
updated_at: '2026-06-01T00:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: `用户的记忆召回灰度测试代号是 ${marker}`,
|
||||
type: 'fact',
|
||||
score: -0.49,
|
||||
created_at: '2026-07-22T00:00:00.000Z',
|
||||
updated_at: '2026-07-22T00:00:00.000Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: '用户偏好简洁回答',
|
||||
type: 'preference',
|
||||
score: 0.3,
|
||||
created_at: '2026-07-21T00:00:00.000Z',
|
||||
updated_at: '2026-07-21T00:00:00.000Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
},
|
||||
embedQuery: async () => [0.25, 0.5, 0.75],
|
||||
});
|
||||
|
||||
const result = await backend.resolve({
|
||||
userId: 'user-1',
|
||||
query: '我之前让你记住的记忆召回灰度测试代号是什么?请只回答完整代号。',
|
||||
limit: 3,
|
||||
});
|
||||
|
||||
assert.match(result.memories[0].text, new RegExp(marker));
|
||||
});
|
||||
|
||||
test('pgvector hybrid ranking keeps vector order when query has no lexical overlap', () => {
|
||||
const ranked = pgvectorMemoryBackendInternals.rankHybridCandidates([
|
||||
{ id: 1, content: 'alpha', score: 0.2 },
|
||||
{ id: 2, content: 'beta', score: 0.8 },
|
||||
], '完全无关的中文查询', 2);
|
||||
assert.equal(ranked[0].id, '2');
|
||||
assert.equal(ranked[1].id, '1');
|
||||
});
|
||||
|
||||
test('pgvector backend validates table names before building SQL', () => {
|
||||
assert.throws(
|
||||
() => createPgvectorMemoryBackend({ tableName: 'memory_embeddings;DROP TABLE users' }),
|
||||
|
||||
Reference in New Issue
Block a user