Modern QA2026Протоколы коммуникации мультиагентных систем
Join

Course03 Agentic Testing Architectures

Cutting-edge · Chapter 03

Протоколы коммуникации мультиагентных систем

Updated Jul 2026

Почему коммуникация важна

Когда агенты обмениваются информацией, протокол коммуникации определяет, будет система работать или нет. Плохие протоколы приводят к потере контекста, каскадным сбоям и агентам, работающим несогласованно. Хорошие протоколы обеспечивают чистую передачу данных, распространение ошибок и распределённую координацию.

Протокол сообщений

from dataclasses import dataclass

@dataclass
class AgentMessage:
    sender: str           # "code_analyzer"
    receiver: str         # "test_generator" or "broadcast"
    message_type: str     # "analysis_complete" | "tests_ready" | "error"
    payload: dict         # Structured data
    priority: int         # 0=low, 1=normal, 2=high, 3=critical
    timestamp: float
    correlation_id: str   # Traces related messages across agents

Типы сообщений

Тип Отправитель Получатель Назначение
analysis_complete Code Analyzer Test Generator «Я проанализировал модуль, вот тестируемые функции»
tests_ready Test Generator Test Runner «Я сгенерировал тесты, они готовы к выполнению»
results_available Test Runner Test Fixer «Тесты выполнены, вот результаты с ошибками»
fix_applied Test Fixer Test Runner «Я исправил падающие тесты, перезапустите их»
error Любой агент Orchestrator «Я завершился с ошибкой, вот что произошло»
budget_warning Любой агент Orchestrator «Я использовал 80% бюджета токенов»

Пример потока сообщений

messages = [
    AgentMessage(
        sender="code_analyzer",
        receiver="test_generator",
        message_type="analysis_complete",
        payload={
            "module": "auth/login.py",
            "functions_to_test": ["authenticate", "validate_token"],
            "complexity_hints": {"authenticate": "high", "validate_token": "medium"},
            "existing_test_count": 3,
            "suggested_test_count": 8
        },
        priority=1,
        timestamp=time.time(),
        correlation_id="sprint-42-auth-refactor"
    ),
    AgentMessage(
        sender="test_generator",
        receiver="test_runner",
        message_type="tests_ready",
        payload={
            "test_file": "tests/test_auth_login.py",
            "test_count": 8,
            "dependencies": ["pytest", "pytest-asyncio", "httpx"]
        },
        priority=1,
        timestamp=time.time(),
        correlation_id="sprint-42-auth-refactor"
    )
]

Идентификаторы корреляции для трассировки

correlation_id необходим для отладки мультиагентных систем. Он связывает все сообщения, относящиеся к одной задаче:

# All messages for the auth-refactor task share the same correlation ID
# This allows you to:
# 1. Filter logs by correlation_id to see the full pipeline
# 2. Measure total pipeline time (first message to last)
# 3. Identify where bottlenecks occur
# 4. Replay a specific task for debugging

def get_pipeline_trace(correlation_id: str) -> list[AgentMessage]:
    """Get all messages for a specific task, ordered by timestamp."""
    return sorted(
        [m for m in message_store if m.correlation_id == correlation_id],
        key=lambda m: m.timestamp
    )

Распространение ошибок

Когда один агент выходит из строя, система должна обработать это корректно. Существуют три стратегии:

Стратегия 1: Пропустить и продолжить

async def run_pipeline(self, modules: list[str]):
    for module in modules:
        try:
            analysis = await self.code_analyzer.analyze(module)
            tests = await self.test_generator.generate(analysis)
            results = await self.test_runner.run(tests)

            if results.has_failures:
                fixed = await self.test_fixer.fix(tests, results)
                results = await self.test_runner.run(fixed)

        except AgentTimeoutError as e:
            self.log.warning(f"Agent timeout on {module}: {e}")
            self.dead_letter_queue.append(module)  # Retry later
            continue

        except Exception as e:
            self.log.error(f"Unexpected failure on {module}: {e}")
            self.alert_human(module, e)  # Escalate
            continue

