fix(gtm): Ultimate prompt syntax robustness, add versions to logs, update migration docs

This commit is contained in:
2025-12-31 15:26:23 +00:00
parent 9ad52893f9
commit 30bfe54536
3 changed files with 47 additions and 32 deletions

View File

@@ -60,13 +60,7 @@ Multi-Line Prompts können in Docker-Umgebungen zu **sehr hartnäckigen Syntaxfe
2. **Nutze die `.format()` Methode** zur Variablen-Injektion. Dies trennt die String-Definition komplett von der Variablen-Interpolation und ist die robusteste Methode. 2. **Nutze die `.format()` Methode** zur Variablen-Injektion. Dies trennt die String-Definition komplett von der Variablen-Interpolation und ist die robusteste Methode.
```python ```python
# Schlecht (fehleranfällig, auch wenn es manchmal funktioniert): # Beispiel: So ist es maximal robust (bevorzugte Methode)
# prompt = f"""
# 1. Mache dies: {var1}
# 2. Mache das: {var2}
# """
# Gut (maximal robust):
prompt_template = """ prompt_template = """
1) Mache dies: {variable_1} 1) Mache dies: {variable_1}
2) Mache das: {variable_2} 2) Mache das: {variable_2}
@@ -76,6 +70,10 @@ Multi-Line Prompts können in Docker-Umgebungen zu **sehr hartnäckigen Syntaxfe
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
``` ```
* **Versionierung für Debugging:** Um sicherzustellen, dass die korrekte Version des Codes läuft, füge Versionsnummern in die Start-Logs des Node.js Servers (`server.cjs`) und des Python Orchestrators (`gtm_architect_orchestrator.py`) ein.
* `server.cjs`: `console.log(`... (Version: ${VERSION})`);`
* `gtm_architect_orchestrator.py`: `print(f"DEBUG: Orchestrator v{__version__} loaded ...")`
* **Signaturen prüfen:** Shared Libraries (`helpers.py`) haben oft ältere Signaturen. Immer die tatsächliche Definition prüfen! * **Signaturen prüfen:** Shared Libraries (`helpers.py`) haben oft ältere Signaturen. Immer die tatsächliche Definition prüfen!
* Beispiel: `call_openai_chat` unterstützt oft kein `system_message` Argument. Stattdessen Prompt manuell zusammenbauen (`sys_instr + "\n\n" + prompt`). * Beispiel: `call_openai_chat` unterstützt oft kein `system_message` Argument. Stattdessen Prompt manuell zusammenbauen (`sys_instr + "\n\n" + prompt`).

View File

@@ -73,8 +73,10 @@ app.get('*', (req, res) => {
}); });
const VERSION = "1.1.1_Fix"; // Add a version for debugging
const server = app.listen(port, () => { const server = app.listen(port, () => {
console.log(`GTM Architect server listening at http://localhost:${port} (Timeout: 600s)`); console.log(`GTM Architect server listening at http://localhost:${port} (Version: ${VERSION})`);
}); });
// Prevent 502 Bad Gateway by increasing Node.js server timeouts to match Nginx // Prevent 502 Bad Gateway by increasing Node.js server timeouts to match Nginx

View File

