Modern QA2026AI-агенты для аудитов доступности
Join

Course10 Visual & Accessibility Testing

Cutting-edge · Chapter 10

AI-агенты для аудитов доступности

Updated Jul 2026

За пределами сканирования на основе правил

AI-агенты могут выйти за пределы сканирования на основе правил и выполнять качественные оценки доступности, приближающиеся к возможностям аудитора-человека. В то время как axe-core проверяет «присутствует ли alt-текст?», AI-агент может оценить «является ли этот alt-текст действительно описательным?».

Что AI-агенты добавляют поверх axe-core

Возможность axe-core (на основе правил) AI-агент
Обнаружение отсутствующего alt-текста Определяет наличие/отсутствие Оценивает, является ли alt-текст осмысленным
Цветовой контраст Вычисляет точные соотношения Определяет, где цвет — единственный дифференциатор
Структура заголовков Проверяет иерархию h1-h6 Оценивает, описывают ли заголовки контент
Качество текста ссылок Обнаруживает пустые ссылки Отмечает «нажмите здесь» и «читать далее»
Инструкции к формам Проверяет ассоциации меток Оценивает, являются ли инструкции понятными
Ясность сообщений об ошибках Не может оценить Оценивает, направляют ли ошибки пользователя к исправлению
Поток чтения Не может оценить между компонентами Оценивает, является ли поток контента логичным
Чувствительность к движению Не может оценить субъективное воздействие Определяет потенциально триггерные анимации

Паттерн промпта для AI-аудита доступности

You are an accessibility auditor reviewing a web page. You have access to:
1. A screenshot of the page
2. The page's accessibility tree (from Playwright)
3. The page's HTML source

Evaluate the page for WCAG 2.1 AA compliance. For each issue found:
- Identify the WCAG success criterion violated
- Rate severity: Critical / Major / Minor
- Describe the user impact (which users are affected and how)
- Provide a specific remediation recommendation

Focus on issues that automated tools typically miss:
- Is the reading order logical?
- Do error messages clearly explain what went wrong and how to fix it?
- Are interactive elements predictable in their behavior?
- Is equivalent information available to users who cannot see the visual layout?
- Are animations respectful of users who prefer reduced motion?

Расширенный промпт для специфических оценок

Review the following alt text for accuracy and quality. For each image,
evaluate whether the alt text:

1. Accurately describes the image content
2. Conveys the same information a sighted user would get
3. Is neither too brief (losing meaning) nor too verbose (annoying to listen to)
4. Avoids redundant phrases like "image of" or "picture of"
5. Is appropriate for the context (e.g., a product image needs different
   alt text than a decorative hero image)

Images and their current alt text:
- Image 1: [product photo of red running shoes] alt="shoe"
- Image 2: [team photo of 12 people] alt="team photo"
- Image 3: [graph showing sales growth from $1M to $5M] alt="graph"
- Image 4: [decorative wave pattern] alt="wave"

For each, rate the current alt text as GOOD, NEEDS IMPROVEMENT, or POOR,
and provide a suggested replacement.

Автоматический AI-обход для аудита доступности

# scripts/ai_accessibility_audit.py
import asyncio
from playwright.async_api import async_playwright

async def crawl_and_audit(base_url: str, max_pages: int = 50):
    """Crawl an application and run accessibility audits on each page."""
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()

        visited = set()
        to_visit = [base_url]
        all_results = []

        while to_visit and len(visited) < max_pages:
            url = to_visit.pop(0)
            if url in visited:
                continue
            visited.add(url)

            try:
                await page.goto(url, timeout=10000)
                await page.wait_for_load_state('networkidle')

                # 1. Run axe-core for rule-based checks
                axe_results = await page.evaluate("""
                    async () => {
                        await new Promise(r => {
                            const s = document.createElement('script');
                            s.src = 'https://cdn.jsdelivr.net/npm/axe-core@4/axe.min.js';
                            s.onload = r;
                            document.head.appendChild(s);
                        });
                        return await axe.run();
                    }
                """)

                # 2. Get accessibility tree for AI analysis
                a11y_tree = await page.accessibility.snapshot()

                # 3. Take screenshot for AI vision analysis
                screenshot = await page.screenshot(full_page=True)

                # 4. Collect links for crawling
                links = await page.evaluate(f"""
                    () => Array.from(document.querySelectorAll('a[href]'))
                        .map(a => a.href)
                        .filter(href => href.startsWith('{base_url}'))
                """)
                to_visit.extend([l for l in links if l not in visited])

                all_results.append({
                    'url': url,
                    'axe_violations': axe_results.get('violations', []),
                    'a11y_tree': a11y_tree,
                    'screenshot': screenshot,
                })

            except Exception as e:
                all_results.append({
                    'url': url,
                    'error': str(e),
                })

        await browser.close()
        return all_results

async def generate_ai_report(results, ai_client):
    """Send collected data to an AI model for qualitative analysis."""
    for result in results:
        if 'error' in result:
            continue

        # Combine axe-core findings with accessibility tree
        context = {
            'url': result['url'],
            'automated_violations': [
                {'rule': v['id'], 'impact': v['impact'], 'count': len(v['nodes'])}
                for v in result['axe_violations']
            ],
            'accessibility_tree_summary': summarize_tree(result['a11y_tree']),
        }

        # Send to AI for qualitative review
        response = ai_client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=2000,
            messages=[{
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": base64.b64encode(result['screenshot']).decode(),
                        },
                    },
                    {
                        "type": "text",
                        "text": f"""Review this page for accessibility issues.
                        URL: {context['url']}
                        Automated findings: {context['automated_violations']}
                        Accessibility tree: {context['accessibility_tree_summary']}

                        Focus on qualitative issues that axe-core cannot detect.""",
                    },
                ],
            }],
        )

        result['ai_review'] = response.content[0].text

def summarize_tree(tree, depth=0, max_depth=3):
    """Summarize an accessibility tree for AI consumption."""
    if not tree or depth > max_depth:
        return ""
    summary = f"{'  ' * depth}{tree.get('role', 'unknown')}"
    if tree.get('name'):
        summary += f": {tree['name']}"
    children = tree.get('children', [])
    child_summaries = [summarize_tree(c, depth + 1, max_depth) for c in children]
    return summary + '\n' + '\n'.join(filter(None, child_summaries))

Сочетание автоматических и AI-аудитов в CI

# .github/workflows/a11y-audit.yml
name: Accessibility Audit
on:
  schedule:
    - cron: '0 6 * * 1'  # Weekly Monday
  workflow_dispatch:

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build && npm run start &

      - name: Run automated + AI audit
        run: |
          python scripts/ai_accessibility_audit.py \
            --base-url http://localhost:3000 \
            --max-pages 50 \
            --output audit-report.json

      - name: Generate HTML report
        run: python scripts/generate_a11y_report.py audit-report.json

      - name: Upload report
        uses: actions/upload-artifact@v4
        with:
          name: accessibility-audit
          path: audit-report.html

AI-аудиты доступности дополняют, а не заменяют инструменты на основе правил. Используйте axe-core для быстрых, детерминистичных проверок при каждом PR. Используйте AI-агентов для более глубокого качественного анализа на еженедельной основе или при каждом релизе. Используйте экспертов-людей для полноспектрального аудита, который ни автоматизация, ни AI не могут полностью воспроизвести.