ai
3 мин
27 сентября 2026 г.
Источник: Dev.to AI Feed

AI-Enhanced Automated DevOps CI/CD Pipeline with Intelligent Decision‑Making — Part 3: Integrating AI for Smart Build Optimizati

Vijay Vinoth
Vijay Vinoth
RSS AI Ingest
AI-Enhanced Automated DevOps CI/CD Pipeline with Intelligent Decision‑Making — Part 3: Integrating AI for Smart Build Optimizati

AI‑Enhanced Automated DevOps CI/CD Pipeline with Intelligent Decision‑Making — Part 3: Integrating AI for Smart Build Optimization Based on my technical understanding as a Lead Programmer Analyst (PHP, Perl, Python, Shell) and the latest i...

AI‑Enhanced Automated DevOps CI/CD Pipeline with Intelligent Decision‑Making — Part 3: Integrating AI for Smart Build Optimization Based on my technical understanding as a Lead Programmer Analyst (PHP, Perl, Python, Shell) and the latest industry trends of September 2026, this article walks you through the practical steps to embed AI‑driven intelligence directly into the build stage of a modern CI/CD pipeline. Quick Recap of Parts 1‑2 In Part 1 we laid the foundation: a fully automated CI/CD workflow built on GitHub Actions, Docker, and Kubernetes, with telemetry collection via Prometheus and Loki. Part 2 introduced the “AI‑Decision Engine” – a lightweight micro‑service that consumes pipeline metrics and, using Claude 4.6 Opus agentic workflows, decides whether to trigger a canary deployment or roll back a release. Why “Smart Build Optimization” Matters Now Builds have become the new bottleneck. As Northflank reports, AI coding assistants now generate > 30 % of production code, inflating commit velocity and stressing traditional build farms. The DevOps.com analysis predicts that autonomous pipelines will self‑prioritize, parallelize, and abort failing jobs before they waste compute cycles. In short, we need an AI layer that predicts failure, trims unnecessary work, and intelligently distributes resources. Architectural Overview Component Role Tech Stack (2026) Source Repository Triggers pipeline on push/PR GitHub (Enterprise) Build Orchestrator Runs jobs, collects metrics, calls AI services GitHub Actions + self‑hosted runner pool (Ubuntu 22.04) AI Prediction Service Predicts build failure probability, recommends test matrix FastAPI (Python 3.12), GPT‑5.4 Pro Parallel Agents, Claude 4.6 Opus Telemetry Store Historical build logs, test flakiness, resource usage PostgreSQL 15 + TimescaleDB extension Decision Engine (Part 2) Consumes AI output to adjust downstream stages Node.js 20, Redis 7 Step‑by‑Step Implementation 1. Capture Rich Build‑Time Telemetry First, augment the GitHub Actions runner to emit JSON‑structured logs. The snippet below adds a build‑metrics step that writes a metrics.json artifact. name: CI – Smart Build on: push: branches: [ main ] pull_request: jobs: build: runs-on: self-hosted env: METRICS_FILE: ${{ runner.temp }}/metrics.json steps: - name: Checkout code uses: actions/checkout@v4 - name: Install build tools run: | sudo apt-get update && sudo apt-get install -y build-essential - name: Start metric collector (background) run: | cat > ${{ env.METRICS_FILE }} ${{ env.METRICS_FILE }}.tmp && mv ${{ env.METRICS_FILE }}.tmp ${{ env.METRICS_FILE }} continue-on-error: true - name: Upload metrics artifact uses: actions/upload-artifact@v4 with: name: build-metrics path: ${{ env.METRICS_FILE }} Notice the continue-on-error flag – we deliberately let the build finish so the metrics can be sent to the AI service even if the compile fails. 2. Build an AI Prediction Service The service receives metrics.json, enriches it with historical data, and queries two LLMs in parallel: Claude 4.6 Opus – orchestrates agentic reasoning (e.g., “should we skip integration tests?”). GPT‑5.4 Pro Parallel Agents – runs a fast regression model on the numeric features (duration, changed files count, past failure rate). Below is a complete app.py that you can drop into a Docker container. """ Smart Build Predictor – FastAPI service Author: Vijay Vinoth (Lead Programmer Analyst) Date: 2026‑09‑27 """ import os import json from typing import Dict, Any import uvicorn import httpx import pandas as pd import numpy as np from fastapi import FastAPI, HTTPException, UploadFile, File from pydantic import BaseModel # ------------------------------------------------- # Configuration – replace with your own secrets # ------------------------------------------------- POSTGRES_DSN = os.getenv("POSTGRES_DSN", "postgresql://ci_user:ci_pass@db:5432/ci_metrics") CLAUDE_ENDPOINT = "https://api.anthropic.com/v1/messages" CLAUDE_API_KEY = os.getenv("CLAUDE_API_KEY") GPT5_ENDPOINT = "https://api.openai.com/v1/chat/completions" GPT5_API_KEY = os.getenv("GPT5_API_KEY") app = FastAPI(title="Smart Build Predictor") # ------------------------------------------------- # Helper: fetch historical features from PostgreSQL # ------------------------------------------------- def fetch_history(sha: str) -> pd.DataFrame: import sqlalchemy as sa engine = sa.create_engine(POSTGRES_DSN) query = sa.text( """ SELECT build_duration_sec, changed_files, failure_flag FROM builds WHERE repo = :repo AND sha != :sha ORDER BY timestamp DESC LIMIT 500 """ ) with engine.connect() as conn: df = pd.read_sql(query, conn, params={"repo": os.getenv("REPO_NAME"), "sha": sha}) return df # ------------------------------------------------- # Model: simple XGBoost (pre‑trained & saved as model.bin) # ------------------------------------------------- import joblib MODEL_PATH = "/app/models/build_failure_xgb.bin" if os.path.exists(MODEL_PATH): xgb_model = joblib.load(MODEL_PATH) else: # Fallback: a dummy logistic regression from sklearn.linear_model import LogisticRegression xgb_model = LogisticRegression() # In production you would train & replace this file. print("⚠️ Using placeholder model – train a real one!") # ------------------------------------------------- # Pydantic schema for incoming telemetry # ------------------------------------------------- class BuildMetrics(BaseModel): repo: str sha: str trigger: str timestamp: str build_duration_sec: int changed_files: int | None = None # optional, will be filled later # ------------------------------------------------- # Core endpoint # ------------------------------------------------- @app.post("/predict") async def predict_build(file: UploadFile = File(...)): # 1️⃣ Load incoming JSON raw = await file.read() try: payload: Dict[str, Any] = json.loads(raw) except json.JSONDecodeError as exc: raise HTTPException(status_code=400, detail=f"Invalid JSON: {exc}") # 2️⃣ Enrich with derived features # Count changed files using git diff (requires repo checkout) repo_path = os.getenv("GITHUB_WORKSPACE", "/tmp/repo") changed = 0 if os.path.isdir(repo_path): # This runs inside the runner's container; git is available. result = os.popen(f"git -C {repo_path} diff --name-only {payload['sha']}^..{payload['sha']} | wc -l").read() changed = int(result.strip()) payload["changed_files"] = changed # 3️⃣ Historical context hist_df = fetch_history(payload["sha"]) # Simple aggregation: mean failure rate over last N builds if not hist_df.empty: mean_failure = hist_df["failure_flag"].mean() else: mean_failure = 0.0 # 4️⃣ Parallel LLM calls async with httpx.AsyncClient(timeout=30) as client: # Claude Opus – agentic reasoning claude_task = client.post( CLAUDE_ENDPOINT, headers={"x-api-key": CLAUDE_API_KEY, "anthropic-version": "2023-06-01"}, json={ "model": "claude-4.6-opus", "max_tokens": 256, "temperature": 0.0, "messages": [ { "role": "user", "content": f"""You are an expert DevOps architect. Given the following build context, decide which test suites can be safely skipped without increasing risk. Provide a JSON response with a boolean `skip_integration` and a short rationale. Build context: {json.dumps(payload, indent=2)} Historical mean failure rate (last 500 builds): {mean_failure:.2%} """ } ], }, ) # GPT‑5.4 – numeric failure probability gpt5_task = client.post( GPT5_ENDPOINT, headers={"Authorization": f"Bearer {GPT5_API_KEY}"}, json={ "model": "gpt-5.4-pro-parallel", "messages": [ { "role": "system", "content": "You are a statistical model. Return ONLY a JSON with a key `failure_probability` (0‑1)." }, { "role": "user", "content": json.dumps({ "build_duration_sec": payload["build_duration_sec"], "changed_files": payload["changed_files"], "mean_historical_failure": mean_failure, }) }, ], "temperature": 0.0, "max_tokens": 64, }, ) claude_resp, gpt5_resp = await httpx.gather(claude_task, gpt5_task) # 5️⃣ Parse responses try: claude_json = json.loads(claude_resp.json()["content"][0]["text"]) skip_integration = claude_json.get("skip_integration", False) rationale = claude_json.get("rationale", "") except Exception: skip_integration = False rationale = "Failed to parse Claude response." try: gpt5_json = json.loads(gpt5_resp.json()["choices"][0]["message"]["content"]) failure_prob = float(gpt5_json.get("failure_probability", 0.0)) except Exception: failure_prob = 0.0 # 6️⃣ Combine into final decision payload decision = { "skip_integration": skip_integration, "skip_reason": rationale, "failure_probability": failure_prob, "timestamp": payload["timestamp"], "sha": payload["sha"], } # 7️⃣ Persist decision for audit import sqlalchemy as sa engine = sa.create_engine(POSTGRES_DSN) with engine.begin() as conn: conn.execute( sa.text( """ INSERT INTO build_predictions (repo, sha, decision, failure_prob, created_at) VALUES (:repo, :sha, :decision, :prob, NOW()) """ ), { "repo": payload["repo"], "sha": payload["sha"], "decision": json.dumps(decision), "prob": failure_prob, }, ) return decision if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) What this service does: Receives the build‑metrics artifact. Computes a cheap “changed‑files” count (helps the model gauge scope). Pulls the last 500 builds from PostgreSQL to calculate a mean failure rate. Calls Claude 4.6 Opus to produce a high‑level decision about skipping expensive integration tests. Simultaneously asks GPT‑5.4 Pro Parallel Agents for a numeric failure probability. Returns a unified JSON payload that downstream steps can consume. 3. Wire the Predictor into the GitHub Actions Workflow We add a new job that uploads the metrics.json artifact, calls the predictor, and conditionally adjusts the test matrix. predict: needs: build runs-on: self-hosted steps: - name: Download metrics uses: actions/download-artifact@v4 with: name: build-metrics path: ./metrics - name: Call AI Predictor id: ai env: PREDICTOR_URL: http://predictor.internal:8000/predict run: | RESPONSE=$(curl -s -X POST "$PREDICTOR_URL" \ -F "file=@metrics/metrics.json") echo "AI_RESPONSE=$RESPONSE" >> $GITHUB_ENV echo "$RESPONSE" | jq . - name: Set matrix based on AI id: matrix run: | SKIP=$(echo "$AI_RESPONSE" | jq -r .skip_integration) if [ "$SKIP" = "true" ]; then echo "matrix={\"test_suite\":[\"unit\"]}" >> $GITHUB_OUTPUT else echo "matrix={\"test_suite\":[\"unit\",\"integration\"]}" >> $GITHUB_OUTPUT fi test: needs: predict runs-on: self-hosted strategy: matrix: ${{ fromJson(needs.predict.outputs.matrix) }} steps: - uses: actions/checkout@v4 - name: Run selected test suite run: | if [ "${{ matrix.test_suite }}" = "unit" ]; then make test-unit else make test-unit && make test-integration fi The predict job is the only place that contacts the AI service, keeping the rest of the pipeline deterministic. The decision to skip integration tests is recorded in the audit table (see service code) for compliance teams. 4. Training the Failure‑Prediction Model While the example uses a placeholder model, production teams should train a gradient‑boosted tree (XGBoost, LightGBM) on the builds table. Below is a reproducible script that runs daily via a cron job in the same Kubernetes namespace. #!/usr/bin/env python3 """ Daily retraining script for the build‑failure model. """ import os import pandas as pd import joblib import sqlalchemy as sa from xgboost import XGBClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score DSN = os.getenv("POSTGRES_DSN") engine = sa.create_engine(DSN) # Pull the last 30 days of builds query = """ SELECT EXTRACT(EPOCH FROM build_duration_sec) AS duration, changed_files, failure_flag FROM builds WHERE timestamp > NOW() - INTERVAL '30 days'; """ df = pd.read_sql(query, engine) X = df[["duration", "changed_files"]] y = df["failure_flag"] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) model = XGBClassifier( n_estimators=200, max_depth=6, learning_rate=0.05, subsample=0.9, colsample_bytree=0.8, eval_metric="auc", n_jobs=4, ) model.fit(X_train, y_train) pred_proba = model.predict_proba(X_test)[:, 1] auc = roc_auc_score(y_test, pred_proba) print(f"✅ Model AUC: {auc:.4f}") # Persist the model MODEL_PATH = "/app/models/build_failure_xgb.bin" joblib.dump(model, MODEL_PATH) print(f"🗄️ Model saved to {MODEL_PATH}") Schedule it with a CronJob manifest: apiVersion: batch/v1 kind: CronJob metadata: name: build-failure-retrainer spec: schedule: "0 2 * * *" # 02:00 UTC daily jobTemplate: spec: template: spec: containers: - name: trainer image: ghcr.io/yourorg/build-predictor:latest command: ["python", "/app/scripts/retrain.py"] envFrom: - secretRef: name: ci-db-credentials restartPolicy: OnFailure 5. Leveraging Claude 4.6 Opus Agentic Workflows for Dynamic Parallelism Claude 4.6 Opus introduces native “agentic” constructs: an LLM can spin up sub‑agents Originally published at https://artificial-inteligence.phptutorial.co.in

Хотите внедрить ИИ в ваш бренд?

Спроектируем и развернем автономных агентов и современный цифровой стек под ваши задачи.

Рассчитать проект