RAG 語意搜尋範例(Enterprise)¶
需求套件:nextpdf/enterprise 難度:進階
先決條件¶
架構概觀¶
PDF 文件
│
▼ NextPDF Enterprise
┌──────────────────────┐
│ PDF 文字提取 │ ─── 保留結構(段落、標題、表格)
│ + 結構分析 │ ─── 章節偵測、頁碼記錄
└──────────┬───────────┘
│
▼ 文字分塊
┌──────────────────────┐
│ Semantic Chunker │ ─── 依語義邊界切分(非固定字元數)
│ (Enterprise) │ ─── 保留上下文重疊
└──────────┬───────────┘
│
▼ 向量化(外部服務)
┌──────────────────────┐
│ Embedding API │ ─── OpenAI / Anthropic / 本地模型
└──────────┬───────────┘
│
▼ 儲存
┌──────────────────────┐
│ Vector Database │ ─── Qdrant / Pinecone / pgvector
└──────────────────────┘
完整程式碼¶
一、PDF 文字提取與分塊¶
<?php
declare(strict_types=1);
use NextPDF\Enterprise\Extraction\PdfTextExtractor;
use NextPDF\Enterprise\Extraction\ValueObjects\ExtractionOptions;
use NextPDF\Enterprise\Rag\SemanticChunker;
use NextPDF\Enterprise\Rag\ValueObjects\ChunkingOptions;
use NextPDF\Enterprise\Rag\ValueObjects\TextChunk;
// ─── 文字提取 ─────────────────────────────────────────────────
$extractor = PdfTextExtractor::create();
$extractedDoc = $extractor->extract(
path: '/documents/technical-manual.pdf',
options: ExtractionOptions::create()
->withStructurePreservation(true) // 保留標題/段落結構
->withTableExtraction(true) // 提取表格內容
->withPageMetadata(true) // 記錄頁碼
->withLanguageDetection(true), // 自動偵測語言
);
// ─── 語義分塊 ─────────────────────────────────────────────────
$chunker = SemanticChunker::create();
$chunks = $chunker->chunk(
document: $extractedDoc,
options: ChunkingOptions::create()
->withMaxChunkSize(512) // 最大 token 數
->withOverlap(50) // 重疊 token 數
->withSentenceBoundary(true) // 在句子邊界切分
->withPreserveCodeBlocks(true) // 完整保留程式碼區塊
->withPreserveTables(true), // 完整保留表格
);
foreach ($chunks as $chunk) {
echo "Chunk ID: {$chunk->id()}\n";
echo "Page: {$chunk->sourcePageRange()}\n";
echo "Section: {$chunk->sectionTitle()}\n";
echo "Text: {$chunk->text()}\n";
echo "---\n";
}
二、向量化與索引¶
use NextPDF\Enterprise\Rag\VectorIndexer;
use NextPDF\Enterprise\Rag\Embeddings\OpenAiEmbeddingProvider;
use NextPDF\Enterprise\Rag\Storage\QdrantVectorStore;
// ─── 嵌入提供者(OpenAI)────────────────────────────────────
$embeddingProvider = OpenAiEmbeddingProvider::create(
apiKey: $_ENV['OPENAI_API_KEY'],
model: 'text-embedding-3-large',
dimensions: 1536,
);
// ─── 向量資料庫(Qdrant)────────────────────────────────────
$vectorStore = QdrantVectorStore::create(
host: $_ENV['QDRANT_HOST'],
apiKey: $_ENV['QDRANT_API_KEY'],
collectionName: 'nextpdf-documents',
vectorSize: 1536,
);
// ─── 建立索引 ─────────────────────────────────────────────────
$indexer = VectorIndexer::create(
embeddingProvider: $embeddingProvider,
vectorStore: $vectorStore,
);
$result = $indexer->index(
chunks: $chunks,
documentId: 'technical-manual-v2',
metadata: [
'filename' => 'technical-manual.pdf',
'version' => '2.0',
'language' => 'zh-TW',
'indexed_at' => date('c'),
],
batchSize: 50, // 每批次 50 個向量
);
echo "Indexed {$result->indexedCount()} chunks.\n";
echo "Failed: {$result->failedCount()}\n";
三、語意搜尋與 RAG 查詢¶
use NextPDF\Enterprise\Rag\SemanticSearcher;
use NextPDF\Enterprise\Rag\ValueObjects\SearchQuery;
use NextPDF\Enterprise\Rag\ValueObjects\SearchOptions;
$searcher = SemanticSearcher::create(
embeddingProvider: $embeddingProvider,
vectorStore: $vectorStore,
);
// ─── 語意搜尋 ─────────────────────────────────────────────────
$results = $searcher->search(
query: SearchQuery::fromText('如何在 PHP 中生成 PDF 數位簽章?'),
options: SearchOptions::create()
->withTopK(5) // 返回最相關的 5 個結果
->withMinScore(0.7) // 最低相似度分數
->withFilter([ // 元資料過濾
'language' => 'zh-TW',
])
->withReranking(true), // 啟用重排序
);
// ─── 建構 RAG 提示詞 ──────────────────────────────────────────
$context = implode("\n\n---\n\n", array_map(
static fn($r) => "來源:{$r->metadata()['filename']} 第 {$r->sourcePageRange()} 頁\n{$r->text()}",
$results->items(),
));
$prompt = <<<PROMPT
請根據以下 NextPDF 文件內容回答問題。
問題:如何在 PHP 中生成 PDF 數位簽章?
相關文件內容:
{$context}
請提供具體的 PHP 程式碼範例,並說明每個步驟。
PROMPT;
// 將 $prompt 傳送給 LLM(Anthropic Claude、OpenAI GPT 等)
// $response = $llmClient->chat($prompt);
批次處理多個 PDF¶
$files = glob('/documents/*.pdf');
foreach ($files as $file) {
$extracted = $extractor->extract(path: $file);
$chunks = $chunker->chunk(document: $extracted);
$indexer->index(chunks: $chunks, documentId: md5($file));
}
程式碼說明¶
延伸閱讀¶
- Enterprise API — 文字提取與 RAG 完整 API
- NextPDF Connect (MCP Server) — AI 代理工具整合