跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

Semantic recall

如果你问朋友上周末做了什么,他们会在记忆中搜索与"上周末"相关的事件,然后告诉你他们做了什么。这大致就是 Mastra 中语义召回的工作方式。

📹 观看视频

观看 Mastra semantic recall,了解 agent 如何从过去的对话中检索相关消息。

语义召回的工作原理
语义召回的工作原理的直接链接

语义召回是一种基于 RAG 的搜索,当消息不再位于最近消息历史中时,它帮助 agent 在较长的交互中保持上下文。

它使用消息的向量 embedding 进行相似度搜索,并与向量存储集成,同时支持在检索到的消息周围配置上下文窗口。

启用后,新消息会被用于查询向量数据库,以寻找语义相似的消息。

从 LLM 获得响应后,所有新消息(user、assistant 以及工具调用/结果)都会被插入向量数据库,以便在后续交互中召回。

快速开始
快速开始的直接链接

语义召回默认禁用。要启用它,请在 options 中设置 semanticRecall: true,并提供 vector 存储和 embedder。对于自行生成 embedding 的存储(例如使用 Automated Embedding 的 MongoDB),则无需提供 embedder。参见服务端 embedding。

src/mastra/agents/index.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore, LibSQLVector } from '@mastra/libsql'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'

const agent = new Agent({
id: 'support-agent',
name: 'SupportAgent',
instructions: 'You are a helpful support agent.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'agent-storage',
url: 'file:./local.db',
}),
vector: new LibSQLVector({
id: 'agent-vector',
url: 'file:./local.db',
}),
embedder: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
options: {
semanticRecall: true,
},
}),
})

使用 recall() 方法
using-the-recall-method的直接链接

listMessages 按 thread ID 检索消息并支持基本的分页,而 recall() 增加了语义搜索支持。当你需要按含义而非时间新近度查找消息时,请使用带 vectorSearchString 的 recall():

const memory = await agent.getMemory()

// Basic recall - similar to listMessages
const { messages } = await memory!.recall({
threadId: 'thread-123',
perPage: 50,
})

// Semantic recall - find messages by meaning
const { messages: relevantMessages } = await memory!.recall({
threadId: 'thread-123',
vectorSearchString: 'What did we discuss about the project deadline?',
threadConfig: {
semanticRecall: true,
},
})

存储配置
存储配置的直接链接

语义召回依赖存储和向量数据库来存储消息及其 embedding。

src/mastra/agents/index.ts
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { LibSQLStore, LibSQLVector } from '@mastra/libsql'

const agent = new Agent({
memory: new Memory({
// this is the default storage db if omitted
storage: new LibSQLStore({
id: 'agent-storage',
url: 'file:./local.db',
}),
// this is the default vector db if omitted
vector: new LibSQLVector({
id: 'agent-vector',
url: 'file:./local.db',
}),
options: {
semanticRecall: true,
},
}),
})

下面每个向量存储页面都包含安装说明、配置参数和使用示例:

召回配置
召回配置的直接链接

以下选项控制语义召回行为:

  1. topK:要检索的相似消息数量
  2. messageRange:每个匹配项要包含的周围消息
  3. scope:是搜索当前 thread,还是搜索某个 resource 的所有 thread
  4. filter:限制搜索结果的元数据条件
const agent = new Agent({
id: 'agent',
memory: new Memory({
options: {
semanticRecall: {
topK: 3, // Retrieve 3 similar messages
messageRange: 2, // Include 2 messages before and after each match
scope: 'resource', // Search all threads for this resource
filter: { projectId: { $eq: 'project-a' } },
},
},
}),
})
备注

LibSQL、OracleDB、PostgreSQL、MongoDB 和 Upstash 存储适配器支持 scope: 'resource'。

元数据过滤
元数据过滤的直接链接

filter 选项将语义召回结果限制为 thread 元数据匹配的消息。

