fix shop research intent fix 3
This commit is contained in:
@@ -53,6 +53,10 @@ parameters:
|
|||||||
- geeigent
|
- geeigent
|
||||||
- empfiehl
|
- empfiehl
|
||||||
- empfehl
|
- empfehl
|
||||||
|
advisory_product_selection_patterns:
|
||||||
|
- '/\bmit\s+welche(?:m|n|r|s)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u'
|
||||||
|
- '/\bwelche(?:r|s|n|m)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:kann|können|koennen|misst|messen|überwacht|ueberwacht|eignet|geeignet|passt|gut|empfehl)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u'
|
||||||
|
- '/\b(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:für|fuer)\b.*\b(?:messung|messen|überwachung|ueberwachung)\b/u'
|
||||||
price_terms:
|
price_terms:
|
||||||
- euro
|
- euro
|
||||||
- €
|
- €
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ parameters:
|
|||||||
detailed_max_count: 5
|
detailed_max_count: 5
|
||||||
header_lines:
|
header_lines:
|
||||||
- 'LIVE SHOP RESULTS (authoritative for current commercial details):'
|
- 'LIVE SHOP RESULTS (authoritative for current commercial details):'
|
||||||
- Use these results as the primary source for current price, availability, URL, and current shop-visible product naming.
|
- Use these results as the primary source for current price, availability, URL, current shop-visible product naming, and explicitly shop-visible product suitability when the user asks which product/device can measure or monitor something.
|
||||||
- If retrieved documents conflict with shop data on price, availability, URL, or current naming, prefer the shop data.
|
- If retrieved documents conflict with shop data on price, availability, URL, current naming, or explicitly shop-visible product suitability, prefer the shop data for those fields.
|
||||||
|
- If retrieved documents do not identify a matching product, but a live shop result explicitly names the requested measurement parameter or application, do not conclude that no matching product exists.
|
||||||
- Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.
|
- Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.
|
||||||
- Do not infer undocumented technical specifications from shop data.
|
- Do not infer undocumented technical specifications from shop data.
|
||||||
- Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.
|
- Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.
|
||||||
@@ -63,6 +64,7 @@ parameters:
|
|||||||
output_priority:
|
output_priority:
|
||||||
rules:
|
rules:
|
||||||
- '- Use retrieved knowledge first to determine the technically matching product or answer.'
|
- '- Use retrieved knowledge first to determine the technically matching product or answer.'
|
||||||
|
- '- For product-selection questions such as which device can measure or monitor a parameter, use relevant live shop results as a fallback when retrieved knowledge does not identify a matching product.'
|
||||||
- '- If shop results are present, use them afterwards to add current price, availability, and the actual URL.'
|
- '- If shop results are present, use them afterwards to add current price, availability, and the actual URL.'
|
||||||
- '- Do not let bundles, accessories, or service items override a better technical match unless the user explicitly asks for them.'
|
- '- Do not let bundles, accessories, or service items override a better technical match unless the user explicitly asks for them.'
|
||||||
technical_rules:
|
technical_rules:
|
||||||
@@ -129,8 +131,9 @@ parameters:
|
|||||||
- '- Never mention external manufacturers, external brands, or external products unless they are explicitly present in the provided sources.'
|
- '- Never mention external manufacturers, external brands, or external products unless they are explicitly present in the provided sources.'
|
||||||
- '- If the sources do not identify a suitable product, do not invent one.'
|
- '- If the sources do not identify a suitable product, do not invent one.'
|
||||||
with_shop_rules:
|
with_shop_rules:
|
||||||
- '- Use shop data as highest priority only for current commercial fields: price, availability, URL, and current shop-visible naming.'
|
- '- Use shop data as highest priority for current commercial fields: price, availability, URL, current shop-visible naming, and explicitly shop-visible product suitability for product-selection questions.'
|
||||||
- '- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation.'
|
- '- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation when it contains a matching product or fact.'
|
||||||
|
- '- If retrieved knowledge is silent or only contains unrelated products, but live shop results explicitly match the requested parameter/application, use the shop results and do not answer with a negative RAG-only conclusion.'
|
||||||
- '- When shop results are present and relevant, include current price and the actual URL if available.'
|
- '- When shop results are present and relevant, include current price and the actual URL if available.'
|
||||||
- '- If the shop data does not provide a positive price for a result, do not output any price for that result.'
|
- '- If the shop data does not provide a positive price for a result, do not output any price for that result.'
|
||||||
- '- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.'
|
- '- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.'
|
||||||
|
|||||||
@@ -61,6 +61,12 @@ final class CommerceIntentConfig
|
|||||||
'empfehl',
|
'empfehl',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private const ADVISORY_PRODUCT_SELECTION_PATTERNS = [
|
||||||
|
'/\bmit\s+welche(?:m|n|r|s)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u',
|
||||||
|
'/\bwelche(?:r|s|n|m)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:kann|können|koennen|misst|messen|überwacht|ueberwacht|eignet|geeignet|passt|gut|empfehl)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u',
|
||||||
|
'/\b(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:für|fuer)\b.*\b(?:messung|messen|überwachung|ueberwachung)\b/u',
|
||||||
|
];
|
||||||
|
|
||||||
private const PRICE_TERMS = [
|
private const PRICE_TERMS = [
|
||||||
'euro',
|
'euro',
|
||||||
'€',
|
'€',
|
||||||
@@ -166,6 +172,12 @@ final class CommerceIntentConfig
|
|||||||
return $this->stringList('advisory_signals', self::ADVISORY_SIGNALS);
|
return $this->stringList('advisory_signals', self::ADVISORY_SIGNALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getAdvisoryProductSelectionPatterns(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('advisory_product_selection_patterns', self::ADVISORY_PRODUCT_SELECTION_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
/** @return string[] */
|
/** @return string[] */
|
||||||
public function getPriceTerms(): array
|
public function getPriceTerms(): array
|
||||||
{
|
{
|
||||||
@@ -287,6 +299,11 @@ final class CommerceIntentConfig
|
|||||||
return 'advisory:';
|
return 'advisory:';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAdvisoryProductSelectionSignalLabel(): string
|
||||||
|
{
|
||||||
|
return 'advisory_product_selection';
|
||||||
|
}
|
||||||
|
|
||||||
public function getProductSearchMinScore(): int
|
public function getProductSearchMinScore(): int
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
@@ -332,6 +349,11 @@ final class CommerceIntentConfig
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAdvisoryProductSelectionSignalScore(): int
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
public function getModelLikeProductPattern(): string
|
public function getModelLikeProductPattern(): string
|
||||||
{
|
{
|
||||||
return '/\b[a-zäöüß][a-zäöüß®\-]*(?:\s+[a-zäöüß][a-zäöüß®\-]*){0,2}\s+\d{2,5}[a-z0-9\-]*\b/u';
|
return '/\b[a-zäöüß][a-zäöüß®\-]*(?:\s+[a-zäöüß][a-zäöüß®\-]*){0,2}\s+\d{2,5}[a-z0-9\-]*\b/u';
|
||||||
|
|||||||
@@ -263,8 +263,9 @@ final class PromptBuilderConfig
|
|||||||
{
|
{
|
||||||
return $this->getStringList('shop_results.header_lines', [
|
return $this->getStringList('shop_results.header_lines', [
|
||||||
'LIVE SHOP RESULTS (authoritative for current commercial details):',
|
'LIVE SHOP RESULTS (authoritative for current commercial details):',
|
||||||
'Use these results as the primary source for current price, availability, URL, and current shop-visible product naming.',
|
'Use these results as the primary source for current price, availability, URL, current shop-visible product naming, and explicitly shop-visible product suitability when the user asks which product/device can measure or monitor something.',
|
||||||
'If retrieved documents conflict with shop data on price, availability, URL, or current naming, prefer the shop data.',
|
'If retrieved documents conflict with shop data on price, availability, URL, current naming, or explicitly shop-visible product suitability, prefer the shop data for those fields.',
|
||||||
|
'If retrieved documents do not identify a matching product, but a live shop result explicitly names the requested measurement parameter or application, do not conclude that no matching product exists.',
|
||||||
'Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.',
|
'Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.',
|
||||||
'Do not infer undocumented technical specifications from shop data.',
|
'Do not infer undocumented technical specifications from shop data.',
|
||||||
'Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.',
|
'Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.',
|
||||||
@@ -291,6 +292,7 @@ final class PromptBuilderConfig
|
|||||||
{
|
{
|
||||||
return $this->getStringList('output_priority.rules', [
|
return $this->getStringList('output_priority.rules', [
|
||||||
'- Use retrieved knowledge first to determine the technically matching product or answer.',
|
'- Use retrieved knowledge first to determine the technically matching product or answer.',
|
||||||
|
'- For product-selection questions such as which device can measure or monitor a parameter, use relevant live shop results as a fallback when retrieved knowledge does not identify a matching product.',
|
||||||
'- If shop results are present, use them afterwards to add current price, availability, and the actual URL.',
|
'- If shop results are present, use them afterwards to add current price, availability, and the actual URL.',
|
||||||
'- Do not let bundles, accessories, or service items override a better technical match unless the user explicitly asks for them.',
|
'- Do not let bundles, accessories, or service items override a better technical match unless the user explicitly asks for them.',
|
||||||
]);
|
]);
|
||||||
@@ -434,8 +436,9 @@ final class PromptBuilderConfig
|
|||||||
public function getFactGroundingWithShopRules(): array
|
public function getFactGroundingWithShopRules(): array
|
||||||
{
|
{
|
||||||
return $this->getStringList('fact_grounding.with_shop_rules', [
|
return $this->getStringList('fact_grounding.with_shop_rules', [
|
||||||
'- Use shop data as highest priority only for current commercial fields: price, availability, URL, and current shop-visible naming.',
|
'- Use shop data as highest priority for current commercial fields: price, availability, URL, current shop-visible naming, and explicitly shop-visible product suitability for product-selection questions.',
|
||||||
'- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation.',
|
'- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation when it contains a matching product or fact.',
|
||||||
|
'- If retrieved knowledge is silent or only contains unrelated products, but live shop results explicitly match the requested parameter/application, use the shop results and do not answer with a negative RAG-only conclusion.',
|
||||||
'- When shop results are present and relevant, include current price and the actual URL if available.',
|
'- When shop results are present and relevant, include current price and the actual URL if available.',
|
||||||
'- If the shop data does not provide a positive price for a result, do not output any price for that result.',
|
'- If the shop data does not provide a positive price for a result, do not output any price for that result.',
|
||||||
'- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.',
|
'- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.',
|
||||||
|
|||||||
@@ -40,10 +40,12 @@ final class CommerceIntentLite
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hasAdvisoryProductSelectionIntent = $this->hasAdvisoryProductSelectionIntent($prompt);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$this->isTechnicalFactualKnowledgeQuery($prompt)
|
$this->isTechnicalFactualKnowledgeQuery($prompt)
|
||||||
&& !$this->hasExplicitCommerceIntent($prompt)
|
&& !$this->hasExplicitCommerceIntent($prompt)
|
||||||
&& !$this->hasAdvisoryProductSelectionIntent($prompt)
|
&& !$hasAdvisoryProductSelectionIntent
|
||||||
) {
|
) {
|
||||||
return $this->buildDetectionResult(
|
return $this->buildDetectionResult(
|
||||||
intent: self::NONE,
|
intent: self::NONE,
|
||||||
@@ -62,6 +64,7 @@ final class CommerceIntentLite
|
|||||||
[$score, $signals] = $this->applySizeSignal($prompt, $score, $signals);
|
[$score, $signals] = $this->applySizeSignal($prompt, $score, $signals);
|
||||||
[$score, $signals] = $this->applySizeTokenSignal($prompt, $score, $signals);
|
[$score, $signals] = $this->applySizeTokenSignal($prompt, $score, $signals);
|
||||||
[$score, $signals] = $this->applyColorSignal($prompt, $score, $signals);
|
[$score, $signals] = $this->applyColorSignal($prompt, $score, $signals);
|
||||||
|
[$score, $signals] = $this->applyAdvisoryProductSelectionSignal($prompt, $score, $signals);
|
||||||
[$score, $signals] = $this->applyAdvisorySignals($prompt, $score, $signals);
|
[$score, $signals] = $this->applyAdvisorySignals($prompt, $score, $signals);
|
||||||
|
|
||||||
$signals = array_values(array_unique($signals));
|
$signals = array_values(array_unique($signals));
|
||||||
@@ -107,6 +110,10 @@ final class CommerceIntentLite
|
|||||||
*/
|
*/
|
||||||
private function hasAdvisoryProductSelectionIntent(string $prompt): bool
|
private function hasAdvisoryProductSelectionIntent(string $prompt): bool
|
||||||
{
|
{
|
||||||
|
if ($this->matchesAnyPattern($prompt, $this->config->getAdvisoryProductSelectionPatterns())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->containsConfiguredAdvisorySignal($prompt)) {
|
if (!$this->containsConfiguredAdvisorySignal($prompt)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -327,6 +334,22 @@ final class CommerceIntentLite
|
|||||||
return [$score, $signals];
|
return [$score, $signals];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $signals
|
||||||
|
* @return array{0:int,1:string[]}
|
||||||
|
*/
|
||||||
|
private function applyAdvisoryProductSelectionSignal(string $prompt, int $score, array $signals): array
|
||||||
|
{
|
||||||
|
if (!$this->matchesAnyPattern($prompt, $this->config->getAdvisoryProductSelectionPatterns())) {
|
||||||
|
return [$score, $signals];
|
||||||
|
}
|
||||||
|
|
||||||
|
$score += $this->config->getAdvisoryProductSelectionSignalScore();
|
||||||
|
$signals[] = $this->config->getAdvisoryProductSelectionSignalLabel();
|
||||||
|
|
||||||
|
return [$score, $signals];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $signals
|
* @param string[] $signals
|
||||||
* @return array{0:int,1:string[]}
|
* @return array{0:int,1:string[]}
|
||||||
|
|||||||
Reference in New Issue
Block a user