This commit is contained in:
team3
2026-06-22 16:30:39 +02:00
parent 36b7aabdb0
commit c5543c0529
4 changed files with 172 additions and 94 deletions

View File

@@ -43,8 +43,9 @@ GUIDE_STEPS = ("Auswahl", "Gliederung", "Inhalte", "Inhalts-Check", "Schreiben",
# Writer skalieren mit der Section-Zahl: 1 Writer je ~30 Sections (gedeckelt).
# Kleine Pakete vermeiden Lazy-Output bei langen Listen und begrenzen den Schaden
# eines fehlgeschlagenen Writers.
WRITER_SECTIONS = 30
WRITER_MAX = 20
# Inhalte/Inhalts-Check/Lese-Prüfung laufen in Paketen von ~GUIDE_CHUNK Bausteinen je Agent.
# Nur der Writer (Schreiben) bleibt 1 Agent je Baustein (variable Längen, kein Kürzen).
GUIDE_CHUNK = 10
# Lese-Prüfung: nur EINE Runde (Check + Fix). Folgerunden brachten kaum Mehrwert
# (1 Agent je Baustein prüft ohnehin fein), kosten aber extra Agenten.
@@ -584,10 +585,10 @@ async def _generate_sections(
plan = _mit_resten(plan, sel_entries)
_set_fertig(content_path, 1) # Gliederung steht
# Chunks festlegen: 1 Chunk = 1 Baustein. So läuft JEDER Section-Schritt (Inhalte,
# Inhalts-Prüfung, Writer, Lese-Check) mit genau einem Agent je Baustein. Der Writer
# rationiert sein Output-Budget dann nicht über viele Sections → längere, variable Texte.
chunks = [[{"title": ch["title"], "nums": [num]}] for ch in plan for num in ch["nums"]]
# Grobe Chunks (~GUIDE_CHUNK Bausteine je Agent) für Inhalte, Inhalts-Check und Lese-Prüfung.
# Der Writer baut darunter pro Baustein (eigene feine Chunks, s.u.) → variable Längen.
total_sections = sum(len(c["nums"]) for c in plan)
chunks = _split_chunks(plan, max(1, math.ceil(total_sections / GUIDE_CHUNK)))
# Subbausteine je Baustein, je Format gefiltert: Guide=relevant · FullGuide=alle · Rest=Rand.
# Subs ohne Relevanz-Feld (Alt-Themen) zählen als „nicht Rand" (→ Guide/FullGuide).
if format_name == "FullGuide":
@@ -706,11 +707,14 @@ async def _generate_sections(
_set_fertig(content_path, 3) # Inhalts-Check durch
# Schritt 4: Schreiben — Writer formuliert die geprüften Inhalte aus (Resume).
# FEINE Chunks: genau 1 Baustein je Writer → variable Längen, kein Budget-Rationieren.
def inhalte_text(chunk) -> str:
nums = [num for ch in chunk for num in ch["nums"] if num in inhalt_by_num]
return "\n\n".join(f"<!-- section: {_titel(entries[num])} -->\n{inhalt_by_num[num]}" for num in nums)
paths = [content_path.parent / f"{content_path.stem}.chunk-{i}.md" for i in range(1, writer_count + 1)]
w_chunks = [[{"title": ch["title"], "nums": [num]}] for ch in plan for num in ch["nums"]]
w_zuteil = [_zuteilung_subs(c, entries, subs_by_titel) for c in w_chunks]
paths = [content_path.parent / f"{content_path.stem}.chunk-{i}.md" for i in range(1, len(w_chunks) + 1)]
offen = [i for i, p in enumerate(paths) if not p.exists()]
if offen:
async def melde(d, t): await _set_step(guide_id, 4, f"Schreibe Sections {d}/{t}")
@@ -719,14 +723,14 @@ async def _generate_sections(
f"{guide_id}-w{i + 1}",
_prompt(
"Guide-Writer",
topic=topic, format_name=format_name, zuteilung=zuteilungen[i],
inhalte=inhalte_text(chunks[i]),
topic=topic, format_name=format_name, zuteilung=w_zuteil[i],
inhalte=inhalte_text(w_chunks[i]),
facts=facts, spec=spec, out_path=paths[i], extra=_extra(instructions),
),
_timeout("writer", chunk_sizes[i]), provider=provider, role="guide", capabilities="full",
_timeout("writer", 1), provider=provider, role="guide", capabilities="full",
)
for i in offen
], writer_count, melde, start=writer_count - len(offen))
], len(w_chunks), melde, start=len(w_chunks) - len(offen))
if is_cancelled():
return None
for i, r in zip(offen, results):