""" Gradio Space: K8s Multi-Agent Debate Demo HuggingFace Space: roanbrasil/k8s-multi-agent """ import json import gradio as gr HARD8_RESULTS = [ {"resource": "Deployment", "rounds": 4, "time": 9.05, "manifest": """apiVersion: apps/v1 kind: Deployment metadata: name: java-app spec: replicas: 2 selector: matchLabels: app: java-app template: metadata: labels: app: java-app spec: containers: - name: java-app image: openjdk:17 resources: limits: memory: "512Mi\""""}, {"resource": "HorizontalPodAutoscaler", "rounds": 4, "time": 10.27, "manifest": """apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: api-server minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50"""}, {"resource": "StatefulSet", "rounds": 4, "time": 7.63, "manifest": """apiVersion: apps/v1 kind: StatefulSet metadata: name: kafka spec: serviceName: kafka replicas: 3 selector: matchLabels: app: kafka template: metadata: labels: app: kafka spec: containers: - name: kafka image: confluentinc/cp-kafka:7.4.0 volumeMounts: - name: kafka-data mountPath: /var/lib/kafka/data volumeClaimTemplates: - metadata: name: kafka-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Gi"""}, {"resource": "Ingress (TLS)", "rounds": 4, "time": 8.33, "manifest": """apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: secure-ingress spec: tls: - hosts: - secure.example.com secretName: tls-secret rules: - host: secure.example.com http: paths: - path: / pathType: Prefix backend: service: name: example-service port: number: 80"""}, {"resource": "PersistentVolumeClaim", "rounds": 4, "time": 6.81, "manifest": """apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgres-pvc namespace: database spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi"""}, {"resource": "CronJob", "rounds": 4, "time": 9.26, "manifest": """apiVersion: batch/v1 kind: CronJob metadata: name: db-backup spec: schedule: "0 2 * * *" jobTemplate: spec: template: spec: containers: - name: backup image: postgres:15 command: ["/bin/sh", "-c", "pg_dump $DATABASE_URL > /backup/dump.sql"] restartPolicy: OnFailure"""}, {"resource": "NetworkPolicy", "rounds": 4, "time": 8.29, "manifest": """apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-netpol namespace: production spec: podSelector: matchLabels: app: api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 80"""}, {"resource": "ClusterRole", "rounds": 4, "time": 8.67, "manifest": """apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"]"""}, ] SINGLE_MODEL_RESULTS = { "Baseline GPT (46M)": {"yaml": 30.0, "k8s": 36.7, "sem": 96.9, "lat": 0.35}, "AttnRes GPT (48M)": {"yaml": 26.7, "k8s": 36.7, "sem": 97.8, "lat": 0.75}, "Qwen2.5-Coder (7B)": {"yaml": 40.0, "k8s": 33.3, "sem": 98.1, "lat": 1.27}, "DeepSeek-Coder (6.7B)":{"yaml": 16.7, "k8s": 33.3, "sem": 95.0, "lat": 1.61}, } ARCHITECTURE_MD = """ ## System Architecture ``` Problem → BM25 RAG (4,794 K8s docs) ↓ Agent 1 (AttnRes GPT 48M) Fast domain specialist ↓ draft kubeconform --strict ↓ error report Agent 2 (Qwen2.5-Coder 7B) Reasoning critic ↓ critique + instruction Agent 1 retries (max 3 rounds) ↓ if not solved Agent 2 generates directly (fallback) ``` **Key design choices:** - **Asymmetric roles**: small model drafts fast, large model reasons deeply - **External validator**: kubeconform provides ground-truth schema signal (no hallucinated validation) - **BM25 RAG**: top-3 K8s-specific documents grounded to each problem - **Max 3 rounds**: bounded latency (~30s worst case) """ def show_hard8_result(resource_name): for r in HARD8_RESULTS: if r["resource"] == resource_name: summary = f"**Resource:** {r['resource']} \n" summary += f"**Debate rounds:** {r['rounds']} \n" summary += f"**Total time:** {r['time']:.2f}s \n" summary += f"**Solved by:** Agent 2 (Qwen2.5-Coder fallback) \n" summary += f"**Single-model K8s%:** 0% (all 4 models failed)\n" return summary, r["manifest"] return "Not found", "" def show_benchmark_table(): rows = [] for model, m in SINGLE_MODEL_RESULTS.items(): rows.append([model, f"{m['yaml']:.1f}%", f"{m['k8s']:.1f}%", f"{m['sem']:.1f}%", f"{m['lat']:.2f}s"]) return rows with gr.Blocks(title="K8s Multi-Agent Debate Demo", theme=gr.themes.Soft()) as demo: gr.Markdown("# K8s Multi-Agent Debate (MDA) System") gr.Markdown( "Combines **AttnRes GPT (48M)** + **Qwen2.5-Coder-7B** + **BM25 RAG** + **kubeconform** " "to generate valid Kubernetes manifests. Achieves **100% schema compliance** on the " "Hard-8 subset where all single models fail.\n\n" "📄 [Paper](https://github.com/roanbrasil/llm-pocs) | " "🤗 [Model](https://huggingface.co/roanbrasil/attnres-devops-gpt) | " "📊 [K8sBench](https://huggingface.co/datasets/roanbrasil/k8sbench)" ) with gr.Tabs(): with gr.Tab("Hard-8 Results"): gr.Markdown("### Hard-8 Subset: Resources all single models fail (0% K8s%)") gr.Markdown("The MDA system solves all 8 via the Agent 2 fallback after 3 debate rounds.") resource_dd = gr.Dropdown( choices=[r["resource"] for r in HARD8_RESULTS], value="HorizontalPodAutoscaler", label="Select K8s resource" ) result_info = gr.Markdown() manifest_out = gr.Code(language="yaml", label="Final valid manifest (kubeconform ✓)") resource_dd.change(show_hard8_result, inputs=resource_dd, outputs=[result_info, manifest_out]) demo.load(lambda: show_hard8_result("HorizontalPodAutoscaler"), outputs=[result_info, manifest_out]) with gr.Tab("K8sBench Leaderboard"): gr.Markdown("### K8sBench: 30-prompt evaluation across 4 models") leaderboard = gr.Dataframe( headers=["Model", "YAML%", "K8s%", "Sem%", "Latency"], value=show_benchmark_table(), label="K8sBench Results", interactive=False ) gr.Markdown( "**K8s%** = kubeconform --strict schema compliance \n" "Domain-specific 48M models **match or exceed** 7B generalists on schema compliance " "while being **3–4× faster**." ) with gr.Tab("Architecture"): gr.Markdown(ARCHITECTURE_MD) gr.Markdown(""" ### Agent Roles | Agent | Model | Role | |-------|-------|------| | **Agent 1** | AttnRes GPT (48M, local GPU) | Fast domain specialist — generates initial draft | | **Agent 2** | Qwen2.5-Coder-7B (Ollama) | Reasoning critic — diagnoses kubeconform errors, instructs Agent 1, generates final manifest on fallback | | **Validator** | kubeconform --strict | External schema arbitrator — provides ground-truth correctness signal | | **RAG** | BM25Okapi over 4,794 K8s docs | Retrieves top-3 relevant examples per problem | """) with gr.Tab("About"): gr.Markdown(""" ## About This demo presents results from: > Brasil, R. (2025). *Can Small Domain-Specific LLMs Compete with General 7B Models on Kubernetes Configuration Generation?* ### Key Findings 1. A **48M domain-specific model** matches **7B generalists** on Kubernetes schema compliance (36.7% vs 33.3%) while being **3.4× faster** 2. **All single models fail** on HPA, StatefulSet, Ingress, PVC (cross-field constraint resources) 3. The **MDA system achieves 100%** on the Hard-8 subset via asymmetric debate with external validation 4. **AttnRes** architectural improvement: −2.1% perplexity, −44% convergence steps ### Resources - 🔗 Code: https://github.com/roanbrasil/llm-pocs - 🤗 Model: https://huggingface.co/roanbrasil/attnres-devops-gpt - 📊 Training corpus: https://huggingface.co/datasets/roanbrasil/devops-gitops-corpus - 📊 K8sBench: https://huggingface.co/datasets/roanbrasil/k8sbench - 📊 RAG corpus: https://huggingface.co/datasets/roanbrasil/k8s-rag-corpus """) demo.launch()