patch 20p
This commit is contained in:
55
RETRIEX_PATCH_20P_HISTORY_PRODUCT_ANCHOR_FOLLOWUP_README.md
Normal file
55
RETRIEX_PATCH_20P_HISTORY_PRODUCT_ANCHOR_FOLLOWUP_README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# RetrieX Patch p20p - History Product Anchor Follow-up Fix
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
|
||||||
|
Behebt den Fall, dass kurze Shop-Follow-ups wie `suche im shop` den Produkt-/Modellanker aus dem vorherigen fachlichen Turn nicht mehr sicher übernehmen.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
1. `welche grenzwerte kann der testomat 2000 thcl messen`
|
||||||
|
2. `suche im shop`
|
||||||
|
|
||||||
|
Vorher konnte die Shop-Suche mit `keine Suchquery` enden, obwohl der vorherige Turn einen klaren Produktanker enthält.
|
||||||
|
|
||||||
|
## Ursache
|
||||||
|
|
||||||
|
Die bisherige Shop-Follow-up-Auflösung nutzte primär extrahierte `Question:`-Zeilen. Wenn diese Extraktion nicht greift oder der stabile Produktanker nur in der Antwort bzw. im gesamten letzten Turn steht, wurde keine belastbare Shopquery erzeugt.
|
||||||
|
|
||||||
|
Außerdem erkannte der Testomat-Modellanker bisher numerische Testomat-Modelle ohne nachgestellten Varianten-/Parameter-Suffix. Dadurch wurde `Testomat 2000 THCL` nicht als kompletter Modellanker erfasst.
|
||||||
|
|
||||||
|
## Änderung
|
||||||
|
|
||||||
|
- `AgentRunner::extractContextualShopSearchQuery()` wurde gehärtet.
|
||||||
|
- Wenn aus den letzten Nutzerfragen keine Query entsteht, werden die neuesten History-Turns selbst geprüft.
|
||||||
|
- Pro Turn wird zuerst die Nutzerfrage ausgewertet.
|
||||||
|
- Danach wird ein expliziter Testomat-Modellanker aus dem gesamten Turn extrahiert.
|
||||||
|
- Das Modellanker-Pattern erlaubt nun numerische Testomat-Modelle mit Suffix, z. B. `Testomat 2000 THCL`.
|
||||||
|
|
||||||
|
## Dateien
|
||||||
|
|
||||||
|
- `src/Agent/AgentRunner.php`
|
||||||
|
- `config/retriex/agent.yaml`
|
||||||
|
|
||||||
|
## Erwartung
|
||||||
|
|
||||||
|
`suche im shop` nach einem technischen Turn zu `Testomat 2000 THCL` soll eine Shopquery wie `testomat 2000 thcl` ableiten, statt mit `keine Suchquery` abzubrechen.
|
||||||
|
|
||||||
|
Der Fix ist generisch für History-Produktanker und enthält keine harte 808- oder THCL-Sonderquery.
|
||||||
|
|
||||||
|
## Prüfungen lokal
|
||||||
|
|
||||||
|
- `php -l src/Agent/AgentRunner.php`: OK
|
||||||
|
- `config/retriex/agent.yaml` mit Python YAML Parser: OK
|
||||||
|
- Regex-Smoke-Test für `Testomat 2000 THCL`, `Testomat 808`, `Testomat EVO TH`: OK
|
||||||
|
|
||||||
|
## Nach dem Einspielen prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
PHP-FPM/OPcache danach neu laden, falls aktiv.
|
||||||
@@ -189,7 +189,7 @@ parameters:
|
|||||||
history_turn_split_pattern: '/(?=^Question:\s)/m'
|
history_turn_split_pattern: '/(?=^Question:\s)/m'
|
||||||
history_question_strip_pattern: '/^Question:\s*.*(?:\R|$)/u'
|
history_question_strip_pattern: '/^Question:\s*.*(?:\R|$)/u'
|
||||||
reference_anchor:
|
reference_anchor:
|
||||||
testomat_model_pattern: '/\bTestomat(?:®)?\s+(?:\d{3,4}|EVO(?:\s+[A-Z]{2,6})?|ECO(?:[-\s]?(?:PLUS|C))?|DUO(?:\s+\d{3,4})?|LAB(?:\s+[A-Z]{2,6})?)\b/iu'
|
testomat_model_pattern: '/\bTestomat(?:®)?\s+(?:\d{3,4}(?:\s+[A-Z]{2,8})?|EVO(?:\s+[A-Z]{2,6})?|ECO(?:[-\s]?(?:PLUS|C))?|DUO(?:\s+\d{3,4})?|LAB(?:\s+[A-Z]{2,6})?)\b/iu'
|
||||||
hardness_value_pattern: '/\b\d+(?:[,.]\d+)?\s*°\s*dH\b/iu'
|
hardness_value_pattern: '/\b\d+(?:[,.]\d+)?\s*°\s*dH\b/iu'
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
|
|||||||
@@ -56,11 +56,14 @@ parameters:
|
|||||||
- davon
|
- davon
|
||||||
- stattdessen
|
- stattdessen
|
||||||
- bitte
|
- bitte
|
||||||
|
- preiswerte
|
||||||
- gern
|
- gern
|
||||||
|
- eine
|
||||||
- größer
|
- größer
|
||||||
- würde
|
- würde
|
||||||
- ich
|
- ich
|
||||||
- gerne
|
- gerne
|
||||||
|
- mein
|
||||||
- größer
|
- größer
|
||||||
- zeige
|
- zeige
|
||||||
- zeig
|
- zeig
|
||||||
@@ -80,6 +83,7 @@ parameters:
|
|||||||
- welches
|
- welches
|
||||||
- welchen
|
- welchen
|
||||||
- sind
|
- sind
|
||||||
|
- zur
|
||||||
- ist
|
- ist
|
||||||
- geeignet
|
- geeignet
|
||||||
- geeigent
|
- geeigent
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ parameters:
|
|||||||
- stattdessen
|
- stattdessen
|
||||||
- bitte
|
- bitte
|
||||||
- gern
|
- gern
|
||||||
|
- preiswerte
|
||||||
|
- zur
|
||||||
|
- mein
|
||||||
|
- eine
|
||||||
- würde
|
- würde
|
||||||
- ich
|
- ich
|
||||||
- gerne
|
- gerne
|
||||||
|
|||||||
@@ -1847,14 +1847,57 @@ final readonly class AgentRunner
|
|||||||
|
|
||||||
$contextQuery = $this->buildContextFallbackShopQuery($question);
|
$contextQuery = $this->buildContextFallbackShopQuery($question);
|
||||||
|
|
||||||
if ($contextQuery !== '' && !$this->isMetaOnlyShopQuery($contextQuery)) {
|
if ($this->isUsableContextualShopQuery($contextQuery)) {
|
||||||
return $contextQuery;
|
return $contextQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->extractContextualShopSearchQueryFromHistoryTurns($commerceHistoryContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractContextualShopSearchQueryFromHistoryTurns(string $commerceHistoryContext): string
|
||||||
|
{
|
||||||
|
foreach ($this->extractHistoryTurnsNewestFirst($commerceHistoryContext) as $turn) {
|
||||||
|
$question = $this->extractQuestionFromHistoryTurn($turn);
|
||||||
|
|
||||||
|
if ($question !== '' && !$this->isMetaOnlyShopQuery($question)) {
|
||||||
|
$contextQuery = $this->buildContextFallbackShopQuery($question);
|
||||||
|
|
||||||
|
if ($this->isUsableContextualShopQuery($contextQuery)) {
|
||||||
|
return $contextQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$modelAnchor = $this->extractFirstTestomatModelAnchor($turn);
|
||||||
|
|
||||||
|
if ($modelAnchor !== '' && !$this->isMetaOnlyShopQuery($modelAnchor)) {
|
||||||
|
return mb_strtolower($modelAnchor, 'UTF-8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function extractQuestionFromHistoryTurn(string $turn): string
|
||||||
|
{
|
||||||
|
if (preg_match($this->agentRunnerConfig->getFollowUpHistoryQuestionPattern(), $turn, $matches) !== 1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sanitizeHistoryQuestion((string) ($matches[1] ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isUsableContextualShopQuery(string $query): bool
|
||||||
|
{
|
||||||
|
$query = trim($query);
|
||||||
|
|
||||||
|
if ($query === '' || $this->isMetaOnlyShopQuery($query)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->tokenizeShopQueryCandidate($query) !== [];
|
||||||
|
}
|
||||||
|
|
||||||
private function buildContextFallbackShopQuery(string $question): string
|
private function buildContextFallbackShopQuery(string $question): string
|
||||||
{
|
{
|
||||||
$tokens = $this->tokenizeShopQueryCandidate($question);
|
$tokens = $this->tokenizeShopQueryCandidate($question);
|
||||||
|
|||||||
Reference in New Issue
Block a user