搜尋及索引
新增於: @mastra/core@1.1.0
搜尋功能讓 Agent 在已建立索引的 Workspace 文件中尋找相關內容。當 Agent 需要回答問題或尋找資料時,可以搜尋已建立索引的內容,毋須讀取每個文件。
運作方式運作方式 的直接連結
Workspace 搜尋分為兩個階段:建立索引及查詢。
建立索引建立索引 的直接連結
內容必須先建立索引,才能供搜尋。為文件建立索引時:
- 內容會被斷詞(拆分成可搜尋的詞彙)
- 對於 BM25:系統會計算詞頻及文件統計資料
- 對於向量搜尋:系統會使用你的 embedder 函式將內容嵌入,並儲存至向量儲存空間
每份已建立索引的文件均包含:
- id - 唯一識別碼(通常是文件路徑)
- content - 文字內容
- metadata - 與文件一併儲存的可選鍵值資料
查詢查詢 的直接連結
搜尋時:
- 查詢會使用與建立索引時相同的斷詞/嵌入方式處理
- 系統會根據文件與查詢的相關程度評分
- 結果會按分數排序,並連同相符內容傳回
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,
},
})
向量搜尋向量搜尋 的直接連結
向量搜尋使用嵌入向量尋找語義相近的內容。此功能需要向量儲存空間及 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
},
})
批次嵌入批次嵌入 的直接連結
上面的 embedder 每次處理一段文字。為包含數百個文件的 Workspace 建立索引時,會呼叫 Provider 數百次,既緩慢又昂貴。
如果 Provider 支援批次處理(例如 OpenAI 的 embedMany),請傳入一個接受文字陣列,並可在一次呼叫中接收多個嵌入向量的 embedder。如要啟用此功能,請在函式上設定 batch: true 屬性。Mastra 會在執行階段檢查該屬性,並切換至批次處理路徑。
以下範例以批次 embedder 取代單一文字 embedder。embedder 函式接受一個陣列,並按相同順序傳回嵌入向量陣列,另附有兩個額外屬性:
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 會將這些屬性讀取為 metadata,而不會傳遞給 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。你亦可為每份文件傳入 metadata。
// 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 回應)
- 你想在建立索引前預先處理內容或將其分塊
- 你需要為文件加入自訂 metadata
自動建立索引自動建立索引 的直接連結
設定 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 分數會根據結果集中的最佳相符項目進行正規化
- 向量分數代表查詢與文件嵌入向量之間的餘弦相似度
- 在混合模式中,系統會使用
vectorWeight參數合併分數
各模式的適用情況各模式的適用情況 的直接連結
| 模式 | 最適合 | 查詢範例 |
|---|---|---|
bm25 | 確切詞彙、技術查詢、程式碼 | "useState hook"、"404 error"、"config.yaml" |
vector | 概念查詢、自然語言 | "how to handle user authentication"、"best practices for error handling" |
hybrid | 一般搜尋、未知查詢類型 | 大多數 Agent 使用情境 |
Agent toolsAgent tools 的直接連結
在 Workspace 上設定搜尋功能後,Agent 會獲得用於搜尋內容及建立內容索引的 Tool。詳情請參閱 Workspace class 參考資料。