fix(gtm): Implement ultimate prompt robustness, version logging, and final doc update

This commit is contained in:
2025-12-31 15:34:45 +00:00
parent 21478f4f71
commit df78055ecf
2 changed files with 41 additions and 199 deletions

View File

@@ -56,15 +56,16 @@ Multi-Line Prompts können in Docker-Umgebungen zu **sehr hartnäckigen Syntaxfe
* **Das Problem:** Der Python-Parser (insbesondere bei `f-strings` in Kombination mit Zahlen/Punkten am Zeilenanfang oder verschachtelten Klammern) kann Multi-Line-Strings (`f"""..."""`) falsch interpretieren, was zu Fehlern wie `SyntaxError: invalid decimal literal` oder `unmatched ')'` führt, auch wenn der Code scheinbar korrekt ist.
* **ULTIMATIVE LÖSUNG (Maximale Robustheit):**
1. **Vermeide `f"""` komplett für komplexe Multi-Line-Prompts.** Definiere stattdessen den Prompt als normalen Multi-Line-String (ohne `f` Präfix).
2. **Nutze die `.format()` Methode** zur Variablen-Injektion. Dies trennt die String-Definition komplett von der Variablen-Interpolation und ist die robusteste Methode.
1. **Vermeide `f"""` komplett für komplexe Multi-Line-Prompts.** Definiere stattdessen den Prompt als **Liste von einzelnen String-Zeilen** und füge sie mit `"\n".join(prompt_parts)` zusammen.
2. **Nutze die `.format()` Methode oder f-Strings in EINZEILIGEN Strings** zur Variablen-Injektion. Dies trennt die String-Definition komplett von der Variablen-Interpolation und ist die robusteste Methode.
```python
# Beispiel: So ist es maximal robust (bevorzugte Methode)
prompt_template = """
1) Mache dies: {variable_1}
2) Mache das: {variable_2}
"""
# Beispiel: Maximal robust
prompt_template_parts = [
"1) Mache dies: {variable_1}",
"2) Mache das: {variable_2}",
]
prompt_template = "\n".join(prompt_template_parts)
prompt = prompt_template.format(variable_1=wert1, variable_2=wert2)
# System-Instruktion muss immer noch vorangestellt werden:
full_prompt = sys_instr + "\n\n" + prompt

View File

@@ -11,7 +11,7 @@ sys.path.append(str(project_root))
from helpers import call_openai_chat
import market_db_manager
__version__ = "1.3.0_SyntaxFix"
__version__ = "1.4.0_UltimatePromptFix"
# Ensure DB is ready
market_db_manager.init_db()
@@ -133,35 +133,35 @@ def analyze_product(data):
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
# Statische Prompt-Teile (keine f-Strings)
# Prompts als Liste von Strings konstruieren, um Syntax-Fehler zu vermeiden
if lang == 'en':
extraction_prompt_static_part = """
PHASE 1-A: TECHNICAL EXTRACTION
Input Product Description: "{product_description}"
Task:
1) Extract key technical features (specs, capabilities).
2) Derive "Hard Constraints". IMPORTANT: Check Vmax (<20km/h = Private Grounds) and Cleaning Type (Vacuum != Heavy Debris/Snow).
3) Create a short raw analysis summary.
Output JSON format ONLY.
"""
extraction_prompt_parts = [
"PHASE 1-A: TECHNICAL EXTRACTION",
f"Input Product Description: \"{product_input[:25000]}\"",
"",
"Task:",
"1) Extract key technical features (specs, capabilities).",
"2) Derive \"Hard Constraints\". IMPORTANT: Check Vmax (<20km/h = Private Grounds) and Cleaning Type (Vacuum != Heavy Debris/Snow).",
"3) Create a short raw analysis summary.",
"",
"Output JSON format ONLY."
]
else:
extraction_prompt_static_part = """
PHASE 1-A: TECHNICAL EXTRACTION
Input Product Description: "{product_description}"
Aufgabe:
1) Extrahiere technische Hauptmerkmale (Specs, Fähigkeiten).
2) Leite "Harte Constraints" ab. WICHTIG: Prüfe Vmax (<20km/h = Privatgelände) und Reinigungstyp (Vakuum != Grobschmutz/Schnee).
3) Erstelle eine kurze Rohanalyse-Zusammenfassung.
Output JSON format ONLY.
"""
# Variablen separat formatieren
extraction_prompt = extraction_prompt_static_part.format(product_description=product_input[:25000])
extraction_prompt_parts = [
"PHASE 1-A: TECHNICAL EXTRACTION",
f"Input Product Description: \"{product_input[:25000]}\"",
"",
"Aufgabe:",
"1) Extrahiere technische Hauptmerkmale (Specs, Fähigkeiten).",
"2) Leite \"Harte Constraints\" ab. WICHTIG: Prüfe Vmax (<20km/h = Privatgelände) und Reinigungstyp (Vakuum != Grobschmutz/Schnee).",
"3) Erstelle eine kurze Rohanalyse-Zusammenfassung.",
"",
"Output JSON format ONLY."
]
extraction_prompt = "\n".join(extraction_prompt_parts)
full_extraction_prompt = sys_instr + "\n\n" + extraction_prompt
print(f"DEBUG: Full Extraction Prompt: \n{full_extraction_prompt[:1000]}...\n", file=sys.stderr)
extraction_response = call_openai_chat(full_extraction_prompt, response_format_json=True)
extraction_data = json.loads(extraction_response)
@@ -169,169 +169,10 @@ Output JSON format ONLY.
constraints_json = json.dumps(extraction_data.get('constraints'))
if lang == 'en':
conflict_prompt_static_part = """
PHASE 1-B: PORTFOLIO CONFLICT CHECK
New Product Features: {features_json_var}
New Product Constraints: {constraints_json_var}
Existing Portfolio:
1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets.
2. "Service Bot Bella": Service/Gastro, indoor, restaurants.
Task:
Check if the new product overlaps significantly with existing ones (is it just a clone?).
Output JSON format ONLY.
"""
conflict_prompt = conflict_prompt_static_part.format(features_json_var=features_json, constraints_json_var=constraints_json)
else:
conflict_prompt_static_part = """
PHASE 1-B: PORTFOLIO CONFLICT CHECK
Neue Produkt-Features: {features_json_var}
Neue Produkt-Constraints: {constraints_json_var}
Existierendes Portfolio:
1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Supermärkte.
2. "Service Bot Bella": Service/Gastro, Indoor, Restaurants.
Aufgabe:
Prüfe, ob das neue Produkt signifikant mit bestehenden Produkten überlappt (Ist es nur ein Klon?).
Output JSON format ONLY.
"""
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
conflict_response = call_openai_chat(full_conflict_prompt, response_format_json=True)
conflict_data = json.loads(conflict_response)
final_result = {**extraction_data, **conflict_data}
print(json.dumps(final_result))
def discover_icps(data):
phase1_result = data.get('phase1Result')
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
features_json = json.dumps(phase1_result.get('features'))
constraints_json = json.dumps(phase1_result.get('constraints'))
if lang == 'en':
prompt_template = """
PHASE 2: ICP DISCOVERY & DATA PROXIES
Based on the product features: {features_json_var}
And constraints: {constraints_json_var}
Output JSON format ONLY:
{{
"icps": [ {{ "name": "Industry Name", "rationale": "Rationale" }} ],
"dataProxies": [ {{ "target": "Criteria", "method": "How" }} ]
}}
"""
prompt = prompt_template.format(features_json_var=features_json, constraints_json_var=constraints_json)
else:
prompt_template = """
PHASE 2: ICP DISCOVERY & DATA PROXIES
Basierend auf Features: {features_json_var}
Und Constraints: {constraints_json_var}
Output JSON format ONLY:
{{
"icps": [ {{ "name": "Branchen Name", "rationale": "Begründung" }} ],
"dataProxies": [ {{ "target": "Kriterium", "method": "Methode" }} ]
}}
"""
prompt = prompt_template.format(features_json_var=features_json, constraints_json_var=constraints_json)
full_prompt = sys_instr + "\n\n" + prompt
response = call_openai_chat(full_prompt, response_format_json=True)
print(response)
def hunt_whales(data):
phase2_result = data.get('phase2Result')
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
icps_json = json.dumps(phase2_result.get('icps'))
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
response = call_openai_chat(full_prompt, response_format_json=True)
print(response)
def develop_strategy(data):
phase3_result = data.get('phase3Result')
phase1_result = data.get('phase1Result')
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
phase3_json = json.dumps(phase3_result)
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
response = call_openai_chat(full_prompt, response_format_json=True)
print(response)
def generate_assets(data):
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
data_json = json.dumps(data)
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
response = call_openai_chat(full_prompt)
print(json.dumps(response))
def generate_sales_enablement(data):
lang = data.get('language', 'de')
sys_instr = get_system_instruction(lang)
data_json = json.dumps(data)
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
response = call_openai_chat(full_prompt, response_format_json=True)
print(response)
def main():
parser = argparse.ArgumentParser(description="GTM Architect Orchestrator")
parser.add_argument("--mode", type=str, required=True, help="Execution mode")
args = parser.parse_args()
print(f"DEBUG: Orchestrator v{__version__} loaded (Mode: {args.mode})", file=sys.stderr)
if not sys.stdin.isatty():
try:
data = json.loads(sys.stdin.read())
except:
data = {}
else:
data = {}
modes = {
"analyze_product": analyze_product,
"discover_icps": discover_icps,
"hunt_whales": hunt_whales,
"develop_strategy": develop_strategy,
"generate_assets": generate_assets,
"generate_sales_enablement": generate_sales_enablement,
"save_project": save_project_handler,
"list_projects": list_projects_handler,
"load_project": load_project_handler,
"delete_project": delete_project_handler
}
if args.mode in modes:
modes[args.mode](data)
else:
print(json.dumps({"error": f"Unknown mode: {args.mode}"}))
if __name__ == "__main__":
main()
conflict_prompt_parts = [
"PHASE 1-B: PORTFOLIO CONFLICT CHECK",
"",
f"New Product Features: {features_json}",
f"New Product Constraints: {constraints_json}",
"",
"Existing Portfolio:",