RAG を用いたリサーチペーパーアシスタントの構築
このガイドでは、学術論文を分析し、その内容に関する特定の質問に Retrieval Augmented Generation(RAG)を用いて回答できる AI リサーチアシスタントを作成します。
例として、基盤となる Transformer 論文「Attention Is All You Need」 を使用します。データベースには、ローカルの LibSQL データベースを使用します。
前提条件
- Node.js
v20.0
以降がインストールされていること - 対応する モデルプロバイダー から取得した API キー
- 既存の Mastra プロジェクト(新規プロジェクトをセットアップする場合は、インストールガイド に従ってください)
RAG の仕組み
RAG がどのように機能し、各コンポーネントをどのように実装するかを見ていきましょう。
Knowledge Store/Index
- テキストをベクトル表現に変換する
- コンテンツを数値ベクトルとして表現する
- 実装: OpenAI の
text-embedding-3-small
を使って埋め込みを作成し、LibSQLVector に保存します
Retriever
- 類似度検索で関連コンテンツを見つける
- クエリの埋め込みを保存済みベクトルと照合する
- 実装: LibSQLVector を使って保存済み埋め込みに対する類似度検索を実行します
Generator
- 取得したコンテンツを LLM で処理する
- 文脈に即した応答を生成する
- 実装: 取得したコンテンツに基づいて GPT-4o-mini で回答を生成します
この実装では次のことを行います:
- Transformer 論文を埋め込みに変換する
- 高速な検索のために LibSQLVector に保存する
- 類似度検索で関連セクションを見つける
- 取得した文脈に基づいて正確な応答を生成する
エージェントの作成
エージェントの挙動を定義し、Mastra プロジェクトに接続して、ベクターストアを作成します。
追加の依存関係をインストールする
インストールガイドの実行後、追加の依存関係をインストールします:
npm install @mastra/rag@latest ai@^4.0.0
Mastra は現在、AI SDK の v5 をサポートしていません(サポートスレッド を参照)。このガイドでは v4 を使用してください。
エージェントを定義する
ここでは RAG 対応のリサーチアシスタントを作成します。エージェントは次を使用します:
- 論文中の関連コンテンツを見つけるためにベクターストア上でセマンティック検索を行う Vector Query Tool
- クエリの理解と回答生成のための GPT-4o-mini
- 論文の分析方法、取得コンテンツの効果的な活用、限界の認識を指示するカスタムインストラクション
新しいファイル src/mastra/agents/researchAgent.ts
を作成し、エージェントを定義します:
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { createVectorQueryTool } from "@mastra/rag";
// Create a tool for semantic search over the paper embeddings
const vectorQueryTool = createVectorQueryTool({
vectorStoreName: "libSqlVector",
indexName: "papers",
model: openai.embedding("text-embedding-3-small"),
});
export const researchAgent = new 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-4o-mini"),
tools: {
vectorQueryTool,
},
});
ベクターストアを作成する
プロジェクトのルートで pwd
コマンドを実行して絶対パスを取得します。パスは次のようになる場合があります:
> pwd
/Users/your-name/guides/research-assistant
src/mastra/index.ts
ファイルで、既存のファイルと設定に次を追加します:
import { Mastra } from "@mastra/core/mastra";
import { LibSQLVector } from "@mastra/libsql";
const libSqlVector = new LibSQLVector({
connectionUrl: "file:/Users/your-name/guides/research-assistant/vector.db",
});
export const mastra = new Mastra({
vectors: { libSqlVector },
});
connectionUrl
には pwd
コマンドで取得した絶対パスを使用してください。これにより、vector.db
ファイルがプロジェクトのルートに作成されます。
このガイドではローカルの LibSQL ファイルへのハードコードされた絶対パスを使用していますが、本番環境では適しません。リモートの永続データベースを使用してください。
Mastra にエージェントを登録する
src/mastra/index.ts
ファイルで、Mastra にエージェントを追加します:
import { Mastra } from "@mastra/core/mastra";
import { LibSQLVector } from "@mastra/libsql";
import { researchAgent } from "./agents/researchAgent";
const libSqlVector = new LibSQLVector({
connectionUrl: "file:/Users/your-name/guides/research-assistant/vector.db",
});
export const mastra = new Mastra({
agents: { researchAgent },
vectors: { libSqlVector },
});
ドキュメントの処理
このセクションでは、論文を取得して小さなチャンクに分割し、各チャンクに対して埋め込みを生成し、それらの情報をベクターデータベースに保存します。
論文の読み込みと処理
このステップでは、URL を指定して論文を取得し、ドキュメントオブジェクトに変換したうえで、扱いやすい小さなチャンクに分割します。チャンクに分割することで、処理がより高速かつ効率的になります。
新しいファイル 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
埋め込みの作成と保存
最後に、RAG 用に次の準備を行います。
- 各テキストチャンクの埋め込みを生成する
- 埋め込みを保持するベクターストアのインデックスを作成する
- 埋め込みとメタデータ(元のテキストとソース情報)の両方をベクターデータベースに保存する
このメタデータは、ベクターストアが関連する一致を見つけたときに、実際のコンテンツを返すために不可欠です。
これにより、エージェントは関連情報を効率よく検索・取得できます。
src/store.ts
ファイルを開き、次を追加します:
import { MDocument } from "@mastra/rag";
import { openai } from "@ai-sdk/openai";
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: openai.embedding("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",
})),
});
最後に、スクリプトをもう一度実行して埋め込みを保存します:
npx bun src/store.ts
操作が成功すれば、ターミナルには出力やエラーは表示されません。
アシスタントをテストする
ベクターデータベースに埋め込みが一通り揃ったので、リサーチアシスタントをさまざまな種類のクエリでテストできます。
新しいファイル src/ask-agent.ts
を作成し、いくつかの種類のクエリを追加します:
import { mastra } from "./mastra";
const agent = mastra.getAgent("researchAgent");
// 基本的な概念に関するクエリ
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);
スクリプトを実行します:
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
別の質問も試してみましょう:
import { mastra } from "./mastra";
const agent = mastra.getAgent("researchAgent");
// 具体的な知見に関するクエリ
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 サーバーを起動して、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手法の例をご覧ください:
- Filter RAG: メタデータによる結果のフィルタリング
- Cleanup RAG: 情報密度の最適化
- Chain of Thought RAG: ワークフローを用いた複雑な推論クエリの処理
- Rerank RAG: 結果の関連性の向上