langchain4j-rag-implementation-patterns
LangChain4jを使用したJava向けのRAG(検索拡張生成)実装パターンを提供します。ドキュメントの取り込みパイプライン、埋め込みストア、ベクター検索、セマンティック検索機能のコードを生成します。PDFやテキストファイルへの質問応答システム、ナレッジベースを持つAIアシスタント、ドキュメントリポジトリのセマンティック検索、出典付きの知識強化AIアプリケーションを構築する際に活用してください。
description の原文を見る
Provides Retrieval-Augmented Generation (RAG) implementation patterns with LangChain4j for Java. Generates document ingestion pipelines, embedding stores, vector search, and semantic search capabilities. Use when building chat-with-documents systems, document Q&A over PDFs or text files, AI assistants with knowledge bases, semantic search over document repositories, or knowledge-enhanced AI applications with source attribution.
SKILL.md 本文
LangChain4j RAG 実装パターン
概要
LangChain4jを使用したRAGシステムの実装:ドキュメント取り込みパイプライン、埋め込みストア、ベクトル検索により、ドキュメントとの会話やナレッジ強化型のAIアプリケーションを実現します。
このスキルを使用する場合
- ドキュメントとの会話システムやPDF、テキストファイル、Webページに対するドキュメントQ&Aの構築
- 企業のナレッジベースや外部ソースにアクセス可能なAIアシスタントの作成
- ドキュメントリポジトリに対するセマンティック検索またはハイブリッド検索の実装
- キュレーションされたナレッジとソースの帰属を持つドメイン固有のAIの構築
手順
RAGプロジェクトの初期化
必要な依存関係を持つ新しいSpring Bootプロジェクトを作成します:
pom.xml:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.8.0</version>
</dependency>
ドキュメント取り込みのセットアップ
検証を含むドキュメント読み込みと処理を構成します:
検証チェックポイント:取り込み後、埋め込み数がセグメント数と一致することを確認し、サンプルクエリで検索をテストします。
@Configuration
public class RAGConfiguration {
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
}
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return new InMemoryEmbeddingStore<>();
}
}
ドキュメント取り込みサービスを作成します:
@Service
@RequiredArgsConstructor
public class DocumentIngestionService {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
public void ingestDocument(String filePath, Map<String, Object> metadata) {
Document document = FileSystemDocumentLoader.loadDocument(filePath);
document.metadata().putAll(metadata);
DocumentSplitter splitter = DocumentSplitters.recursive(
500, 50, new OpenAiTokenCountEstimator("text-embedding-3-small")
);
List<TextSegment> segments = splitter.split(document);
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
embeddingStore.addAll(embeddings, segments);
// 検証:埋め込み数がセグメント数と一致することを確認
if (embeddings.size() != segments.size()) {
throw new IllegalStateException("Embedding count mismatch: expected " + segments.size() + ", got " + embeddings.size());
}
}
public boolean validateIngestion(String testQuery) {
// 検証:サンプルクエリで検索をテスト
Embedding queryEmbedding = embeddingModel.embed(testQuery).content();
List<EmbeddingMatch<TextSegment>> results = embeddingStore.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(1)
.build()
).matches();
return !results.isEmpty();
}
}
コンテンツ検索の構成
フィルタリング機能を備えたコンテンツ検索をセットアップします:
検証チェックポイント:構成後、既知のクエリで検索をテストして、埋め込みが検索可能であることを確認します。
@Configuration
public class ContentRetrieverConfiguration {
@Bean
public ContentRetriever contentRetriever(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.7)
.build();
}
}
RAG対応AIサービスの作成
コンテキスト検索を備えたAIサービスを定義します:
interface KnowledgeAssistant {
@SystemMessage("""
You are a knowledgeable assistant with access to a comprehensive knowledge base.
When answering questions:
1. Use the provided context from the knowledge base
2. If information is not in the context, clearly state this
3. Provide accurate, helpful responses
4. When possible, reference specific sources
5. If the context is insufficient, ask for clarification
""")
String answerQuestion(String question);
}
@Service
@RequiredArgsConstructor
public class KnowledgeService {
private final KnowledgeAssistant assistant;
public KnowledgeService(ChatModel chatModel, ContentRetriever contentRetriever) {
this.assistant = AiServices.builder(KnowledgeAssistant.class)
.chatModel(chatModel)
.contentRetriever(contentRetriever)
.build();
}
public String answerQuestion(String question) {
return assistant.answerQuestion(question);
}
}
例
基本的なドキュメント処理
public class BasicRAGExample {
public static void main(String[] args) {
var embeddingStore = new InMemoryEmbeddingStore<TextSegment>();
var embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
var ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(Document.from("Spring Boot is a framework for building Java applications with minimal configuration."));
var retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.build();
}
}
マルチドメインアシスタント
interface MultiDomainAssistant {
@SystemMessage("""
You are an expert assistant with access to multiple knowledge domains:
- Technical documentation
- Company policies
- Product information
- Customer support guides
Tailor your response based on the type of question and available context.
Always indicate which domain the information comes from.
""")
String answerQuestion(@MemoryId String userId, String question);
}
階層型RAG
@Service
@RequiredArgsConstructor
public class HierarchicalRAGService {
private final EmbeddingStore<TextSegment> chunkStore;
private final EmbeddingStore<TextSegment> summaryStore;
private final EmbeddingModel embeddingModel;
public String performHierarchicalRetrieval(String query) {
List<EmbeddingMatch<TextSegment>> summaryMatches = searchSummaries(query);
List<TextSegment> relevantChunks = new ArrayList<>();
for (EmbeddingMatch<TextSegment> summaryMatch : summaryMatches) {
String documentId = summaryMatch.embedded().metadata().getString("documentId");
List<EmbeddingMatch<TextSegment>> chunkMatches = searchChunksInDocument(query, documentId);
chunkMatches.stream()
.map(EmbeddingMatch::embedded)
.forEach(relevantChunks::add);
}
return generateResponseWithChunks(query, relevantChunks);
}
}
ベストプラクティス
ドキュメントセグメンテーション
- ほとんどのアプリケーションでは、500~1000トークンのチャンク単位での再帰的な分割を使用してください
- コンテキスト保持のため、チャンク間に20~50トークンのオーバーラップを保つ
- 分割時にドキュメント構造(見出し、段落)を考慮してください
- トークン認識スプリッタを使用して最適な埋め込み生成を実現します
メタデータ戦略
- フィルタリングと帰属のための充実したメタデータを含める:
- マルチテナンシー用のユーザーとテナント識別子
- ドキュメント型とカテゴリ分類
- 作成および変更タイムスタンプ
- バージョンおよび著者情報
- 機密性およびアクセスレベルタグ
クエリ処理
- クエリの前処理とクリーニングを実装する
- より良い再現率を得るためにクエリ拡張を検討する
- ユーザーコンテキストに基づいた動的フィルタリングを適用する
- 結果品質向上のための再ランキングを使用する
パフォーマンス最適化
- 繰り返しクエリの埋め込みをキャッシュする
- バルク操作用にバッチ埋め込み生成を使用する
- 大きな結果セットに対してページネーションを実装する
- 長時間の操作に対して非同期処理を検討する
一般的なパターン
シンプルなRAGパイプライン
@RequiredArgsConstructor
@Service
public class SimpleRAGPipeline {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
private final ChatModel chatModel;
public String answerQuestion(String question) {
Embedding queryEmbedding = embeddingModel.embed(question).content();
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.build();
List<TextSegment> segments = embeddingStore.search(request).matches().stream()
.map(EmbeddingMatch::embedded)
.collect(Collectors.toList());
String context = segments.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
return chatModel.generate(context + "\n\nQuestion: " + question + "\nAnswer:");
}
}
ハイブリッド検索(ベクトル+キーワード)
@Service
@RequiredArgsConstructor
public class HybridSearchService {
private final EmbeddingStore<TextSegment> vectorStore;
private final FullTextSearchEngine keywordEngine;
private final EmbeddingModel embeddingModel;
public List<Content> hybridSearch(String query, int maxResults) {
// ベクトル検索
List<Content> vectorResults = performVectorSearch(query, maxResults);
// キーワード検索
List<Content> keywordResults = performKeywordSearch(query, maxResults);
// RRFアルゴリズムを使用して結果を結合し再ランキングする
return combineResults(vectorResults, keywordResults, maxResults);
}
}
トラブルシューティング
検証の失敗
埋め込み数の不一致:セグメント数と埋め込み数が異なる場合にスローされます。スプリッタの構成とモデルの可用性を確認してください。
検索結果が空:validateIngestion(testQuery)を呼び出して、埋め込みが検索可能であることを確認します。ドキュメントが正常に取り込まれたかどうかを確認してください。
検索スコアが低い:minScoreしきい値(デフォルト0.7)がユースケースに対して高すぎないか確認してください。既知のクエリでテストしてください。
よくある問題
検索結果が不十分
- ドキュメントチャンクサイズとオーバーラップの設定を確認する
- 埋め込みモデルの互換性を確認する
- メタデータフィルタが厳しすぎないことを確認する
- 再ランキングステップの追加を検討する
- 埋め込みが存在することを確認するために検証を実行する
パフォーマンスが遅い
- 頻繁なクエリに対してキャッシュされた埋め込みを使用する
- ベクトルストアのデータベースインデックスを最適化する
- 大規模なデータセット用にページネーションを実装する
- バルク操作の非同期処理を検討する
メモリ使用量が多い
- 大規模なデータセットにはディスクベースの埋め込みストアを使用する
- 適切なページネーションとフィルタリングを実装する
- 未使用の埋め込みを定期的にクリーンアップする
- チャンクサイズを監視して最適化する
制約と警告
- 埋め込みモデルのコスト:大規模なドキュメント集合の埋め込み生成は高額になる可能性があります。キャッシングとバッチ処理を実装してください。
- ベクトルストアのスケーラビリティ:メモリ内ストアは開発専用です。本番環境ではPinecone、Qdrant、Redisなどの永続的なストアを使用してください。
- チャンクサイズのトレードオフ:小さいチャンクは精度が向上しますがコンテキストが失われます。大きいチャンクはコンテキストが保持されますがノイズが増える可能性があります。
- 陳旧化データ:キャッシュされた埋め込みはソースドキュメントが変更されると陳旧化します。更新戦略を実装してください。
- トークン制限:RAGコンテキストウィンドウに制限があります。通常、検索された3~5チャンクが標準モデル制限内に収まります。
- ハルシネーションリスク:RAGはハルシネーションを軽減しますが排除しません。常に重要な応答をソースに対して検証してください。
- レイテンシ:ベクトル検索と埋め込み生成はレイテンシを追加します。リアルタイムアプリケーション用に非同期処理を検討してください。
- メタデータフィルタリング:過度に制限的なフィルタは結果が返されない可能性があります。フォールバック戦略を実装してください。
- マルチテナンシー:テナント間データ漏洩を防ぐために、適切なメタデータの分離を確保してください。
参考資料
API リファレンス- 完全なAPI ドキュメントとインターフェース例- 本番環境対応の例とパターン- LangChain4j 公式ドキュメント
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
agent-browser
AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。
anyskill
AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。
engram
AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。
skyvern
AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。
pinchbench
PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。
openui
OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。