@@ -11,6 +11,8 @@ sys.path.append(str(project_root))
from helpers import call_openai_chat from helpers import call_openai_chat
import market_db_manager import market_db_manager
__version__ = "1.3.0_SyntaxFix"
# Ensure DB is ready # Ensure DB is ready
market_db_manager.init_db() market_db_manager.init_db()
@@ -131,8 +133,9 @@ def analyze_product(data):
lang = data.get('language', 'de') lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang) sys_instr = get_system_instruction(lang)
# Statische Prompt-Teile (keine f-Strings)
if lang == 'en': if lang == 'en':
extraction_prompt_template = """ extraction_prompt_static_part = """
PHASE 1-A: TECHNICAL EXTRACTION PHASE 1-A: TECHNICAL EXTRACTION
Input Product Description: "{product_description}" Input Product Description: "{product_description}"
@@ -143,9 +146,8 @@ Task:
Output JSON format ONLY. Output JSON format ONLY.
""" """
extraction_prompt = extraction_prompt_template.format(product_description=product_input[:25000])
else: else:
extraction_prompt_template = """ extraction_prompt_static_part = """
PHASE 1-A: TECHNICAL EXTRACTION PHASE 1-A: TECHNICAL EXTRACTION
Input Product Description: "{product_description}" Input Product Description: "{product_description}"
@@ -156,7 +158,8 @@ Aufgabe:
Output JSON format ONLY. Output JSON format ONLY.
""" """
extraction_prompt = extraction_prompt_template.format(product_description=product_input[:25000]) # Variablen separat formatieren
extraction_prompt = extraction_prompt_static_part.format(product_description=product_input[:25000])
full_extraction_prompt = sys_instr + "\n\n" + extraction_prompt full_extraction_prompt = sys_instr + "\n\n" + extraction_prompt
extraction_response = call_openai_chat(full_extraction_prompt, response_format_json=True) extraction_response = call_openai_chat(full_extraction_prompt, response_format_json=True)
@@ -166,11 +169,11 @@ Output JSON format ONLY.
constraints_json = json.dumps(extraction_data.get('constraints')) constraints_json = json.dumps(extraction_data.get('constraints'))
if lang == 'en': if lang == 'en':
conflict_prompt_template = """ conflict_prompt_static_part = """
PHASE 1-B: PORTFOLIO CONFLICT CHECK PHASE 1-B: PORTFOLIO CONFLICT CHECK
New Product Features: {features_json} New Product Features: {features_json_var}
New Product Constraints: {constraints_json} New Product Constraints: {constraints_json_var}
Existing Portfolio: Existing Portfolio:
1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets. 1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets.
@@ -181,13 +184,13 @@ Check if the new product overlaps significantly with existing ones (is it just a
Output JSON format ONLY. Output JSON format ONLY.
""" """
conflict_prompt = conflict_prompt_template.format(features_json=features_json, constraints_json=constraints_json) conflict_prompt = conflict_prompt_static_part.format(features_json_var=features_json, constraints_json_var=constraints_json)
else: else:
conflict_prompt_template = """ conflict_prompt_static_part = """
PHASE 1-B: PORTFOLIO CONFLICT CHECK PHASE 1-B: PORTFOLIO CONFLICT CHECK
Neue Produkt-Features: {features_json} Neue Produkt-Features: {features_json_var}
Neue Produkt-Constraints: {constraints_json} Neue Produkt-Constraints: {constraints_json_var}
Existierendes Portfolio: Existierendes Portfolio:
1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Supermärkte. 1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Supermärkte.
@@ -198,7 +201,7 @@ Prüfe, ob das neue Produkt signifikant mit bestehenden Produkten überlappt (Is
Output JSON format ONLY. Output JSON format ONLY.
""" """
conflict_prompt = conflict_prompt_template.format(features_json=features_json, constraints_json=constraints_json) conflict_prompt = conflict_prompt_static_part.format(features_json_var=features_json, constraints_json_var=constraints_json)
full_conflict_prompt = sys_instr + "\n\n" + conflict_prompt full_conflict_prompt = sys_instr + "\n\n" + conflict_prompt
conflict_response = call_openai_chat(full_conflict_prompt, response_format_json=True) conflict_response = call_openai_chat(full_conflict_prompt, response_format_json=True)
@@ -218,8 +221,8 @@ def discover_icps(data):
if lang == 'en': if lang == 'en':
prompt_template = """ prompt_template = """
PHASE 2: ICP DISCOVERY & DATA PROXIES PHASE 2: ICP DISCOVERY & DATA PROXIES
Based on the product features: {features_json} Based on the product features: {features_json_var}
And constraints: {constraints_json} And constraints: {constraints_json_var}
Output JSON format ONLY: Output JSON format ONLY:
{{ {{
@@ -227,12 +230,12 @@ Output JSON format ONLY:
"dataProxies": [ {{ "target": "Criteria", "method": "How" }} ] "dataProxies": [ {{ "target": "Criteria", "method": "How" }} ]
}} }}
""" """
prompt = prompt_template.format(features_json=features_json, constraints_json=constraints_json) prompt = prompt_template.format(features_json_var=features_json, constraints_json_var=constraints_json)
else: else:
prompt_template = """ prompt_template = """
PHASE 2: ICP DISCOVERY & DATA PROXIES PHASE 2: ICP DISCOVERY & DATA PROXIES
Basierend auf Features: {features_json} Basierend auf Features: {features_json_var}
Und Constraints: {constraints_json} Und Constraints: {constraints_json_var}
Output JSON format ONLY: Output JSON format ONLY:
{{ {{
@@ -240,7 +243,7 @@ Output JSON format ONLY:
"dataProxies": [ {{ "target": "Kriterium", "method": "Methode" }} ] "dataProxies": [ {{ "target": "Kriterium", "method": "Methode" }} ]
}} }}
""" """
prompt = prompt_template.format(features_json=features_json, constraints_json=constraints_json) prompt = prompt_template.format(features_json_var=features_json, constraints_json_var=constraints_json)
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt, response_format_json=True) response = call_openai_chat(full_prompt, response_format_json=True)
@@ -251,7 +254,10 @@ def hunt_whales(data):
lang = data.get('language', 'de') lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang) sys_instr = get_system_instruction(lang)
icps_json = json.dumps(phase2_result.get('icps')) icps_json = json.dumps(phase2_result.get('icps'))
prompt = f"PHASE 3: WHALE HUNTING for {icps_json}. Identify 3-5 concrete DACH companies per industry and buying center roles. Output JSON ONLY." prompt_template = """
PHASE 3: WHALE HUNTING for {icps_json_var}. Identify 3-5 concrete DACH companies per industry and buying center roles. Output JSON ONLY.
"""
prompt = prompt_template.format(icps_json_var=icps_json)
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt, response_format_json=True) response = call_openai_chat(full_prompt, response_format_json=True)
print(response) print(response)
@@ -262,7 +268,10 @@ def develop_strategy(data):
lang = data.get('language', 'de') lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang) sys_instr = get_system_instruction(lang)
phase3_json = json.dumps(phase3_result) phase3_json = json.dumps(phase3_result)
prompt = f"PHASE 4: STRATEGY Matrix for {phase3_json}. Apply Hybrid logic. Output JSON ONLY." prompt_template = """
PHASE 4: STRATEGY Matrix for {phase3_json_var}. Apply Hybrid logic. Output JSON ONLY.
"""
prompt = prompt_template.format(phase3_json_var=phase3_json)
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt, response_format_json=True) response = call_openai_chat(full_prompt, response_format_json=True)
print(response) print(response)
@@ -271,7 +280,10 @@ def generate_assets(data):
lang = data.get('language', 'de') lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang) sys_instr = get_system_instruction(lang)
data_json = json.dumps(data) data_json = json.dumps(data)
prompt = f"PHASE 5: GTM STRATEGY REPORT Markdown. Use facts, TCO, ROI. Data: {data_json}" prompt_template = """
PHASE 5: GTM STRATEGY REPORT Markdown. Use facts, TCO, ROI. Data: {data_json_var}
"""
prompt = prompt_template.format(data_json_var=data_json)
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt) response = call_openai_chat(full_prompt)
print(json.dumps(response)) print(json.dumps(response))
@@ -280,7 +292,10 @@ def generate_sales_enablement(data):
lang = data.get('language', 'de') lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang) sys_instr = get_system_instruction(lang)
data_json = json.dumps(data) data_json = json.dumps(data)
prompt = f"PHASE 6: Battlecards and MJ Prompts. Data: {data_json}. Output JSON ONLY." prompt_template = """
PHASE 6: Battlecards and MJ Prompts. Data: {data_json_var}. Output JSON ONLY.
"""
prompt = prompt_template.format(data_json_var=data_json)
full_prompt = sys_instr + "\n\n" + prompt full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt, response_format_json=True) response = call_openai_chat(full_prompt, response_format_json=True)
print(response) print(response)
@@ -290,7 +305,7 @@ def main():
parser.add_argument("--mode", type=str, required=True, help="Execution mode") parser.add_argument("--mode", type=str, required=True, help="Execution mode")
args = parser.parse_args() args = parser.parse_args()
print(f"DEBUG: Orchestrator v1.2 loaded (Mode: {args.mode})", file=sys.stderr) print(f"DEBUG: Orchestrator v{__version__} loaded (Mode: {args.mode})", file=sys.stderr)
if not sys.stdin.isatty(): if not sys.stdin.isatty():
try: try: