Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
YouTube Security VideosVisual Studio Code: VS Code Learn: Extending Agents(24.09.2026 um 21:00 Uhr)
•
YouTube Security VideosGoogle Cloud Tech: Turn Audio into Action with Gemini 3.5 Transcribe(24.09.2026 um 21:00 Uhr)
••••
Unix & Linux ServerUSN-8815-1: libass vulnerabilities(24.09.2026 um 16:57 Uhr)
•••••
YouTube Security VideosVisual Studio Code: VS Code Learn: Extending Agents(24.09.2026 um 21:00 Uhr)
•
YouTube Security VideosGoogle Cloud Tech: Turn Audio into Action with Gemini 3.5 Transcribe(24.09.2026 um 21:00 Uhr)
••••
Unix & Linux ServerUSN-8815-1: libass vulnerabilities(24.09.2026 um 16:57 Uhr)
•••••
Intelligence View
⚡ tsecurity.de Intelligence

MLOps / LLMOps — CI/CD Pipelines for Continuous Quality Assurance

Introduction Through Chapter 4 (Security), we implemented Evals, Observability, and Security as individual components. In this chapter, we integrate them into a system for continuous operations. LLMOps shares DNA with MLOps but faces…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Introduction



Through Chapter 4 (Security), we implemented Evals, Observability, and Security as individual components. In this chapter, we integrate them into a system for continuous operations.



LLMOps shares DNA with MLOps but faces fundamentally different challenges. Prompts are code, Evals replace unit tests, provider switching is routine, and costs are unpredictable.




[Before] Manually executed scripts
python evals/eval_rag.py ← run by hand
python security/secure_rag.py ← run by hand

[Now — LLMOps] Automated on every GitHub push
→ Evals check quality
→ Security validation
→ Auto-deploy when quality bar is met






The 2026 MLOps Maturity Model identifies Level 2 (CI/CD automation) as delivering the highest ROI — and most organizations sit between Level 1 and 2.









How LLMOps Differs from MLOps



LLMOps adds LLM-specific concerns on top of MLOps: prompt versioning and evaluation, hallucination monitoring, RAG retrieval quality measurement, token cost management, and content safety monitoring.




























MLOps LLMOps
Version control model files Version control prompts
Test with accuracy / loss Test with Evals (LLM-as-a-Judge)
Deploy models Deploy prompt configurations
Monitor data drift Monitor answer quality and costs








Directory Structure






pgvector-tutorial/
├── existing files
│
├── llmops/
│ ├── prompt_registry.py # ★ Prompt version management
│ ├── ci_eval.py # ★ CI evaluation script
│ └── cost_tracker.py # ★ API cost tracking
│
└── .github/
└── workflows/
└── llmops.yml # ★ GitHub Actions CI/CD pipeline












1. Prompt Version Management — llmops/prompt_registry.py



Prompts are code. They need version control, diff views, approval workflows, and rollback capability.




# llmops/prompt_registry.py
"""
Prompt version management

Changing a prompt can drastically affect RAG answer quality.
Track which version of each prompt is in use.
"""
import hashlib
from dataclasses import dataclass

PROMPTS = {
"rag_answer": {
"v1.0.0": {
"template": """Answer the question based on the following documents.

# Reference Documents
{context}

# Question
{question}

# Answer
""",
"description": "Initial version",
},
"v1.1.0": {
"template": """Answer the question based on the following documents.
If the information is not in the documents, say
"This information is not available in the documents."

# Reference Documents
{context}

# Question
{question}

# Answer (concise, based on the documents)
""",
"description": "Anti-hallucination: explicitly instruct to not answer outside documents",
},
"v1.2.0": {
"template": """You are a document search assistant.
Answer questions based solely on the following documents.

Constraints:
- Do not answer information not in the documents
- Do not speculate or fill gaps
- If unknown, say
"This information is not available in the documents"

# Reference Documents
{context}

# Question
{question}

# Answer
""",
"description": "Security hardening: explicit role + constraints in system prompt style",
},
}
}


def get_prompt(name: str, version: str = "latest") -> str:
"""Retrieve a prompt template."""
if name not in PROMPTS:
raise ValueError(f"Prompt '{name}' not found")

versions = PROMPTS[name]

if version == "latest":
version = sorted(versions.keys())[-1]

if version not in versions:
raise ValueError(f"Version '{version}' not found")

return versions[version]["template"]


def list_versions(name: str) -> list[dict]:
"""Return version list for a prompt."""
if name not in PROMPTS:
raise ValueError(f"Prompt '{name}' not found")

result = []
for version, info in PROMPTS[name].items():
template_hash = hashlib.md5(info["template"].encode()).hexdigest()[:8]
result.append({
"version": version,
"description": info["description"],
"hash": template_hash,
})
return result


def compare_versions(name: str, v1: str, v2: str) -> dict:
"""Compare the diff between two versions."""
t1 = get_prompt(name, v1)
t2 = get_prompt(name, v2)

lines1 = set(t1.split("\n"))
lines2 = set(t2.split("\n"))

added = lines2 - lines1
removed = lines1 - lines2

return {
"added_lines": len(added),
"removed_lines": len(removed),
"char_diff": len(t2) - len(t1),
"sample_added": list(added)[:3],
}


if __name__ == "__main__":
print("=== Prompt Version List ===\n")
for version_info in list_versions("rag_answer"):
print(f" {version_info['version']} [{version_info['hash']}] - {version_info['description']}")

print("\n=== Diff: v1.0.0 → v1.2.0 ===")
diff = compare_versions("rag_answer", "v1.0.0", "v1.2.0")
print(f" Lines added: {diff['added_lines']}")
print(f" Lines removed: {diff['removed_lines']}")
print(f" Char delta: {diff['char_diff']:+d}")

print("\n=== Latest (v1.2.0) Prompt ===")
print(get_prompt("rag_answer", "latest"))









mkdir llmops
python llmops/prompt_registry.py












2. CI Evaluation Script — llmops/ci_eval.py



This script runs automatically on every GitHub push. It fails CI if quality drops below the threshold.




