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.
Example of use
<?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