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_question_strip_pattern: '/^Question:\s*.*(?:\R|$)/u'
|
||||
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'
|
||||
|
||||
messages:
|
||||
|
||||
@@ -56,11 +56,14 @@ parameters:
|
||||
- davon
|
||||
- stattdessen
|
||||
- bitte
|
||||
- preiswerte
|
||||
- gern
|
||||
- eine
|
||||
- größer
|
||||
- würde
|
||||
- ich
|
||||
- gerne
|
||||
- mein
|
||||
- größer
|
||||
- zeige
|
||||
- zeig
|
||||
@@ -80,6 +83,7 @@ parameters:
|
||||
- welches
|
||||
- welchen
|
||||
- sind
|
||||
- zur
|
||||
- ist
|
||||
- geeignet
|
||||
- geeigent
|
||||
|
||||
@@ -58,6 +58,10 @@ parameters:
|
||||
- stattdessen
|
||||
- bitte
|
||||
- gern
|
||||
- preiswerte
|
||||
- zur
|
||||
- mein
|
||||
- eine
|
||||
- würde
|
||||
- ich
|
||||
- gerne
|
||||
|
||||
@@ -1847,14 +1847,57 @@ final readonly class AgentRunner
|
||||
|
||||
$contextQuery = $this->buildContextFallbackShopQuery($question);
|
||||
|
||||
if ($contextQuery !== '' && !$this->isMetaOnlyShopQuery($contextQuery)) {
|
||||
if ($this->isUsableContextualShopQuery($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 '';
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
$tokens = $this->tokenizeShopQueryCandidate($question);
|
||||
|
||||
Reference in New Issue
Block a user