跳至主要內容

使用 RAG 建置研究論文助理

在本指南中,你將建立一個 AI 研究助理,使用 Retrieval Augmented Generation(RAG)分析學術論文,並回答與論文內容相關的特定問題。

你將以 Transformer 的原始論文 「Attention Is All You Need」作為範例,並使用本機 libSQL 資料庫。

先決條件
「先決條件」的直接連結

  • 已安裝 Node.js v22.13.0 或更新版本
  • 具備支援的 Model Provider 所提供的 API key
  • 已有 Mastra 專案(請依照安裝指南設定新專案)

RAG 的運作方式
「RAG 的運作方式」的直接連結

以下說明 RAG 的運作方式,以及你將如何實作各個元件。

Knowledge Store/Index
「Knowledge Store/Index」的直接連結

  • 將文字轉換為向量表示法
  • 建立內容的數值表示法
  • 實作方式:使用 OpenAI 的 text-embedding-3-small 建立 embeddings,並將它們儲存在 LibSQLVector 中

Retriever
「Retriever」的直接連結

  • 透過相似度搜尋尋找相關內容
  • 將查詢 embeddings 與已儲存的向量配對
  • 實作方式:使用 LibSQLVector 對已儲存的 embeddings 執行相似度搜尋

Generator
「Generator」的直接連結

  • 使用 LLM 處理擷取到的內容
  • 建立包含情境資訊的回應
  • 實作方式:使用 OpenAI model,根據擷取到的內容產生答案

你的實作將會:

  1. 將 Transformer 論文處理為 embeddings
  2. 將它們儲存在 LibSQLVector 中,以便快速擷取
  3. 使用相似度搜尋尋找相關段落
  4. 使用擷取到的情境產生準確回應

建立 Agent
「建立 Agent」的直接連結

接下來將定義 Agent 的行為、將其連線至 Mastra 專案,並建立 vector store。

  1. 安裝其他相依套件

    完成安裝指南後,還需要安裝其他相依套件:

    npm install @mastra/rag@latest ai
  2. 現在你將建立支援 RAG 的研究助理。此 Agent 使用:

    • Vector Query Tool,對 vector store 執行語意搜尋,以尋找論文中的相關內容
    • OpenAI model,用於理解查詢並產生回應
    • 自訂 instructions,用來引導 Agent 分析論文、有效使用擷取到的內容,並說明其限制

    建立新檔案 src/mastra/agents/researchAgent.ts 並定義 Agent:

    src/mastra/agents/researchAgent.ts
    import { Agent } from '@mastra/core/agent'
    import { ModelRouterEmbeddingModel } from '@mastra/core/llm'
    import { createVectorQueryTool } from '@mastra/rag'

    // Create a tool for semantic search over the paper embeddings
    const vectorQueryTool = createVectorQueryTool({
    vectorStoreName: 'libSqlVector',
    indexName: 'papers',
    model: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
    })

    export const researchAgent = new Agent({
    id: 'research-agent',
    name: 'Research Assistant',
    instructions: `You are a helpful research assistant that analyzes academic papers and technical documents.
    Use the provided vector query tool to find relevant information from your knowledge base,
    and provide accurate, well-supported answers based on the retrieved content.
    Focus on the specific content available in the tool and acknowledge if you cannot find sufficient information to answer a question.
    Base your responses only on the content provided, not on general knowledge.`,
    model: 'openai/gpt-5.6-sol',
    tools: {
    vectorQueryTool,
    },
    })
  3. 在專案根目錄中使用 pwd 指令取得絕對路徑。路徑可能類似如下:

    > pwd
    /Users/your-name/guides/research-assistant

    將下列內容加入現有的 src/mastra/index.ts 檔案與設定:

    src/mastra/index.ts
    import { Mastra } from '@mastra/core'
    import { LibSQLVector } from '@mastra/libsql'

    const libSqlVector = new LibSQLVector({
    id: 'research-vectors',
    url: 'file:/Users/your-name/guides/research-assistant/vector.db',
    })

    export const mastra = new Mastra({
    vectors: { libSqlVector },
    })

    url 請使用透過 pwd 指令取得的絕對路徑。如此一來,vector.db 檔案會建立在專案根目錄。

    備註

    本指南為了示範而使用寫死的絕對路徑來指向本機 libSQL 檔案,但這不適用於正式環境。正式使用時,應改用遠端持久性資料庫。

  4. src/mastra/index.ts 檔案中,將 Agent 加入 Mastra:

    src/mastra/index.ts
    import { Mastra } from '@mastra/core'
    import { LibSQLVector } from '@mastra/libsql'
    import { researchAgent } from './agents/researchAgent'

    const libSqlVector = new LibSQLVector({
    id: 'research-vectors',
    url: 'file:/Users/your-name/guides/research-assistant/vector.db',
    })

    export const mastra = new Mastra({
    agents: { researchAgent },
    vectors: { libSqlVector },
    })

處理文件
「處理文件」的直接連結