const agent = new Agent({
id: 'agent',
memory: new Memory({
options: {
semanticRecall: {
scope: 'resource',
filter: {
projectId: { $eq: 'project-a' },
category: { $in: ['work', 'personal'] },
},
},
},
}),
})

过滤器匹配的是消息保存时存储在消息 embedding 上的元数据。如果 thread 元数据之后发生更改,现有 embedding 会保留先前的元数据,直到这些消息被再次保存或索引。

支持的过滤器操作符:

  • $and:逻辑与
  • $eq:等于
  • $gt:大于
  • $gte:大于或等于
  • $in:在数组中
  • $lt:小于
  • $lte:小于或等于
  • $ne:不等于
  • $nin:不在数组中
  • $or:逻辑或

以下示例演示了常见用例的元数据过滤器:

// Filter by project
const options = {
semanticRecall: { filter: { projectId: { $eq: 'my-project' } } },
}

// Filter by multiple categories
const options = {
semanticRecall: { filter: { category: { $in: ['work', 'research'] } } },
}

// Filter by project and priority
const options = {
semanticRecall: {
filter: {
$and: [{ projectId: { $eq: 'project-a' } }, { priority: { $gte: 3 } }],
},
},
}

服务端 embedding
服务端 embedding的直接链接

某些向量存储会自行生成 embedding。使用这类存储时,语义召回无需 embedder 即可运行:数据库在写入时对每条消息进行 embedding,在搜索文本到达时对其进行 embedding。embedding 提供商完全不需要出现在你的应用中。

MongoDB 通过 Automated Embedding 实现这一点:在向量存储上指定一个 Voyage AI 模型,并省略 embedder。

src/mastra/agents/index.ts
import { Memory } from '@mastra/memory'
import { MongoDBStore, MongoDBVector } from '@mastra/mongodb'

const memory = new Memory({
storage: new MongoDBStore({
id: 'agent-storage',
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
}),
vector: new MongoDBVector({
id: 'agent-vector',
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
autoEmbed: { model: 'voyage-4' },
}),
options: {
semanticRecall: { topK: 3, messageRange: 2 },
},
})

消息以文本形式存储,由 MongoDB 对其进行 embedding,因此模型选择和向量维度属于索引,而不属于你的应用。通过 agent 和通过 recall() 的召回方式相同。

MongoDB 在后台对新写入的消息进行 embedding。刚刚保存的消息可能无法立即被召回。

其他所有存储都要求你的应用提供向量,并且仍然需要 embedder。在既没有 embedder 也没有服务端 embedding 存储的情况下启用语义召回,会抛出错误并同时指出这两个选项。

Embedder 配置
Embedder 配置的直接链接

语义召回依赖 embedding 模型将消息转换为 embedding。Mastra 通过 model router 支持使用 provider/model 字符串指定 embedding 模型,你也可以使用任何与 AI SDK 兼容的 embedding 模型。

使用 Model Router(推荐)
使用 Model Router(推荐)的直接链接

最简单的方式是使用带自动补全支持的 provider/model 字符串:

src/mastra/agents/index.ts
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'

const agent = new Agent({
id: 'agent',
memory: new Memory({
embedder: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
options: {
semanticRecall: true,
},
}),
})

支持的 embedding 模型:

  • OpenAI:text-embedding-3-small、text-embedding-3-large、text-embedding-ada-002
  • Google:gemini-embedding-001
  • OpenRouter:访问来自多个提供商的 embedding 模型
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'

const agent = new Agent({
id: 'agent',
memory: new Memory({
embedder: new ModelRouterEmbeddingModel({
providerId: 'openrouter',
modelId: 'openai/text-embedding-3-small',
}),
}),
})

model router 会自动处理从环境变量(OPENAI_API_KEY、GOOGLE_API_KEY、OPENROUTER_API_KEY)检测 API key。Google 模型还会回退到 GOOGLE_GENERATIVE_AI_API_KEY。

使用 AI SDK 包
使用 AI SDK 包的直接链接

