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 $relevantDocumentsstring $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 $documentsstring $queryint $topK): array {
    
$embeddingConfig = new OpenAIConfig(apiKey$apiKeymodel'text-embedding-3-small');
    
$chatConfig = new OpenAIConfig(apiKey$apiKeymodel'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,
    ];
}