Case 1. Internal corporate assistant for regulations and policies

A pure PHP RAG example for answering employee questions from approved internal documents

In this case, we build a simple corporate knowledge assistant with chunking, embeddings, retrieval, access filtering, and controlled context building before answer generation.

 
<?php

include 'code-en.php';

$userRole = 'employee';
$queryText = 'How many days do we have to report a data leak?';
$topK = 3;

$chunks = splitIntoChunks($documents, 1);
$chunksById = [];
$chunkEmbeddings = [];

foreach (
$chunks as $chunk) {
    
$chunkId = (int)$chunk['id'];
    
$chunksById[$chunkId] = $chunk;
    
$chunkEmbeddings[$chunkId] = embedChunkText((string)$chunk['content']);
}

$queryEmbedding = embedChunkText($queryText);
$scores = [];

foreach (
$chunkEmbeddings as $chunkId => $vector) {
    
$scores[$chunkId] = cosineSimilarity($queryEmbedding, $vector);
}

arsort($scores);
$rankedChunks = [];

foreach (
$scores as $chunkId => $score) {
    
$chunk = $chunksById[$chunkId];

    
$rankedChunks[] = [
        
'chunk_id' => $chunkId,
        
'score' => $score,
        
'document' => $chunk['document'],
        
'section' => $chunk['section'],
        
'access' => $chunk['access'],
        
'allowed_for_user' => canUserAccessChunk($userRole, (string)$chunk['access'], $roleToScopes),
        
'content' => $chunk['content'],
    ];
}

$topRetrievedRows = array_slice($rankedChunks, 0, $topK);
$contextChunks = [];

foreach (
$topRetrievedRows as $row) {
    if (
$row['allowed_for_user']) {
        
$contextChunks[] = $chunksById[(int)$row['chunk_id']];
    }
}

$contextBlocks = [];

foreach (
$contextChunks as $chunk) {
    
$contextBlocks[] = '[' . $chunk['document'] . ', section ' . $chunk['section'] . "]\n" . $chunk['content'];
}

$contextText = implode("\n\n", $contextBlocks);

$systemInstruction = 'Use only approved context chunks. Do not invent facts. If context is missing, refuse to answer and say what source is required.';
$answerPayload = buildAnswerFromContext($queryText, $contextChunks);


echo 
'Case goal:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
'Build a simple corporate RAG assistant in pure PHP for questions over approved internal policies.' . PHP_EOL;
echo 
PHP_EOL;

echo 
'Scenario:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
'Question: ' . $queryText . PHP_EOL;
echo 
'User role: ' . $userRole . PHP_EOL;
echo 
PHP_EOL;

echo 
'Stage 1. Chunking:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
array_to_matrix($chunks, withHeaders: true, withPadding: true, withCommas: false, showRowNumbers: true);
echo 
PHP_EOL . PHP_EOL;

echo 
'Stage 2. Chunk embeddings:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
array_to_matrix($chunkEmbeddings, showRowNumbers: true);
echo 
PHP_EOL . PHP_EOL;

echo 
'Stage 3. Retrieval (cosine similarity, Top-K=' . $topK . '):' . PHP_EOL;
echo 
'-----------' . PHP_EOL;

foreach (
$topRetrievedRows as $row) {
    
$score = number_format((float) $row['score'], 6, '.', '');
    
$access = $row['allowed_for_user'] ? 'allowed' : 'blocked';

    echo 
'chunk_' . $row['chunk_id'] . ' | score=' . $score . ' | ' . $row['document'] . ' | access=' . $access . PHP_EOL;
}
echo 
PHP_EOL;

echo 
'Optional stage. Access filtering:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;

foreach (
$topRetrievedRows as $row) {
    if (
$row['allowed_for_user']) {
        continue;
    }

    echo 
'Excluded chunk_' . $row['chunk_id'] . ' (' . $row['document'] . ') due to access policy.' . PHP_EOL;
}
echo 
PHP_EOL;

echo 
'Stage 4. Controlled context building:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
'Instruction:' . PHP_EOL;
echo 
$systemInstruction . PHP_EOL . PHP_EOL;
echo 
'Context:' . PHP_EOL;
echo 
$contextText . PHP_EOL . PHP_EOL;

echo 
'Stage 5. Answer generation:' . PHP_EOL;
echo 
'-----------' . PHP_EOL;
echo 
'Answer: ' . $answerPayload['answer'] . PHP_EOL;
echo 
'Source: ' . $answerPayload['source'] . PHP_EOL;
Result: Memory: 0.033 Mb Time running: < 0.001 sec.
Case goal:
-----------
Build a simple corporate RAG assistant in pure PHP for questions over approved internal policies.

Scenario:
-----------
Question: How many days do we have to report a data leak?
User role: employee

Stage 1. Chunking:
-----------
#: [id document_id document                section access content                                                                                         ]
1: [1  1           HR Policy v3            4.2     all    Remote work from another country is possible only after approval from HR and the direct manager.]
2: [2  1           HR Policy v3            4.2     all    The request must be submitted before travel and include the planned location and period.        ]
3: [3  2           Security Policy v2      2.1     all    Security incidents must be reported within 24 hours after discovery.                            ]
4: [4  2           Security Policy v2      2.1     all    The report must include incident type, affected systems, and initial mitigation steps.          ]
5: [5  3           Legal Incident Playbook 7.3     legal  Notification to external legal parties must be prepared within 72 hours after data leakage.     ]
6: [6  3           Legal Incident Playbook 7.3     legal  All communication drafts require legal department approval before sending.                      ]

Stage 2. Chunk embeddings:
-----------
1: [1.001, 1.001, 1.001, 0.001, 0.001, 0.001, 0.48]
2: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.44]
3: [0.001, 0.001, 0.001, 1.001, 1.001, 1.001, 0.34]
4: [0.001, 0.001, 0.001, 1.001, 1.001, 0.001, 0.43]
5: [0.001, 0.001, 0.001, 1.001, 0.001, 1.001, 0.455]
6: [0.001, 0.001, 1.001, 0.001, 0.001, 0.001, 0.37]

Stage 3. Retrieval (cosine similarity, Top-K=3):
-----------
chunk_3 | score=0.998264 | Security Policy v2 | access=allowed
chunk_4 | score=0.813595 | Security Policy v2 | access=allowed
chunk_5 | score=0.811772 | Legal Incident Playbook | access=blocked

Optional stage. Access filtering:
-----------
Excluded chunk_5 (Legal Incident Playbook) due to access policy.

Stage 4. Controlled context building:
-----------
Instruction:
Use only approved context chunks. Do not invent facts. If context is missing, refuse to answer and say what source is required.

Context:
[Security Policy v2, section 2.1]
Security incidents must be reported within 24 hours after discovery.

[Security Policy v2, section 2.1]
The report must include incident type, affected systems, and initial mitigation steps.

Stage 5. Answer generation:
-----------
Answer: According to Security Policy v2, incidents must be reported within 24 hours after discovery.
Source: Security Policy v2, section 2.1