你也可以直接使用 AI SDK 的 embedding 模型:

import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'

const agent = new Agent({
id: 'agent',
memory: new Memory({
embedder: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
}),
})

使用 FastEmbed(本地)
使用 FastEmbed(本地)的直接链接

要使用 FastEmbed(本地 embedding 模型),请安装 @mastra/fastembed:

npm install @mastra/fastembed@latest

然后在 memory 中配置它:

import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { fastembed } from '@mastra/fastembed'

const agent = new Agent({
id: 'agent',
memory: new Memory({
embedder: fastembed,
}),
})

FastEmbed 还为非英文内容提供了多语言 E5 模型。E5 是非对称的,因此它作为两个模型暴露:multilingualE5LargePassage 用于你索引的文本,multilingualE5LargeQuery 用于搜索文本。

import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { fastembed } from '@mastra/fastembed'

const agent = new Agent({
id: 'agent',
memory: new Memory({
embedder: fastembed.multilingualE5LargePassage,
}),
})

Memory 在存储和召回消息时使用同一个 embedder,因此请选择这两个模型之一并一致地使用它。仅当你能控制流水线两端时(例如用 passage 模型建立索引、用 query 模型搜索的 RAG 工作流),才使用配对的 multilingualE5LargeQuery 模型。

多语言 E5 生成 1024 维向量。你的向量索引必须以匹配的维度创建,并且 E5 向量不能与同一索引中来自其他 embedder 的向量混用。

FastEmbed 模型每个输入最多嵌入 512 个 token(约 2,000 到 2,500 个英文字符)。更长的输入会被截断,因此超出限制的文本不会影响 embedding,也无法被语义召回找到。发生这种情况时,AI SDK v3 FastEmbed 模型会返回警告,旧版 v1 和 v2 模型则不会。如果你使用 FastEmbed 嵌入长文档,请将其分块以适应窗口,例如在 MDocument.chunk() 中使用 maxSize: 1500。

PostgreSQL 索引优化
PostgreSQL 索引优化的直接链接

使用 PostgreSQL 作为向量存储时,你可以通过配置向量索引来优化语义召回性能。这对于拥有数千条消息的大规模部署尤为重要。

PostgreSQL 同时支持 IVFFlat 和 HNSW 索引。默认情况下,Mastra 会创建 IVFFlat 索引,但 HNSW 索引通常能提供更好的性能,尤其是对使用内积距离的 OpenAI embedding。

import { Memory } from '@mastra/memory'
import { PostgresStore, PgVector } from '@mastra/pg'

const agent = new Agent({
memory: new Memory({
storage: new PostgresStore({
id: 'agent-storage',
connectionString: process.env.DATABASE_URL,
}),
vector: new PgVector({
id: 'agent-vector',
connectionString: process.env.DATABASE_URL,
}),
options: {
semanticRecall: {
topK: 5,
messageRange: 2,
indexConfig: {
type: 'hnsw', // Use HNSW for better performance
metric: 'dotproduct', // Best for OpenAI embeddings
m: 16, // Number of bi-directional links (default: 16)
efConstruction: 64, // Size of candidate list during construction (default: 64)
},
},
},
}),
})

有关索引配置选项和性能调优的详细信息,请参阅 PgVector 配置指南。

禁用语义召回
禁用语义召回的直接链接

语义召回默认禁用(semanticRecall: false)。每次调用都会增加延迟,因为新消息在 LLM 接收之前需要被转换为 embedding 并用于查询向量数据库。

在以下情况下应保持语义召回禁用:

  • 消息历史已为当前对话提供足够的上下文。
  • 你正在构建性能敏感的应用,例如实时双向音频,其中 embedding 和向量查询的延迟较为明显。

查看召回的消息
查看召回的消息的直接链接

启用 tracing 后,通过语义召回检索到的任何消息都会出现在 agent 的 trace 输出中,与最近消息历史(如果已配置)并列展示。