Case 4. RAG for internal documentation with LLPhant
A controlled internal documentation QA pipeline in PHP with LLPhant
In this case we move from pure PHP RAG to LLPhant components for embeddings and vector storage while preserving strict control over retrieval, context building, and hallucination prevention.
Example of code:
<?php
use LLPhant\Chat\Enums\ChatRole;
use LLPhant\Chat\Message;
use LLPhant\Chat\OpenAIChat;
use LLPhant\Embeddings\Document;
use LLPhant\Embeddings\EmbeddingGenerator\EmbeddingGeneratorInterface;
use LLPhant\Embeddings\EmbeddingGenerator\OpenAI\OpenAI3SmallEmbeddingGenerator;
use LLPhant\Embeddings\VectorStores\Memory\MemoryVectorStore;
use LLPhant\OpenAIConfig;
function documentsForOutputRows(array $documents): array {
$rows = [];
foreach ($documents as $index => $document) {
$rows[] = [
'id' => $index + 1,
'content' => $document->content,
];
}
return $rows;
}
function buildControlledContextPrompt(array $relevantDocuments, string $query): string {
$context = 'You answer strictly based on the context below. ';
$context .= "If the answer is missing, say that information is insufficient.\n\n";
$context .= "Context:\n";
foreach ($relevantDocuments as $document) {
$context .= '- ' . ($document->content ?? '') . "\n";
}
$context .= "\nQuestion: {$query}";
return $context;
}
function makeDocument(string $content): Document {
$document = new Document();
$document->content = $content;
return $document;
}
function runRagWithLlphant(string $apiKey, array $documents, string $query, int $topK): array {
$embeddingConfig = new OpenAIConfig(apiKey: $apiKey, model: 'text-embedding-3-small');
$chatConfig = new OpenAIConfig(apiKey: $apiKey, model: 'gpt-4o-mini');
$embeddingGenerator = new OpenAI3SmallEmbeddingGenerator($embeddingConfig);
$vectorStore = new MemoryVectorStore();
$embeddedDocuments = $embeddingGenerator->embedDocuments($documents);
$vectorStore->addDocuments($embeddedDocuments);
$queryEmbedding = $embeddingGenerator->embedText($query);
$relevantDocuments = $vectorStore->similaritySearch($queryEmbedding, $topK);
$contextPrompt = buildControlledContextPrompt($relevantDocuments, $query);
$chat = new OpenAIChat($chatConfig);
$message = new Message();
$message->role = ChatRole::User;
$message->content = $contextPrompt;
$answer = $chat->generateText((string)$message);
return [
'query' => $query,
'top_k' => $topK,
'documents' => $documents,
'relevant_documents' => $relevantDocuments,
'context_prompt' => $contextPrompt,
'answer' => (string)$answer,
];
}