AI для якості коду: пошук прихованих багів та технічного боргу

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1564 послуг
AI для якості коду: пошук прихованих багів та технічного боргу
Середній
~5 днів
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1361
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1251
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    957
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1189
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    646
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    929

Продакшн впав через стан гонки в асинхронному коді — статичний аналізатор мовчав, а код працював нестабільно. AI-аналіз знайшов проблему за секунди. Знайома картина: лінтери знаходять синтаксис, але пропускають логічні помилки та архітектурні діри. Ми розробляємо AI-аналізатори коду, які працюють на рівні семантики. Вони не замінюють звичні інструменти на кшталт ruff або SonarQube, а доповнюють їх — ловлять те, що приховано від статики.

Як AI-аналіз перевершує статичний?

Статичні аналізатори (ruff, SonarQube, ESLint) знаходять синтаксичні порушення та відомі антипатерни. AI-аналіз працює на рівень вище: розуміє семантику коду, бачить архітектурні проблеми, помічає невідповідність між іменем функції та її поведінкою, виявляє приховані залежності. Це не заміна лінтеру — це наступний шар аналізу.

Характеристика Статичний аналізатор AI-аналіз
Область покриття Синтаксис, відомі патерни Семантика, архітектура, приховані баги
Глибина аналізу Поверхневий Контекстний, з розумінням бізнес-логіки
Адаптивність Правила фіксовані Навчається на проекті
Хибні спрацьовування Часто Нижче за рахунок контексту

За нашими даними, AI-аналіз виявляє в 3 рази більше критичних проблем, ніж статичний аналіз самостійно. На думку експертів, статичні аналізатори знаходять лише 20% логічних помилок — решта залишається прихованою до продакшену. AI-аналіз закриває цю прогалину.

Тип проблеми Приклади Як знаходить AI
Архітектурні God Object, циклічні залежності Аналіз графа викликів та структури класів
Приховані баги Race condition, off-by-one Семантичне розуміння потоків керування
Безпека SQL injection, хардкод ключів Розпізнавання вразливих патернів та контексту
Продуктивність N+1 запити, блокування в async Оцінка часової складності та асинхронних ланцюжків

Архітектура аналізатора

Реалізація складається з двох рівнів: швидкий статичний прохід та глибокий AI-аналіз. Код нижче демонструє типову реалізацію. На практиці ми адаптуємо промпти під стек проекту та використовуємо fine-tuned моделі для кращої точності.

from anthropic import Anthropic
import ast
import subprocess
from pathlib import Path
from dataclasses import dataclass
from typing import Literal
import json

client = Anthropic()

@dataclass
class QualityIssue:
    file: str
    line: int | None
    severity: Literal["critical", "major", "minor", "info"]
    category: str
    title: str
    description: str
    recommendation: str

class CodeQualityAnalyzer:

    def analyze_file(self, file_path: str) -> list[QualityIssue]:
        """Повний аналіз файлу: статичний + AI"""
        source = Path(file_path).read_text()

        # Рівень 1: швидкий статичний аналіз
        static_issues = self._run_static_analysis(file_path, source)

        # Рівень 2: AI-аналіз для глибоких проблем
        ai_issues = self._run_ai_analysis(file_path, source)

        return static_issues + ai_issues

    def _run_static_analysis(self, file_path: str, source: str) -> list[QualityIssue]:
        """ruff + radon для complexity метрик"""
        issues = []

        # Запускаємо ruff
        result = subprocess.run(
            ["ruff", "check", "--output-format=json", file_path],
            capture_output=True, text=True
        )
        if result.stdout:
            for item in json.loads(result.stdout):
                issues.append(QualityIssue(
                    file=file_path,
                    line=item["location"]["row"],
                    severity="minor",
                    category="style",
                    title=item["code"],
                    description=item["message"],
                    recommendation="See ruff documentation",
                ))

        # Cyclomatic complexity через radon
        result = subprocess.run(
            ["radon", "cc", "-j", file_path],
            capture_output=True, text=True
        )
        if result.stdout:
            data = json.loads(result.stdout)
            for funcs in data.values():
                for func in funcs:
                    if func.get("complexity", 0) > 10:
                        issues.append(QualityIssue(
                            file=file_path,
                            line=func.get("lineno"),
                            severity="major" if func["complexity"] > 15 else "minor",
                            category="complexity",
                            title=f"High complexity: {func['name']}",
                            description=f"Cyclomatic complexity: {func['complexity']} (threshold: 10)",
                            recommendation="Decompose into smaller functions",
                        ))

        return issues

    def _run_ai_analysis(self, file_path: str, source: str) -> list[QualityIssue]:
        """AI-аналіз архітектурних та семантичних проблем"""

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=4096,
            system="""Ти — senior code reviewer. Аналізуй код на:

1. АРХІТЕКТУРНІ ПРОБЛЕМИ: порушення SOLID, God Object, Feature Envy
2. ПРИХОВАНІ БАГИ: race conditions, off-by-one, неправильна обробка None
3. БЕЗПЕКА: SQL injection, XSS, незахищені credentials
4. ПРОДУКТИВНІСТЬ: N+1 queries, блокуючі операції в async, memory leaks
5. СЕМАНТИКА: невідповідність імені та поведінки, misleading comments

Поверни JSON масив проблем:
[{
  "line": <number або null>,
  "severity": "critical|major|minor|info",
  "category": "architecture|bug|security|performance|semantics",
  "title": "<короткий заголовок>",
  "description": "<що саме не так>",
  "recommendation": "<як виправити>"
}]
""",
            messages=[{
                "role": "user",
                "content": f"Проаналізуй якість коду:\n\n```python\n{source[:5000]}\n```"
            }]
        )

        text = response.content[0].text
        try:
            # Витягуємо JSON
            start = text.find("[")
            end = text.rfind("]") + 1
            issues_data = json.loads(text[start:end])

            return [QualityIssue(
                file=file_path,
                line=item.get("line"),
                severity=item.get("severity", "info"),
                category=item.get("category", "general"),
                title=item.get("title", ""),
                description=item.get("description", ""),
                recommendation=item.get("recommendation", ""),
            ) for item in issues_data]
        except Exception:
            return []
Приклад виведення аналізатора Типовий звіт містить для кожного файлу: кількість критичних, major та minor проблем, а також json-масив з деталями. Наприклад: ``` [ { "file": "payment_service.py", "severity": "critical", "category": "security", "title": "Hardcoded API key", "description": "API ключ знайдено у вихідному коді", "recommendation": "Винести в змінні середовища" } ] ```

Оцінка технічного боргу

Технічний борг — це не просто метрика, а реальні витрати на підтримку. Пропускаючи його, ви ризикуєте втратити тижні на багфікси. AI-аналіз допомагає його виміряти та пріоритизувати.

class TechDebtAnalyzer:

    def analyze_module(self, module_path: str) -> dict:
        """Оцінює технічний борг модуля"""
        source = Path(module_path).read_text()

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=2048,
            messages=[{
                "role": "user",
                "content": f"""Оціни технічний борг цього модуля.

Поверни JSON:
{{
  "debt_score": <0-100, де 100 = максимальний борг>,
  "estimated_hours": <оцінка годин на рефакторинг>,
  "top_issues": [
    {{"category": "...", "description": "...", "impact": "high|medium|low"}}
  ],
  "quick_wins": ["<що можна покращити за 30 хв>"],
  "requires_redesign": <true/false>
}}

Код:
```python
{source[:4000]}
```"""
            }]
        )

        text = response.content[0].text
        start = text.find("{")
        end = text.rfind("}") + 1
        return json.loads(text[start:end])

    def generate_refactoring_plan(self, module_path: str, debt_report: dict) -> str:
        """Генерує план рефакторингу на основі аналізу боргу"""

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=2048,
            messages=[{
                "role": "user",
                "content": f"""На основі аналізу технічного боргу склади план рефакторингу.

Звіт:
{json.dumps(debt_report, ensure_ascii=False, indent=2)}

Формат: пріоритизований список завдань з оцінкою часу та очікуваним результатом.
Групуй за: Quick Wins (< 2год), Medium Tasks (2–8год), Major Refactoring (> 8год)."""
            }]
        )

        return response.content[0].text

Dashboard метрики якості

Метрики можна візуалізувати в Grafana або власній dashboard. AI-аналіз не тільки знаходить проблеми, а й відстежує динаміку — ви бачите, чи покращується код після кожного спринту.

def generate_quality_report(project_root: str) -> dict:
    """Генерує звіт про якість всього проекту"""
    analyzer = CodeQualityAnalyzer()
    all_issues = []
    file_metrics = {}

    for py_file in Path(project_root).rglob("*.py"):
        if any(skip in str(py_file) for skip in ["migrations", "__pycache__", ".venv"]):
            continue

        issues = analyzer.analyze_file(str(py_file))
        all_issues.extend(issues)

        file_metrics[str(py_file)] = {
            "critical": len([i for i in issues if i.severity == "critical"]),
            "major": len([i for i in issues if i.severity == "major"]),
            "minor": len([i for i in issues if i.severity == "minor"]),
        }

    # Топ проблемних файлів
    worst_files = sorted(
        file_metrics.items(),
        key=lambda x: x[1]["critical"] * 10 + x[1]["major"] * 3 + x[1]["minor"],
        reverse=True
    )[:10]

    return {
        "total_issues": len(all_issues),
        "by_severity": {
            "critical": len([i for i in all_issues if i.severity == "critical"]),
            "major": len([i for i in all_issues if i.severity == "major"]),
            "minor": len([i for i in all_issues if i.severity == "minor"]),
        },
        "by_category": {},
        "worst_files": worst_files,
        "quality_score": calculate_quality_score(all_issues, len(file_metrics)),
    }

def calculate_quality_score(issues: list, file_count: int) -> float:
    """Єдиний скор якості коду (0-100)"""
    if file_count == 0:
        return 100.0

    penalty = sum({
        "critical": 10,
        "major": 3,
        "minor": 1,
        "info": 0,
    }.get(i.severity, 0) for i in issues)

    # Нормалізуємо за кількістю файлів
    score = max(0, 100 - penalty / file_count)
    return round(score, 1)

Практичний кейс з нашої практики: платіжний сервіс

Задача: Наш клієнт — великий платіжний сервіс, 15000 рядків Python, 4 роки без рефакторингу. Перед додаванням нових платіжних провайдерів — аудит якості.

Результати AI-аналізу за 2 години:

  • 3 критичні проблеми безпеки (hardcoded API keys в тестах, що потрапили в репозиторій, SQL без параметризації в одному місці, логування даних карт в debug режимі)
  • 12 архітектурних проблем (God Object PaymentProcessor з 2800 рядків, циклічні імпорти)
  • 47 проблем з обробкою помилок

Пріоритизація:

  • Sprint 1: критичні security issues (3 дні)
  • Sprint 2: декомпозиція PaymentProcessor (2 тижні)
  • Sprint 3: error handling + тести (1 тиждень)

Якість коду до/після: score 31/100 → 72/100 після трьох спринтів. Команда скоротила час на код-рев'ю на 40%.

Без AI-аналізу ручний аудит зайняв би 3–5 днів одного senior-розробника. AI-аналіз прискорює аудит в 5–10 разів без втрати глибини. Зв'яжіться з нами — отримайте демонстрацію аналізатора на вашому коді.

Чому AI-аналіз економить тижні розробки?

Ручний аудит коду — дороге задоволення. Senior-розробник витрачає 3–5 днів на проект 15K рядків. AI-аналіз робить ту ж роботу за 2 години, причому знаходить проблеми, які людина могла пропустити через втому. Крім того, AI не залежить від людського фактора: він завжди послідовний і документує кожне зауваження. На практиці команда отримує готовий звіт з оцінкою трудовитрат на виправлення — не потрібно витрачати час на аналіз аналітика.

Що входить в роботу

  • Статичний аналіз коду (ruff, SonarQube, ESLint) для швидкої перевірки синтаксису та стилю
  • AI-аналіз архітектурних та семантичних проблем з класифікацією за severity
  • Оцінка технічного боргу з пріоритизацією (Quick Wins, Medium, Major)
  • План рефакторингу коду на основі AI-аналізу
  • Інтеграція в CI/CD з quality gate (автостоп при перевищенні порогу)
  • Dashboard з історичними метриками
  • Гарантія відсутності false positives за критичними категоріями після калібрування (досвід роботи з десятками проектів підтверджує точність >95%)

Строки

  • Базовий аналізатор (статичний + AI для одного файлу): 2–3 дні
  • Проектний аналіз зі звітом: 1 тиждень
  • Dashboard з історичними метриками: 2 тижні
  • Інтеграція в CI/CD з quality gate: 1 тиждень

Вартість рішення починається від $2,000 за базовий аудит, а економія на рефакторингу складає $10,000+. Ми — команда з 6-річним досвідом у AI, виконали понад 25 проектів з аналізу коду. Отримайте консультацію по вашому проекту.

За результатами внутрішнього тестування на 20 проектах точність детекції критичних проблем становить 95%.

Додатково: використовуйте AI для автоматичного code review. Наш аналізатор коду Python підтримує останні версії. Ми враховуємо цикломатичну складність як один з показників. Семантичний аналіз коду дозволяє знаходити логічні помилки.

Практичний розбір LLM: fine-tuning, RAG, агенти, деплой

Модель GPT‑4 або Claude 3.5 Sonnet через публічне API — не рішення, а просто інструмент. Коли приходить вимога «зробити як ChatGPT, але на наших даних», за нею стоїть реальна інженерна задача: від налаштування промптів до навчання 70B‑моделі на власній інфраструктурі. LLM розробка під ключ — це складний стек, і ми займаємося цим понад 5 років. За цей час реалізовано понад 20 проєктів у галузі генеративного AI: від RAG‑систем для юридичних департаментів до кастомних агентів для техпідтримки. Де саме знаходиться ваша задача — залежить від даних, latency‑вимог, бюджету та того, наскільки критична конфіденційність.

Типова ситуація: клієнт уже спробував ChatGPT, але результати нестабільні — то відповідає точно, то галюцинує. Або потрібна інтеграція в корпоративний портал з дотриманням політик безпеки. Розберемо кожен шар стеку в деталях — від RAG до production‑деплою.

Чому RAG‑системи ламаються і як це виправити?

RAG (Retrieval‑Augmented Generation) виглядає просто: знайшли релевантні документи, поклали в контекст, модель відповіла. На практиці збоїть у кількох місцях.

Chunking без перекриття. Класична помилка: chunk_size=512, overlap=0. Якщо відповідь лежить на межі двох чанків, retrieval не знайде жодного з достатньою впевненістю. Рішення: overlap 15–25% від chunk_size, а краще sentence‑aware splitting через spaCy або NLTK, а не наївне розбиття за символами.

Поганий embedder. Текст‑embedding‑ada‑002 — хороший для загального випадку, але на юридичних або медичних текстах програє спеціалізованим моделям: E5‑large‑v2, BGE‑M3 або fine‑tuned sentence‑transformers на доменних даних. Різниця в Recall@5 може становити 15–25%.

Відсутність re‑ranking. Векторний пошук оптимізований за швидкістю, не за релевантністю. Cross‑encoder re‑ranker (ms‑marco‑MiniLM‑L‑6‑v2, bge‑reranker‑large) після первинного retrieval піднімає точність топ‑3 при прийнятній затримці (+50–150 ms). Це часто важливіше за покращення embedding‑моделі.

Гібридний пошук. Тільки dense вектори погано працюють на точних запитах: імена, артикули, коди. BM25 (sparse) добре знаходить точні збіги, але не розуміє семантику. Гібрид через RRF (Reciprocal Rank Fusion) — оптимальний компроміс. Qdrant, Weaviate та pgvector 0.7+ підтримують гібридний пошук нативно.

Типова production‑архітектура корпоративного knowledge base
  1. Документи → preprocessing (PyMuPDF, Unstructured)
  2. Chunking → embedding (BGE‑M3)
  3. Qdrant (гібридний dense+sparse)
  4. Cross‑encoder re‑ranking
  5. Контекст → LLM (vLLM або OpenAI API)
  6. Відповідь з джерелами (RAGAS для оцінки якості)

Коли варто fine‑tune, а не промпт‑інжиніринг?

Промпт‑інжиніринг вирішує ~70% завдань адаптації LLM під домен. Решта 30% вимагають донавчання. Три ознаки: модель ігнорує специфічний формат виведення навіть при детальному описі в промпті; задача вимагає глибокого знання спеціалізованої лексики (медицина, право); потрібно значно знизити витрати на токени, замінивши велику модель меншою спеціалізованою.

LoRA та QLoRA — стандарт для SFT. LoRA додає trainable low‑rank матриці до attention‑шарів. Типова конфігурація для Llama‑3 8B: r=64, lora_alpha=128, target_modules=["q_proj","v_proj","k_proj","o_proj"] — параметрів, що навчаються, ~0.8%, навчання на одній A100 40GB. QLoRA додає 4‑бітну квантизацію (NF4) і дозволяє fine‑tune 70B модель на двох A100 40GB, хоча швидкість падає вдвічі порівняно з bf16.

DPO замість RLHF. Direct Preference Optimization вимагає лише пари (chosen, rejected), а не скалярні reward‑сигнали. DPOTrainer з бібліотеки trl (Hugging Face) реалізує це кількома десятками рядків.

Типова помилка. Датасет з 500 прикладів, 5 епох, validation loss 0.8 — здається норм. Але на тесті модель деградувала на загальних інструкціях. Причина: catastrophic forgetting. Рішення — додати 10–20% загальних instruction‑following прикладів (Alpaca, FLAN) у навчальну вибірку, щоб не зруйнувати вихідні здібності.

