1514 lines
64 KiB
Markdown
1514 lines
64 KiB
Markdown
# AI-Call Looping Architektur
|
|
|
|
## Übersicht
|
|
|
|
Dieses Dokument beschreibt die zentrale Architektur für **AI-Calls mit Looping-Funktionalität** nach cut-response. Es dokumentiert die verschiedenen Use Cases, ihre Looping-Mechanismen, Continuation-Prompt-Strukturen und die Unterschiede zwischen ihnen.
|
|
|
|
**Fokus**: AI-Loop-Call mit automatischen Iterationen nach unvollständigen JSON-Responses.
|
|
|
|
**Ziel**: Übersichtliche Grundlage für das Aufräumen und Vereinheitlichen der Looping-Logik.
|
|
|
|
---
|
|
|
|
## Use Cases Summary
|
|
|
|
**Alle registrierten Use Cases**:
|
|
1. `section_content` - Section-Content-Generierung ✅ **Looping**
|
|
2. `chapter_structure` - Chapter-Struktur-Generierung ✅ **Looping**
|
|
3. `code_structure` - Code-Struktur-Generierung ✅ **Looping**
|
|
4. `code_content` - Code-Content-Generierung ✅ **Looping**
|
|
|
|
**Vergleichstabelle**:
|
|
|
|
| Use Case | Looping | Direct Return | Accumulation | Extraction | Prompt Builder | Template Konsistenz | Prompt Builder Parameter |
|
|
|----------|---------|---------------|--------------|------------|----------------|---------------------|------------------------|
|
|
| `section_content` | ✅ | ✅ | ❌ | ❌ | `buildSectionPromptWithContinuation()` | ✅ IDENTISCH | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` |
|
|
| `chapter_structure` | ✅ | ✅ | ❌ | ❌ | `buildChapterStructurePromptWithContinuation()` | ✅ IDENTISCH | `userPrompt`, `contentParts`, `outputFormat`, `services` |
|
|
| `code_structure` | ✅ | ✅ | ❌ | ❌ | ❌ **FEHLT** | ❌ PROBLEM | ❌ **FEHLT** |
|
|
| `code_content` | ✅ | ✅ | ✅ | ❌ | `buildCodeContentPromptWithContinuation()` | ✅ IDENTISCH | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` |
|
|
|
|
**Hinweis zu Prompt-Builder-Parametern**:
|
|
- Alle Prompt-Builder akzeptieren zusätzlich: `continuationContext: Dict[str, Any]` (wird automatisch übergeben)
|
|
- Aktuell verwenden alle Builder `**kwargs` für Parameter-Extraktion
|
|
- **Ziel-Architektur**: Explizite Parameter statt `**kwargs` (siehe "Ziel-Architektur" Abschnitt)
|
|
|
|
---
|
|
|
|
## Kern-System: `callAiWithLooping`
|
|
|
|
**Location**: `gateway/modules/services/serviceAi/subAiCallLooping.py`
|
|
|
|
**Zentrale Funktion**: `AiCallLooper.callAiWithLooping()`
|
|
|
|
**Funktionsweise**:
|
|
1. **Erste Iteration**: Verwendet den initialen Prompt
|
|
2. **Weitere Iterationen (nach cut-response)**:
|
|
- Prüft, ob JSON vollständig ist (String-basierte und Parsing-basierte Checks)
|
|
- Wenn unvollständig: Baut Continuation-Prompt mit `promptBuilder`
|
|
- Merged JSON-Fragmente mit Overlap-Detection
|
|
- Wiederholt bis JSON vollständig oder kein Overlap gefunden
|
|
|
|
**Loop-Bedingungen**:
|
|
- **Stoppt wenn**: JSON vollständig, kein Overlap gefunden, Fehler, max Iterationen erreicht
|
|
- **Weiter wenn**: JSON unvollständig, Overlap gefunden, Parsing fehlgeschlagen
|
|
|
|
---
|
|
|
|
## Ziel-Architektur: Harmonisiertes AI-Looping-System
|
|
|
|
### 1. Continuation-Context-Building
|
|
|
|
**Aktueller Zustand**:
|
|
- `buildContinuationContext(allSections, lastRawResponse, useCaseId)` extrahiert `template_structure` aus dem Response
|
|
- `template_structure` wird aus dem Response abgeleitet, nicht explizit übergeben
|
|
|
|
**⚠️ KRITISCH: Template-Struktur NICHT extrahieren**
|
|
- **Template-Struktur wird NICHT aus dem initialen Prompt extrahiert**
|
|
- **Template-Struktur wird NICHT aus dem Response extrahiert**
|
|
- **Template-Struktur ist ein expliziter Parameter**, der beim Erstellen des initialen Prompts erstellt wird
|
|
- **Derselbe Template-Struktur-Parameter** wird dann für den Continuation-Prompt verwendet
|
|
- Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt
|
|
|
|
**Ziel-Architektur**:
|
|
```python
|
|
from pydantic import BaseModel
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
class ContinuationContext(BaseModel):
|
|
"""Pydantic model for continuation context information."""
|
|
section_count: int
|
|
delivered_summary: str
|
|
cut_off_element: Optional[str] = None
|
|
element_before_cutoff: Optional[str] = None
|
|
template_structure: Optional[str] = None # JSON structure template from initial prompt
|
|
last_complete_part: Optional[str] = None
|
|
incomplete_part: Optional[str] = None
|
|
structure_context: Optional[str] = None
|
|
last_raw_json: Optional[str] = None
|
|
|
|
def buildContinuationContext(
|
|
allSections: List[Dict[str, Any]],
|
|
lastRawResponse: Optional[str] = None,
|
|
useCaseId: Optional[str] = None,
|
|
templateStructure: Optional[str] = None # NEU: Expliziter Parameter
|
|
) -> ContinuationContext:
|
|
"""
|
|
Build context information from accumulated sections for continuation prompt.
|
|
|
|
Args:
|
|
allSections: List of ALL sections accumulated across ALL iterations
|
|
lastRawResponse: Raw JSON response from last iteration (can be broken/incomplete)
|
|
useCaseId: Optional use case ID to determine expected JSON structure
|
|
templateStructure: JSON structure template from initial prompt (MUST be identical)
|
|
|
|
Returns:
|
|
ContinuationContext: Pydantic model with all continuation context information
|
|
"""
|
|
# ... implementation ...
|
|
return ContinuationContext(
|
|
section_count=len(allSections),
|
|
delivered_summary=delivered_summary,
|
|
cut_off_element=cut_off_element,
|
|
element_before_cutoff=element_before_cutoff,
|
|
template_structure=templateStructure, # Explizit übergeben
|
|
last_complete_part=last_complete_part,
|
|
incomplete_part=incomplete_part,
|
|
structure_context=structure_context,
|
|
last_raw_json=lastRawResponse
|
|
)
|
|
```
|
|
|
|
**Vorteile**:
|
|
- ✅ **Typsicherheit**: Pydantic-Modell statt Dict für bessere IDE-Support und Validierung
|
|
- ✅ **Konsistenz**: Gleiche Architektur wie andere Modelle im System (z.B. Prompt-Args-Dataclasses)
|
|
- ✅ **Validierung**: Automatische Validierung der Felder durch Pydantic
|
|
- ✅ **Dokumentation**: Explizite Feld-Definitionen statt Dict-Keys
|
|
- ✅ Initialer und iterativer Prompt haben garantiert die gleiche Struktur
|
|
- ✅ Keine Abhängigkeit von Response-Parsing für Template-Extraktion
|
|
- ✅ Explizite Kontrolle über Template-Struktur
|
|
|
|
**Erforderliche Änderungen**:
|
|
1. `ContinuationContext` Pydantic-Modell erstellen (`jsonUtils.py` oder separate Model-Datei)
|
|
2. `buildContinuationContext()` erweitern um `templateStructure` Parameter
|
|
3. `buildContinuationContext()` Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext`
|
|
4. Alle Aufrufe von `buildContinuationContext()` anpassen, um `templateStructure` zu übergeben
|
|
5. Alle Verwendungen von `continuationContext` anpassen (Dict-Zugriff → Attribut-Zugriff)
|
|
- `continuationContext.get("delivered_summary")` → `continuationContext.delivered_summary`
|
|
- `continuationContext.get("cut_off_element")` → `continuationContext.cut_off_element`
|
|
- etc.
|
|
|
|
---
|
|
|
|
### 2. Prompt-Builder-Architektur
|
|
|
|
**Aktueller Zustand**:
|
|
- Alle Prompt-Builder verwenden `**kwargs` für Parameter
|
|
- Parameter werden aus `kwargs` extrahiert (nicht typsicher)
|
|
- 3 identische Instanzen von `buildSectionPromptWithContinuation()` in `subStructureFilling.py`
|
|
|
|
**Ziel-Architektur**:
|
|
|
|
**Entscheidungen**:
|
|
- ✅ **BasePrompt als Parameter übergeben**: Saubere Lösung, garantiert Identität mit initialem Prompt
|
|
- ✅ **Dataclasses für Parameter-Strukturen**: Ja, für Typsicherheit und bessere Code-Qualität
|
|
- ✅ **Schrittweise Migration**: Von `**kwargs` zu expliziten Parametern mit klarem Plan
|
|
- ✅ **Einheitliche Signatur**: Alle Builder auf die gleiche Signatur umstellen
|
|
|
|
**Einheitliche Signatur mit Dataclasses**:
|
|
```python
|
|
from typing import Protocol
|
|
from dataclasses import dataclass
|
|
|
|
# Beispiel: Section Content Prompt Args
|
|
@dataclass
|
|
class SectionPromptArgs:
|
|
"""Type-safe arguments for section content prompt builder."""
|
|
section: Dict[str, Any]
|
|
contentParts: List[ContentPart]
|
|
userPrompt: str
|
|
generationHint: str
|
|
allSections: List[Dict[str, Any]]
|
|
sectionIndex: int
|
|
isAggregation: bool
|
|
services: Any
|
|
|
|
# Beispiel: Chapter Structure Prompt Args
|
|
@dataclass
|
|
class ChapterStructurePromptArgs:
|
|
"""Type-safe arguments for chapter structure prompt builder."""
|
|
userPrompt: str
|
|
contentParts: List[ContentPart]
|
|
outputFormat: str
|
|
services: Any
|
|
|
|
# Einheitliche Signatur für ALLE Prompt-Builder:
|
|
class PromptBuilder(Protocol):
|
|
"""Protocol for prompt builders with unified signature."""
|
|
async def __call__(
|
|
self,
|
|
continuationContext: ContinuationContext, # Pydantic-Modell (NICHT Optional - wird immer übergeben)
|
|
templateStructure: str, # Expliziter Parameter (aus promptArgs) - NICHT extrahiert, sondern als Parameter übergeben
|
|
basePrompt: str, # Initialer Prompt (als Parameter übergeben) - NICHT regeneriert, sondern als Parameter übergeben
|
|
promptArgs: Any # Dataclass mit use-case-spezifischen Parametern
|
|
) -> str:
|
|
"""Build continuation prompt with unified signature."""
|
|
...
|
|
```
|
|
|
|
**Vorteile**:
|
|
- ✅ Typsicherheit durch Dataclasses
|
|
- ✅ Einheitliche Signatur für alle Builder
|
|
- ✅ BasePrompt als Parameter garantiert Identität
|
|
- ✅ Bessere IDE-Support und Dokumentation
|
|
|
|
**Aufruf-Stelle** (`subAiCallLooping.py` Zeile 124):
|
|
```python
|
|
# Aktueller Aufruf:
|
|
iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs)
|
|
```
|
|
|
|
**Aktuelle Signaturen (INKONSISTENT)**:
|
|
- `buildSectionPromptWithContinuation(continuationContext: Dict[str, Any], **kwargs)` → `continuationContext` NICHT Optional
|
|
- `buildChapterStructurePromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)` → `continuationContext` Optional
|
|
- `buildCodeContentPromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)` → `continuationContext` Optional
|
|
|
|
**Problem**: Inkonsistente Signaturen! Einige Builder haben `Optional`, andere nicht.
|
|
|
|
**Parameter-Übergabe-Unterschiede (AKTUELL)**:
|
|
|
|
| Use Case | Parameter-Übergabe | Beschreibung |
|
|
|----------|-------------------|--------------|
|
|
| `section_content` | Alle `promptArgs` werden übergeben | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` |
|
|
| `chapter_structure` | Alle `promptArgs` werden übergeben | `userPrompt`, `contentParts`, `outputFormat`, `services` |
|
|
| `code_content` | Alle `promptArgs` werden übergeben | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` |
|
|
| Andere Use Cases (historisch) | Gefilterte `promptArgs` | Nur: `outputFormat`, `userPrompt`, `title`, `extracted_content`, `services` |
|
|
|
|
**Hinweis**: Die historische Unterscheidung zwischen `section_content` (alle Parameter) und anderen Use Cases (gefilterte Parameter) wurde bereits aufgehoben. Alle aktuellen Use Cases verwenden alle `promptArgs`.
|
|
|
|
**⚠️ KRITISCH: Template-Struktur-Quelle**
|
|
|
|
**WICHTIG**: Template-Struktur wird **NICHT aus dem initialen Prompt extrahiert**. Stattdessen:
|
|
|
|
| Use Case | Template-Erstellung | Beschreibung |
|
|
|----------|---------------------|--------------|
|
|
| `section_content` | Wird erstellt via `_getContentStructureExample(contentType)` | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) |
|
|
| `chapter_structure` | Wird erstellt aus "EXAMPLE STRUCTURE" Struktur | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) |
|
|
| `code_content` | Wird erstellt aus JSON-Struktur-Definition | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) |
|
|
| `code_structure` | Wird erstellt aus "## FILE STRUCTURE REQUIREMENTS" | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) |
|
|
|
|
**Ziel-Architektur**:
|
|
- **Template wird beim Erstellen des initialen Prompts erstellt** (nicht extrahiert!)
|
|
- **Template wird als separater Parameter zurückgegeben**: `(prompt, templateStructure)`
|
|
- **Template wird in `promptArgs` gespeichert** beim Aufruf von `callAiWithLooping()`
|
|
- **Template wird aus `promptArgs` geholt** und an Continuation-Prompt-Builder übergeben
|
|
- **Garantiert exakte Identität** zwischen initialem und Continuation-Prompt
|
|
|
|
**Einheitliche Signatur (ZIEL)**:
|
|
```python
|
|
# Einheitliche Signatur für ALLE Prompt-Builder:
|
|
async def buildXxxPromptWithContinuation(
|
|
continuationContext: ContinuationContext, # Pydantic-Modell (NICHT Optional - wird immer übergeben)
|
|
templateStructure: str, # Expliziter Parameter (aus promptArgs)
|
|
basePrompt: str, # Initialer Prompt (als Parameter übergeben)
|
|
promptArgs: Any # Dataclass mit use-case-spezifischen Parametern
|
|
) -> str:
|
|
"""Build continuation prompt with unified signature."""
|
|
...
|
|
```
|
|
|
|
**Erforderliche Änderungen**:
|
|
|
|
1. **Einheitlicher Prompt-Builder für `section_content`**:
|
|
- 3 Instanzen zu einer einzigen Funktion konsolidieren
|
|
- Funktion als Methode der Klasse definieren (nicht nested)
|
|
- Dataclass `SectionPromptArgs` für Parameter verwenden
|
|
|
|
2. **Alle Prompt-Builder harmonisieren**:
|
|
- `continuationContext` als **NICHT-Optional** Parameter (wird immer übergeben)
|
|
- `templateStructure` als expliziten Parameter hinzufügen
|
|
- `basePrompt` als expliziten Parameter hinzufügen (garantiert Identität)
|
|
- Dataclasses für use-case-spezifische Parameter einführen
|
|
- `**kwargs` schrittweise durch Dataclass-Parameter ersetzen
|
|
|
|
3. **`buildCodeStructurePromptWithContinuation()` implementieren**:
|
|
- Als Klassenmethode in `CodeGenerationPath`
|
|
- Ähnlich wie `buildChapterStructurePromptWithContinuation()`
|
|
- Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303 in `codePath.py`)
|
|
- Dataclass `CodeStructurePromptArgs` erstellen
|
|
|
|
4. **Aufruf-Stelle anpassen** (`subAiCallLooping.py` Zeile 112-124):
|
|
```python
|
|
# Aktuell:
|
|
continuationContext = buildContinuationContext(allSections, lastRawResponse, useCaseId) # Gibt Dict zurück
|
|
iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs)
|
|
|
|
# Verwendung (aktuell):
|
|
deliveredSummary = continuationContext.get("delivered_summary", "")
|
|
cutOffElement = continuationContext.get("cut_off_element", "")
|
|
|
|
# Ziel (nach vollständiger Migration):
|
|
# templateStructure und basePrompt werden bereits beim Erstellen des initialen Prompts als Parameter übergeben
|
|
templateStructure = promptArgs.get("templateStructure") # Aus promptArgs
|
|
basePrompt = prompt # Initialer Prompt (wird bereits übergeben)
|
|
continuationContext = buildContinuationContext(
|
|
allSections, lastRawResponse, useCaseId, templateStructure
|
|
)
|
|
|
|
# Dataclass aus promptArgs erstellen (use-case-spezifisch)
|
|
# Beispiel für section_content:
|
|
sectionArgs = SectionPromptArgs(
|
|
section=promptArgs["section"],
|
|
contentParts=promptArgs["contentParts"],
|
|
userPrompt=promptArgs["userPrompt"],
|
|
generationHint=promptArgs["generationHint"],
|
|
allSections=promptArgs["allSections"],
|
|
sectionIndex=promptArgs["sectionIndex"],
|
|
isAggregation=promptArgs["isAggregation"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
promptArgs=sectionArgs # Dataclass statt **kwargs
|
|
)
|
|
```
|
|
|
|
**⚠️ WICHTIG: Keine Rückwärtskompatibilität**
|
|
- **Keine Backward Compatibility** - neue Architektur wird vollständig implementiert
|
|
- **Keine Fallback-Logik** - alle Parameter sind REQUIRED
|
|
- **Klare neue Architektur** - alte Implementierungen werden vollständig ersetzt
|
|
|
|
**Schrittweise Migration**:
|
|
- **Phase 1**: `ContinuationContext` Pydantic-Modell erstellen, `templateStructure` als expliziten Parameter hinzufügen
|
|
- **Phase 2**: `basePrompt` als expliziten Parameter hinzufügen
|
|
- **Phase 3**: Prompt-Builder konsolidieren und als Klassenmethoden definieren
|
|
- **Phase 4**: Alle Builder auf einheitliche Signatur umstellen (einheitliche Continuation-Prompt-Struktur)
|
|
- **Phase 5**: Dataclasses einführen und `**kwargs` schrittweise ersetzen
|
|
|
|
---
|
|
|
|
### 5. Prompt-Builder-Aufruf-Mechanismus
|
|
|
|
**Zentrale Aufruf-Stelle**: `subAiCallLooping.py` Zeile 112-124
|
|
|
|
**Aktueller Aufruf-Mechanismus**:
|
|
```python
|
|
# In subAiCallLooping.py (Zeile 112-124):
|
|
if (len(allSections) > 0 or lastRawResponse) and promptBuilder and promptArgs:
|
|
# Build continuation context
|
|
continuationContext = buildContinuationContext(allSections, lastRawResponse, useCaseId)
|
|
|
|
# Ensure services is available in promptArgs
|
|
if not promptArgs.get('services') and hasattr(self, 'services'):
|
|
promptArgs['services'] = self.services
|
|
|
|
# Call prompt builder with continuationContext and **kwargs
|
|
iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs)
|
|
else:
|
|
# First iteration - use original prompt
|
|
iterationPrompt = prompt
|
|
```
|
|
|
|
**Aufruf-Beispiele für verschiedene Use Cases**:
|
|
|
|
#### 1. `section_content` Use Case
|
|
|
|
**Aufruf-Stelle**: `subStructureFilling.py` (3 Instanzen: Zeilen ~850, ~1100, ~1461)
|
|
|
|
**Aktueller Aufruf**:
|
|
```python
|
|
# In _generateSectionContent() oder ähnlicher Methode:
|
|
generationPrompt, templateStructure = self._buildSectionGenerationPrompt(
|
|
section=section,
|
|
contentParts=contentParts,
|
|
userPrompt=userPrompt,
|
|
generationHint=generationHint,
|
|
allSections=allSections,
|
|
sectionIndex=sectionIndex,
|
|
isAggregation=isAggregation,
|
|
language=language
|
|
)
|
|
|
|
# Nested function definieren (wird später als promptBuilder übergeben)
|
|
async def buildSectionPromptWithContinuation(
|
|
continuationContext: Dict[str, Any],
|
|
**kwargs
|
|
) -> str:
|
|
# Extrahiert Parameter aus kwargs:
|
|
section = kwargs.get("section")
|
|
contentParts = kwargs.get("contentParts", [])
|
|
userPrompt = kwargs.get("userPrompt", "")
|
|
generationHint = kwargs.get("generationHint", "")
|
|
allSections = kwargs.get("allSections", [])
|
|
sectionIndex = kwargs.get("sectionIndex", 0)
|
|
isAggregation = kwargs.get("isAggregation", False)
|
|
# ... baut Continuation-Prompt
|
|
return continuationPrompt
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
aiResponse = await self.aiService.callAiWithLooping(
|
|
prompt=generationPrompt,
|
|
options=options,
|
|
promptBuilder=buildSectionPromptWithContinuation, # Nested function
|
|
promptArgs={
|
|
"section": section,
|
|
"contentParts": contentParts,
|
|
"userPrompt": userPrompt,
|
|
"generationHint": generationHint,
|
|
"allSections": allSections,
|
|
"sectionIndex": sectionIndex,
|
|
"isAggregation": isAggregation,
|
|
"services": self.services
|
|
},
|
|
useCaseId="section_content",
|
|
debugPrefix=f"{chapterId}_section_{sectionId}",
|
|
contentParts=contentParts
|
|
)
|
|
```
|
|
|
|
**Ziel-Aufruf (nach Migration)**:
|
|
```python
|
|
# In _generateSectionContent():
|
|
generationPrompt, templateStructure = self._buildSectionGenerationPrompt(...)
|
|
|
|
# Prompt-Builder als Klassenmethode (konsolidiert):
|
|
# (wird als self.buildSectionPromptWithContinuation definiert)
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
aiResponse = await self.aiService.callAiWithLooping(
|
|
prompt=generationPrompt,
|
|
options=options,
|
|
promptBuilder=self.buildSectionPromptWithContinuation, # Klassenmethode
|
|
promptArgs={
|
|
"section": section,
|
|
"contentParts": contentParts,
|
|
"userPrompt": userPrompt,
|
|
"generationHint": generationHint,
|
|
"allSections": allSections,
|
|
"sectionIndex": sectionIndex,
|
|
"isAggregation": isAggregation,
|
|
"services": self.services,
|
|
"templateStructure": templateStructure, # NEU: Explizit hinzugefügt
|
|
"basePrompt": generationPrompt # NEU: Explizit hinzugefügt
|
|
},
|
|
useCaseId="section_content",
|
|
debugPrefix=f"{chapterId}_section_{sectionId}",
|
|
contentParts=contentParts
|
|
)
|
|
|
|
# In subAiCallLooping.py (nach Migration):
|
|
templateStructure = promptArgs.get("templateStructure")
|
|
basePrompt = prompt # Initialer Prompt
|
|
continuationContext = buildContinuationContext(
|
|
allSections, lastRawResponse, useCaseId, templateStructure
|
|
)
|
|
|
|
# Dataclass erstellen (use-case-spezifisch):
|
|
sectionArgs = SectionPromptArgs(
|
|
section=promptArgs["section"],
|
|
contentParts=promptArgs["contentParts"],
|
|
userPrompt=promptArgs["userPrompt"],
|
|
generationHint=promptArgs["generationHint"],
|
|
allSections=promptArgs["allSections"],
|
|
sectionIndex=promptArgs["sectionIndex"],
|
|
isAggregation=promptArgs["isAggregation"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
promptArgs=sectionArgs # Dataclass statt **kwargs
|
|
)
|
|
```
|
|
|
|
#### 2. `chapter_structure` Use Case
|
|
|
|
**Aufruf-Stelle**: `subStructureGeneration.py` Zeile 162-176
|
|
|
|
**Aktueller Aufruf**:
|
|
```python
|
|
# In _generateChapterStructure():
|
|
structurePrompt = self._buildChapterStructurePrompt(
|
|
userPrompt=userPrompt,
|
|
contentParts=contentParts,
|
|
outputFormat=outputFormat
|
|
)
|
|
|
|
# Nested function definieren:
|
|
async def buildChapterStructurePromptWithContinuation(
|
|
continuationContext: Optional[Dict[str, Any]] = None,
|
|
**kwargs
|
|
) -> str:
|
|
userPrompt = kwargs.get("userPrompt", "")
|
|
contentParts = kwargs.get("contentParts", [])
|
|
outputFormat = kwargs.get("outputFormat", "txt")
|
|
# ... baut Continuation-Prompt
|
|
return continuationPrompt or basePrompt
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
aiResponseJson = await self.aiService.callAiWithLooping(
|
|
prompt=structurePrompt,
|
|
options=options,
|
|
promptBuilder=buildChapterStructurePromptWithContinuation,
|
|
promptArgs={
|
|
"userPrompt": userPrompt,
|
|
"outputFormat": outputFormat,
|
|
"services": self.services
|
|
# HINWEIS: contentParts wird NICHT übergeben (nur Metadata im Prompt)
|
|
},
|
|
useCaseId="chapter_structure",
|
|
debugPrefix="chapter_structure_generation",
|
|
contentParts=None # Explizit None - nur Metadata benötigt
|
|
)
|
|
```
|
|
|
|
**Ziel-Aufruf (nach Migration)**:
|
|
```python
|
|
# In _generateChapterStructure():
|
|
structurePrompt, templateStructure = self._buildChapterStructurePrompt(...)
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
aiResponseJson = await self.aiService.callAiWithLooping(
|
|
prompt=structurePrompt,
|
|
options=options,
|
|
promptBuilder=self.buildChapterStructurePromptWithContinuation, # Klassenmethode
|
|
promptArgs={
|
|
"userPrompt": userPrompt,
|
|
"outputFormat": outputFormat,
|
|
"services": self.services,
|
|
"templateStructure": templateStructure, # NEU
|
|
"basePrompt": structurePrompt # NEU
|
|
},
|
|
useCaseId="chapter_structure",
|
|
debugPrefix="chapter_structure_generation",
|
|
contentParts=None
|
|
)
|
|
|
|
# In subAiCallLooping.py (nach Migration):
|
|
chapterArgs = ChapterStructurePromptArgs(
|
|
userPrompt=promptArgs["userPrompt"],
|
|
contentParts=promptArgs.get("contentParts", []),
|
|
outputFormat=promptArgs["outputFormat"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
promptArgs=chapterArgs # Dataclass
|
|
)
|
|
```
|
|
|
|
#### 3. `code_content` Use Case
|
|
|
|
**Aufruf-Stelle**: `codePath.py` Zeile 812-830
|
|
|
|
**Aktueller Aufruf**:
|
|
```python
|
|
# In _generateCodeContent() -> generateFileContent():
|
|
contentPrompt = f"""# TASK: Generate Code File Content
|
|
...
|
|
Return ONLY valid JSON in this format:
|
|
{{
|
|
"files": [
|
|
{{
|
|
"filename": "{filename}",
|
|
"content": "// Complete code here",
|
|
...
|
|
}}
|
|
]
|
|
}}
|
|
"""
|
|
|
|
# Nested function definieren:
|
|
async def buildCodeContentPromptWithContinuation(
|
|
continuationContext: Optional[Dict[str, Any]] = None,
|
|
**kwargs
|
|
) -> str:
|
|
filename = kwargs.get("filename", "")
|
|
fileType = kwargs.get("fileType", "")
|
|
functions = kwargs.get("functions", [])
|
|
classes = kwargs.get("classes", [])
|
|
dependencies = kwargs.get("dependencies", [])
|
|
metadata = kwargs.get("metadata", {})
|
|
userPrompt = kwargs.get("userPrompt", "")
|
|
contentParts = kwargs.get("contentParts", [])
|
|
contextInfo = kwargs.get("contextInfo", "")
|
|
# ... baut Continuation-Prompt
|
|
return continuationPrompt or basePrompt
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
contentJson = await self.services.ai.callAiWithLooping(
|
|
prompt=contentPrompt,
|
|
options=options,
|
|
promptBuilder=buildCodeContentPromptWithContinuation,
|
|
promptArgs={
|
|
"filename": filename,
|
|
"fileType": fileType,
|
|
"functions": functions,
|
|
"classes": classes,
|
|
"dependencies": dependencies,
|
|
"metadata": metadata,
|
|
"userPrompt": userPrompt,
|
|
"contentParts": contentParts,
|
|
"contextInfo": contextInfo,
|
|
"services": self.services
|
|
},
|
|
useCaseId="code_content",
|
|
debugPrefix=f"code_content_{fileStructure.get('id', 'file')}",
|
|
)
|
|
```
|
|
|
|
**Ziel-Aufruf (nach Migration)**:
|
|
```python
|
|
# In generateFileContent():
|
|
contentPrompt, templateStructure = self._buildCodeContentPrompt(...)
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
contentJson = await self.services.ai.callAiWithLooping(
|
|
prompt=contentPrompt,
|
|
options=options,
|
|
promptBuilder=self.buildCodeContentPromptWithContinuation, # Klassenmethode
|
|
promptArgs={
|
|
"filename": filename,
|
|
"fileType": fileType,
|
|
"functions": functions,
|
|
"classes": classes,
|
|
"dependencies": dependencies,
|
|
"metadata": metadata,
|
|
"userPrompt": userPrompt,
|
|
"contentParts": contentParts,
|
|
"contextInfo": contextInfo,
|
|
"services": self.services,
|
|
"templateStructure": templateStructure, # NEU
|
|
"basePrompt": contentPrompt # NEU
|
|
},
|
|
useCaseId="code_content",
|
|
debugPrefix=f"code_content_{fileStructure.get('id', 'file')}",
|
|
)
|
|
|
|
# In subAiCallLooping.py (nach Migration):
|
|
codeContentArgs = CodeContentPromptArgs(
|
|
filename=promptArgs["filename"],
|
|
fileType=promptArgs["fileType"],
|
|
functions=promptArgs["functions"],
|
|
classes=promptArgs["classes"],
|
|
dependencies=promptArgs["dependencies"],
|
|
metadata=promptArgs["metadata"],
|
|
userPrompt=promptArgs["userPrompt"],
|
|
contentParts=promptArgs["contentParts"],
|
|
contextInfo=promptArgs["contextInfo"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
promptArgs=codeContentArgs # Dataclass
|
|
)
|
|
```
|
|
|
|
#### 4. `code_structure` Use Case
|
|
|
|
**Aufruf-Stelle**: `codePath.py` Zeile 311-317
|
|
|
|
**Aktueller Aufruf** (OHNE Prompt-Builder - noch nicht implementiert):
|
|
```python
|
|
# In _generateCodeStructure():
|
|
structureJson = await self.services.ai.callAiWithLooping(
|
|
prompt=structurePrompt,
|
|
options=options,
|
|
useCaseId="code_structure",
|
|
debugPrefix="code_structure_generation",
|
|
contentParts=contentParts
|
|
# KEIN promptBuilder - noch nicht implementiert!
|
|
)
|
|
```
|
|
|
|
**Ziel-Aufruf (nach Implementierung)**:
|
|
```python
|
|
# In _generateCodeStructure():
|
|
structurePrompt, templateStructure = self._buildCodeStructurePrompt(...)
|
|
|
|
# Aufruf von callAiWithLooping:
|
|
structureJson = await self.services.ai.callAiWithLooping(
|
|
prompt=structurePrompt,
|
|
options=options,
|
|
promptBuilder=self.buildCodeStructurePromptWithContinuation, # NEU: Implementieren
|
|
promptArgs={
|
|
"userPrompt": userPrompt,
|
|
"contentParts": contentParts,
|
|
"services": self.services,
|
|
"templateStructure": templateStructure, # NEU
|
|
"basePrompt": structurePrompt # NEU
|
|
},
|
|
useCaseId="code_structure",
|
|
debugPrefix="code_structure_generation",
|
|
contentParts=contentParts
|
|
)
|
|
|
|
# In subAiCallLooping.py (nach Migration):
|
|
codeStructureArgs = CodeStructurePromptArgs(
|
|
userPrompt=promptArgs["userPrompt"],
|
|
contentParts=promptArgs["contentParts"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
promptArgs=codeStructureArgs # Dataclass
|
|
)
|
|
```
|
|
|
|
**Zusammenfassung der Aufruf-Mechanismen**:
|
|
|
|
| Use Case | Aktueller Aufruf | Ziel-Aufruf | Status |
|
|
|----------|------------------|-------------|--------|
|
|
| `section_content` | ✅ Mit `promptBuilder` (nested function, 3 Instanzen) | ✅ Klassenmethode, Dataclass `SectionPromptArgs` | ⏳ Migration erforderlich |
|
|
| `chapter_structure` | ✅ Mit `promptBuilder` (nested function) | ✅ Klassenmethode, Dataclass `ChapterStructurePromptArgs` | ⏳ Migration erforderlich |
|
|
| `code_content` | ✅ Mit `promptBuilder` (nested function) | ✅ Klassenmethode, Dataclass `CodeContentPromptArgs` | ⏳ Migration erforderlich |
|
|
| `code_structure` | ❌ OHNE `promptBuilder` | ✅ Klassenmethode, Dataclass `CodeStructurePromptArgs` | ⏳ Implementierung erforderlich |
|
|
|
|
**Wichtige Punkte**:
|
|
1. **Zentrale Aufruf-Stelle**: Alle Prompt-Builder werden zentral in `subAiCallLooping.py` Zeile 112-124 aufgerufen
|
|
2. **Parameter-Übergabe**: Aktuell via `**kwargs` in `promptArgs` Dict, zukünftig via Dataclasses
|
|
3. **Template-Struktur**: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben
|
|
4. **BasePrompt**: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben
|
|
5. **Konsolidierung**: `section_content` hat 3 identische Instanzen → 1 konsolidierte Klassenmethode
|
|
|
|
**Parameter-Mapping für explizite Signatures mit Dataclasses**:
|
|
|
|
| Prompt-Builder | Aktuelle Parameter (aus `**kwargs`) | Dataclass | Ziel-Signature (einheitlich) |
|
|
|----------------|--------------------------------------|-----------|------------------------------|
|
|
| `buildSectionPromptWithContinuation()` | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` | `SectionPromptArgs` | `async def buildSectionPromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: SectionPromptArgs) -> str` |
|
|
| `buildChapterStructurePromptWithContinuation()` | `userPrompt`, `contentParts`, `outputFormat`, `services` | `ChapterStructurePromptArgs` | `async def buildChapterStructurePromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: ChapterStructurePromptArgs) -> str` |
|
|
| `buildCodeContentPromptWithContinuation()` | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` | `CodeContentPromptArgs` | `async def buildCodeContentPromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: CodeContentPromptArgs) -> str` |
|
|
| `buildCodeStructurePromptWithContinuation()` | ❌ **FEHLT** | `CodeStructurePromptArgs` | `async def buildCodeStructurePromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: CodeStructurePromptArgs) -> str` |
|
|
|
|
**Vollständige Dataclass-Definitionen**:
|
|
```python
|
|
@dataclass
|
|
class SectionPromptArgs:
|
|
"""Type-safe arguments for section content prompt builder."""
|
|
section: Dict[str, Any]
|
|
contentParts: List[ContentPart]
|
|
userPrompt: str
|
|
generationHint: str
|
|
allSections: List[Dict[str, Any]]
|
|
sectionIndex: int
|
|
isAggregation: bool
|
|
services: Any
|
|
|
|
@dataclass
|
|
class ChapterStructurePromptArgs:
|
|
"""Type-safe arguments for chapter structure prompt builder."""
|
|
userPrompt: str
|
|
contentParts: List[ContentPart]
|
|
outputFormat: str
|
|
services: Any
|
|
|
|
@dataclass
|
|
class CodeContentPromptArgs:
|
|
"""Type-safe arguments for code content prompt builder."""
|
|
filename: str
|
|
fileType: str
|
|
functions: List[Dict]
|
|
classes: List[Dict]
|
|
dependencies: List[str]
|
|
metadata: Dict[str, Any]
|
|
userPrompt: str
|
|
contentParts: List[ContentPart]
|
|
contextInfo: str
|
|
services: Any
|
|
|
|
@dataclass
|
|
class CodeStructurePromptArgs:
|
|
"""Type-safe arguments for code structure prompt builder."""
|
|
userPrompt: str
|
|
contentParts: List[ContentPart]
|
|
services: Any
|
|
```
|
|
|
|
**Prompt-Builder Locations und Konsolidierung**:
|
|
|
|
| Prompt-Builder | Location | Anzahl | Typ | Konsolidierung |
|
|
|----------------|----------|--------|-----|----------------|
|
|
| `buildSectionPromptWithContinuation` | `subStructureFilling.py` | 3 Instanzen | Nested functions (Zeilen 814, 1100, 1461) | ✅ 3 → 1 (als Klassenmethode in `StructureFiller`) |
|
|
| `buildChapterStructurePromptWithContinuation` | `subStructureGeneration.py` | 1 Instanz | Nested function (Zeile 111) | ✅ Als Klassenmethode in `StructureGenerator` |
|
|
| `buildCodeContentPromptWithContinuation` | `codePath.py` | 1 Instanz | Nested function (Zeile 683) | ✅ Als Klassenmethode in `CodeGenerationPath` |
|
|
| `buildCodeStructurePromptWithContinuation` | ❌ **FEHLT** | 0 | - | ✅ Als Klassenmethode in `CodeGenerationPath` (neu erstellen) |
|
|
|
|
**Architektur-Entscheidung**:
|
|
- **NICHT** in eine zentrale Klasse verschieben (zu enge Kopplung)
|
|
- **ABER**: Konsolidierung innerhalb der jeweiligen Klassen
|
|
- **Vorteil**: Modulare Struktur, keine enge Kopplung, einfache Wartung
|
|
|
|
**Aufruf-Mechanismus**:
|
|
- Alle Builder werden in `subAiCallLooping.py` Zeile 124 aufgerufen
|
|
- Einheitliche Signatur ermöglicht einheitlichen Aufruf ohne use-case-spezifische Logik
|
|
- Nach Migration: `await promptBuilder(continuationContext=..., templateStructure=..., basePrompt=..., promptArgs=dataclassInstance)`
|
|
|
|
---
|
|
|
|
### 3. Template-Struktur-Parameter
|
|
|
|
**⚠️ KRITISCH: Template-Struktur ist ein expliziter Parameter**
|
|
|
|
**WICHTIG**:
|
|
- **Template-Struktur wird NICHT aus dem initialen Prompt extrahiert**
|
|
- **Template-Struktur wird NICHT aus dem Response extrahiert**
|
|
- **Template-Struktur ist ein expliziter Parameter**, der beim Erstellen des initialen Prompts **erstellt** wird
|
|
- **Derselbe Template-Struktur-Parameter** wird dann für den Continuation-Prompt verwendet
|
|
- Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt
|
|
|
|
**Ziel-Architektur**:
|
|
- **Template wird beim Erstellen des initialen Prompts als expliziter Parameter erstellt**
|
|
- **Template wird in `promptArgs` gespeichert** beim Aufruf von `callAiWithLooping()`
|
|
- **Template wird aus `promptArgs` extrahiert** und an `buildContinuationContext()` und `promptBuilder` übergeben
|
|
- **Keine Extraktion aus Prompt-String** - Template ist ein expliziter Parameter, garantiert identisch
|
|
|
|
**Beispiel-Implementierung**:
|
|
```python
|
|
# Beim Erstellen des initialen Prompts:
|
|
def _buildSectionGenerationPrompt(
|
|
self,
|
|
section: Dict[str, Any],
|
|
contentParts: List[ContentPart],
|
|
userPrompt: str,
|
|
generationHint: str,
|
|
allSections: List[Dict[str, Any]],
|
|
sectionIndex: int,
|
|
isAggregation: bool,
|
|
language: str
|
|
) -> tuple[str, str]: # Gibt (prompt, templateStructure) zurück
|
|
"""Build section generation prompt and return prompt + template structure.
|
|
|
|
WICHTIG: templateStructure wird hier ERSTELLT (nicht extrahiert) und als separater
|
|
Parameter zurückgegeben. Derselbe Parameter wird dann für den Continuation-Prompt verwendet.
|
|
"""
|
|
|
|
contentType = section.get("content_type", "paragraph")
|
|
contentStructureExample = self._getContentStructureExample(contentType)
|
|
|
|
# Template-Struktur explizit ERSTELLEN (nicht extrahieren!)
|
|
# Dies ist der Parameter, der später für den Continuation-Prompt verwendet wird
|
|
templateStructure = f"""{{
|
|
"elements": [
|
|
{{
|
|
"type": "{contentType}",
|
|
"content": {contentStructureExample}
|
|
}}
|
|
]
|
|
}}"""
|
|
|
|
# Prompt mit Template erstellen (Template wird hier eingebettet)
|
|
prompt = f"""...
|
|
Return ONLY valid JSON in this format:
|
|
{templateStructure}
|
|
..."""
|
|
|
|
# WICHTIG: Beide zurückgeben - prompt UND templateStructure als separater Parameter
|
|
return prompt, templateStructure # templateStructure wird NICHT aus prompt extrahiert!
|
|
|
|
# Beim Aufruf von callAiWithLooping:
|
|
prompt, templateStructure = self._buildSectionGenerationPrompt(...)
|
|
promptArgs["templateStructure"] = templateStructure # In promptArgs speichern
|
|
promptArgs["basePrompt"] = prompt # BasePrompt auch speichern
|
|
|
|
# Später im Continuation-Prompt:
|
|
templateStructure = promptArgs.get("templateStructure") # Aus promptArgs holen
|
|
basePrompt = promptArgs.get("basePrompt") # BasePrompt aus promptArgs holen
|
|
continuationContext = buildContinuationContext(
|
|
allSections, lastRawResponse, useCaseId, templateStructure
|
|
)
|
|
|
|
# Dataclass erstellen (nach Migration):
|
|
sectionArgs = SectionPromptArgs(
|
|
section=promptArgs["section"],
|
|
contentParts=promptArgs["contentParts"],
|
|
userPrompt=promptArgs["userPrompt"],
|
|
generationHint=promptArgs["generationHint"],
|
|
allSections=promptArgs["allSections"],
|
|
sectionIndex=promptArgs["sectionIndex"],
|
|
isAggregation=promptArgs["isAggregation"],
|
|
services=promptArgs["services"]
|
|
)
|
|
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure, # Derselbe Parameter wie im initialen Prompt
|
|
basePrompt=basePrompt, # Derselbe Prompt wie initial
|
|
promptArgs=sectionArgs # Dataclass statt **kwargs
|
|
)
|
|
```
|
|
|
|
**Vorteil**:
|
|
- ✅ Garantierte Identität: Initialer und Continuation-Prompt verwenden exakt denselben Template-Parameter
|
|
- ✅ Keine Extraktion nötig: Template wird nicht aus Prompt-String geparst
|
|
- ✅ Einfacher: Template wird einmal erstellt und wiederverwendet
|
|
|
|
**Erforderliche Änderungen**:
|
|
1. **Alle Prompt-Erstellungs-Funktionen anpassen**:
|
|
- Template-Struktur **explizit erstellen** (nicht extrahieren!)
|
|
- Template-Struktur als separater Rückgabewert zurückgeben: `(prompt, templateStructure)`
|
|
- Template-Struktur in `promptArgs` speichern beim Aufruf von `callAiWithLooping()`
|
|
2. **In `callAiWithLooping()`**:
|
|
- `templateStructure` aus `promptArgs` holen (REQUIRED - Fehler wenn fehlt)
|
|
- `basePrompt` aus `prompt` Parameter holen (ist der initiale Prompt)
|
|
- Beide an `buildContinuationContext()` und `promptBuilder` übergeben
|
|
3. **Alle Prompt-Builder anpassen**:
|
|
- `templateStructure` als expliziten Parameter akzeptieren (nicht extrahieren!)
|
|
- `basePrompt` als expliziten Parameter akzeptieren (nicht regenerieren!)
|
|
- Template und BasePrompt direkt verwenden (garantiert identisch mit initialem Prompt)
|
|
|
|
---
|
|
|
|
### 4. Konsolidierung: 3 Instanzen → 1 Funktion
|
|
|
|
**Aktueller Zustand**:
|
|
- 3 identische Instanzen von `buildSectionPromptWithContinuation()` in `subStructureFilling.py`
|
|
- Unterschiede nur in `promptArgs` (z.B. `contentParts` manchmal leer, manchmal gefüllt)
|
|
|
|
**Ziel-Architektur**:
|
|
```python
|
|
class StructureFiller:
|
|
"""Handles structure filling for document generation."""
|
|
|
|
async def buildSectionPromptWithContinuation(
|
|
self,
|
|
continuationContext: Dict[str, Any],
|
|
templateStructure: str, # NEU: Expliziter Parameter
|
|
section: Dict[str, Any],
|
|
contentParts: List[ContentPart],
|
|
userPrompt: str,
|
|
generationHint: str,
|
|
allSections: List[Dict[str, Any]],
|
|
sectionIndex: int,
|
|
isAggregation: bool,
|
|
language: str
|
|
) -> str:
|
|
"""
|
|
Build section prompt with continuation context.
|
|
|
|
Single unified implementation for all section content generation contexts.
|
|
"""
|
|
# Build base prompt
|
|
basePrompt = self._buildSectionGenerationPrompt(
|
|
section=section,
|
|
contentParts=contentParts,
|
|
userPrompt=userPrompt,
|
|
generationHint=generationHint,
|
|
allSections=allSections,
|
|
sectionIndex=sectionIndex,
|
|
isAggregation=isAggregation,
|
|
language=language
|
|
)
|
|
|
|
# Use provided templateStructure (from initial prompt)
|
|
# This ensures exact match between initial and continuation prompts
|
|
structureTemplate = f"""JSON Structure Template:
|
|
{templateStructure}
|
|
|
|
"""
|
|
|
|
# Build continuation prompt with template and context
|
|
...
|
|
```
|
|
|
|
**Erforderliche Änderungen**:
|
|
1. Eine einzige Methode `buildSectionPromptWithContinuation()` in `StructureFiller` Klasse definieren
|
|
2. Alle 3 nested functions entfernen
|
|
3. Alle Aufrufe anpassen, um die neue Methode zu verwenden
|
|
|
|
---
|
|
|
|
## Zusammenfassung: Erforderliche Code-Änderungen
|
|
|
|
### Priorität 1: Template-Struktur-Konsistenz (KRITISCH)
|
|
|
|
1. **`ContinuationContext` Pydantic-Modell erstellen** (`jsonUtils.py` oder separate Model-Datei):
|
|
- Alle Felder definieren: `section_count`, `delivered_summary`, `cut_off_element`, `element_before_cutoff`, `template_structure`, `last_complete_part`, `incomplete_part`, `structure_context`, `last_raw_json`
|
|
- Optional-Felder korrekt markieren
|
|
|
|
2. **`buildContinuationContext()` erweitern** (`jsonUtils.py`):
|
|
- Parameter `templateStructure: Optional[str]` hinzufügen
|
|
- Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext`
|
|
- `ContinuationContext`-Instanz erstellen und zurückgeben statt Dict
|
|
|
|
3. **Prompt-Erstellungs-Funktionen anpassen** (z.B. `_buildSectionGenerationPrompt()`, `_buildChapterStructurePrompt()`, etc.):
|
|
- Template-Struktur explizit erstellen (nicht extrahieren)
|
|
- Template-Struktur in `promptArgs` speichern beim Erstellen des initialen Prompts
|
|
- Template-Struktur als Teil des Prompts einbetten
|
|
|
|
4. **Alle Verwendungen von `continuationContext` anpassen**:
|
|
- **Prompt-Builder** (`subStructureFilling.py`, `subStructureGeneration.py`, `codePath.py`, etc.):
|
|
- `continuationContext.get("delivered_summary")` → `continuationContext.delivered_summary`
|
|
- `continuationContext.get("cut_off_element")` → `continuationContext.cut_off_element`
|
|
- `continuationContext.get("element_before_cutoff")` → `continuationContext.element_before_cutoff`
|
|
- `continuationContext.get("template_structure")` → `continuationContext.template_structure`
|
|
- `continuationContext.get("last_complete_part")` → `continuationContext.last_complete_part`
|
|
- `continuationContext.get("incomplete_part")` → `continuationContext.incomplete_part`
|
|
- `continuationContext.get("structure_context")` → `continuationContext.structure_context`
|
|
- `continuationContext.get("last_raw_json")` → `continuationContext.last_raw_json`
|
|
- **Andere Verwendungen** (`subPromptBuilderGeneration.py`, etc.):
|
|
- Alle Dict-Zugriffe auf Attribut-Zugriffe umstellen
|
|
|
|
5. **`callAiWithLooping()` anpassen** (`subAiCallLooping.py`):
|
|
- **Parameter-Validierung**: `templateStructure` und `basePrompt` aus `promptArgs` holen (REQUIRED - Fehler wenn fehlt)
|
|
- **Error Handling**: `ValueError` werfen wenn `templateStructure` oder `basePrompt` fehlen
|
|
- `templateStructure` an `buildContinuationContext()` übergeben
|
|
- `basePrompt` aus `prompt` Parameter holen (ist der initiale Prompt)
|
|
- `continuationContext` (Pydantic-Modell) an `promptBuilder` übergeben
|
|
- `templateStructure` und `basePrompt` an `promptBuilder` übergeben
|
|
|
|
### Priorität 2: Prompt-Builder-Harmonisierung
|
|
|
|
4. **`buildSectionPromptWithContinuation()` konsolidieren** (`subStructureFilling.py`):
|
|
- 3 Instanzen zu einer Methode zusammenführen
|
|
- Als Klassenmethode definieren (nicht nested)
|
|
|
|
5. **Alle Prompt-Builder erweitern**:
|
|
- `templateStructure` als expliziten Parameter hinzufügen
|
|
- Template aus Parameter verwenden (nicht aus `continuationContext` extrahieren)
|
|
|
|
### Priorität 3: Typsicherheit (Optional, aber empfohlen)
|
|
|
|
6. **Typsichere Parameter einführen**:
|
|
- Dataclasses für Parameter-Strukturen erstellen
|
|
- `**kwargs` durch explizite Parameter ersetzen
|
|
|
|
---
|
|
|
|
## Use Cases im Detail
|
|
|
|
**Hinweis zu JSON-Template-Strukturen**:
|
|
Die **JSON-Template-Struktur im Prompt** ist die Struktur, die der AI im initialen Prompt als Vorlage gegeben wird. Diese Struktur wird auch im Continuation-Prompt verwendet, um Konsistenz zu gewährleisten. Die Template-Struktur zeigt der AI, welches JSON-Format erwartet wird.
|
|
|
|
---
|
|
|
|
### 1. `section_content` ✅
|
|
|
|
**JSON-Template-Struktur im Prompt**:
|
|
```json
|
|
{
|
|
"elements": [
|
|
{
|
|
"type": "{contentType}",
|
|
"content": {contentStructureExample}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Template-Quelle**: `_getContentStructureExample(contentType)` - dynamisch je nach `contentType`:
|
|
- `table`: `{"headers": ["Column1", "Column2"], "rows": [["Value1", "Value2"], ["Value3", "Value4"]]}`
|
|
- `bullet_list`: `{"items": ["Item 1", "Item 2", "Item 3"]}`
|
|
- `heading`: `{"text": "Section Title", "level": 2}`
|
|
- `paragraph`: `{"text": "This is paragraph text."}`
|
|
- `code_block`: `{"code": "function example() { return true; }", "language": "javascript"}`
|
|
- `image`: `{"base64Data": "<base64_encoded_image_data>", "altText": "Description", "caption": "Optional caption"}`
|
|
|
|
**Prompt-Location**: `subStructureFilling.py` Zeile 2338-2348 ("## OUTPUT FORMAT")
|
|
|
|
**Looping-Mechanismus**:
|
|
- ✅ **In `loopingUseCases` Liste**: Ja
|
|
- ✅ **In `directReturnUseCases` Liste**: Ja
|
|
- ✅ **Unterstützt Iterationen**: Ja
|
|
- ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`)
|
|
- ✅ **Requires Extraction**: Nein (`requiresExtraction=False`)
|
|
|
|
**Prompt-Builder**:
|
|
- **Spezifisch**: `buildSectionPromptWithContinuation()` (3 Instanzen → **SOLLTE konsolidiert werden**)
|
|
- **Parameter**: Alle `promptArgs` werden übergeben
|
|
- **Location**: `subStructureFilling.py` (nested functions → **SOLLTE Klassenmethode werden**)
|
|
|
|
**Merging-Strategie**:
|
|
- String-basiertes Merging mit Overlap-Detection
|
|
- Fallback auf Deep-Structure-Merging bei Parsing-Fehlern
|
|
- Normalisierung: Konvertiert Listen von Strings zu `paragraph` Elementen
|
|
|
|
**Besonderheiten**:
|
|
- Verwendet spezifischen Prompt-Builder (`buildSectionPromptWithContinuation`)
|
|
- JSON-Struktur-Template kommt aus initialem Prompt (`_getContentStructureExample()`)
|
|
- **PROBLEM**: 3 verschiedene Implementierungen des Prompt-Builders (je nach Kontext)
|
|
- **Template-Struktur-Quelle**: ✅ **KORREKT** - Kommt aus initialem Prompt, nicht aus Response-Extraktion
|
|
|
|
**Template-Struktur-Quelle Analyse**:
|
|
- ✅ **`section_content`**: Template kommt aus initialem Prompt via `_getContentStructureExample(contentType)`
|
|
- ✅ **Template wird dynamisch generiert** basierend auf `contentType` (z.B. `table`, `paragraph`, etc.)
|
|
- ✅ **Template wird im Continuation-Prompt exakt wiederholt** (gleiche Logik wie im initialen Prompt)
|
|
- ✅ **Keine Extraktion aus Response** - Template wird als Parameter übergeben (Ziel-Architektur)
|
|
|
|
**✅ Template-Konsistenz geprüft**:
|
|
- **Initial**: `subStructureFilling.py` Zeile 2342-2349 ("## OUTPUT FORMAT")
|
|
- **Continuation**: `subStructureFilling.py` Zeile 877-887 ("JSON Structure Template")
|
|
- **Status**: ✅ **IDENTISCH** - Beide verwenden `contentType = section.get("content_type", "paragraph")` und `contentStructureExample = self._getContentStructureExample(contentType)`
|
|
|
|
---
|
|
|
|
### 2. `chapter_structure` ✅
|
|
|
|
**JSON-Template-Struktur im Prompt**:
|
|
```json
|
|
{
|
|
"metadata": {
|
|
"title": "...",
|
|
"language": "..."
|
|
},
|
|
"documents": [{
|
|
"id": "doc_1",
|
|
"title": "...",
|
|
"filename": "...",
|
|
"outputFormat": "...",
|
|
"language": "...",
|
|
"chapters": [
|
|
{
|
|
"id": "chapter_1",
|
|
"level": 1,
|
|
"title": "...",
|
|
"contentParts": {},
|
|
"generationHint": "...",
|
|
"sections": []
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
```
|
|
|
|
**Template-Quelle**: Im initialen Prompt bei "EXAMPLE STRUCTURE" (Zeile 418-445 in `subStructureGeneration.py`)
|
|
|
|
**Prompt-Location**: `subStructureGeneration.py` Zeile 418-445 ("EXAMPLE STRUCTURE")
|
|
|
|
**Looping-Mechanismus**:
|
|
- ✅ **In `loopingUseCases` Liste**: Ja
|
|
- ✅ **In `directReturnUseCases` Liste**: Ja
|
|
- ✅ **Unterstützt Iterationen**: Ja
|
|
- ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`)
|
|
- ✅ **Requires Extraction**: Nein (`requiresExtraction=False`)
|
|
|
|
**Prompt-Builder**:
|
|
- **Spezifisch**: `buildChapterStructurePromptWithContinuation()` (nested function in `subStructureGeneration.py`)
|
|
- **Parameter**: Alle `promptArgs` werden übergeben (`userPrompt`, `contentParts`, `outputFormat`, `services`)
|
|
- **Location**: `subStructureGeneration.py` (nested function)
|
|
|
|
**Merging-Strategie**:
|
|
- String-basiertes Merging mit Overlap-Detection
|
|
- Fallback auf Deep-Structure-Merging bei Parsing-Fehlern
|
|
- Direkter Return nach Completion
|
|
|
|
**Besonderheiten**:
|
|
- Verwendet spezifischen Prompt-Builder (`buildChapterStructurePromptWithContinuation`)
|
|
- JSON-Struktur-Template kommt aus initialem Prompt ("EXAMPLE STRUCTURE")
|
|
- Template wird im Continuation-Prompt exakt wiederholt
|
|
|
|
**✅ Template-Konsistenz geprüft**:
|
|
- **Initial**: `subStructureGeneration.py` Zeile 418-445 ("EXAMPLE STRUCTURE")
|
|
- **Continuation**: `subStructureGeneration.py` Zeile 111-155 (`buildChapterStructurePromptWithContinuation`)
|
|
- **Status**: ✅ **IDENTISCH** - Beide verwenden das gleiche Template aus `_buildChapterStructurePrompt()`
|
|
|
|
---
|
|
|
|
### 3. `code_structure` ✅
|
|
|
|
**JSON-Template-Struktur im Prompt**:
|
|
```json
|
|
{
|
|
"metadata": {
|
|
"language": "",
|
|
"projectType": "single_file|multi_file",
|
|
"projectName": ""
|
|
},
|
|
"files": [
|
|
{
|
|
"id": "",
|
|
"filename": "",
|
|
"fileType": "",
|
|
"dependencies": [],
|
|
"imports": [],
|
|
"functions": [],
|
|
"classes": []
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Template-Quelle**: Im initialen Prompt bei "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303 in `codePath.py`)
|
|
|
|
**Prompt-Location**: `codePath.py` Zeile 276-303 ("## FILE STRUCTURE REQUIREMENTS")
|
|
|
|
**Looping-Mechanismus**:
|
|
- ✅ **In `loopingUseCases` Liste**: Ja
|
|
- ✅ **In `directReturnUseCases` Liste**: Ja
|
|
- ✅ **Unterstützt Iterationen**: Ja
|
|
- ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`)
|
|
- ✅ **Requires Extraction**: Nein (`requiresExtraction=False`)
|
|
|
|
**Prompt-Builder**:
|
|
- **Status**: ❌ **FEHLT** - Kein `promptBuilder` wird übergeben
|
|
- **Problem**: Continuation-Prompts werden nicht unterstützt
|
|
|
|
**Merging-Strategie**:
|
|
- String-basiertes Merging mit Overlap-Detection
|
|
- Fallback auf Deep-Structure-Merging bei Parsing-Fehlern
|
|
- Direkter Return nach Completion
|
|
|
|
**Besonderheiten**:
|
|
- **KRITISCH**: Es gibt **KEINEN `promptBuilder`** für `code_structure`!
|
|
- Continuation-Prompts werden nicht gebaut, daher keine Iterationen möglich
|
|
|
|
**❌ Template-Konsistenz geprüft**:
|
|
- **Initial**: `codePath.py` Zeile 276-303 ("## FILE STRUCTURE REQUIREMENTS")
|
|
- **Continuation**: ❌ **FEHLT** - Kein Prompt-Builder vorhanden
|
|
- **Status**: ❌ **PROBLEM** - Es gibt **KEINEN `promptBuilder`** für `code_structure`! Continuation-Prompts werden nicht unterstützt.
|
|
- **Erforderliche Änderung**: Ein `buildCodeStructurePromptWithContinuation()` muss erstellt werden, der:
|
|
1. Das Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303) extrahiert
|
|
2. Es im Continuation-Prompt als "JSON Structure Template:" wiederholt
|
|
3. Die gleiche Struktur wie `buildChapterStructurePromptWithContinuation` verwendet
|
|
|
|
---
|
|
|
|
### 4. `code_content` ✅
|
|
|
|
**JSON-Template-Struktur im Prompt**:
|
|
```json
|
|
{
|
|
"files": [
|
|
{
|
|
"filename": "{filename}",
|
|
"content": "// Complete code here",
|
|
"functions": [],
|
|
"classes": []
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Template-Quelle**: Im initialen Prompt bei "Return ONLY valid JSON in this format:" (Zeile 668-678 in `codePath.py`)
|
|
|
|
**Prompt-Location**: `codePath.py` Zeile 643-679
|
|
|
|
**Looping-Mechanismus**:
|
|
- ✅ **In `loopingUseCases` Liste**: Ja
|
|
- ✅ **In `directReturnUseCases` Liste**: Ja
|
|
- ✅ **Unterstützt Iterationen**: Ja
|
|
- ✅ **Unterstützt Accumulation**: Ja (`supportsAccumulation=True`)
|
|
- ✅ **Requires Extraction**: Nein (`requiresExtraction=False`)
|
|
|
|
**Prompt-Builder**:
|
|
- **Spezifisch**: `buildCodeContentPromptWithContinuation()` (nested function in `codePath.py`)
|
|
- **Parameter**: Alle `promptArgs` werden übergeben (`filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services`)
|
|
- **Location**: `codePath.py` (nested function)
|
|
|
|
**Merging-Strategie**:
|
|
- String-basiertes Merging mit Overlap-Detection
|
|
- Fallback auf Deep-Structure-Merging bei Parsing-Fehlern
|
|
- Direkter Return nach Completion
|
|
|
|
**Besonderheiten**:
|
|
- Verwendet spezifischen Prompt-Builder (`buildCodeContentPromptWithContinuation`)
|
|
- JSON-Struktur-Template kommt aus initialem Prompt (Zeile 668-678)
|
|
- Template wird im Continuation-Prompt exakt wiederholt
|
|
|
|
**✅ Template-Konsistenz geprüft**:
|
|
- **Initial**: `codePath.py` Zeile 668-678 ("Return ONLY valid JSON in this format:")
|
|
- **Continuation**: `codePath.py` Zeile 668-678 (wird im `buildCodeContentPromptWithContinuation` exakt wiederholt)
|
|
- **Status**: ✅ **IDENTISCH** - Beide verwenden das gleiche Template mit den gleichen Beispielwerten
|
|
|
|
---
|
|
|
|
## Merging-Strategien
|
|
|
|
**Merging-Strategien**:
|
|
- **Primär**: String-basiertes Merging mit `mergeJsonStringsWithOverlap()`
|
|
- **Fallback**: Deep-Structure-Merging bei Parsing-Fehlern (für alle Use Cases)
|
|
- Wenn String-Merge erfolgreich, aber Parsing fehlschlägt: Versucht jedes Fragment einzeln zu parsen
|
|
- Verwendet `mergeDeepStructures()` für intelligentes Merging der geparsten Fragmente
|
|
- Funktioniert rekursiv für beliebige JSON-Strukturen (Arrays, Objekte, verschachtelt)
|
|
- **Overlap-Detection**: Multi-Strategy (exact, line-based, partial line-based, structure-aware)
|
|
|
|
---
|
|
|
|
## Continuation-Prompt-Strukturen im Detail
|
|
|
|
### Fix vs. Variabel Analyse
|
|
|
|
**Kernprinzip**: Alle Iterations-Prompts sollten nach der **gleichen Logik** aufgebaut sein, aber für verschiedene JSON-Strukturen. Die Struktur des Iterations-Prompts selbst sollte bei allen Use Cases **gleich** sein.
|
|
|
|
#### ✅ FIX (sollte bei allen Use Cases identisch sein)
|
|
|
|
| Element | Inhalt | Beschreibung |
|
|
|---------|--------|--------------|
|
|
| **Separator** | `--- CONTINUATION REQUEST ---` | Trennlinie zwischen Base Prompt und Continuation-Anweisungen |
|
|
| **Einleitung** | `The previous JSON response was incomplete. Continue from where it stopped.` | Standard-Einleitung für alle Continuation-Requests |
|
|
| **Section-Header** | `JSON Structure Template:` | Header für Template-Sektion |
|
|
| **Section-Header** | `Context showing structure hierarchy with cut point:` | Header für Context-Sektion |
|
|
| **Section-Header** | `Overlap Requirement:` | Header für Overlap-Anweisungen |
|
|
| **Overlap-Anweisung** | `To ensure proper merging, your response MUST start by repeating approximately the last 100 characters from the previous response, then continue with new content.` | Standard-Overlap-Anweisung |
|
|
| **Section-Header** | `Last ~100 characters from previous response (repeat these at the start):` | Header für Overlap-Context |
|
|
| **Section-Header** | `TASK:` | Header für Task-Anweisungen |
|
|
| **TASK Punkt 1** | `Start your response by repeating the last ~100 characters shown above (for overlap/merging)` | Overlap-Start-Anweisung |
|
|
| **TASK Punkt 2** | `Complete the incomplete element shown in the context above (marked with CUT POINT)` | Completion-Anweisung |
|
|
| **TASK Punkt 3** | `Continue generating the remaining content following the JSON structure template above` | Continuation-Anweisung |
|
|
| **TASK Punkt 4** | `Return ONLY valid JSON following the structure template - no overlap/continuation wrapper objects` | Format-Anweisung |
|
|
| **Section-Header** | `CRITICAL:` | Header für kritische Anweisungen |
|
|
| **CRITICAL Punkt 1** | `Your response must be valid JSON matching the structure template above` | JSON-Format-Anforderung |
|
|
| **CRITICAL Punkt 2** | `Start with overlap (~100 chars) then continue seamlessly` | Overlap-Seamless-Anweisung |
|
|
| **CRITICAL Punkt 3** | `Complete the incomplete element and continue with remaining elements` | Completion-Continuation-Anweisung |
|
|
|
|
#### 🔄 VARIABEL (use-case-spezifisch)
|
|
|
|
| Element | Beschreibung | Aktuelle Implementierung |
|
|
|---------|--------------|-------------------------|
|
|
| **`basePrompt`** | Initialer Prompt (use-case-spezifisch) | Wird als Parameter übergeben, variiert je nach Use Case |
|
|
| **`structureTemplate`** | JSON-Struktur-Template (use-case-spezifisch) | Wird aus initialem Prompt extrahiert oder als Parameter übergeben |
|
|
| **`unifiedContext`** | Hierarchischer Cut-Point-Context (use-case-spezifisch, aber gleiche Logik) | Wird aus `_buildIncompleteContext()` erstellt - sollte für alle Use Cases nach gleicher Logik funktionieren |
|
|
| **`overlapContext`** | Letzte ~100 Zeichen (gleiche Logik, aber unterschiedlicher Inhalt) | `lastRawJson[-100:].strip()` - gleiche Logik für alle |
|
|
|
|
**⚠️ MANDATORY: Alle Use Cases müssen die einheitliche Struktur verwenden**
|
|
|
|
**Wichtig**:
|
|
- ✅ **Fix-Elemente** MÜSSEN bei allen Use Cases **exakt identisch** sein - keine Variationen erlaubt
|
|
- 🔄 **Variable Elemente** variieren im Inhalt, aber die **Logik** zur Erstellung ist gleich
|
|
- ✅ **Alle Use Cases** (`section_content`, `chapter_structure`, `code_structure`, `code_content`) verwenden **dieselbe Continuation-Prompt-Struktur**
|
|
|
|
### Einheitliche Continuation-Prompt-Struktur (Ziel)
|
|
|
|
**⚠️ MANDATORY: Alle Use Cases MÜSSEN diese einheitliche Struktur verwenden**
|
|
|
|
**Keine Variationen erlaubt** - alle Use Cases (`section_content`, `chapter_structure`, `code_structure`, `code_content`) verwenden **exakt dieselbe Continuation-Prompt-Struktur**:
|
|
|
|
1. **Base Prompt** (initialer Prompt - unverändert, als Parameter übergeben)
|
|
2. **--- CONTINUATION REQUEST ---** (Trennlinie)
|
|
3. **JSON Structure Template:** (Header)
|
|
4. **Template-Struktur** (exakt identisch mit initialem Prompt, als Parameter übergeben)
|
|
5. **Context showing structure hierarchy with cut point:** (Header)
|
|
6. **Hierarchischer Context** (hierarchischer Cut-Point-Context)
|
|
7. **Overlap Requirement:** (Header)
|
|
8. **Overlap-Anweisung** (~100 Zeichen)
|
|
9. **Last ~100 characters from previous response (repeat these at the start):** (Header)
|
|
10. **Overlap-Context** (letzte ~100 Zeichen)
|
|
11. **TASK:** (Header)
|
|
12. **TASK-Anweisungen** (4 Punkte)
|
|
13. **CRITICAL:** (Header)
|
|
14. **CRITICAL-Anweisungen** (3 Punkte)
|
|
|
|
**⚠️ KRITISCH: Template-Konsistenz**
|
|
- Das `JSON Structure Template` im Continuation-Prompt **MUSS exakt identisch** mit dem Template im initialen Prompt sein
|
|
- **Template wird NICHT extrahiert** - es wird als expliziter Parameter (`templateStructure`) übergeben
|
|
- **BasePrompt wird NICHT regeneriert** - es wird als expliziter Parameter (`basePrompt`) übergeben
|
|
- Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt
|
|
|
|
### Die 3 Prompt-Systeme für `section_content`
|
|
|
|
**Besonderheit**: Der `section_content` Use Case verwendet **3 verschiedene Prompt-Systeme**, die sich durch den **Verarbeitungsmodus** unterscheiden, aber alle die gleiche Template-Struktur verwenden:
|
|
|
|
#### System 1: Aggregation-Modus
|
|
|
|
**Kontext**: `if needsAggregation and useAiCall`
|
|
|
|
**Verwendung**:
|
|
- Alle ContentParts einer Section werden **zusammen** verarbeitet
|
|
- Ein einziger AI-Call für alle Parts
|
|
- Verwendet `isAggregation=True` im Prompt
|
|
|
|
**Code-Location**:
|
|
- `subStructureFilling.py` Zeile ~611-922
|
|
- `buildSectionPromptWithContinuation` Zeile ~814-901
|
|
|
|
**Besonderheiten**:
|
|
- Verarbeitet mehrere ContentParts gleichzeitig
|
|
- Aggregiert alle Parts zu einem einzigen Prompt
|
|
- Verwendet `useCaseId="section_content"`
|
|
|
|
#### System 2: Einzelverarbeitung ohne ContentParts
|
|
|
|
**Kontext**: `if len(contentPartIds) == 0 and useAiCall and generationHint`
|
|
|
|
**Verwendung**:
|
|
- **Keine ContentParts** vorhanden
|
|
- Generation **nur mit generationHint**
|
|
- Content wird von Grund auf generiert
|
|
|
|
**Code-Location**:
|
|
- `subStructureFilling.py` Zeile ~1039-1208
|
|
- `buildSectionPromptWithContinuation` Zeile ~1101-1197
|
|
|
|
**Besonderheiten**:
|
|
- Generiert Content ohne Input-ContentParts
|
|
- Verwendet nur `generationHint` als Basis
|
|
- Verwendet `useCaseId="section_content"`
|
|
|
|
#### System 3: Einzelverarbeitung mit ContentParts
|
|
|
|
**Kontext**: Einzelne ContentParts werden nacheinander verarbeitet
|
|
|
|
**Verwendung**:
|
|
- **Einzelne ContentParts** werden sequenziell verarbeitet
|
|
- Jeder Part wird einzeln an die AI gesendet
|
|
- Mehrere AI-Calls pro Section (einer pro Part)
|
|
|
|
**Code-Location**:
|
|
- `subStructureFilling.py` Zeile ~1350-1570
|
|
- `buildSectionPromptWithContinuation` Zeile ~1463-1567
|
|
|
|
**Besonderheiten**:
|
|
- Verarbeitet Parts einzeln
|
|
- Kann mehrere Iterationen pro Section haben
|
|
- Verwendet `useCaseId="section_content"`
|
|
|
|
**Gemeinsame Basis aller 3 Systeme**:
|
|
- ✅ Alle verwenden die **gleiche Template-Struktur** aus `_getContentStructureExample()`
|
|
- ✅ Alle verwenden `useCaseId="section_content"`
|
|
- ✅ Alle verwenden die **gleiche Continuation-Prompt-Struktur** (Fix-Elemente)
|
|
- ✅ Alle verwenden `buildSectionPromptWithContinuation()` (aktuell 3 Instanzen, zukünftig 1 konsolidierte Funktion)
|
|
|
|
**Entscheidungslogik** (in `_processSingleSection()`):
|
|
```python
|
|
if needsAggregation and useAiCall:
|
|
# System 1: Aggregation
|
|
elif len(contentPartIds) == 0 and useAiCall and generationHint:
|
|
# System 2: Ohne ContentParts
|
|
else:
|
|
# System 3: Mit ContentParts (Einzelverarbeitung)
|
|
```
|
|
|
|
**Ziel-Architektur**:
|
|
- Alle 3 Systeme sollten die **konsolidierte** `buildSectionPromptWithContinuation()` Klassenmethode verwenden
|
|
- Template-Struktur wird als Parameter übergeben (garantiert Identität)
|
|
- BasePrompt wird als Parameter übergeben (garantiert Identität)
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
**Parameter-Validierung in `callAiWithLooping()`**:
|
|
|
|
```python
|
|
# In subAiCallLooping.py:
|
|
if (len(allSections) > 0 or lastRawResponse) and promptBuilder and promptArgs:
|
|
# REQUIRED: templateStructure und basePrompt müssen in promptArgs vorhanden sein
|
|
templateStructure = promptArgs.get("templateStructure")
|
|
if not templateStructure:
|
|
raise ValueError(
|
|
f"templateStructure is REQUIRED in promptArgs for use case '{useCaseId}'. "
|
|
"Prompt creation functions must return (prompt, templateStructure) tuple."
|
|
)
|
|
|
|
basePrompt = promptArgs.get("basePrompt")
|
|
if not basePrompt:
|
|
# Fallback: use prompt parameter (should be the same)
|
|
basePrompt = prompt
|
|
# Log warning if they differ
|
|
if basePrompt != prompt:
|
|
logger.warning(
|
|
f"basePrompt not found in promptArgs for use case '{useCaseId}', "
|
|
"using prompt parameter instead. This may indicate a bug."
|
|
)
|
|
|
|
# Build continuation context
|
|
continuationContext = buildContinuationContext(
|
|
allSections, lastRawResponse, useCaseId, templateStructure
|
|
)
|
|
|
|
# Call prompt builder with validated parameters
|
|
iterationPrompt = await promptBuilder(
|
|
continuationContext=continuationContext,
|
|
templateStructure=templateStructure,
|
|
basePrompt=basePrompt,
|
|
**promptArgs # During migration, still use **kwargs
|
|
)
|
|
```
|
|
|
|
**Error Messages**:
|
|
- Klare Fehlermeldungen wenn REQUIRED Parameter fehlen
|
|
- Hinweise auf erwartete Format (z.B. "Prompt creation functions must return (prompt, templateStructure) tuple")
|
|
- Logging für Warnungen (z.B. wenn basePrompt nicht in promptArgs gefunden wird)
|
|
|
|
---
|
|
|
|
## Implementierungs-Roadmap
|
|
|
|
### Phase 1: ContinuationContext Pydantic-Modell und Template-Struktur-Parameter (KRITISCH)
|
|
1. ✅ `ContinuationContext` Pydantic-Modell erstellen (`jsonUtils.py` oder separate Model-Datei)
|
|
2. ✅ `buildContinuationContext()` um `templateStructure` Parameter erweitern
|
|
3. ✅ `buildContinuationContext()` Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext`
|
|
4. ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um `templateStructure` zu **erstellen** (nicht extrahieren!) und als `(prompt, templateStructure)` Tuple zurückzugeben
|
|
5. ✅ Alle Aufrufe anpassen, um `templateStructure` in `promptArgs` zu speichern
|
|
6. ✅ `callAiWithLooping()` anpassen, um `templateStructure` aus `promptArgs` zu holen (mit Validierung) und an `buildContinuationContext()` zu übergeben
|
|
7. ✅ Alle Prompt-Builder um `templateStructure` Parameter erweitern (als expliziten Parameter, nicht extrahieren!)
|
|
|
|
### Phase 2: BasePrompt als Parameter
|
|
8. ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um `basePrompt` in `promptArgs` zu speichern (oder aus `prompt` Parameter verwenden)
|
|
9. ✅ `callAiWithLooping()` anpassen, um `basePrompt` aus `promptArgs` zu holen (mit Validierung)
|
|
10. ✅ Alle Prompt-Builder um `basePrompt` Parameter erweitern (als expliziten Parameter, nicht regenerieren!)
|
|
11. ✅ BasePrompt als Parameter übergeben (garantiert Identität mit initialem Prompt)
|
|
|
|
### Phase 3: Prompt-Builder-Konsolidierung und einheitliche Continuation-Prompt-Struktur
|
|
12. ✅ `buildSectionPromptWithContinuation()` konsolidieren (3 → 1)
|
|
13. ✅ `buildCodeStructurePromptWithContinuation()` implementieren (fehlt aktuell)
|
|
14. ✅ Alle Prompt-Builder als Klassenmethoden definieren (nicht nested)
|
|
15. ✅ **Alle Prompt-Builder auf einheitliche Continuation-Prompt-Struktur umstellen** (siehe "Einheitliche Continuation-Prompt-Struktur")
|
|
16. ✅ `continuationContext` als NICHT-Optional Parameter (wird immer übergeben, Typ: `ContinuationContext`)
|
|
|
|
### Phase 4: Einheitliche Signatur
|
|
17. ✅ Alle Builder auf einheitliche Signatur umstellen:
|
|
- `continuationContext: ContinuationContext` (Pydantic-Modell, NICHT Optional)
|
|
- `templateStructure: str` (expliziter Parameter)
|
|
- `basePrompt: str` (expliziter Parameter)
|
|
- `promptArgs: Any` (während Migration noch Dict, später Dataclass)
|
|
|
|
### Phase 5: Typsicherheit mit Dataclasses
|
|
18. ✅ Dataclasses für Parameter-Strukturen einführen (`SectionPromptArgs`, `ChapterStructurePromptArgs`, `CodeContentPromptArgs`, `CodeStructurePromptArgs`)
|
|
19. ✅ Schrittweise Migration von `**kwargs` zu Dataclass-Parametern
|
|
20. ✅ Alle Builder auf Dataclass-basierte Parameter umstellen (`promptArgs: SectionPromptArgs` statt `promptArgs: Any`)
|
|
|
|
---
|
|
|