Eine minimale, robuste Pipeline für AI-first Blogartikel mit Web-Recherche, Zwei-Modell-Workflow und deploybaren Artefakten.
Blog-Pipeline/
prompts/
masterprompt.md
researchprompt.md
writerprompt.md
inputs/
outputs/
src/
__init__.py
config.py
utils.py
research.py
llm.py
generate.py
deploy.py
requirements.txt
README.md
cd /srv/Container/Blog-Pipeline
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txtAlternativ ohne Aktivierung der Shell:
cd /srv/Container/Blog-Pipeline
.venv/bin/pip install -r requirements.txtDie Pipeline lädt Umgebungsvariablen explizit aus /srv/Container/.env via python-dotenv.
Beispielvariablen (keine Secrets committen):
IONOS_SFTP_PASS='***'
IONOS_SFTP_HOST='home436434446.1and1-data.host'
IONOS_SFTP_PORT='22'
IONOS_SFTP_PROTOKOLL='SFTP'
# /the-implementers.de
IONOS_SFTP_USER_THE_IMPLEMENTERS_WEBSEITE='acc571362055'
# /schifferm.de
IONOS_SFTP_USER_THE_IMPLEMENTERS_WEBSEITE='acc210464821'
# LLM / Ollama
OLLAMA_HOST_PORT='http://192.168.5.28:11434'Zusätzliche optionale Variablen:
OPENAI_BASE_URL(überschreibt Ollama URL)OPENAI_API_KEY(auch für OpenAI-kompatible Gateways)RESEARCH_MODEL(defaultgpt-oss:20b)WRITER_MODEL(defaultmistral-nemo:12b)IONOS_SFTP_USER(expliziter Deploy-User)IONOS_SFTP_REMOTE_BASE(remote Zielpfad, default/)
Lege eine YAML-Datei in inputs/*.yaml an.
Pflichtfelder:
THEMAZIELGRUPPEZIELESCHWERPUNKTEHALTUNG
Optional:
KONTEXTTONALITÄTLANGUAGE(defaultde)DATE(default: heute)SLUG(sonst ausTHEMAgeneriert)
Siehe inputs/example.yaml.
.venv/bin/python -m src.research --input inputs/example.yaml --k 8
.venv/bin/python -m src.generate --input inputs/example.yaml --with-research --k 8
.venv/bin/python -m src.generate --input inputs/example.yaml --with-research --k 8 --swap-models
.venv/bin/python -m src.deploy --input inputs/example.yaml --deploy --dry-runDie Pipeline schreibt nach outputs/<slug>/:
research_sources.jsonresearch_corpus.mdresearch_summary.txtfact_check_notes.txtcanonical_sources.txtkey_entities.jsondraft_outline.mdarticle.mdexecutive_summary.txtkey_takeaways.txtseo.jsonschema.jsonldlinkedin.txtimage_prompts.txtcodex_deploy_prompt.txt
- Research (
src.research)
- Baut 3-6 Suchanfragen aus Briefing-Feldern.
- Nutzt Brave Search API, falls
BRAVE_API_KEYgesetzt ist; sonst DuckDuckGo HTML-Fallback (bei Anti-Bot-Challenge mit Yahoo HTML als sekundärem Fallback). - Dedupliziert Domains (max. 2 pro Domain), extrahiert Inhalte mit
trafilaturaund Fallbackreadability-lxml. - Verwirft Quellen < 1500 Zeichen.
- Schreibt
research_sources.jsonundresearch_corpus.mdnachoutputs/<slug>/.
- Generation (
src.generate)
- Schritt A (
gpt-oss:20bdefault): Research-Summary + Fact-Check ausprompts/researchprompt.md. - Schritt B (
mistral-nemo:12bdefault): finaler Artikel + Artefakte ausprompts/writerprompt.md. --swap-modelstauscht A/B-Modelle für Tests.- Validiert Marker, JSON-LD, Artikelstruktur und SEO-Limits.
- Normalisiert Bildprompts auf exakt 3, jeweils mit
1.91:1undno text in image.
- Deploy (
src.deploy)
- Optionaler SFTP-Upload der generierten Dateien in
outputs/<slug>/. --dry-runzeigt nur Upload-Plan.
src/config.py verwendet standardmäßig:
OPENAI_BASE_URL, falls gesetzt- sonst
OLLAMA_HOSToderOLLAMA_HOST_PORT+/v1 - fallback
http://127.0.0.1:11434/v1
API-Key kommt aus OPENAI_API_KEY (kann für Ollama ein Platzhalter sein).
- Keine Secrets in Git committen.
- SFTP-User mit Least-Privilege verwenden (nur notwendige Zielpfade).
- Falls möglich Key-basierte Authentifizierung statt Passwort.
- Netzwerkseitig Zielhost- und Port-Allowlist einschränken.
- Deploy nur über dedizierte CI/Runner-Umgebungen mit Secret-Management.
- Fehler
python: command not found: - Nutze
python3oder direkt.venv/bin/python. - Fehler
ModuleNotFoundError: - Stelle sicher, dass du aus dem Projektroot ausführst und die venv nutzt.
- Leere Suchergebnisse im DDG-Fallback:
- Die Pipeline erkennt DDG-Challenges automatisch und nutzt Yahoo als sekundären HTML-Fallback.
- Lange LLM-Laufzeiten:
- Über
.envsteuerbar mitREQUEST_TIMEOUT_RESEARCH_SECONDS,REQUEST_TIMEOUT_WRITER_SECONDS,LLM_RETRIES,LLM_MAX_TOKENS.