用途
本技能用于在 chat() 调用中加入服务端记忆(server-side memory)。当你需要跨轮次或跨会话地召回上下文时可使用它,例如用户期望「记住上次告诉你的内容」、需要按用户或按线程保存并复用上下文、以及接入托管记忆服务(mem0、Honcho、Hindsight)。
不适用:仅用于保留最近消息的场景不应使用本中间件,那应使用 chat() 的 messages 数组。记忆用于跨轮次 / 跨会话召回,而非单轮内的历史记录。
主要能力
所有能力位于 @tanstack/ai-memory。记忆适配器是一个单一契约,包含两个动词:recall 与 save。中间件本身很薄:在模型运行前将召回内容写入 system prompt,在本轮结束后再执行保存。
接入方式
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { memoryMiddleware } from '@tanstack/ai-memory'
import { inMemory } from '@tanstack/ai-memory/in-memory'
import { requireSession } from './auth'
const memory = inMemory() // dev/tests only — see the in-memory skill
export async function POST(request: Request) {
const { messages } = await request.json()
// Resolved by your auth layer from cookies/headers — never from the request body.
const session = await requireSession(request)
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
context: { session },
middleware: [
memoryMiddleware({
adapter: memory,
// Derive scope server-side from trusted session state.
scope: () => ({ threadId: session.threadId, userId: session.userId }),
}),
],
})
return toServerSentEventsResponse(stream)
}
memoryMiddleware 选项:adapter、scope(静态值或基于 ctx 的函数)、role(默认为 'recall+save',也可为 'save-only'),以及 onRecall / onSave 遥测回调。
契约
import type {
MemoryFact,
MemoryScope,
MemorySnapshot,
MemoryTurn,
RecallResult,
SaveReceipt,
} from '@tanstack/ai-memory'
interface MemoryAdapter {
readonly id: string
recall: (scope: MemoryScope, query: string) => Promise<RecallResult> // { systemPrompt, fragments?, tools?, toolGuidance? }
save: (scope: MemoryScope, turn: MemoryTurn) => Promise<Array<SaveReceipt>> // turn = { user, assistant }; extraction lives HERE
inspect?: (scope: MemoryScope) => Promise<MemorySnapshot> // optional (devtools)
listFacts?: (scope: MemoryScope) => Promise<Array<MemoryFact>> // optional (devtools)
}
recall 负责判断相关性并渲染 systemPrompt;它还可返回 tools + toolGuidance,将记忆的直接控制权交给模型(hindsight 即如此)。 save 负责抽取(extraction)——将原始轮次转换为需要持久化的内容。
Scope 安全
MemoryScope 是来自 @tanstack/ai 的共享 Scope 类型的别名:{ threadId, userId?, tenantId?, namespace? }。它是隔离边界。永远不要信任客户端提供的 userId / threadId。应从 session/auth 在服务端解析 scope,并通过 chat({ context: { session } }) 传入已校验的 session。若接受请求体中的 thread id,使用前必须先校验它属于该会话用户。
适配器
- inMemory() / redis() — 对 threadId + 可选 userId/tenantId 做精确匹配(忽略 namespace)。Redis 索引键包含全部三个片段。
- hindsight() — bank 为 {tenant|_}{user}{threadId}。
- mem0() — 使用 user_id + run_id(threadId);无 tenantId。
- honcho() — session 为 {tenant|_}__{threadId};设置后 peer 会带租户前缀。
- 自定义 — 实现 recall/save,并运行来自 @tanstack/ai-memory/testkit 的 runMemoryAdapterContract。
限制与失败模式
记忆故障为非致命:recall 或 save 抛出异常时触发 memory:error,运行将以降级的记忆状态继续。流式输出永不被阻塞;保存失败也不会导致本轮失败。
Devtools
aiEventClient(来自 @tanstack/ai-event-client)上有五类事件:memory:retrieve:started / :completed、memory:persist:started / :completed、memory:error(phase: 'recall' | 'save')。事件载荷携带适配器 id 与片段/回执数量,不包含完整记忆文本。仅当 scope 已被解析时,错误事件才会包含 scope;若解析器抛出异常,则省略 scope。
适用场景
- 用户期望跨会话的「记住」体验
- 需要跨会话存活的按用户或按线程上下文
- 接入托管记忆服务(mem0、Honcho、Hindsight)