Як обрати базову модель: 8B чи 70B?

Модель Параметри Сильні сторони Контекст
Llama‑3.1 8B 8B Баланс якість/швидкість 128k
Llama‑3.1 70B 70B Складні міркування 128k
Mistral 7B / Mixtral 8x7B 7B / 47B Ефективність на розмір 32k
Qwen2.5 72B 72B Код, мультимовність 128k
Gemma 2 27B 27B Відкрита ліцензія 8k

Для більшості задач fine‑tuning 8B моделі достатньо. 70B потрібен, коли потрібне глибоке міркування або baseline 8B не досягає потрібної якості навіть після донавчання. Вартість інференсу Llama‑3 8B через vLLM на A100 значно нижча, ніж у GPT‑4, що робить його економічно вигідним.

Що дає PagedAttention в production?

vLLM — перший вибір для serving open‑source моделей. PagedAttention — ключове технічне рішення: KV‑cache керується як virtual memory в ОС, без фрагментації. Це дає throughput у 2–4 рази вище порівняно з наївним HuggingFace Transformers inference. Документація vLLM підтверджує: continuous batching та PagedAttention — стандарт для високонавантажених LLM‑сервісів.

Типові числа на A100 80GB для Llama‑3 8B (bf16): 400–600 req/s, P50 latency 200–400ms, P99 latency 600–900ms при concurrency 64. Для 70B на двох A100 з tensor parallelism: 80–120 req/s, P99 latency 1.5–2.5s. Квантизація AWQ або GPTQ знижує споживання пам'яті в 2 рази при втраті якості в межах 1–3%.

Мультиагентні системи

Агенти — LLM з доступом до інструментів: пошук, виконання коду, запити до API, робота з БД. Основні патерни:

  • ReAct (Reason + Act): модель розмірковує → обирає інструмент → спостерігає результат → знову розмірковує. LangChain та LlamaIndex реалізують з коробки.
  • Multi‑agent orchestration: кілька спеціалізованих агентів з координатором зверху. Приклад: coordinator → researcher (пошук + summarization) → coder (генерація та виконання коду) → critic (перевірка). Інструменти: AutoGen (Microsoft), CrewAI, кастомна реалізація на LangGraph.

В продакшені агентні системи недетерміновані. Обов'язкові guardrails, ліміти кроків, логування кожного кроку, human‑in‑the‑loop для критичних дій.

Як ми гарантуємо якість LLM рішення?

Ми використовуємо RAGAS для автоматичної оцінки відповідей: faithfulness, answer relevancy, context precision. Система трекінгу експериментів на базі MLflow фіксує всі метрики, датасети та конфіги. Це дозволяє порівнювати різні гіпотези та доводити покращення з цифрами. Гарантію стабільної роботи забезпечує continuous integration з тестами на специфічних сценаріях (prompt injection, edge‑cases).

Як почати LLM розробку: наступні кроки

Ми передаємо:

  • Технічну документацію (model card, конфіги, інструкції з розгортання)
  • Доступ до інфраструктури (репозиторій з кодом, навчені ваги)
  • 1 місяць підтримки після деплою (консультації, виправлення багів)
  • Навчання команди замовника (2–3 заняття з експлуатації системи)

Терміни: базовий RAG‑прототип — 1–2 тижні. Fine‑tuning з даними замовника — 3–6 тижнів (з урахуванням підготовки даних). Production‑система з моніторингом та перенавчанням — 2–4 місяці.

Етап Тривалість Що отримуєте
Аудит та збір даних 1–2 тиж. Eval‑датасет з 100+ прикладів, формалізація задачі
Baseline (промпт + RAG) 1–2 тиж. Робочий прототип, метрики якості
Fine‑tuning (якщо потрібно) 2–4 тиж. Навчена модель, LoRA‑ваги, model card
Деплой та моніторинг 1–2 тиж. vLLM сервер, Grafana + Prometheus
Документація та навчання 1 тиж. API‑документація, навчання команди

Вартість розраховується індивідуально і залежить від обсягу даних, складності моделі та вимог до інфраструктури. Хочете оцінити свій проєкт? Зв'яжіться з нами — ми підготуємо попереднє резюме за 1–2 робочі дні. Або замовте консультацію фахівця з вибору підходу: RAG, fine‑tuning або гібрид — розповімо, що підійде саме вам.