# llmops/ci_eval.py
"""
CI/CD evaluation script

Runs on every push. Returns exit code 1 if quality
falls below thresholds, causing CI to fail.
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import psycopg2
from google import genai
from google.genai import types
from dotenv import load_dotenv
import time
import json
from llmops.prompt_registry import get_prompt
from evals.dataset import EVAL_DATASET

load_dotenv()

client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))

conn = psycopg2.connect(
host=os.getenv("DB_HOST"),
port=os.getenv("DB_PORT"),
dbname=os.getenv("DB_NAME"),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"),
)
cur = conn.cursor()

# ── Quality thresholds (CI fails if below these) ─────────────
QUALITY_THRESHOLDS = {
"context_recall": 0.80,
"answer_relevancy": 0.70,
"overall": 0.75,
}

PROMPT_VERSION = os.getenv("PROMPT_VERSION", "latest")


def get_embedding(text: str) -> list[float]:
result = client.models.embed_content(
model="gemini-embedding-001",
contents=text,
config=types.EmbedContentConfig(
task_type="RETRIEVAL_QUERY",
output_dimensionality=768,
),
)
return result.embeddings[0].values


def search(query: str, top_k: int = 3) -> list[dict]:
query_embedding = get_embedding(query)
cur.execute("""
SELECT title, body,
1 - (embedding <=> %s::vector) AS similarity
FROM documents
ORDER BY embedding <=> %s::vector
LIMIT %s;
""", (query_embedding, query_embedding, top_k))
rows = cur.fetchall()
return [
{"title": r[0], "body": r[1], "similarity": round(r[2], 4)}
for r in rows
]


def rag_answer_with_prompt(question: str, prompt_version: str) -> tuple[str, list[dict]]:
docs = search(question, top_k=3)
context = "\n\n".join([f"[{d['title']}]\n{d['body']}" for d in docs])
prompt_template = get_prompt("rag_answer", prompt_version)
prompt = prompt_template.format(context=context, question=question)

for attempt in range(3):
try:
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
)
return response.text, docs
except Exception as e:
if ("503" in str(e) or "429" in str(e)) and attempt < 2:
time.sleep((attempt + 1) * 15)
else:
raise


def eval_context_recall(retrieved_docs, expected_docs):
retrieved_titles = [d["title"] for d in retrieved_docs]
hit = sum(1 for expected in expected_docs if expected in retrieved_titles)
return hit / len(expected_docs) if expected_docs else 0.0


def eval_answer_relevancy(answer, keywords):
hit = sum(1 for kw in keywords if kw.lower() in answer.lower())
return hit / len(keywords) if keywords else 0.0


def run_ci_eval(prompt_version: str = "latest") -> dict:
print(f"CI evaluation started: prompt version={prompt_version}")
print("=" * 60)

results = []

for item in EVAL_DATASET:
print(f"\n[{item['id']}] {item['question']}")

try:
answer, retrieved_docs = rag_answer_with_prompt(item["question"], prompt_version)
time.sleep(3)

context_recall = eval_context_recall(retrieved_docs, item["expected_docs"])
answer_relevancy = eval_answer_relevancy(answer, item["expected_answer_keywords"])
overall = (context_recall + answer_relevancy) / 2

results.append({
"id": item["id"],
"context_recall": context_recall,
"answer_relevancy": answer_relevancy,
"overall": overall,
})

status = "✓" if overall >= QUALITY_THRESHOLDS["overall"] else "✗"
print(f" {status} Context Recall: {context_recall:.2f} | Relevancy: {answer_relevancy:.2f} | Overall: {overall:.2f}")

except Exception as e:
print(f" ERROR: {e}")
results.append({
"id": item["id"],
"context_recall": 0.0,
"answer_relevancy": 0.0,
"overall": 0.0,
"error": str(e),
})

avg_recall = sum(r["context_recall"] for r in results) / len(results)
avg_relevancy = sum(r["answer_relevancy"] for r in results) / len(results)
avg_overall = sum(r["overall"] for r in results) / len(results)

report = {
"prompt_version": prompt_version,
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
"metrics": {
"context_recall": round(avg_recall, 3),
"answer_relevancy": round(avg_relevancy, 3),
"overall": round(avg_overall, 3),
},
"thresholds": QUALITY_THRESHOLDS,
"passed": (
avg_recall >= QUALITY_THRESHOLDS["context_recall"] and
avg_relevancy >= QUALITY_THRESHOLDS["answer_relevancy"] and
avg_overall >= QUALITY_THRESHOLDS["overall"]
),
"results": results,
}

return report


if __name__ == "__main__":
report = run_ci_eval(PROMPT_VERSION)

print("\n" + "=" * 60)
print("CI Evaluation Report")
print("=" * 60)
print(f"Prompt version: {report['prompt_version']}")
print(f"Context Recall: {report['metrics']['context_recall']:.3f} (threshold: {QUALITY_THRESHOLDS['context_recall']})")
print(f"Answer Relevancy: {report['metrics']['answer_relevancy']:.3f} (threshold: {QUALITY_THRESHOLDS['answer_relevancy']})")
print(f"Overall: {report['metrics']['overall']:.3f} (threshold: {QUALITY_THRESHOLDS['overall']})")

with open("llmops/eval_report.json", "w") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print("\nReport saved to llmops/eval_report.json")

if report["passed"]:
print("\n✅ CI Evaluation: PASSED — Ready to deploy")
sys.exit(0)
else:
print("\n❌ CI Evaluation: FAILED — Quality thresholds not met")
sys.exit(1)












3. GitHub Actions CI/CD Pipeline — .github/workflows/llmops.yml



A pipeline that automatically runs evaluations on every push to GitHub.




# .github/workflows/llmops.yml
name: LLMOps CI/CD Pipeline

on:
push:
branches: [main]
paths:
- "*.py"
- "llmops/**"
- "evals/**"
- "security/**"
pull_request:
branches: [main]

jobs:
# ── Job 1: Security validation ───────────────────────────────
security-test:
name: Security Validation
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: pip install -r requirements.txt

- name: Run input validator tests
run: python security/input_validator.py
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}

# ── Job 2: RAG quality gate (Evals) ─────────────────────────
eval-gate:
name: RAG Quality Gate
runs-on: ubuntu-latest
needs: security-test

services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_PASSWORD: password
POSTGRES_DB: vectordb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: pip install -r requirements.txt

- name: Setup DB and seed data
run: |
python 01_setup_db.py
python 02_create_index.py
python 03_ingest.py
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
DB_HOST: localhost
DB_PORT: 5432
DB_NAME: vectordb
DB_USER: postgres
DB_PASSWORD: password

- name: Run CI Eval (Quality Gate)
run: python llmops/ci_eval.py
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
DB_HOST: localhost
DB_PORT: 5432
DB_NAME: vectordb
DB_USER: postgres
DB_PASSWORD: password
PROMPT_VERSION: latest

- name: Upload eval report
uses: actions/upload-artifact@v4
if: always()
with:
name: eval-report
path: llmops/eval_report.json

# ── Job 3: Deploy (only if quality gate passes) ──────────────
deploy:
name: Deploy to Render
runs-on: ubuntu-latest
needs: eval-gate
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

steps:
- name: Deploy to Render
run: curl -X POST "${{ secrets.RENDER_DEPLOY_HOOK_URL }}"












4. The LLMOps Pipeline in Full






Developer pushes code
↓
GitHub Actions triggered
↓
[Job 1] Security test
→ Test prompt injection detection with input_validator.py
↓ Pass
[Job 2] RAG quality evaluation (Evals gate)
→ Measure Context Recall and Answer Relevancy with ci_eval.py
→ Verify quality meets threshold (Overall ≥ 75%)
→ Save eval report as artifact
↓ Pass
[Job 3] Production deployment
→ Auto-deploy to Render
→ Langfuse tracing begins












5. Comparing Prompt Versions






# Evaluate with v1.1.0
PROMPT_VERSION=v1.1.0 python llmops/ci_eval.py

# Evaluate with v1.2.0
PROMPT_VERSION=v1.2.0 python llmops/ci_eval.py

# Compare scores and set the better version as "latest"












Common Errors

































Error Cause Fix
ModuleNotFoundError: llmops Path not configured Check sys.path.append(...)
CI eval FAILED Score below threshold Improve prompt or adjust thresholds
GitHub Actions timeout Gemini rate limit Increase time.sleep()
Render Deploy Hook not triggering Secret not configured Check GitHub Secrets








Next Steps





  • [Chapter 6: Fine-tuning] — Specialize a model for your domain using LoRA


  • Multi-agent — Design systems where multiple Agents collaborate


  • Governance — EU AI Act compliance, risk management, audit logs

CTI Threat Relationship Graph3 Knoten / 2 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
SOC Incident Playbook: Vulnerability Remediation & Verification
Syntax validiert (0 Fehler)
title: Detect Exploitation - MLOps / LLMOps — CI/CD Pipelines for Continuous Quality Assurance
id: 36664c35-4484-43e1-b712-6b0e20c8c6da
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "MLOps / LLMOps — CI/CD Pipelin" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("MLOps  LLMOps  CICD Pipelines for Contin")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*MLOps  LLMOps  CICD Pipelines for Contin*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "MLOps  LLMOps  CICD Pipelines for Contin"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc
🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich MLOps / LLMOps — CI/CD Pipelines for Con.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten MLOps / LLMOps — CI/CD Pipelines for Continuous Quality Assurance

Thematisch verwandte Begriffe: MLOps, LLMOps, CICD, Pipelines · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61823 | code16 Sharp is a Laravel-based framework for building content-managemen…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...
↗ Original-Quelle