Разработка AI-анализа качества кода

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка AI-анализа качества кода
Средний
~5 дней
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    901
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1119
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    853

AI-анализ качества кода

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

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

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 []

Анализ технического долга

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 метрики качества

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)

Практический кейс: платёжный сервис

Задача: Legacy-платёжный сервис, 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 после трёх спринтов.

Без AI-анализа ручной аудит занял бы 3–5 дней одного senior-разработчика.

Сроки

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