Используйте, когда: Модули независимы. Сбой одного не должен блокировать остальные.

Стратегия 2: Быстрый отказ

async def run_pipeline(self, modules: list[str]):
    for module in modules:
        try:
            analysis = await self.code_analyzer.analyze(module)
            tests = await self.test_generator.generate(analysis)
            results = await self.test_runner.run(tests)
        except AgentBudgetExceeded as e:
            self.log.error(f"Budget exceeded on {module}: {e}")
            break  # Stop processing ALL modules

Используйте, когда: Ошибка бюджета или лимита запросов означает, что продолжение всё равно завершится неудачей.

Стратегия 3: Резервные агенты

async def analyze_with_fallback(self, module: str):
    """Try the primary analyzer, fall back to a simpler one."""
    try:
        return await self.primary_analyzer.analyze(module)
    except AgentTimeoutError:
        self.log.warning(f"Primary analyzer timed out, using fallback")
        return await self.fallback_analyzer.analyze(module)

Используйте, когда: У вас есть более простой и быстрый агент, дающий результат ниже качеством, но приемлемый.

Паттерны коммуникации

Паттерн 1: Конвейер (последовательный)

Analyzer -> Generator -> Runner -> Fixer -> Runner

Каждый агент передаёт результат следующему. Просто и предсказуемо.

Паттерн 2: Публикация-подписка

class MessageBus:
    def __init__(self):
        self.subscribers = defaultdict(list)

    def subscribe(self, message_type: str, handler: Callable):
        self.subscribers[message_type].append(handler)

    def publish(self, message: AgentMessage):
        for handler in self.subscribers[message.message_type]:
            handler(message)

# Usage
bus = MessageBus()
bus.subscribe("analysis_complete", test_generator.on_analysis_complete)
bus.subscribe("analysis_complete", coverage_tracker.on_analysis_complete)
bus.subscribe("tests_ready", test_runner.on_tests_ready)
bus.subscribe("error", alerting_service.on_error)

Несколько агентов могут реагировать на одно событие. Coverage Tracker и Test Generator оба получают результат анализа.

Паттерн 3: Запрос-ответ

class AgentProxy:
    """Synchronous request-response to another agent."""

    async def request(self, target_agent: str, action: str, data: dict) -> dict:
        request_id = str(uuid4())
        self.send(AgentMessage(
            sender=self.agent_id,
            receiver=target_agent,
            message_type=f"request:{action}",
            payload={"request_id": request_id, **data},
            priority=2,
        ))

        # Wait for response with timeout
        response = await self.wait_for_response(request_id, timeout=30)
        return response.payload

Мониторинг мультиагентной коммуникации

class CommunicationMonitor:
    """Track message flow health across agents."""

    def __init__(self):
        self.message_count = defaultdict(int)
        self.error_count = defaultdict(int)
        self.latencies = defaultdict(list)

    def on_message(self, message: AgentMessage):
        key = f"{message.sender}->{message.receiver}"
        self.message_count[key] += 1

        if message.message_type == "error":
            self.error_count[message.sender] += 1

    def report(self) -> dict:
        return {
            "total_messages": sum(self.message_count.values()),
            "messages_by_channel": dict(self.message_count),
            "errors_by_agent": dict(self.error_count),
            "error_rate": sum(self.error_count.values()) / max(sum(self.message_count.values()), 1),
        }

Ключевой вывод

Протоколы коммуникации мультиагентных систем определяют надёжность системы. Используйте структурированные сообщения с идентификаторами корреляции для трассировки, реализуйте стратегии распространения ошибок (пропуск, быстрый отказ, резервный агент) в зависимости от модели зависимостей и мониторьте здоровье потока сообщений для раннего обнаружения узких мест и сбоев.