move tokens to config part 2
This commit is contained in:
35
RETRIEX_PROMPT_CONFIG_FIX_README.md
Normal file
35
RETRIEX_PROMPT_CONFIG_FIX_README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# RetrieX Prompt Config Centralization Fix
|
||||||
|
|
||||||
|
This patch centralizes PromptBuilder wording and label configuration in `config/retriex/prompt.yaml` while keeping the previous PHP defaults as fallbacks.
|
||||||
|
|
||||||
|
Changed files:
|
||||||
|
|
||||||
|
- `config/retriex/prompt.yaml`
|
||||||
|
- `src/Config/PromptBuilderConfig.php`
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- Section labels
|
||||||
|
- Conversation context intro lines
|
||||||
|
- Live shop result prompt rules
|
||||||
|
- Output priority rules
|
||||||
|
- Response format rules
|
||||||
|
- Language rules
|
||||||
|
- Fact grounding rules
|
||||||
|
- Retrieved knowledge / URL source labels
|
||||||
|
- Shop result field labels
|
||||||
|
- Technical product model pattern
|
||||||
|
|
||||||
|
Intentionally unchanged:
|
||||||
|
|
||||||
|
- Main active system prompt from the database
|
||||||
|
- Retrieval logic
|
||||||
|
- Shop search logic
|
||||||
|
- Vocabulary / intent / agent config logic
|
||||||
|
- PromptBuilderConfig keyword detection, which remains backed by `vocabulary.yaml`
|
||||||
|
|
||||||
|
After applying:
|
||||||
|
|
||||||
|
1. Clear Symfony cache.
|
||||||
|
2. Run the known 1.4.2 regression prompts.
|
||||||
|
3. Verify that generated prompt sections remain identical to the previous behavior.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Prompt budget and prompt rendering limits.
|
# Prompt budget, prompt rendering limits and prompt wording rules.
|
||||||
# Existing prompt wording/rules remain in PromptBuilderConfig for this minimal-invasive round.
|
# Prompt text values are mirrored from PromptBuilderConfig defaults; PHP fallbacks remain active.
|
||||||
parameters:
|
parameters:
|
||||||
retriex.prompt.config:
|
retriex.prompt.config:
|
||||||
budget:
|
budget:
|
||||||
@@ -15,4 +15,165 @@ parameters:
|
|||||||
shop_results:
|
shop_results:
|
||||||
max_results_in_prompt: 24
|
max_results_in_prompt: 24
|
||||||
detailed_max_count: 5
|
detailed_max_count: 5
|
||||||
|
header_lines:
|
||||||
|
- '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.
|
||||||
|
- If retrieved documents conflict with shop data on price, availability, URL, or current naming, prefer the shop data.
|
||||||
|
- 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.
|
||||||
|
- Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.
|
||||||
|
- Do not merge a device identified in retrieved knowledge with price, URL, product number, or availability from a different shop item such as a reagent, accessory,
|
||||||
|
kit, consumable, or service item.
|
||||||
|
- If a shop result has no price field, do not state a price for it.
|
||||||
|
- Never interpret a missing price or a zero price as free, kostenlos, gratis, or available for 0.00 EUR.
|
||||||
|
overflow_notice_template: Only the top %d ranked shop results are shown here out of %d total results.
|
||||||
|
fields:
|
||||||
|
product_number_label: Product number
|
||||||
|
manufacturer_label: Manufacturer
|
||||||
|
price_label: Price
|
||||||
|
availability_label: Available
|
||||||
|
availability_yes_label: 'yes'
|
||||||
|
availability_no_label: 'no'
|
||||||
|
highlight_prefix: '- '
|
||||||
|
url_label: URL
|
||||||
|
product_image_label: Product image
|
||||||
|
description_label: Description
|
||||||
|
meta_information_label: Meta information
|
||||||
technical_product_keyword_match_threshold: 2
|
technical_product_keyword_match_threshold: 2
|
||||||
|
sections:
|
||||||
|
system_label: SYSTEM
|
||||||
|
user_question_label: USER QUESTION
|
||||||
|
conversation_context_label: CONVERSATION CONTEXT (contextual only)
|
||||||
|
shop_search_query_label: SHOP SEARCH QUERY
|
||||||
|
output_priority_label: OUTPUT PRIORITY
|
||||||
|
response_format_label: RESPONSE FORMAT RULES
|
||||||
|
language_rules_label: LANGUAGE RULES
|
||||||
|
fact_grounding_rules_label: FACT GROUNDING RULES
|
||||||
|
retrieved_knowledge_label: RETRIEVED KNOWLEDGE (primary for technical matching and factual explanation)
|
||||||
|
url_content_label: CONTENT FROM URL (authoritative if user-provided)
|
||||||
|
conversation_context:
|
||||||
|
intro_lines:
|
||||||
|
- The following messages are previous turns of this conversation.
|
||||||
|
- Use them only to resolve references, follow-up questions, and user intent.
|
||||||
|
- Previous assistant answers are not a factual source for technical values, product compatibility, indicators, ranges, prices, or availability.
|
||||||
|
- All factual claims must come from retrieved factual knowledge, user-provided URL content, or live shop data.
|
||||||
|
- Conversation context must not override retrieved factual knowledge or live shop data.
|
||||||
|
shop_search:
|
||||||
|
source_line: 'Source: Shop Search'
|
||||||
|
output_priority:
|
||||||
|
rules:
|
||||||
|
- '- Use retrieved knowledge first to determine the technically matching product or answer.'
|
||||||
|
- '- 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.'
|
||||||
|
response_format:
|
||||||
|
base_rules:
|
||||||
|
- '- Keep normal spacing between all words. Never fuse words together.'
|
||||||
|
- '- Use short, clean paragraphs or short labeled sections.'
|
||||||
|
- '- Do not use persuasive or promotional wording.'
|
||||||
|
- '- Do not repeat the same fact in slightly different wording.'
|
||||||
|
- '- Never mention brands, manufacturers, model names, or product families that do not appear in the provided shop results, retrieved knowledge, URL content,
|
||||||
|
or conversation context.'
|
||||||
|
- '- If no suitable product is explicitly grounded in the provided sources, say that plainly instead of inventing alternatives.'
|
||||||
|
- '- Do not generate external alternative lists, vendor suggestions, or purchase recommendations unless they are explicitly present in the provided sources.'
|
||||||
|
- '- Do not combine technical identity from one source with commercial fields from a different product.'
|
||||||
|
- '- Product number, price, availability, and URL must belong to the same explicitly grounded product.'
|
||||||
|
with_shop_rules:
|
||||||
|
- '- If a product is identified, prefer this structure per product: product name, product number, price, availability, URL, then only the most relevant technical
|
||||||
|
facts.'
|
||||||
|
- '- 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 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.'
|
||||||
|
without_shop_rules:
|
||||||
|
- '- If no shop results are present, do not compensate by inventing external products or external manufacturers.'
|
||||||
|
technical_rules:
|
||||||
|
- '- Write like technical documentation: precise, neutral, and source-close.'
|
||||||
|
- '- Prefer exact values, ranges, thresholds, compatibility notes, and application areas over general explanation.'
|
||||||
|
- '- If the sources only support a negative finding, output only that negative finding and do not add speculative alternatives.'
|
||||||
|
accessory_rules:
|
||||||
|
- '- If the user asks for a matching accessory, separate the answer into: main device and matching accessory.'
|
||||||
|
- '- The main device must come first. The accessory must not replace the main device.'
|
||||||
|
- '- Only name an accessory as matching if compatibility is explicitly grounded in the provided sources.'
|
||||||
|
- '- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says
|
||||||
|
so.'
|
||||||
|
language:
|
||||||
|
rules:
|
||||||
|
- '- Answer only in the same language as the user question.'
|
||||||
|
- '- All headings, labels, notes, and structural elements must be in the same language as the user question.'
|
||||||
|
- '- Do not switch languages unless the user does.'
|
||||||
|
- '- If headings are used, write them in the user''s language.'
|
||||||
|
fact_grounding:
|
||||||
|
base_rules:
|
||||||
|
- '- State only facts that are explicitly present in the provided sources.'
|
||||||
|
- '- Extract concrete values exactly when they are present, including units, ranges, model names, indicator names, IP classes, temperatures, pressures, dimensions,
|
||||||
|
counts, relay outputs, current outputs, and error codes.'
|
||||||
|
- '- Do not invent missing values.'
|
||||||
|
- '- Do not replace missing values with estimates, defaults, or typical industry assumptions.'
|
||||||
|
- '- Do not claim that information is missing if it appears in the provided sources.'
|
||||||
|
- '- Do not compare with other products unless those products are also present in the provided sources.'
|
||||||
|
- '- Prefer source-faithful wording over persuasive wording.'
|
||||||
|
- '- Avoid marketing language such as ''ideal'', ''perfect'', ''unverzichtbar'', ''entscheidend'', ''optimal'', ''kosteneffizient'', ''prozesssicher'', or ''state-of-the-art''.'
|
||||||
|
- '- Clearly separate explicit facts from inferences.'
|
||||||
|
- '- If a conclusion goes beyond the source wording, label it exactly as ''Inference:''.'
|
||||||
|
- '- If a sentence cannot be traced to the provided sources, do not write it.'
|
||||||
|
- '- For follow-up questions, use the conversation only to resolve what the user refers to; do not copy technical facts from previous assistant answers unless
|
||||||
|
the same fact is present in the current retrieved 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.'
|
||||||
|
with_shop_rules:
|
||||||
|
- '- Use shop data as highest priority only for current commercial fields: price, availability, URL, and current shop-visible naming.'
|
||||||
|
- '- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation.'
|
||||||
|
- '- 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.'
|
||||||
|
- '- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.'
|
||||||
|
- '- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says
|
||||||
|
so.'
|
||||||
|
- '- Do not claim that an accessory is required, necessary, used for calibration, or sets the measurement range unless this is explicitly stated in the provided
|
||||||
|
sources.'
|
||||||
|
- '- Do not assign the product number, price, URL, or availability of a reagent, accessory, kit, set, consumable, or service item to a device identified in
|
||||||
|
retrieved knowledge.'
|
||||||
|
- '- Only use commercial fields for the main product when the shop item and the technically identified product clearly refer to the same product identity.'
|
||||||
|
- '- If the shop match is ambiguous, keep the technical identification and commercial details separate.'
|
||||||
|
without_shop_rules:
|
||||||
|
- '- Use retrieved knowledge as authoritative for factual answers.'
|
||||||
|
- '- If no shop results are present, do not compensate with external recommendations or external product suggestions.'
|
||||||
|
technical_rules:
|
||||||
|
- '- For technical product questions, answer primarily with explicitly stated facts.'
|
||||||
|
- '- Behave like a technical documentation assistant, not like a sales advisor.'
|
||||||
|
- '- Keep interpretations minimal and do not generalize application areas beyond the provided sources.'
|
||||||
|
- '- Do not describe benefits, consequences, risks, or operational outcomes unless they are explicitly stated in the sources.'
|
||||||
|
- '- Do not translate technical facts into business value unless the source explicitly does so.'
|
||||||
|
- '- Do not recommend process changes unless explicitly present in the source.'
|
||||||
|
- '- Do not use persuasive summaries or advisory conclusions.'
|
||||||
|
- '- If the retrieved knowledge describes one specific named product, stay within that product and do not merge related product families or variants.'
|
||||||
|
- '- Use neutral engineering language.'
|
||||||
|
- '- Do not name specific chemicals, indicator substances, standards, or mechanisms unless explicitly stated in the source.'
|
||||||
|
- '- If the source states signal logic such as green/red, output that signal logic only and do not expand it into operational recommendations or alarm semantics
|
||||||
|
unless explicitly stated.'
|
||||||
|
- '- If the source lists application areas, repeat only those areas and do not broaden them.'
|
||||||
|
- '- If the source names an indicator and threshold, reproduce that exactly without extrapolation.'
|
||||||
|
- '- For lowest, highest, smallest, largest, minimum, maximum, Grenzwert, Messbereich or Aufloesung questions, first identify the exact numeric extreme from
|
||||||
|
the retrieved knowledge and answer that value directly.'
|
||||||
|
- '- For lowest/highest/minimum/maximum questions, answer only the requested extreme unless the user explicitly asks for a comparison or alternatives.'
|
||||||
|
- '- For direct numeric lookup questions such as which device measures a given threshold, answer with the exact matching device/value pair first and avoid advisory
|
||||||
|
caveats.'
|
||||||
|
- '- Do not add the runner-up product, second-lowest value, or adjacent range unless the user asks for it.'
|
||||||
|
- '- Do not add calibration, accuracy, pretreatment, temperature, or application notes unless those exact notes are requested and explicitly present in the
|
||||||
|
retrieved source.'
|
||||||
|
- '- For follow-up questions such as "which indicator measures that value", first resolve the referenced value/device, then use the retrieved source entry that
|
||||||
|
explicitly connects value, device and indicator.'
|
||||||
|
- '- For numeric extreme questions, do not combine a value, device name, indicator name, range or product variant from different chunks unless the same retrieved
|
||||||
|
entry explicitly connects them.'
|
||||||
|
- '- If several devices or indicators are present, keep each device-indicator-range assignment separate and do not transfer an indicator from one product to
|
||||||
|
another.'
|
||||||
|
- '- If the source states only a threshold function, do not expand it into broader control logic.'
|
||||||
|
- '- If a detail is not explicitly stated in the provided sources, say so plainly.'
|
||||||
|
- '- Prefer short, source-close sentences over explanatory expansion.'
|
||||||
|
- '- If the sources only support that a product family is not suitable, output only that unsuitability and stop there.'
|
||||||
|
retrieved_knowledge:
|
||||||
|
source_line: 'Source: Documents'
|
||||||
|
url_content:
|
||||||
|
source_line: 'Source: URL'
|
||||||
|
technical_product_model_pattern: /\b[\p{L}]{2,}\s?\d{2,5}\b/u
|
||||||
|
|||||||
@@ -151,6 +151,19 @@ final class PromptBuilderConfig
|
|||||||
return is_numeric($value) ? (float) $value : $default;
|
return is_numeric($value) ? (float) $value : $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getString(string $path, string $default): string
|
||||||
|
{
|
||||||
|
$value = $this->getValue($path, $default);
|
||||||
|
|
||||||
|
if (!is_scalar($value)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = (string) $value;
|
||||||
|
|
||||||
|
return $value !== '' ? $value : $default;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
@@ -204,17 +217,17 @@ final class PromptBuilderConfig
|
|||||||
|
|
||||||
public function getSystemSectionLabel(): string
|
public function getSystemSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'SYSTEM';
|
return $this->getString('sections.system_label', 'SYSTEM');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserQuestionSectionLabel(): string
|
public function getUserQuestionSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'USER QUESTION';
|
return $this->getString('sections.user_question_label', 'USER QUESTION');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConversationContextSectionLabel(): string
|
public function getConversationContextSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'CONVERSATION CONTEXT (contextual only)';
|
return $this->getString('sections.conversation_context_label', 'CONVERSATION CONTEXT (contextual only)');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,23 +235,23 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getConversationContextIntroLines(): array
|
public function getConversationContextIntroLines(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('conversation_context.intro_lines', [
|
||||||
'The following messages are previous turns of this conversation.',
|
'The following messages are previous turns of this conversation.',
|
||||||
'Use them only to resolve references, follow-up questions, and user intent.',
|
'Use them only to resolve references, follow-up questions, and user intent.',
|
||||||
'Previous assistant answers are not a factual source for technical values, product compatibility, indicators, ranges, prices, or availability.',
|
'Previous assistant answers are not a factual source for technical values, product compatibility, indicators, ranges, prices, or availability.',
|
||||||
'All factual claims must come from retrieved factual knowledge, user-provided URL content, or live shop data.',
|
'All factual claims must come from retrieved factual knowledge, user-provided URL content, or live shop data.',
|
||||||
'Conversation context must not override retrieved factual knowledge or live shop data.',
|
'Conversation context must not override retrieved factual knowledge or live shop data.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopSearchQuerySectionLabel(): string
|
public function getShopSearchQuerySectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'SHOP SEARCH QUERY';
|
return $this->getString('sections.shop_search_query_label', 'SHOP SEARCH QUERY');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopSearchQuerySourceLine(): string
|
public function getShopSearchQuerySourceLine(): string
|
||||||
{
|
{
|
||||||
return 'Source: Shop Search';
|
return $this->getString('shop_search.source_line', 'Source: Shop Search');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,7 +259,7 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getLiveShopResultsHeaderLines(): array
|
public function getLiveShopResultsHeaderLines(): array
|
||||||
{
|
{
|
||||||
return [
|
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, and current shop-visible product naming.',
|
||||||
'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, or current naming, prefer the shop data.',
|
||||||
@@ -256,17 +269,17 @@ final class PromptBuilderConfig
|
|||||||
'Do not merge a device identified in retrieved knowledge with price, URL, product number, or availability from a different shop item such as a reagent, accessory, kit, consumable, or service item.',
|
'Do not merge a device identified in retrieved knowledge with price, URL, product number, or availability from a different shop item such as a reagent, accessory, kit, consumable, or service item.',
|
||||||
'If a shop result has no price field, do not state a price for it.',
|
'If a shop result has no price field, do not state a price for it.',
|
||||||
'Never interpret a missing price or a zero price as free, kostenlos, gratis, or available for 0.00 EUR.',
|
'Never interpret a missing price or a zero price as free, kostenlos, gratis, or available for 0.00 EUR.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLiveShopResultsOverflowNoticeTemplate(): string
|
public function getLiveShopResultsOverflowNoticeTemplate(): string
|
||||||
{
|
{
|
||||||
return 'Only the top %d ranked shop results are shown here out of %d total results.';
|
return $this->getString('shop_results.overflow_notice_template', 'Only the top %d ranked shop results are shown here out of %d total results.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOutputPrioritySectionLabel(): string
|
public function getOutputPrioritySectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'OUTPUT PRIORITY';
|
return $this->getString('sections.output_priority_label', 'OUTPUT PRIORITY');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,16 +287,16 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getOutputPriorityRules(): array
|
public function getOutputPriorityRules(): array
|
||||||
{
|
{
|
||||||
return [
|
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.',
|
||||||
'- 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.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResponseFormatSectionLabel(): string
|
public function getResponseFormatSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'RESPONSE FORMAT RULES';
|
return $this->getString('sections.response_format_label', 'RESPONSE FORMAT RULES');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,7 +304,7 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getResponseFormatBaseRules(): array
|
public function getResponseFormatBaseRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('response_format.base_rules', [
|
||||||
'- Keep normal spacing between all words. Never fuse words together.',
|
'- Keep normal spacing between all words. Never fuse words together.',
|
||||||
'- Use short, clean paragraphs or short labeled sections.',
|
'- Use short, clean paragraphs or short labeled sections.',
|
||||||
'- Do not use persuasive or promotional wording.',
|
'- Do not use persuasive or promotional wording.',
|
||||||
@@ -301,7 +314,7 @@ final class PromptBuilderConfig
|
|||||||
'- Do not generate external alternative lists, vendor suggestions, or purchase recommendations unless they are explicitly present in the provided sources.',
|
'- Do not generate external alternative lists, vendor suggestions, or purchase recommendations unless they are explicitly present in the provided sources.',
|
||||||
'- Do not combine technical identity from one source with commercial fields from a different product.',
|
'- Do not combine technical identity from one source with commercial fields from a different product.',
|
||||||
'- Product number, price, availability, and URL must belong to the same explicitly grounded product.',
|
'- Product number, price, availability, and URL must belong to the same explicitly grounded product.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,14 +322,14 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getResponseFormatWithShopRules(): array
|
public function getResponseFormatWithShopRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('response_format.with_shop_rules', [
|
||||||
'- If a product is identified, prefer this structure per product: product name, product number, price, availability, URL, then only the most relevant technical facts.',
|
'- If a product is identified, prefer this structure per product: product name, product number, price, availability, URL, then only the most relevant technical facts.',
|
||||||
'- Keep price, availability, and URL on separate lines when they are present.',
|
'- 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.',
|
'- 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 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 the commercial match is uncertain, say that commercial details for the main product are not clearly available in the provided shop results.',
|
'- 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.',
|
'- If no price is shown for a shop item, omit the price instead of writing 0,00 €, free, kostenlos, or a guessed price.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -324,9 +337,9 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getResponseFormatWithoutShopRules(): array
|
public function getResponseFormatWithoutShopRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('response_format.without_shop_rules', [
|
||||||
'- If no shop results are present, do not compensate by inventing external products or external manufacturers.',
|
'- If no shop results are present, do not compensate by inventing external products or external manufacturers.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,11 +347,11 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getResponseFormatTechnicalRules(): array
|
public function getResponseFormatTechnicalRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('response_format.technical_rules', [
|
||||||
'- Write like technical documentation: precise, neutral, and source-close.',
|
'- Write like technical documentation: precise, neutral, and source-close.',
|
||||||
'- Prefer exact values, ranges, thresholds, compatibility notes, and application areas over general explanation.',
|
'- Prefer exact values, ranges, thresholds, compatibility notes, and application areas over general explanation.',
|
||||||
'- If the sources only support a negative finding, output only that negative finding and do not add speculative alternatives.',
|
'- If the sources only support a negative finding, output only that negative finding and do not add speculative alternatives.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -346,17 +359,17 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getResponseFormatAccessoryRules(): array
|
public function getResponseFormatAccessoryRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('response_format.accessory_rules', [
|
||||||
'- If the user asks for a matching accessory, separate the answer into: main device and matching accessory.',
|
'- If the user asks for a matching accessory, separate the answer into: main device and matching accessory.',
|
||||||
'- The main device must come first. The accessory must not replace the main device.',
|
'- The main device must come first. The accessory must not replace the main device.',
|
||||||
'- Only name an accessory as matching if compatibility is explicitly grounded in the provided sources.',
|
'- Only name an accessory as matching if compatibility is explicitly grounded in the provided sources.',
|
||||||
'- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says so.',
|
'- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says so.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLanguageRulesSectionLabel(): string
|
public function getLanguageRulesSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'LANGUAGE RULES';
|
return $this->getString('sections.language_rules_label', 'LANGUAGE RULES');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -364,17 +377,17 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getLanguageRules(): array
|
public function getLanguageRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('language.rules', [
|
||||||
'- Answer only in the same language as the user question.',
|
'- Answer only in the same language as the user question.',
|
||||||
'- All headings, labels, notes, and structural elements must be in the same language as the user question.',
|
'- All headings, labels, notes, and structural elements must be in the same language as the user question.',
|
||||||
'- Do not switch languages unless the user does.',
|
'- Do not switch languages unless the user does.',
|
||||||
'- If headings are used, write them in the user\'s language.',
|
'- If headings are used, write them in the user\'s language.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFactGroundingRulesSectionLabel(): string
|
public function getFactGroundingRulesSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'FACT GROUNDING RULES';
|
return $this->getString('sections.fact_grounding_rules_label', 'FACT GROUNDING RULES');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -382,7 +395,7 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getFactGroundingBaseRules(): array
|
public function getFactGroundingBaseRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('fact_grounding.base_rules', [
|
||||||
'- State only facts that are explicitly present in the provided sources.',
|
'- State only facts that are explicitly present in the provided sources.',
|
||||||
'- Extract concrete values exactly when they are present, including units, ranges, model names, indicator names, IP classes, temperatures, pressures, dimensions, counts, relay outputs, current outputs, and error codes.',
|
'- Extract concrete values exactly when they are present, including units, ranges, model names, indicator names, IP classes, temperatures, pressures, dimensions, counts, relay outputs, current outputs, and error codes.',
|
||||||
'- Do not invent missing values.',
|
'- Do not invent missing values.',
|
||||||
@@ -390,14 +403,14 @@ final class PromptBuilderConfig
|
|||||||
'- Do not claim that information is missing if it appears in the provided sources.',
|
'- Do not claim that information is missing if it appears in the provided sources.',
|
||||||
'- Do not compare with other products unless those products are also present in the provided sources.',
|
'- Do not compare with other products unless those products are also present in the provided sources.',
|
||||||
'- Prefer source-faithful wording over persuasive wording.',
|
'- Prefer source-faithful wording over persuasive wording.',
|
||||||
'- Avoid marketing language such as \'ideal\', \'perfect\', \'unverzichtbar\', \'entscheidend\', \'optimal\', \'kosteneffizient\', \'prozesssicher\', or \'state-of-the-art\'.',
|
"- Avoid marketing language such as 'ideal', 'perfect', 'unverzichtbar', 'entscheidend', 'optimal', 'kosteneffizient', 'prozesssicher', or 'state-of-the-art'.",
|
||||||
'- Clearly separate explicit facts from inferences.',
|
'- Clearly separate explicit facts from inferences.',
|
||||||
'- If a conclusion goes beyond the source wording, label it exactly as \'Inference:\'.',
|
"- If a conclusion goes beyond the source wording, label it exactly as 'Inference:'.",
|
||||||
'- If a sentence cannot be traced to the provided sources, do not write it.',
|
'- If a sentence cannot be traced to the provided sources, do not write it.',
|
||||||
'- For follow-up questions, use the conversation only to resolve what the user refers to; do not copy technical facts from previous assistant answers unless the same fact is present in the current retrieved sources.',
|
'- For follow-up questions, use the conversation only to resolve what the user refers to; do not copy technical facts from previous assistant answers unless the same fact is present in the current retrieved sources.',
|
||||||
'- 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.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,7 +418,7 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getFactGroundingWithShopRules(): array
|
public function getFactGroundingWithShopRules(): array
|
||||||
{
|
{
|
||||||
return [
|
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 only for current commercial fields: price, availability, URL, and current shop-visible naming.',
|
||||||
'- 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 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.',
|
||||||
@@ -416,7 +429,7 @@ final class PromptBuilderConfig
|
|||||||
'- Do not assign the product number, price, URL, or availability of a reagent, accessory, kit, set, consumable, or service item to a device identified in retrieved knowledge.',
|
'- Do not assign the product number, price, URL, or availability of a reagent, accessory, kit, set, consumable, or service item to a device identified in retrieved knowledge.',
|
||||||
'- Only use commercial fields for the main product when the shop item and the technically identified product clearly refer to the same product identity.',
|
'- Only use commercial fields for the main product when the shop item and the technically identified product clearly refer to the same product identity.',
|
||||||
'- If the shop match is ambiguous, keep the technical identification and commercial details separate.',
|
'- If the shop match is ambiguous, keep the technical identification and commercial details separate.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -424,10 +437,10 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getFactGroundingWithoutShopRules(): array
|
public function getFactGroundingWithoutShopRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('fact_grounding.without_shop_rules', [
|
||||||
'- Use retrieved knowledge as authoritative for factual answers.',
|
'- Use retrieved knowledge as authoritative for factual answers.',
|
||||||
'- If no shop results are present, do not compensate with external recommendations or external product suggestions.',
|
'- If no shop results are present, do not compensate with external recommendations or external product suggestions.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -435,7 +448,7 @@ final class PromptBuilderConfig
|
|||||||
*/
|
*/
|
||||||
public function getFactGroundingTechnicalRules(): array
|
public function getFactGroundingTechnicalRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->getStringList('fact_grounding.technical_rules', [
|
||||||
'- For technical product questions, answer primarily with explicitly stated facts.',
|
'- For technical product questions, answer primarily with explicitly stated facts.',
|
||||||
'- Behave like a technical documentation assistant, not like a sales advisor.',
|
'- Behave like a technical documentation assistant, not like a sales advisor.',
|
||||||
'- Keep interpretations minimal and do not generalize application areas beyond the provided sources.',
|
'- Keep interpretations minimal and do not generalize application areas beyond the provided sources.',
|
||||||
@@ -461,82 +474,82 @@ final class PromptBuilderConfig
|
|||||||
'- If a detail is not explicitly stated in the provided sources, say so plainly.',
|
'- If a detail is not explicitly stated in the provided sources, say so plainly.',
|
||||||
'- Prefer short, source-close sentences over explanatory expansion.',
|
'- Prefer short, source-close sentences over explanatory expansion.',
|
||||||
'- If the sources only support that a product family is not suitable, output only that unsuitability and stop there.',
|
'- If the sources only support that a product family is not suitable, output only that unsuitability and stop there.',
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRetrievedKnowledgeSectionLabel(): string
|
public function getRetrievedKnowledgeSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'RETRIEVED KNOWLEDGE (primary for technical matching and factual explanation)';
|
return $this->getString('sections.retrieved_knowledge_label', 'RETRIEVED KNOWLEDGE (primary for technical matching and factual explanation)');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRetrievedKnowledgeSourceLine(): string
|
public function getRetrievedKnowledgeSourceLine(): string
|
||||||
{
|
{
|
||||||
return 'Source: Documents';
|
return $this->getString('retrieved_knowledge.source_line', 'Source: Documents');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlContentSectionLabel(): string
|
public function getUrlContentSectionLabel(): string
|
||||||
{
|
{
|
||||||
return 'CONTENT FROM URL (authoritative if user-provided)';
|
return $this->getString('sections.url_content_label', 'CONTENT FROM URL (authoritative if user-provided)');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlContentSourceLine(): string
|
public function getUrlContentSourceLine(): string
|
||||||
{
|
{
|
||||||
return 'Source: URL';
|
return $this->getString('url_content.source_line', 'Source: URL');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopProductNumberLabel(): string
|
public function getShopProductNumberLabel(): string
|
||||||
{
|
{
|
||||||
return 'Product number';
|
return $this->getString('shop_results.fields.product_number_label', 'Product number');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopManufacturerLabel(): string
|
public function getShopManufacturerLabel(): string
|
||||||
{
|
{
|
||||||
return 'Manufacturer';
|
return $this->getString('shop_results.fields.manufacturer_label', 'Manufacturer');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopPriceLabel(): string
|
public function getShopPriceLabel(): string
|
||||||
{
|
{
|
||||||
return 'Price';
|
return $this->getString('shop_results.fields.price_label', 'Price');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopAvailabilityLabel(): string
|
public function getShopAvailabilityLabel(): string
|
||||||
{
|
{
|
||||||
return 'Available';
|
return $this->getString('shop_results.fields.availability_label', 'Available');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopAvailabilityYesLabel(): string
|
public function getShopAvailabilityYesLabel(): string
|
||||||
{
|
{
|
||||||
return 'yes';
|
return $this->getString('shop_results.fields.availability_yes_label', 'yes');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopAvailabilityNoLabel(): string
|
public function getShopAvailabilityNoLabel(): string
|
||||||
{
|
{
|
||||||
return 'no';
|
return $this->getString('shop_results.fields.availability_no_label', 'no');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopHighlightPrefix(): string
|
public function getShopHighlightPrefix(): string
|
||||||
{
|
{
|
||||||
return '- ';
|
return $this->getString('shop_results.fields.highlight_prefix', '- ');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopUrlLabel(): string
|
public function getShopUrlLabel(): string
|
||||||
{
|
{
|
||||||
return 'URL';
|
return $this->getString('shop_results.fields.url_label', 'URL');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopProductImageLabel(): string
|
public function getShopProductImageLabel(): string
|
||||||
{
|
{
|
||||||
return 'Product image';
|
return $this->getString('shop_results.fields.product_image_label', 'Product image');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopDescriptionLabel(): string
|
public function getShopDescriptionLabel(): string
|
||||||
{
|
{
|
||||||
return 'Description';
|
return $this->getString('shop_results.fields.description_label', 'Description');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShopMetaInformationLabel(): string
|
public function getShopMetaInformationLabel(): string
|
||||||
{
|
{
|
||||||
return 'Meta information';
|
return $this->getString('shop_results.fields.meta_information_label', 'Meta information');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -563,6 +576,6 @@ final class PromptBuilderConfig
|
|||||||
|
|
||||||
public function getTechnicalProductModelPattern(): string
|
public function getTechnicalProductModelPattern(): string
|
||||||
{
|
{
|
||||||
return '/\b[\p{L}]{2,}\s?\d{2,5}\b/u';
|
return $this->getString('technical_product_model_pattern', '/\b[\p{L}]{2,}\s?\d{2,5}\b/u');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user