optimize technical truth

This commit is contained in:
team 1
2026-04-28 17:00:12 +02:00
parent 8d9f863143
commit bca015129c
5 changed files with 471 additions and 314 deletions

View File

@@ -6,6 +6,29 @@ namespace App\Config;
final class PromptBuilderConfig
{
private const MAIN_DEVICE_REQUEST_ROLE_KEYWORDS = [
'messanlage', 'messanlagen', 'anlage', 'anlagen', 'messgerät', 'messgeraet',
'messgeräte', 'messgeraete', 'analysegerät', 'analysegeraet', 'analysegeräte',
'analysegeraete', 'analysator', 'analysatoren', 'analyzer', 'gerät', 'geraet',
'geräte', 'geraete', 'system', 'systeme', 'monitor', 'monitore', 'controller',
];
private const MAIN_DEVICE_PRODUCT_ROLE_KEYWORDS = [
'messanlage', 'messanlagen', 'messgerät', 'messgeraet', 'messgeräte', 'messgeraete',
'analysegerät', 'analysegeraet', 'analysegeräte', 'analysegeraete', 'analysator',
'analysatoren', 'analyzer', 'online-analysator', 'online analysator',
'online-analysegerät', 'online analysegeraet', 'gerät', 'geraet', 'geräte',
'geraete', 'system', 'systeme', 'monitor', 'monitore', 'controller',
];
private const ACCESSORY_PRODUCT_ROLE_KEYWORDS = [
'indikator', 'indikatoren', 'indicator', 'reagenz', 'reagenzien', 'reagent',
'zubehör', 'zubehor', 'ersatzteil', 'ersatzteile', 'kit', 'set',
'verbrauchsmaterial', 'consumable', 'nachfüll', 'nachfuell', 'refill',
'lösung', 'loesung', 'solution', 'teststreifen', 'test strip', 'filter',
'pumpenkopf', 'motorblock', 'service set', 'serviceset', 'service-set',
];
private const TECHNICAL_PRODUCT_KEYWORDS = [
'technisch',
'technical',
@@ -69,70 +92,6 @@ final class PromptBuilderConfig
'ergänzung',
'ergaenzung',
];
private const MAIN_DEVICE_REQUEST_ROLE_KEYWORDS = [
'anlage',
'messanlage',
'gerät',
'geraet',
'messgerät',
'messgeraet',
'analysegerät',
'analysegeraet',
'analysator',
'analyzer',
'system',
'monitor',
'controller',
'testomat',
'pockettester',
];
private const MAIN_DEVICE_PRODUCT_ROLE_KEYWORDS = [
'messgerät',
'messgeraet',
'analysegerät',
'analysegeraet',
'analysator',
'analyzer',
'messanlage',
'controller',
'testomat 2000',
'testomat 808',
'testomat evo',
'pockettester',
];
private const ACCESSORY_PRODUCT_ROLE_KEYWORDS = [
'indikator',
'indicator',
'indikatortyp',
'reagenz',
'reagent',
'reagenzsatz',
'kalibrierlösung',
'kalibrierloesung',
'pufferlösung',
'pufferloesung',
'reinigungslösung',
'reinigungsloesung',
'kalibrier',
'puffer',
'buffer',
'zubehör',
'zubehor',
'accessory',
'ersatzteil',
'verbrauch',
'consumable',
'kit',
'set',
'flasche',
'bottle',
'100 ml',
'500 ml',
'100ml',
'500ml',
];
/**
* @param array<string, mixed> $config
@@ -357,29 +316,6 @@ final class PromptBuilderConfig
return $this->getString('shop_results.exact_product_name_label', 'Exact shop product name');
}
public function getShopRequestedRoleLabel(): string
{
return $this->getString('shop_results.requested_role_label', 'Requested product role');
}
public function getShopInferredRoleLabel(): string
{
return $this->getString('shop_results.inferred_role_label', 'Inferred shop product role');
}
public function getShopRoleCompatibilityLabel(): string
{
return $this->getString('shop_results.role_compatibility_label', 'Role compatibility with request');
}
public function getShopRoleMismatchNotice(): string
{
return $this->getString(
'shop_results.role_mismatch_notice',
'Role mismatch: this record is kept only as a separate shop hit; do not use its description, price, URL, or product number as the main device/system answer.'
);
}
/**
* @return string[]
*/
@@ -497,7 +433,6 @@ final class PromptBuilderConfig
'- Keep price, availability, and URL on separate lines when they are present.',
'- Only use shop price, URL, product number, or availability for the main product when the shop result clearly matches that same main product.',
'- If the matching shop item appears to be an accessory, reagent, consumable, set, or kit, keep it separate and do not present its commercial fields as the main device.',
'- If a SHOP PRODUCT RECORD is classified as accessory_or_consumable while the requested product role is main_device_or_system, do not use that record as a product recommendation headline.',
'- If the commercial match is uncertain, say that commercial details for the main product are not clearly available in the provided shop results.',
'- If no price is shown for a shop item, omit the price instead of writing 0,00 €, free, kostenlos, or a guessed price.',
'- For every shop hit shown in the answer, copy the exact shop product name verbatim from the same SHOP PRODUCT RECORD as the item heading.',
@@ -607,6 +542,9 @@ final class PromptBuilderConfig
'- If the shop match is ambiguous, keep the technical identification and commercial details separate.',
'- Shop product names are authoritative for their own shop URL, product number, price, availability, image, description, and metadata.',
'- Do not rewrite a shop record heading with a similar device name from retrieved knowledge. If identities differ or are uncertain, separate the RAG device from the shop hit.',
'- If the user asks for a main device, measuring device, analyzer, system, or measuring installation, do not present an accessory, indicator, reagent, kit, set, consumable, or service item as the requested main solution.',
'- If the only shop hit is role-incompatible with the requested product role, state that no matching main-device shop hit is available in the provided shop data; mention the incompatible hit only as a separate accessory/consumable hit if useful.',
'- Never rename a role-incompatible accessory shop record into a main device in headings, summaries, or shop-hit lines.',
]);
}
@@ -732,6 +670,53 @@ final class PromptBuilderConfig
return $this->getString('shop_results.fields.meta_information_label', 'Meta information');
}
public function getShopRequestedRoleLabel(): string
{
return $this->getString('shop_results.fields.requested_role_label', 'Requested product role');
}
public function getShopInferredRoleLabel(): string
{
return $this->getString('shop_results.fields.inferred_role_label', 'Inferred shop product role');
}
public function getShopRoleCompatibilityLabel(): string
{
return $this->getString('shop_results.fields.role_compatibility_label', 'Role compatibility with request');
}
public function getShopRoleIncompatibleCommercialSuppressionNote(): string
{
return $this->getString(
'shop_results.fields.role_incompatible_commercial_suppression_note',
'Commercial fields suppressed: this shop record is not a matching main-device result for the requested product role.'
);
}
/**
* @return string[]
*/
public function getMainDeviceRequestRoleKeywords(): array
{
return $this->getStringList('role_guard.main_device_request_keywords', self::MAIN_DEVICE_REQUEST_ROLE_KEYWORDS);
}
/**
* @return string[]
*/
public function getMainDeviceProductRoleKeywords(): array
{
return $this->getStringList('role_guard.main_device_product_keywords', self::MAIN_DEVICE_PRODUCT_ROLE_KEYWORDS);
}
/**
* @return string[]
*/
public function getAccessoryProductRoleKeywords(): array
{
return $this->getStringList('role_guard.accessory_product_keywords', self::ACCESSORY_PRODUCT_ROLE_KEYWORDS);
}
/**
* @return string[]
*/
@@ -754,39 +739,6 @@ final class PromptBuilderConfig
);
}
/**
* @return string[]
*/
public function getMainDeviceRequestRoleKeywords(): array
{
return $this->getStringList(
'product_roles.main_device_request_keywords',
self::MAIN_DEVICE_REQUEST_ROLE_KEYWORDS
);
}
/**
* @return string[]
*/
public function getMainDeviceProductRoleKeywords(): array
{
return $this->getStringList(
'product_roles.main_device_product_keywords',
self::MAIN_DEVICE_PRODUCT_ROLE_KEYWORDS
);
}
/**
* @return string[]
*/
public function getAccessoryProductRoleKeywords(): array
{
return $this->getStringList(
'product_roles.accessory_product_keywords',
self::ACCESSORY_PRODUCT_ROLE_KEYWORDS
);
}
public function getTechnicalProductModelPattern(): string
{
return $this->getString('technical_product_model_pattern', '/\b[\p{L}]{2,}\s?\d{2,5}\b/u');