137 lines
4.9 KiB
PHP
137 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Agent;
|
|
|
|
use App\Context\ContextService;
|
|
use App\Context\UrlAnalyzer;
|
|
use DateTimeImmutable;
|
|
|
|
final class PromptBuilder
|
|
{
|
|
public function __construct(
|
|
private readonly ContextService $contextService,
|
|
private readonly UrlAnalyzer $urlAnalyzer,
|
|
)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Build the final prompt string for the LLM.
|
|
*
|
|
* @param string $prompt
|
|
* @param string $userId
|
|
* @param string $urlContent
|
|
* @param string[] $knowledgeChunks
|
|
* @param bool $fullContext
|
|
*/
|
|
public function build(
|
|
string $prompt,
|
|
string $userId,
|
|
string $urlContent,
|
|
array $knowledgeChunks,
|
|
bool $fullContext = false,
|
|
): string
|
|
{
|
|
$now = (new DateTimeImmutable())->format('Y-m-d H:i:s');
|
|
|
|
// ------------------------------------------------------------
|
|
// 1) SYSTEM INSTRUCTIONS
|
|
// ------------------------------------------------------------
|
|
$systemLines = [
|
|
'You are a conversational AI assistant.',
|
|
'Respond clearly, precisely, and in context of the ongoing conversation.',
|
|
'The conversation context is authoritative and must be respected.',
|
|
'External knowledge is supporting information only.',
|
|
'If the user asks for contact details such as phone number, email address, postal address or contact person, and the provided context contains such information, answer explicitly with the concrete data.',
|
|
'Do not omit contact details.',
|
|
'It is allowed and desired to quote contact data verbatim if it appears in the context.',
|
|
"Current date and time: {$now}",
|
|
'',
|
|
'IMPORTANT FORMATTING RULES:',
|
|
'- Always answer in valid Markdown.',
|
|
'- Use headings, lists, and paragraphs where appropriate.',
|
|
'- Insert line breaks early and often.',
|
|
'- Never write long paragraphs without newlines.',
|
|
'- Each list item must start on a new line.',
|
|
'- Prefer short paragraphs over dense text blocks.',
|
|
'',
|
|
'IMPORTANT LANGUAGE RULES:',
|
|
'- If the user input contains misspellings, silently use the correct canonical terms in your answer.',
|
|
'- Never mention, explain, or point out spelling mistakes.',
|
|
'- Do not ask clarifying questions about possible misspellings.',
|
|
'- Do not repeat or quote misspelled terms from the user input.',
|
|
'- Always use the correct technical spelling found in the provided context.',
|
|
'- Answer directly and confidently using always correct canonical terminology.'
|
|
];
|
|
|
|
$systemBlock = "SYSTEM:\n" . implode("\n", $systemLines);
|
|
|
|
// ------------------------------------------------------------
|
|
// 2) CONVERSATION CONTEXT (AUTHORITATIVE)
|
|
// ------------------------------------------------------------
|
|
$history = $this->contextService->buildUserContext(
|
|
userId: $userId,
|
|
full: $fullContext
|
|
);
|
|
|
|
$contextBlock = '';
|
|
if ($history !== '') {
|
|
$contextBlock =
|
|
"CONVERSATION CONTEXT (authoritative):\n" .
|
|
"The following messages are the previous turns of this conversation.\n" .
|
|
"They must be considered when answering the next question.\n\n" .
|
|
$history;
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// 3) EXTERNAL KNOWLEDGE (SUPPORTING)
|
|
// ------------------------------------------------------------
|
|
$knowledgeParts = [];
|
|
|
|
if ($knowledgeChunks !== []) {
|
|
$lines = [];
|
|
|
|
foreach ($knowledgeChunks as $i => $chunk) {
|
|
$n = $i + 1;
|
|
$lines[] = "[{$n}] {$chunk}";
|
|
}
|
|
|
|
$knowledgeParts[] =
|
|
"RETRIEVED KNOWLEDGE (supporting):\n" .
|
|
implode("\n\n", $lines);
|
|
}
|
|
|
|
if ($urlContent !== '') {
|
|
$knowledgeParts[] =
|
|
"CONTENT FROM URL (supporting):\n" .
|
|
$urlContent;
|
|
}
|
|
|
|
$knowledgeBlock = '';
|
|
if ($knowledgeParts !== []) {
|
|
$knowledgeBlock = implode("\n\n", $knowledgeParts);
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// 4) USER QUESTION
|
|
// ------------------------------------------------------------
|
|
$userBlock =
|
|
"USER QUESTION:\n" .
|
|
$prompt;
|
|
|
|
// ------------------------------------------------------------
|
|
// 5) FINAL PROMPT ASSEMBLY
|
|
// ------------------------------------------------------------
|
|
$blocks = array_filter([
|
|
$systemBlock,
|
|
$contextBlock,
|
|
$knowledgeBlock,
|
|
$userBlock,
|
|
]);
|
|
|
|
return implode("\n\n", $blocks);
|
|
}
|
|
}
|