搜尋與索引
新增於: @mastra/core@1.1.0
搜尋功能可讓 Agent 在已建立索引的 Workspace 檔案中找出相關內容。Agent 需要回答問題或尋找資訊時,可以搜尋索引內容,不必讀取每個檔案。
運作方式「運作方式」的直接連結
Workspace 搜尋分成兩個階段:建立索引與查詢。
建立索引「建立索引」的直接連結
內容必須先建立索引才能搜尋。為文件建立索引時:
- 內容會被 Tokenize(拆分成可搜尋的詞彙)
- BM25:計算詞頻與文件統計資料
- 向量:使用 Embedder 函式將內容嵌入,並儲存在向量儲存區
每份已建立索引的文件包含:
- id - 唯一識別碼(通常是檔案路徑)
- content - 文字內容
- metadata - 與文件一同儲存的選用鍵值資料
查詢「查詢」的直接連結
搜尋時:
- 查詢會使用與建立索引時相同的 Tokenization/Embedding 方式處理
- 依文件與查詢的相關性評分
- 依分數排序結果,並連同相符內容傳回
Workspace 支援三種搜尋模式:BM25 關鍵字搜尋、向量語意搜尋,以及結合兩者的混合搜尋。
BM25 關鍵字搜尋「BM25 關鍵字搜尋」的直接連結
BM25 會依詞頻與文件長度為文件評分,適合精確比對與特定術語。
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
})
若要自訂 BM25 參數(k1 是詞頻飽和度,b 是文件長度正規化):
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: {
k1: 1.5,
b: 0.75,
},
})
向量搜尋「向量搜尋」的直接連結
向量搜尋使用 Embedding 尋找語意相似的內容,需要向量儲存區與 Embedder 函式。
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
import { PineconeVector } from '@mastra/pinecone'
import { embed } from 'ai'
import { openai } from '@ai-sdk/openai'
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
vectorStore: new PineconeVector({
apiKey: process.env.PINECONE_API_KEY,
index: 'workspace-index',
}),
embedder: async (text: string) => {
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: text,
})
return embedding
},
})
批次 Embedding「批次 Embedding」的直接連結
上述 Embedder 每次接收一段文字。為含數百個檔案的 Workspace 建立索引時,會呼叫 Provider 數百次,既緩慢又昂貴。
當 Provider 支援批次處理時(例如 OpenAI 的 embedMany),請傳入接收文字陣列並能在單次呼叫中取回多個 Embedding 的 Embedder。若要選用此功能,請在函式上設定 batch: true 屬性。Mastra 會在執行階段檢查該屬性,並切換至批次路徑。
以下範例將單一文字 Embedder 改為批次 Embedder。此函式接收陣列,並以相同順序傳回 Embedding 陣列,另帶有兩個額外屬性:
batch: true:標示函式支援批次處理。若缺少此屬性,Mastra 會逐段文字呼叫函式。maxBatchSize:Provider 單次呼叫可接受的最大陣列。Mastra 會依此大小分割較大的請求並平行傳送。請設為 Provider 文件中的限制(例如 OpenAI 為 2048、Cohere 為 96、Voyage 為 128)。省略時,所有待處理文字會在單一請求中送出。
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
import { PineconeVector } from '@mastra/pinecone'
import { embedMany } from 'ai'
import { openai } from '@ai-sdk/openai'
const model = openai.embedding('text-embedding-3-small')
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
vectorStore: new PineconeVector({
apiKey: process.env.PINECONE_API_KEY,
index: 'workspace-index',
}),
embedder: Object.assign(
async (texts: string[]) => {
const { embeddings } = await embedMany({ model, values: texts })
return embeddings
},
{ batch: true as const, maxBatchSize: 2048 },
),
})
Object.assign 會將 batch 與 maxBatchSize 屬性加入 Embedder 函式。Mastra 將它們讀作中繼資料,絕不會傳給 Provider。
單一文字 Embedder 仍可使用。函式簽章 (text: string) => Promise<number[]> 並未變更,因此現有程式碼不必修改即可繼續執行。
混合搜尋「混合搜尋」的直接連結
同時設定 BM25 與向量搜尋,即可啟用結合關鍵字比對與語意理解的混合模式。
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
vectorStore: pineconeVector,
embedder: embedderFn,
})
自訂索引名稱「自訂索引名稱」的直接連結
搜尋索引名稱預設衍生自 Workspace ID。若要設定自訂名稱,請使用 searchIndexName:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
searchIndexName: 'my_workspace_vectors',
})
索引名稱必須是有效的 SQL 識別碼:以字母或底線開頭,只能包含字母、數字或底線,且最多 63 個字元。
建立內容索引「建立內容索引」的直接連結
手動建立索引「手動建立索引」的直接連結
使用 workspace.index(),以程式方式將內容加入搜尋索引。檔案路徑會成為文件 ID,也可以為每份文件傳入中繼資料。
// Basic indexing
await workspace.index('/docs/guide.md', 'Content of the guide...')
// Index with metadata for filtering or context
await workspace.index('/docs/api.md', apiDocContent, {
metadata: {
category: 'api',
version: '2.0',
},
})
手動建立索引適用於:
- 要建立索引的內容並非來自檔案(例如資料庫記錄、API 回應)
- 想在建立索引前預先處理或分割內容
- 需要為文件加入自訂中繼資料
自動建立索引「自動建立索引」的直接連結
設定 autoIndexPaths,即可在 Workspace 初始化時自動為檔案建立索引。每個項目可以是目錄路徑(遞迴建立索引),或用於選擇性建立索引的 glob 模式。
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
autoIndexPaths: ['docs', 'support/faq'],
})
await workspace.init()
呼叫 init() 時,系統會讀取所有相符檔案並建立搜尋索引。檔案路徑會成為文件 ID。
Glob 模式可讓你為特定檔案類型建立索引:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
autoIndexPaths: ['docs/**/*.md', 'support/**/*.txt'],
})
搜尋「搜尋」的直接連結
使用 workspace.search() 尋找相關內容。結果會依相關性分數排序。
const results = await workspace.search('password reset')
for (const result of results) {
console.log(`${result.id}: ${result.score}`)
console.log(result.content)
}
搜尋選項「搜尋選項」的直接連結
你可以使用選項自訂搜尋行為:
const results = await workspace.search('authentication flow', {
topK: 10,
mode: 'hybrid',
minScore: 0.5,
vectorWeight: 0.5,
})
| 選項 | 說明 |
|---|---|
topK | 要傳回的結果數量上限。預設:5 |
mode | 搜尋模式:'bm25'、'vector' 或 'hybrid'。預設會依設定選用最佳的可用模式。 |
minScore | 篩除低於此分數門檻(0–1)的結果。 |
vectorWeight | 在混合模式中,向量分數相對於 BM25 的權重。0 = 全部 BM25,1 = 全部向量,0.5 = 兩者相等。 |
搜尋結果「搜尋結果」的直接連結
每筆結果包含:
interface SearchResult {
id: string // Document ID (typically file path)
content: string // The matching content
score: number // Relevance score (0-1)
lineRange?: {
// Lines where the match was found
start: number
end: number
}
metadata?: Record<string, unknown> // Metadata stored with the document
scoreDetails?: {
// Score breakdown (hybrid mode only)
vector?: number
bm25?: number
}
}
理解分數:
- 分數範圍為 0 到 1,其中 1 代表完全相符
- BM25 分數會依結果集中的最佳相符項目正規化
- 向量分數代表查詢與文件 Embedding 之間的餘弦相似度
- 在混合模式中,系統會使用
vectorWeight參數合併分數
各模式的適用時機「各模式的適用時機」的直接連結
| 模式 | 最適合 | 查詢範例 |
|---|---|---|
bm25 | 精確詞彙、技術查詢、程式碼 | "useState Hook"、"404 錯誤"、"config.yaml" |
vector | 概念式查詢、自然語言 | "如何處理使用者驗證"、"錯誤處理的最佳實務" |
hybrid | 一般搜尋、未知查詢類型 | 多數 Agent 使用情境 |
Agent Tool「Agent Tool」的直接連結
在 Workspace 上設定搜尋後,Agent 會取得搜尋內容及建立內容索引的 Tool。詳情請參閱 Workspace 類別參考。