Vectorize
长期语义记忆。"Margaret 怎么看 Tom?"——靠语义而非关键词来回答。
什么是 Vectorize?
Cloudflare Vectorize 是一个无服务器向量数据库,与 Workers 深度集成。
在 AI World Sim 中,它将 NPC 的长期记忆 存储为向量嵌入。当模拟需要为某个 NPC 召回相关的过往事件时,通过语义相似度进行查询。
为什么需要向量记忆?
D1 按时间顺序存储记忆。要单独用 D1 找到 "Margaret 怎么看 Tom?",就得扫描她的所有日记。
有了 Vectorize:
- 嵌入查询:"Margaret 对 Tom 的看法"
- 向 Vectorize 查询最相似的 Top-K 条记忆
- 瞬间返回语义相关的记忆
这与人类记忆的工作方式一致——我们按意义而非日期来回忆。
索引结构
我们为整个 NPC 记忆语料使用一个 Vectorize 索引,通过元数据按 NPC 过滤。
元数据结构
每个向量携带元数据:
ts
interface VectorMetadata {
npcId: string;
type: 'event' | 'relationship' | 'opinion' | 'place';
day: number;
importance: number;
decayFactor: number;
textPreview: string;
}嵌入模型
默认使用 OpenAI 的 text-embedding-3-small(1536 维)。也可以使用 Workers AI 的 @cf/baai/bge-base-en-v1.5(768 维)作为免费的本地嵌入方案。
何时进行记忆嵌入
1. 实时嵌入(Tick 过程中)
当一条高重要性的短期记忆被创建(importance > 0.7)时,立即嵌入并写入 Vectorize。
ts
async function indexMemory(memory: ShortTermMemory, env: Env) {
const embedding = await embed(memory.content, env);
await env.VECTORIZE.upsert([{
id: memory.id,
values: embedding,
metadata: {
npcId: memory.npcId,
type: 'event',
day: memory.worldTime.day,
importance: memory.importance,
decayFactor: 0,
textPreview: memory.content.slice(0, 200),
},
}]);
}2. 后台整合(每 6 小时)
较旧的每日摘要会被浓缩为 1~2 句话并进行嵌入。
检索 API
简单查询
ts
async function recall(npcId: string, query: string, env: Env, topK = 5) {
const queryEmbedding = await embed(query, env);
const results = await env.VECTORIZE.query(queryEmbedding, {
topK,
filter: { npcId },
returnMetadata: true,
});
return results.matches.map(m => ({
text: m.metadata.textPreview,
importance: m.metadata.importance,
day: m.metadata.day,
score: m.score,
}));
}加权查询
在决策场景下,会应用衰减权重:
ts
function weightedRecall(matches: Match[], currentDay: number) {
return matches
.map(m => ({
...m,
effectiveScore: m.score * m.metadata.importance / (1 + (currentDay - m.metadata.day) * m.metadata.decayFactor),
}))
.sort((a, b) => b.effectiveScore - a.effectiveScore);
}使用场景
1. 决策上下文
NPC 在决定做什么时,会查询相关记忆:
ts
const context = await recall(
npcId,
`${npc.name} is deciding whether to go to the pub tonight`,
env
);2. 日记生成
写日记时,会调出相关的过往事件。
3. 关系上下文
两个 NPC 互动时,各自回忆与对方的历史。
衰减与清理
记忆不会永存。有两个机制:
衰减因子
每条记忆都有一个 decayFactor,随时间增长。检索时,衰减会降低有效分数。
主动清理
每日任务会查询所有 decayFactor > 0.9 的记忆。对重要的重新嵌入,其余删除。
故障处理
| 故障 | 处理方式 |
|---|---|
| 嵌入 API 失败 | 记忆仍存储在 D1 中;稍后重试嵌入 |
| Vectorize 查询返回空 | 决策模块降级为仅使用短期记忆 |
| 索引大小达到上限 | 激进清理 + 较旧记忆仅保留在 D1 中 |
这里不存储什么
- ❌ 原始日记文本(在 D1 中)
- ❌ 短期记忆(在 D1 中)
- ❌ NPC 当前状态(在 D1 中)
- ❌ 世界事件(在 D1 中)
只有语义记忆存放在 Vectorize 中。