在接下來的步驟中,你會擷取研究論文並將其分割成較小的 chunks,然後產生 embeddings,並將 chunks 儲存至 vector database。

  1. 在此步驟中,系統會透過 URL 擷取研究論文,接著將其轉換為 document object,再分割成較小且易於處理的 chunks。分割成 chunks 可讓處理作業更快速、更有效率。

    建立新檔案 src/store.ts 並加入下列內容:

    src/store.ts
    import { MDocument } from '@mastra/rag'

    // Load the paper
    const paperUrl = 'https://arxiv.org/html/1706.03762'
    const response = await fetch(paperUrl)
    const paperText = await response.text()

    // Create document and chunk it
    const doc = MDocument.fromText(paperText)
    const chunks = await doc.chunk({
    strategy: 'recursive',
    maxSize: 512,
    overlap: 50,
    separators: ['\n\n', '\n', ' '],
    })

    console.log('Number of chunks:', chunks.length)

    在終端機中執行此檔案:

    npx bun src/store.ts

    你應該會得到以下回應:

    Number of chunks: 892
  2. 最後,你會透過下列步驟為 RAG 準備內容:

    1. 為每個文字 chunk 產生 embeddings
    2. 建立 vector store index 來保存 embeddings
    3. 將 embeddings 與 metadata(原始文字及來源資訊)儲存至 vector database
    備註

    此 metadata 非常重要,因為 vector store 找到相關配對時,可透過它傳回實際內容。

    Agent 會使用 vector index 搜尋並擷取相關資訊。

    開啟 src/store.ts 檔案並加入下列內容:

    src/store.ts
    import { MDocument } from '@mastra/rag'
    import { embedMany } from 'ai'
    import { mastra } from './mastra'

    // Load the paper
    const paperUrl = 'https://arxiv.org/html/1706.03762'
    const response = await fetch(paperUrl)
    const paperText = await response.text()

    // Create document and chunk it
    const doc = MDocument.fromText(paperText)
    const chunks = await doc.chunk({
    strategy: 'recursive',
    maxSize: 512,
    overlap: 50,
    separators: ['\n\n', '\n', ' '],
    })

    // Generate embeddings
    const { embeddings } = await embedMany({
    model: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
    values: chunks.map(chunk => chunk.text),
    })

    // Get the vector store instance from Mastra
    const vectorStore = mastra.getVector('libSqlVector')

    // Create an index for paper chunks
    await vectorStore.createIndex({
    indexName: 'papers',
    dimension: 1536,
    })

    // Store embeddings
    await vectorStore.upsert({
    indexName: 'papers',
    vectors: embeddings,
    metadata: chunks.map(chunk => ({
    text: chunk.text,
    source: 'transformer-paper',
    })),
    })

    最後,再次執行 script 以儲存 embeddings:

    npx bun src/store.ts

    如果操作成功,終端機中應該不會顯示任何輸出或錯誤。

測試助理
「測試助理」的直接連結

vector database 現在已包含所有 embeddings,你可以使用不同類型的查詢來測試研究助理。

建立新檔案 src/ask-agent.ts 並加入不同類型的查詢:

src/ask-agent.ts
import { mastra } from './mastra'
const agent = mastra.getAgent('researchAgent')

// Basic query about concepts
const query1 = 'What problems does sequence modeling face with neural networks?'
const response1 = await agent.generate(query1)
console.log('\nQuery:', query1)
console.log('Response:', response1.text)

執行 script:

npx bun src/ask-agent.ts

你應該會看到類似以下的輸出:

Query: What problems does sequence modeling face with neural networks?
Response: Sequence modeling with neural networks faces several key challenges:
1. Vanishing and exploding gradients during training, especially with long sequences
2. Difficulty handling long-term dependencies in the input
3. Limited computational efficiency due to sequential processing
4. Challenges in parallelizing computations, resulting in longer training times

嘗試另一個問題:

src/ask-agent.ts
import { mastra } from './mastra'
const agent = mastra.getAgent('researchAgent')

// Query about specific findings
const query2 = 'What improvements were achieved in translation quality?'
const response2 = await agent.generate(query2)
console.log('\nQuery:', query2)
console.log('Response:', response2.text)

輸出:

Query: What improvements were achieved in translation quality?
Response: The model showed significant improvements in translation quality, achieving more than 2.0
BLEU points improvement over previously reported models on the WMT 2014 English-to-German translation
task, while also reducing training costs.

啟動應用程式
「啟動應用程式」的直接連結

啟動 Mastra server,透過 API 提供研究助理:

mastra dev

你的研究助理可透過下列位置存取:

http://localhost:4111/api/agents/researchAgent/generate

使用 curl 測試:

curl -X POST http://localhost:4111/api/agents/researchAgent/generate \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "What were the main findings about model parallelization?" }
]
}'

進階 RAG 範例
「進階 RAG 範例」的直接連結

探索下列範例,了解更進階的 RAG 技術: