diff --git a/config/retriex/agent.yaml b/config/retriex/agent.yaml index 77ccd69..f118929 100644 --- a/config/retriex/agent.yaml +++ b/config/retriex/agent.yaml @@ -211,13 +211,6 @@ parameters: # Legacy/domain override list. Generic German stopwords are provided by # language cleanup profile `rag_evidence`. Keep RAG/product-role terms here. stop_terms: - - suche - - suchen - - finde - - finden - - zeige - - einen - - einem - ohne - messen - messung @@ -471,31 +464,8 @@ parameters: - grenzwerte - grenzwerten - welche - - welcher - - welches - - welchem - - welchen - gut - geeignet - - was - - wie - - wo - - kann - - koennen - - können - - konnte - - könnte - - ich - - mir - - wir - - man - - nutzen - - benutzen - - verwenden - - verwende - - nehmen - - zur - - zum - messen - gemessen meta_only_terms: @@ -507,21 +477,6 @@ parameters: - kostet - shopsuche - shop-suche - - suche - - suchen - - such - - finde - - find - - zeige - - zeig - - im - - in - - nach - - danach - - damit - - dafür - - dafuer - - hierzu language_preservation: enabled: true language_markers: diff --git a/config/retriex/commerce.yaml b/config/retriex/commerce.yaml index 662003c..2f6934a 100644 --- a/config/retriex/commerce.yaml +++ b/config/retriex/commerce.yaml @@ -25,7 +25,6 @@ parameters: # language cleanup profile `commerce_query`. Keep only commerce-specific or # historically sensitive phrases here. phrases_to_remove: - - suche - welches gerät - welche gerät - welches modell @@ -43,58 +42,22 @@ parameters: - geeigent - verfügbarkeit - verfuegbarkeit - - empfiehl - - antwort - - kurze - - ich # Legacy/domain override list. Generic German stopwords and conversation # filler terms are provided by language cleanup profile `commerce_query`. filter_search_tokens: - - zusätzlich - - stattdessen - preiswerte - lösung - größer - - würde - welchem - - mein - - zeige - - zeig - - such - - suche - - finde - - find - - mir - - von - - im - - in - welche - welcher - welches - welchen - - zur - geeignet - geeigent - verfügbarkeit - verfuegbarkeit - - prüfe - - pruefe - - sowie - - seine - - seinen - - seiner - - seinem - - seines - - siene - - sienen - - siener - - sienem - - sienes - - gebe - - gib - - nenne - - nenn - preis - preise - preisen diff --git a/config/retriex/governance.yaml b/config/retriex/governance.yaml index c36c102..f1717fe 100644 --- a/config/retriex/governance.yaml +++ b/config/retriex/governance.yaml @@ -82,6 +82,7 @@ parameters: - commerce_query - rag_evidence - shop_context_fallback + - retrieval_reference_cleanup required_profile_terms: commerce_query: stopwords: diff --git a/config/retriex/language.yaml b/config/retriex/language.yaml index 80918a2..ebf50ad 100644 --- a/config/retriex/language.yaml +++ b/config/retriex/language.yaml @@ -81,17 +81,37 @@ parameters: - eine - einer - eines + - einen + - einem - und - oder + - aber + - sowie - mit - für - fuer + - von + - vom + - im + - in + - nach + - zur + - zum - ist - sind + - wird + - werden + - wurde - kann - können - koennen - + - kannst + - könnte + - koennte + - würde + - wuerde + - würden + - wuerden conversation: - bitte - mal @@ -105,6 +125,76 @@ parameters: - also - danke + + pronouns: + - ich + - mir + - mein + - meine + - meinen + - meiner + - meinem + - meines + - seine + - seinen + - seiner + - seinem + - seines + - siene + - sienen + - siener + - sienem + - sienes + + user_instruction_terms: + - suche + - such + - suchen + - finde + - find + - finden + - zeige + - zeig + - gebe + - gib + - nenne + - nenn + - empfiehl + - prüfe + - pruefe + + response_style: + - antwort + - kurze + - kurz + - zusätzlich + - zusaetzlich + - stattdessen + + + question_terms: + - welcher + - welches + - welchem + - welchen + - was + - wie + - wo + + usage_terms: + - nutzen + - benutzen + - verwenden + - verwende + - nehmen + + reference_fillers: + - danach + - damit + - dafür + - dafuer + - hierzu + phrase_groups: user_instruction: - ich suche @@ -127,11 +217,29 @@ parameters: - uebersicht - auflistung + + retrieval_reference: + - vorherige + - vorheriger + - nutzerfrage + - aktuelle + - folgefrage + - frage + - antwort + - technische + - referenzanker + - referenzaufloesung + - referenzauflösung + - faktenquelle + cleanup_profiles: commerce_query: stopword_groups: - de_core - conversation + - pronouns + - user_instruction_terms + - response_style phrase_groups: - user_instruction protected_term_groups: @@ -141,6 +249,18 @@ parameters: stopword_groups: - de_core - conversation + - user_instruction_terms + protected_term_groups: + - protected_terms + + + retrieval_reference_cleanup: + stopword_groups: + - de_core + - conversation + - question_terms + meta_term_groups: + - retrieval_reference protected_term_groups: - protected_terms @@ -148,6 +268,12 @@ parameters: stopword_groups: - de_core - conversation + - pronouns + - user_instruction_terms + - question_terms + - usage_terms + - reference_fillers + - response_style phrase_groups: - user_instruction meta_term_groups: diff --git a/config/retriex/retrieval.yaml b/config/retriex/retrieval.yaml index ce6394f..aec8a6f 100644 --- a/config/retriex/retrieval.yaml +++ b/config/retriex/retrieval.yaml @@ -90,56 +90,10 @@ parameters: - code - wert - werte + generic_exact_selection_cleanup_profile: retrieval_reference_cleanup generic_exact_selection_tokens: - - vorherige - - vorheriger - - nutzerfrage - - aktuelle - - folgefrage - - frage - - antwort - - technische - - referenzanker - - referenzaufloesung - - referenzauflösung - - faktenquelle - keine - welche - - welcher - - welches - - welchem - - welchen - - wird - - werden - - wurde - - kann - - koennen - - können - - mit - - der - - die - - das - - den - - dem - - ein - - eine - - einer - - eines - - ist - - sind - - was - - wie - - wo - - zum - - zur - - fuer - - für - - durch - - von - - vom - - und - - oder - - auch generic_product_tokens: - produkt - produkte diff --git a/src/Config/NdjsonHybridRetrieverConfig.php b/src/Config/NdjsonHybridRetrieverConfig.php index 9615232..8d7823d 100644 --- a/src/Config/NdjsonHybridRetrieverConfig.php +++ b/src/Config/NdjsonHybridRetrieverConfig.php @@ -196,6 +196,11 @@ final class NdjsonHybridRetrieverConfig return $this->requiredStringList('exact_detail_tokens'); } + public function genericExactSelectionCleanupProfile(): string + { + return $this->requiredString('generic_exact_selection_cleanup_profile'); + } + /** @return string[] */ public function genericExactSelectionTokens(): array { @@ -316,6 +321,7 @@ final class NdjsonHybridRetrieverConfig 'exact_selection_indicator_table_required_primary_terms' => $this->exactSelectionIndicatorTableRequiredPrimaryTerms(), 'exact_selection_indicator_table_required_context_terms' => $this->exactSelectionIndicatorTableRequiredContextTerms(), 'exact_detail_tokens' => $this->exactDetailTokens(), + 'generic_exact_selection_cleanup_profile' => $this->genericExactSelectionCleanupProfile(), 'generic_exact_selection_tokens' => $this->genericExactSelectionTokens(), 'generic_product_tokens' => $this->genericProductTokens(), 'important_short_model_tokens' => $this->importantShortModelTokens(), @@ -369,6 +375,22 @@ final class NdjsonHybridRetrieverConfig return $value; } + private function requiredString(string $key): string + { + $value = $this->requiredValue($key); + + if (!is_scalar($value)) { + throw $this->invalid($key, 'must be a non-empty string'); + } + + $value = trim((string) $value); + if ($value === '') { + throw $this->invalid($key, 'must be a non-empty string'); + } + + return $value; + } + /** @return string[] */ private function requiredStringList(string $key): array { diff --git a/src/Config/RetriexEffectiveConfigProvider.php b/src/Config/RetriexEffectiveConfigProvider.php index bdea903..d5f2a2e 100644 --- a/src/Config/RetriexEffectiveConfigProvider.php +++ b/src/Config/RetriexEffectiveConfigProvider.php @@ -1059,6 +1059,13 @@ final readonly class RetriexEffectiveConfigProvider $errors[] = 'retrieval.hard_max_chunks must be greater than 0.'; } + $cleanupProfile = $retrieval['generic_exact_selection_cleanup_profile'] ?? null; + if (!is_string($cleanupProfile) || trim($cleanupProfile) === '') { + $errors[] = 'retrieval.generic_exact_selection_cleanup_profile must be a non-empty string.'; + } elseif (!in_array(trim($cleanupProfile), $this->languageCleanupConfig->getCleanupProfileNames(), true)) { + $errors[] = 'retrieval.generic_exact_selection_cleanup_profile references unknown language cleanup profile: ' . trim($cleanupProfile) . '.'; + } + $this->validateStringListMap($retrieval['vocabulary'] ?? [], 'retrieval.vocabulary', $errors, $warnings); $inventory = $retrieval['inventory_parameter'] ?? []; diff --git a/src/Knowledge/Retrieval/NdjsonHybridRetriever.php b/src/Knowledge/Retrieval/NdjsonHybridRetriever.php index 7288af7..2850a7f 100644 --- a/src/Knowledge/Retrieval/NdjsonHybridRetriever.php +++ b/src/Knowledge/Retrieval/NdjsonHybridRetriever.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Knowledge\Retrieval; use App\Catalog\EntityCatalogService; +use App\Config\LanguageCleanupConfig; use App\Config\NdjsonHybridRetrieverConfig; use App\Entity\ModelGenerationConfig; use App\Intent\CatalogIntentLite; @@ -46,6 +47,7 @@ final readonly class NdjsonHybridRetriever implements RetrieverInterface private EntityCatalogService $entityCatalogService, private QueryEnricher $queryEnricher, private NdjsonHybridRetrieverConfig $retrieverConfig, + private LanguageCleanupConfig $languageCleanupConfig, ) { } @@ -942,7 +944,19 @@ final readonly class NdjsonHybridRetriever implements RetrieverInterface private function isGenericExactSelectionToken(string $token): bool { - return in_array($token, $this->retrieverConfig->genericExactSelectionTokens(), true); + return in_array($token, $this->genericExactSelectionCleanupTokens(), true); + } + + /** @return string[] */ + private function genericExactSelectionCleanupTokens(): array + { + $profileName = $this->retrieverConfig->genericExactSelectionCleanupProfile(); + + return array_values(array_unique(array_merge( + $this->languageCleanupConfig->getStopWordsForProfile($profileName), + $this->languageCleanupConfig->getMetaTermsForProfile($profileName), + $this->retrieverConfig->genericExactSelectionTokens() + ))); } /**