harden retrieval logic
bugfixes
This commit is contained in:
@@ -51,6 +51,9 @@ final readonly class AgentRunner
|
||||
$shopResults = [];
|
||||
$sources = [];
|
||||
$optimizedShopQuery = '';
|
||||
$shopSearchQuery = '';
|
||||
$commerceIntent = CommerceIntentLite::NONE;
|
||||
$commerceHistoryContext = '';
|
||||
|
||||
$this->agentLogger->info('Agent run started', [
|
||||
'userId' => $userId,
|
||||
@@ -97,7 +100,7 @@ final readonly class AgentRunner
|
||||
|
||||
$commerceHistoryContext = $this->buildCommerceHistoryContext($userId);
|
||||
|
||||
if($commerceHistoryContext){
|
||||
if ($commerceHistoryContext !== '') {
|
||||
$this->addSource($sources, 'Chatverlauf');
|
||||
}
|
||||
|
||||
@@ -109,6 +112,16 @@ final readonly class AgentRunner
|
||||
|
||||
$shopSearchQuery = $optimizedShopQuery !== '' ? $optimizedShopQuery : $prompt;
|
||||
|
||||
$this->agentLogger->info('Commerce search prepared', [
|
||||
'userId' => $userId,
|
||||
'commerceIntent' => $commerceIntent,
|
||||
'usedOptimizedShopQuery' => $optimizedShopQuery !== '',
|
||||
'optimizedShopQuery' => $optimizedShopQuery,
|
||||
'shopSearchQuery' => $shopSearchQuery,
|
||||
'hasCommerceHistoryContext' => $commerceHistoryContext !== '',
|
||||
'commerceHistoryContextLength' => mb_strlen($commerceHistoryContext),
|
||||
]);
|
||||
|
||||
yield $this->systemMsg(
|
||||
'Ich rufe Recherchedaten ab (type: ' . $commerceIntent . ')',
|
||||
'think'
|
||||
@@ -126,7 +139,9 @@ final readonly class AgentRunner
|
||||
}
|
||||
}
|
||||
|
||||
$knowledgeChunks = $this->limitKnowledgeChunks($knowledgeChunks, $commerceIntent);
|
||||
if ($shopResults !== []) {
|
||||
$knowledgeChunks = $this->limitKnowledgeChunks($knowledgeChunks, $commerceIntent);
|
||||
}
|
||||
|
||||
yield $this->systemMsg('Ich analysiere alle Informationen...', 'think');
|
||||
|
||||
@@ -148,6 +163,7 @@ final readonly class AgentRunner
|
||||
'userId' => $userId,
|
||||
'finalPrompt' => $finalPrompt,
|
||||
'optimizedShopQuery' => $optimizedShopQuery,
|
||||
'shopSearchQuery' => $shopSearchQuery,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -198,6 +214,10 @@ final readonly class AgentRunner
|
||||
'knowledgeChunkCount' => count($knowledgeChunks),
|
||||
'hasUrlContent' => $urlContent !== '',
|
||||
'usedOptimizedShopQuery' => $optimizedShopQuery !== '',
|
||||
'optimizedShopQuery' => $optimizedShopQuery,
|
||||
'shopSearchQuery' => $shopSearchQuery,
|
||||
'hasCommerceHistoryContext' => $commerceHistoryContext !== '',
|
||||
'commerceHistoryContextLength' => mb_strlen($commerceHistoryContext),
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$this->agentLogger->error('Agent run failed', [
|
||||
@@ -282,6 +302,8 @@ final readonly class AgentRunner
|
||||
'userId' => $userId,
|
||||
'commerceIntent' => $commerceIntent,
|
||||
'query' => $query,
|
||||
'hasCommerceHistoryContext' => $commerceHistoryContext !== '',
|
||||
'commerceHistoryContextLength' => mb_strlen($commerceHistoryContext),
|
||||
'exception' => $e,
|
||||
]);
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ final readonly class PromptBuilder
|
||||
*/
|
||||
private const MIN_PROMPT_BUDGET_TOKENS = 1024;
|
||||
|
||||
/**
|
||||
* Limit how many ranked shop results are passed into the final prompt.
|
||||
* The shop search may return many candidates, but the LLM should only see
|
||||
* the most relevant top subset after local reranking.
|
||||
*/
|
||||
private const MAX_SHOP_RESULTS_IN_PROMPT = 8;
|
||||
|
||||
/**
|
||||
* Technical product prompts should be answered like documentation,
|
||||
* not like sales copy.
|
||||
@@ -84,8 +91,7 @@ final readonly class PromptBuilder
|
||||
private ContextService $contextService,
|
||||
private SystemPromptRepository $systemPromptRepository,
|
||||
private ModelGenerationConfigProvider $modelGenerationConfigProvider,
|
||||
)
|
||||
{
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,18 +228,21 @@ final readonly class PromptBuilder
|
||||
"Source: Shop Search";
|
||||
}
|
||||
|
||||
if ($shopResults === []) {
|
||||
$normalizedShopResults = array_values(array_filter(
|
||||
$shopResults,
|
||||
static fn(mixed $product): bool => $product instanceof ShopProductResult
|
||||
));
|
||||
|
||||
if ($normalizedShopResults === []) {
|
||||
return $this->implodeBlocks($parts);
|
||||
}
|
||||
|
||||
$isDetailed = count($shopResults) <= 5;
|
||||
$totalCount = count($normalizedShopResults);
|
||||
$limitedShopResults = array_slice($normalizedShopResults, 0, self::MAX_SHOP_RESULTS_IN_PROMPT);
|
||||
$isDetailed = count($limitedShopResults) <= 5;
|
||||
$lines = [];
|
||||
|
||||
foreach ($shopResults as $i => $product) {
|
||||
if (!$product instanceof ShopProductResult) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($limitedShopResults as $i => $product) {
|
||||
$n = $i + 1;
|
||||
$entryParts = [
|
||||
"[{$n}] " . $this->normalizeBlockText($product->name),
|
||||
@@ -283,13 +292,19 @@ final readonly class PromptBuilder
|
||||
}
|
||||
|
||||
if ($lines !== []) {
|
||||
$parts[] =
|
||||
$header =
|
||||
"LIVE SHOP RESULTS (authoritative for current commercial details):\n" .
|
||||
"Use these results as the primary source for current price, availability, URL, and current shop-visible product naming.\n" .
|
||||
"If retrieved documents conflict with shop data on price, availability, URL, or current naming, prefer the shop data.\n" .
|
||||
"Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.\n" .
|
||||
"Do not infer undocumented technical specifications from shop data.\n\n" .
|
||||
implode("\n\n", $lines);
|
||||
"Do not infer undocumented technical specifications from shop data.";
|
||||
|
||||
if ($totalCount > count($limitedShopResults)) {
|
||||
$header .= "\n" .
|
||||
"Only the top " . count($limitedShopResults) . " ranked shop results are shown here out of {$totalCount} total results.";
|
||||
}
|
||||
|
||||
$parts[] = $header . "\n\n" . implode("\n\n", $lines);
|
||||
}
|
||||
|
||||
return $this->implodeBlocks($parts);
|
||||
|
||||
Reference in New Issue
Block a user