From 90023df24d3e8ea1bf8b7dca545ffb5fbd1d47c7 Mon Sep 17 00:00:00 2001 From: team 1 Date: Wed, 6 May 2026 13:36:40 +0200 Subject: [PATCH] fix p49 --- config/retriex/agent.yaml | 8 ++ src/Agent/AgentRunner.php | 160 ++++++++++++------------------- src/Config/AgentRunnerConfig.php | 13 +++ 3 files changed, 84 insertions(+), 97 deletions(-) diff --git a/config/retriex/agent.yaml b/config/retriex/agent.yaml index 0f68a8d..4579f8a 100644 --- a/config/retriex/agent.yaml +++ b/config/retriex/agent.yaml @@ -500,6 +500,14 @@ parameters: direct_result_guard: enabled: true + compound_prefix_match: + enabled: true + # Some Shopware product names combine the requested product type with + # a noun suffix, for example "pH-Pufferlösung". Keep this list small + # and explicit so broad direct-result filtering remains safe. + terms: + - puffer + - kalibrierpuffer length_sort: enabled: true diff --git a/src/Agent/AgentRunner.php b/src/Agent/AgentRunner.php index 6302294..acff5b3 100644 --- a/src/Agent/AgentRunner.php +++ b/src/Agent/AgentRunner.php @@ -292,26 +292,6 @@ final readonly class AgentRunner $optimizedShopQuery = ''; } - $referentialAnchoredShopSearchQuery = $this->guardReferentialShopQueryFallbackWithHistoryAnchor( - prompt: $originalPrompt, - shopSearchQuery: $shopSearchQuery, - commerceHistoryContext: $shopQueryHistoryContext - ); - - if ($referentialAnchoredShopSearchQuery !== $shopSearchQuery) { - $this->agentLogger->info('Enriched referential shop fallback query with history anchor', [ - 'userId' => $userId, - 'prompt' => $prompt, - 'routingPrompt' => $routingPrompt, - 'optimizedShopQuery' => $optimizedShopQuery, - 'shopSearchQuery' => $shopSearchQuery, - 'referentialAnchoredShopSearchQuery' => $referentialAnchoredShopSearchQuery, - ]); - - $shopSearchQuery = $referentialAnchoredShopSearchQuery; - $optimizedShopQuery = ''; - } - $ragAnchoredShopSearchQuery = $this->enrichShopSearchQueryWithRagAnchor( prompt: $originalPrompt, shopSearchQuery: $shopSearchQuery, @@ -2601,83 +2581,6 @@ final readonly class AgentRunner return trim($query); } - private function guardReferentialShopQueryFallbackWithHistoryAnchor( - string $prompt, - string $shopSearchQuery, - string $commerceHistoryContext - ): string { - if (!$this->agentRunnerConfig->isShopQueryContextAnchorEnrichmentEnabled()) { - return $shopSearchQuery; - } - - if (trim($commerceHistoryContext) === '') { - return $shopSearchQuery; - } - - if (!$this->shouldUseCommerceHistoryForShopQuery($prompt)) { - return $shopSearchQuery; - } - - $combined = trim($shopSearchQuery . ' ' . $prompt); - if (!$this->containsConfiguredShopQueryAnchorTrigger($combined)) { - return $shopSearchQuery; - } - - $anchor = $this->normalizeShopQueryAnchor( - $this->extractLatestConfiguredShopQueryContextAnchor($commerceHistoryContext) - ); - - if ($anchor === '' || $this->queryAlreadyContainsAllAnchorTokens($shopSearchQuery, $anchor)) { - return $shopSearchQuery; - } - - $referentialQuery = $this->extractReferentialShopQueryTriggerTerms($combined); - if ($referentialQuery === '') { - return $shopSearchQuery; - } - - $template = $this->agentRunnerConfig->getShopQueryContextAnchorEnrichmentTemplate(); - $enriched = $this->renderAgentTemplate($template, [ - 'anchor' => $anchor, - 'query' => $referentialQuery, - ]); - $enriched = preg_replace('/\s+/u', ' ', $enriched) ?? $enriched; - $enriched = trim($enriched); - - return $enriched !== '' ? $enriched : $shopSearchQuery; - } - - private function extractReferentialShopQueryTriggerTerms(string $text): string - { - $tokens = $this->tokenizeShopQueryCandidate($text); - - if ($tokens === []) { - return ''; - } - - $triggerTokens = []; - foreach ($this->agentRunnerConfig->getShopQueryContextAnchorEnrichmentTriggerTerms() as $term) { - foreach ($this->tokenizeShopQueryCandidate($term) as $termToken) { - $triggerTokens[$termToken] = true; - } - } - - if ($triggerTokens === []) { - return ''; - } - - $out = []; - foreach ($tokens as $token) { - if (!isset($triggerTokens[$token]) || isset($out[$token])) { - continue; - } - - $out[$token] = $token; - } - - return implode(' ', array_values($out)); - } - private function enrichReferentialShopQueryFromHistory( string $query, string $sourcePrompt, @@ -3339,6 +3242,69 @@ final readonly class AgentRunner if ($this->containsAllShopQueryTokens($productText, $term)) { return true; } + + if ($this->containsAllShopQueryTokensWithCompoundPrefixes($productText, $term)) { + return true; + } + } + + return false; + } + + private function containsAllShopQueryTokensWithCompoundPrefixes(string $text, string $term): bool + { + if (!$this->agentRunnerConfig->isDirectShopResultGuardCompoundPrefixMatchEnabled()) { + return false; + } + + $tokens = $this->tokenizeShopQueryCandidate($text); + $termTokens = $this->tokenizeShopQueryCandidate($term); + + if ($tokens === [] || $termTokens === []) { + return false; + } + + $exactTokens = array_fill_keys($tokens, true); + + foreach ($termTokens as $termToken) { + if (isset($exactTokens[$termToken])) { + continue; + } + + if (!$this->directProductTermAllowsCompoundPrefixMatch($termToken)) { + return false; + } + + $matchedPrefix = false; + $termTokenLength = mb_strlen($termToken, 'UTF-8'); + + foreach ($tokens as $token) { + if (mb_strlen($token, 'UTF-8') <= $termTokenLength) { + continue; + } + + if (mb_substr($token, 0, $termTokenLength, 'UTF-8') === $termToken) { + $matchedPrefix = true; + break; + } + } + + if (!$matchedPrefix) { + return false; + } + } + + return true; + } + + private function directProductTermAllowsCompoundPrefixMatch(string $termToken): bool + { + foreach ($this->agentRunnerConfig->getDirectShopResultGuardCompoundPrefixTerms() as $configuredTerm) { + foreach ($this->tokenizeShopQueryCandidate($configuredTerm) as $configuredToken) { + if ($termToken === $configuredToken) { + return true; + } + } } return false; diff --git a/src/Config/AgentRunnerConfig.php b/src/Config/AgentRunnerConfig.php index df8f757..9693032 100644 --- a/src/Config/AgentRunnerConfig.php +++ b/src/Config/AgentRunnerConfig.php @@ -1140,6 +1140,19 @@ final class AgentRunnerConfig return $this->getRequiredBool('shop_prompt.direct_result_guard.enabled'); } + public function isDirectShopResultGuardCompoundPrefixMatchEnabled(): bool + { + return $this->getOptionalBool('shop_prompt.direct_result_guard.compound_prefix_match.enabled', false); + } + + /** + * @return string[] + */ + public function getDirectShopResultGuardCompoundPrefixTerms(): array + { + return $this->getOptionalStringList('shop_prompt.direct_result_guard.compound_prefix_match.terms'); + } + public function isShopResultLengthSortEnabled(): bool { return $this->getRequiredBool('shop_prompt.length_sort.enabled');