diff --git a/config/retriex/genre.yaml b/config/retriex/genre.yaml index 7c37773..5ea827c 100644 --- a/config/retriex/genre.yaml +++ b/config/retriex/genre.yaml @@ -1166,6 +1166,9 @@ parameters: - brauerei - brauereien - brauwasser + - schwimmbad + - schwimmbecken + - pool - 0,02 stopword_cleanup: origin: genre_native @@ -1259,6 +1262,9 @@ parameters: - brauerei - brauereien - brauwasser + - schwimmbad + - schwimmbecken + - pool - redox - orp - ph diff --git a/patch_history/RETRIEX_PATCH_83_SHOP_QUERY_TOKEN_CORRECTION_PRESERVATION_README.md b/patch_history/RETRIEX_PATCH_83_SHOP_QUERY_TOKEN_CORRECTION_PRESERVATION_README.md new file mode 100644 index 0000000..43a587d --- /dev/null +++ b/patch_history/RETRIEX_PATCH_83_SHOP_QUERY_TOKEN_CORRECTION_PRESERVATION_README.md @@ -0,0 +1,66 @@ +# RetrieX Patch p83 - Shop Query Token Correction Preservation + +## Ziel + +Direkte Shop-Suchanfragen sollen Tippfehler-Korrekturen aus `commerce.search_token_corrections` auch dann behalten, wenn die finale Agent-Shopquery vorher durch LLM-Optimierung oder positive Token-Filterung stark reduziert wurde. + +Konkreter Regression-Guard: + +```text +ich würde gern chlor im schwinnbad messen +``` + +soll nicht mehr auf die zu breite Shopquery + +```text +chlor +``` + +reduziert werden, sondern den korrigierten Anwendungskontext behalten: + +```text +chlor schwimmbad +``` + +## Änderungen + +- `src/Agent/AgentRunner.php` + - injiziert `CommerceQueryParserConfig`, um die bestehende zentrale `search_token_corrections`-Liste wiederzuverwenden. + - wendet diese Korrekturen vor der finalen Shopquery-Stopword-/Positive-Token-Filterung an. + - korrigiert auch den Prompt-Kontext in `preserveCurrentInputShopQueryTerms()`, damit ein Tippfehler wie `schwinnbad` als konfigurierter Preservation-Term `schwimmbad` erkannt wird. + +- `config/retriex/genre.yaml` + - ergänzt `schwimmbad`, `schwimmbecken` und `pool` als erhaltenswerte Shop-Kontexttokens. + - ergänzt dieselben Begriffe in der kleinen positiven Shopquery-Allowlist, damit die finale Query nicht wieder auf `chlor` reduziert wird. + +## Nicht geändert + +- Kein Retrieval-/Scoring-/Ranking-Fix. +- Keine Shop-Matching-Änderung. +- Keine neue harte Tippfehlerliste im PHP-Core. +- Die bestehende `commerce.search_token_corrections`-Liste bleibt Source of Truth für Korrekturen wie `schwinnbad -> schwimmbad`. + +## Erwartete Wirkung + +```text +ich würde gern chlor im schwinnbad messen +=> chlor schwimmbad +``` + +```text +ich würde gern chlor im schwimmbad messen +=> chlor schwimmbad +``` + +Breite Chlor-Suchen ohne Pool-/Schwimmbad-Kontext bleiben unverändert möglich. + +## Empfohlene Prüfungen + +```bash +php -l src/Agent/AgentRunner.php +bin/console cache:clear +bin/console mto:agent:config:validate +bin/console mto:agent:regression:test +bin/console mto:agent:config:audit-source --details +bin/console mto:agent:config:audit-patterns --details +``` diff --git a/src/Agent/AgentRunner.php b/src/Agent/AgentRunner.php index fc0e33e..6792bdd 100644 --- a/src/Agent/AgentRunner.php +++ b/src/Agent/AgentRunner.php @@ -9,6 +9,7 @@ use App\Commerce\ProductRoleResolver; use App\Commerce\SearchRepairService; use App\Commerce\ShopSearchService; use App\Config\AgentRunnerConfig; +use App\Config\CommerceQueryParserConfig; use App\Config\LanguageCleanupConfig; use App\Context\ContextService; use App\Context\UrlAnalyzer; @@ -33,6 +34,7 @@ final readonly class AgentRunner private SearchRepairService $searchRepairService, private ReferenceAnchorExtractor $referenceAnchorExtractor, private CommerceIntentLite $commerceIntentLite, + private CommerceQueryParserConfig $commerceQueryParserConfig, private OllamaClient $ollamaClient, private LoggerInterface $agentLogger, private AgentRunnerConfig $agentRunnerConfig, @@ -1651,6 +1653,7 @@ final readonly class AgentRunner : $this->preserveCurrentInputShopQueryTerms($prompt, $shopSearchQuery); $query = $this->cleanupDirectProductAttributeShopQuery($prompt, $query); + $query = $this->applyConfiguredShopSearchTokenCorrections($query); return $this->cleanupShopQueryStopwords($query); } @@ -1988,14 +1991,17 @@ final readonly class AgentRunner $shopSearchQuery = trim($shopSearchQuery); if ($shopSearchQuery === '' || !$this->agentRunnerConfig->isShopQueryCurrentInputPreservationEnabled()) { - return $shopSearchQuery; + return $this->applyConfiguredShopSearchTokenCorrections($shopSearchQuery); } - $promptTokens = array_fill_keys($this->tokenizeShopQueryCandidate($prompt), true); - $queryTokens = array_fill_keys($this->tokenizeShopQueryCandidate($shopSearchQuery), true); + $correctedPrompt = $this->applyConfiguredShopSearchTokenCorrections($prompt); + $correctedShopSearchQuery = $this->applyConfiguredShopSearchTokenCorrections($shopSearchQuery); + + $promptTokens = array_fill_keys($this->tokenizeShopQueryCandidate($correctedPrompt), true); + $queryTokens = array_fill_keys($this->tokenizeShopQueryCandidate($correctedShopSearchQuery), true); if ($promptTokens === [] || $queryTokens === []) { - return $shopSearchQuery; + return $correctedShopSearchQuery; } $appendTokens = []; @@ -2023,10 +2029,38 @@ final readonly class AgentRunner } if ($appendTokens === []) { - return $shopSearchQuery; + return $correctedShopSearchQuery; } - return trim($shopSearchQuery . ' ' . implode(' ', array_values($appendTokens))); + return trim($correctedShopSearchQuery . ' ' . implode(' ', array_values($appendTokens))); + } + + private function applyConfiguredShopSearchTokenCorrections(string $text): string + { + $text = trim($text); + + if ($text === '') { + return ''; + } + + foreach ($this->commerceQueryParserConfig->getSearchTokenCorrections() as $from => $to) { + $from = trim((string) $from); + $to = trim((string) $to); + + if ($from === '' || $to === '') { + continue; + } + + $text = preg_replace( + '/\b' . preg_quote($from, '/') . '\b/u', + $to, + $text + ) ?? $text; + } + + $text = preg_replace('/\s+/u', ' ', $text) ?? $text; + + return trim($text); } /**