Pull to refresh

Comments 15

что я не поняло, так зачем плодить сущности, и делать отдельный ACP и A2G если все равно оно работает через A2A.
Сам все это гоняю, и в отсутствие единого стандарта аля MCP получается какая каша.

Не a2g, а ag2 - это фреймворк для создания агентов. В статье как раз написано, что данный протокол (ACP) регламентирует управление CLI агентами

А есть нормальная обзорная статья по AG2? Может напишете

хорошо, у меня тогда более глубокий вопрос, на который я сам себе ответить не могу, что лучше реализовывать, A2A с подобным протоколом, что удобно, ведь из коробки, или все это через шину, с алгоритмическим управлением event'ов.
Если у пользователя идет общение с родительским агентом, то все event сообщения от вторичного агента становятся контекст-спамом, на который агент для пользователя будет отвлекаться. Если скипать, то где тогда event'ы брать?
Городить шину поверх A2A? или в AG2 есть хорошие решения?

В AG2 есть встроенная поддержка A2A - https://docs.ag2.ai/docs/user-guide/a2a/client/
Ничего не надо самому писать: завернул одного агента в A2A-Server, в другом сделал A2A-Client для работы с этим сервером и воткнул сабагентом - все

Затем, чтобы дешевле стало создавать новых агентов согласно принятым стандартам - и тем способствовать их конкуренции с закрытыми агентами, в первую очередь CC и Codex-ом.

Это нужно MS, которая планирует превратить свои OS и облачную экосистему в агентский харнесс.

Отличная статья, спасибо. Хочу добавить пару мыслей из практики - про то, где ACP-агенты в «авто»-режиме неожиданно больно кусаются.

1. Permission_policy="auto" не равен «безопасно» fs_root не контролирует сетевые вызовы. Агент может сходить в платный API, запушить в GitHub под вашими кредами, дёрнуть npm install из скомпрометированного пакета - и ни одна из этих операций не попадёт под fs_root. Граница, за которой человек обязан остаться в цикле - там, где действие имеет необратимые последствия за пределами файловой системы.

2. Стрим событий - главная фича, её недооценивают Через события можно строить дашборд, где сразу видно: сколько токенов ушло на размышления vs на код, какие файлы трогал, на каком шаге завис. Без стрима вы не отловите режим, когда агент 40 раз подряд читает один файл, потому что «забыл» его содержимое. Для production-эксплуатации события важнее, чем сам факт программного управления.

3. В протоколе не хватает rate limiting / cost control Нет механизма сказать агенту «у тебя осталось 5000 токенов» или «ты уже сделал 20 tool calls». Один неудачный промпт может сжечь квоту. Можно убить процесс на стороне хоста, но было бы удобнее, если бы протокол позволял передавать бюджет агенту.

4. ACP vs MCP - их путают MCP - tools layer (агент → инструменты), ACP - orchestration layer (код → агент), A2A - network layer (агент ↔ агент). Разные уровни абстракции, и хорошо, что стандартизированы независимо.

Спасибо, правда не сталкивался с тем, что люди путают данные протоколы, ибо каждый под разную задачу)

По поводу безопасности, все знают, что буква S в аббревиатурах ai, acp и a2a обозначает Security.:) Я думаю, самые громкие будущие атаки на доверенную среду будут так или иначе использовать внедренные мультиагентные системы...

Полезная вводная информация про ACP (Agent Client Protocol) - инструмент, который будет управлять CLI, чтобы вам меньше самому переписываться с ии в консоли.

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

Единственное что надо от вашей программы теперь это уже управление самой этой упряжкой, ответы на запросы от ИИ агентов и т. д.

Сначала мы создали CLI чтобы человеку было удобно управлять ИИ агентами через своеобразную упряжку в виде CLI. Теперь мы хотим управлять этой упряжкой из других программ, в том числе и из других ИИ агентов насколько я понимаю, которые могут быть как в нашей программе, так и в другой CLI программе. Так может получиться достаточно интересная и не очевидная рекурсия CLI упряжек между собой 😂😂😂

Шутки-шутками, но на практике в использовании ag2 хорошо себя показывает)

use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::Mutex; use tracing::{info, warn};

// ============================================================ // 1. СЕМАНТИЧЕСКИЙ АНАЛИЗ РИСКА (AST EXTENSION) // ============================================================

#[derive(Debug, Clone, Serialize, Deserialize)] pub enum Opcode { ReadFile(String), WriteFile(String), DeleteFile(String), ExecuteCommand(String), PushToRemote, Calculate, }

#[derive(Debug, Clone)] pub struct SyntaxNode { pub op: Opcode, pub children: Vec, }

impl SyntaxNode { /// Вычисляет “вес опасности” операции. /// Чем выше число, тем больше потенциальный ущерб для репозитория. pub fn risk_score(&self) -> f32 { let base_risk = match &self.op { Opcode::Calculate => 0.1, Opcode::ReadFile() => 0.5, Opcode::ExecuteCommand(cmd) => if cmd.contains(“rm”) || cmd.contains(“sudo”) { 8.0 } else { 2.0 }, Opcode::WriteFile() => 3.0, Opcode::DeleteFile(_) => 7.0, Opcode::PushToRemote => 9.5, // Критическая зона };

    let child_risk: f32 = self.children.iter().map(|c| c.risk_score()).sum();
    base_risk + (child_risk * 0.2) // Риск накапливается, но с затуханием
}

}

// ============================================================ // 2. МОДЕЛЬ ДОВЕРИЯ И КОНФИГУРАЦИЯ // ============================================================

#[derive(Debug, Clone)] pub struct TrustModel { pub score: f32, // Текущий уровень доверия (0.0 - 1.0) pub history_len: u32, // Количество успешных операций подряд }

impl TrustModel { pub fn new() -> Self { Self { score: 0.5, history_len: 0 } // Начинаем с нейтрального доверия }

pub fn update(&mut self, success: bool) {
    if success {
        self.score = (self.score + 0.05).min(1.0);
        self.history_len += 1;
    } else {
        self.score *= 0.4; // Жесткое падение при ошибке
        self.history_len = 0;
        warn!("Trust score plummeted due to failure!");
    }
}

}

#[derive(Debug, Clone)] pub struct AdaptiveConfig { pub autonomy_level: u8, // 0 (HITL) - 10 (Full Auto) pub trust: TrustModel, }

// ============================================================ // 3. ПРИНЯТИЕ РЕШЕНИЙ (THE GATEKEEPER) // ============================================================

#[derive(Debug)] pub enum PermissionDecision { AutoApprove, RequireHumanApproval { reason: String, risk: f32 }, BlockOperation { reason: String }, }

pub struct AutonomyGatekeeper { config: Arc<Mutex>, }

impl AutonomyGatekeeper { pub fn new() -> Self { Self { config: Arc::new(Mutex::new(AdaptiveConfig { autonomy_level: 2, // Начинаем с осторожного режима trust: TrustModel::new(), })), } }

/// Главная логика: можно ли агенту выполнить этот узел AST?
pub async fn evaluate(&self, node: &SyntaxNode) -> PermissionDecision {
    let config = self.config.lock().await;
    let risk = node.risk_score();
    let level = config.autonomy_level;

    // Логика границы:
    // 1. Если риск критический (> 8.0) — всегда человек.
    // 2. Если автономия низкая (< 3) — человек для всего, что сложнее чтения.
    // 3. Если автономия высокая — разрешаем всё, кроме Push/Delete.

    if risk > 8.0 {
        return PermissionDecision::RequireHumanApproval {
            reason: "Critical operation detected (Push/Delete/Dangerous CMD)".to_string(),
            risk,
        };
    }

    if level < 3 && risk > 1.0 {
        return PermissionDecision::RequireHumanApproval {
            reason: format!("Low autonomy level ({}) requires approval for risk {:.1}", level, risk),
            risk,
        };
    }

    PermissionDecision::AutoApprove
}

/// Обратная связь от исполнения (Афферентация)
pub async fn report_result(&self, success: bool) {
    let mut config = self.config.lock().await;
    config.trust.update(success);

    // Адаптация уровня автономии на основе доверия
    let new_level = match config.trust.score {
        s if s > 0.9 => 8,
        s if s > 0.7 => 5,
        s if s > 0.4 => 2,
        _ => 0,
    };

    if new_level != config.autonomy_level {
        info!("🔄 Autonomy Level Adapted: {} -> {}", config.autonomy_level, new_level);
        config.autonomy_level = new_level;
    }
}

}

// ============================================================ // 4. ДЕМО-СЦЕНАРИЙ // ============================================================

#[tokio::main] async fn main() { let gatekeeper = AutonomyGatekeeper::new();

// Сценарий 1: Агент хочет прочитать файл (Низкий риск)
let read_node = SyntaxNode {
    op: Opcode::ReadFile("config.toml".to_string()),
    children: vec![],
};

// Сценарий 2: Агент хочет сделать Push в main (Критический риск)
let push_node = SyntaxNode {
    op: Opcode::PushToRemote,
    children: vec![],
};

println!("--- Start of Simulation ---");

// Проверка чтения
match gatekeeper.evaluate(&read_node).await {
    PermissionDecision::AutoApprove => println!("✅ [AUTO] ReadFile allowed."),
    other => println!("⛔ [BLOCK] ReadFile: {:?}", other),
}

// Имитируем успехи, чтобы повысить доверие
for _ in 0..10 {
    gatekeeper.report_result(true).await;
}

// Проверка Push после повышения доверия
match gatekeeper.evaluate(&push_node).await {
    PermissionDecision::AutoApprove => println!("✅ [AUTO] PushToRemote allowed."),
    PermissionDecision::RequireHumanApproval { reason, .. } => {
        println!("⚠️ [HITL] PushToRemote requires human: {}", reason);
    }
    _ => {}
}

}

Описание архитектуры

Этот скрипт реализует концепцию «Зарабатываемой автономии». Вот как это работает:

  1. Семантический вес (risk_score): В отличие от обычной сложности кода, мы оцениваем опасность операции. Чтение файла имеет вес 0.5, а PushToRemote или rm -rf9.5. Это позволяет системе отличать безобидный рефакторинг от потенциально разрушительных действий.

  2. Динамический уровень автономии (autonomy_level): Уровень не фиксирован в конфиге. Он начинается с низкого значения (режим «Параноик»). По мере того как агент успешно выполняет задачи (получает положительную афферентацию), его trust_score растет, и система автоматически повышает уровень автономии.

  3. Жесткий сброс (Fail-Safe): Если агент совершает ошибку (возвращает success: false), его доверие падает на 60% мгновенно. Это имитирует человеческую реакцию: после одной серьезной ошибки вы перестаете доверять коллеге «на автопилоте» и начинаете проверять каждый его шаг.

  4. Триггеры HITL (Human-in-the-Loop): Граница проходит по двум осям:

    • Ось Риска: Операции с весом > 8.0 (продакшен, удаление) никогда не выполняются автоматически, независимо от доверия.

    • Ось Доверия: При низком уровне доверия даже средние риски (вес > 1.0) требуют подтверждения.

Почему это лучше простого permission_policy="auto"?

Обычный auto бинарен: либо всё можно, либо всё нельзя. Эта система контекстуальна. Она позволяет агенту быть сверхэффективным в безопасных задачах

Sign up to leave a comment.

Articles