跳到主内容

Agent-as-Grid-Node

核心概念

Agent-as-Grid-Node

Agent-as-Grid-Node 是 EnerOS 的核心设计理念:每个 Agent 在逻辑上是电网中的一个节点,具备明确的电气位置、管辖范围、权限边界与生命周期。Agent 不是游离于电网之外的程序,而是电网拓扑的一等参与者,通过电网拓扑自然地与其他节点协作。

设计理念

传统 AgentOS 的局限

通用 AgentOS(如 AutoGen、LangGraph、CrewAI)将 Agent 视为纯粹的逻辑单元,与物理世界解耦。这种模型在电力场景下面临严重问题:

问题描述后果
无位置感Agent 不知道自己管哪个变电站决策无法落地
无拓扑感知Agent 之间通过预定义信道通信无法应对拓扑变化
无权限边界Agent 可任意操作任何设备安全风险高
无物理约束Agent 决策可能违反电气定律决策不可执行
无状态同步Agent 状态与电网状态脱节决策基于过时数据

Agent-as-Grid-Node 的解决思路

EnerOS 将每个 Agent 绑定到电网的一个具体节点,赋予其:

  1. 位置:明确绑定到母线、变电站或设备
  2. 连接:通过电网拓扑与其他 Agent 通信
  3. 状态:感知并维护所在节点的运行状态
  4. 行为:能在权限范围内对所在节点执行控制
  5. 边界:物理与逻辑的权限边界由内核强制

Agent 节点模型

节点属性

每个 Agent 节点包含以下内核维护的属性:

属性类型说明示例
node_idNodeId绑定的电气节点 IDBusId(1) / DeviceId(“tr-001”)
node_typeNodeType节点类型Bus / Device / Switch / Substation
electrical_positionElectricalPos电气位置(电压等级/区域)110kV / 华东区
jurisdictionJurisdiction管辖范围(设备集合)[Breaker-1, Breaker-2, Tr-1]
permissionsPermissionSet权限位掩码READ | WRITE | CONTROL
priorityPriority调度优先级Normal / High / Critical
livenessLiveness生命周期状态Init / Active / Paused / Dead
use eneros_agent::{Agent, AgentContext, AgentResult, NodeBinding, Permission};
use eneros_topology::{BusId, VoltageLevel, RegionId};

/// Agent 节点绑定信息(内核维护)
#[derive(Clone, Debug)]
pub struct NodeBinding {
    /// 绑定的电气节点 ID
    pub node_id: BusId,
    /// 节点类型
    pub node_type: NodeType,
    /// 电气位置
    pub electrical_position: ElectricalPosition,
    /// 管辖的设备集合
    pub jurisdiction: Vec<DeviceId>,
    /// 权限位掩码
    pub permissions: PermissionSet,
    /// 调度优先级
    pub priority: Priority,
}

/// 电气位置
#[derive(Clone, Debug)]
pub struct ElectricalPosition {
    pub voltage_level: VoltageLevel, // 500kV / 220kV / 110kV / 35kV / 10kV
    pub region: RegionId,             // 所属调度区域
    pub substation: Option<SubstationId>,
}

/// 权限位
bitflags::bitflags! {
    pub struct PermissionSet: u32 {
        const READ       = 0b0000_0001; // 读取节点状态
        const WRITE      = 0b0000_0010; // 写入节点属性
        const CONTROL    = 0b0000_0100; // 控制设备(开关、调压)
        const DISPATCH   = 0b0000_1000; // 调度发电出力
        const TRADE      = 0b0001_0000; // 参与电力交易
        const ISLAND     = 0b0010_0000; // 孤岛运行授权
        const EMERGENCY  = 0b0100_0000; // 紧急控制权限
    }
}

节点绑定示例

use eneros_agent::{AgentRegistry, NodeBinding, PermissionSet, Priority};

let mut registry = AgentRegistry::new();

// 创建一个绑定到母线 1 的调度 Agent
let binding = NodeBinding {
    node_id: BusId(1),
    node_type: NodeType::Bus,
    electrical_position: ElectricalPosition {
        voltage_level: VoltageLevel::Kv110,
        region: RegionId::from("east"),
        substation: Some(SubstationId::from("ss-001")),
    },
    jurisdiction: vec![
        DeviceId::from("gen-1"),
        DeviceId::from("gen-2"),
        DeviceId::from("tr-1"),
    ],
    permissions: PermissionSet::READ | PermissionSet::DISPATCH | PermissionSet::CONTROL,
    priority: Priority::High,
};

let agent = DispatchAgent::new(binding.clone());
registry.register("dispatch-east-1", agent, binding).await?;

Agent 类型与节点绑定

不同类型的 Agent 绑定到不同类型的电网节点:

Agent 类型节点类型典型绑定管辖范围权限
DispatchAgent发电母线电厂/风电场发电机组READ+DISPATCH
SelfHealingAgent开关/分段器配网开关馈线段READ+CONTROL+EMERGENCY
OperationAgent设备变压器/断路器单一设备READ+WRITE+CONTROL
EnergyAgent负荷母线工业园区/商业区负荷聚合READ+TRADE
TradingAgent区域根节点虚拟电厂区域资源READ+TRADE+DISPATCH
ProtectionAgent保护装置变电站保护保护区域READ+EMERGENCY
MonitoringAgent任意节点监测点测点集合READ

节点生命周期

Agent 节点遵循明确的生命周期,由内核统一管理:

   ┌─────────┐  register   ┌─────────┐  activate   ┌─────────┐
   │  Init   │ ──────────→ │ Pending │ ──────────→ │ Active  │
   └─────────┘             └─────────┘             └─────────┘

                                  ┌──────────────────────┤
                                  │ pause                │ error
                                  ▼                      ▼
                              ┌─────────┐           ┌─────────┐
                              │ Paused  │           │ Degraded│
                              └─────────┘           └─────────┘
                                  │                      │
                                  │ resume               │ recover
                                  └──────┬───────────────┘

                                     ┌─────────┐
                                     │ Active  │
                                     └─────────┘

                                         │ shutdown

                                     ┌─────────┐
                                     │  Dead   │
                                     └─────────┘
状态说明内核行为
Init创建未注册不分配资源
Pending已注册未激活分配资源,未调度
Active运行中正常调度,参与协作
Paused暂停保留状态,不调度
Degraded降级运行仅保留只读权限
Dead已终止释放资源,注销节点
use eneros_agent::{LifecycleEvent, LifecycleManager};

let lifecycle = LifecycleManager::new(&registry);

// 注册并激活
lifecycle.register("dispatch-east-1", agent).await?;
lifecycle.activate("dispatch-east-1").await?;

// 监听生命周期事件
while let Some(event) = lifecycle.events().recv().await {
    match event {
        LifecycleEvent::Activated { agent_id, node_id } => {
            log::info!("Agent {} 在节点 {} 上激活", agent_id, node_id);
        }
        LifecycleEvent::Paused { agent_id, reason } => {
            log::warn!("Agent {} 被暂停: {}", agent_id, reason);
        }
        LifecycleEvent::Degraded { agent_id, error } => {
            log::error!("Agent {} 降级: {:?}", agent_id, error);
        }
        LifecycleEvent::Terminated { agent_id } => {
            log::info!("Agent {} 已终止", agent_id);
        }
    }
}

节点间通信

拓扑感知通信

Agent 之间的通信不是通过预定义的 IP/端口,而是通过电网拓扑自动路由:

impl Agent for DispatchAgent {
    async fn run(&mut self, ctx: &mut AgentContext) -> AgentResult<()> {
        // 获取所在电气岛的邻居节点
        let neighbors = ctx.get_neighbors(self.node_id).await?;

        // 通过拓扑路径向下游 Agent 发送消息
        for neighbor in neighbors {
            if neighbor.is_load_bus() {
                ctx.send_to_node(
                    neighbor.node_id,
                    Message::LoadShed { amount_mw: 5.0 },
                ).await?;
            }
        }

        // 向管辖范围内的设备 Agent 广播
        ctx.broadcast_to_jurisdiction(
            self.binding.jurisdiction.clone(),
            Message::SetGeneration { target_mw: 80.0 },
        ).await?;

        Ok(())
    }
}

通信模式

EnerOS 支持四种节点间通信模式:

模式语义延迟适用场景
send_to_node点对点,单一接收者< 100μs直接协作
broadcast_to_jurisdiction广播到管辖设备< 500μs设备同步控制
publish_to_island发布到电气岛所有节点< 1ms岛级广播
request_response请求-响应,带超时< 5ms协商式协作
// 1. 点对点
let ack = ctx.send_to_node(
    BusId(2),
    Message::VoltageAdjust { target_pu: 1.0 },
).await?;

// 2. 广播到管辖范围
ctx.broadcast_to_jurisdiction(
    self.jurisdiction.clone(),
    Message::SyncState { timestamp: now!() },
).await?;

// 3. 电气岛发布
ctx.publish_to_island(
    self.node_id,
    Topic::FrequencyEvent { hz: 49.8 },
).await?;

// 4. 请求-响应
let response = ctx.request(
    BusId(3),
    Request::GetState,
    Duration::milliseconds(100),
).await?;

拓扑感知协作

单线协作示例

母线1 ─── 线路 ─── 母线2 ─── 变压器 ─── 母线3
  |                    |                    |
DispatchAgent A    OperationAgent B    EnergyAgent C

当 DispatchAgent A 调整发电出力时:

  1. Agent A 通过拓扑感知到母线 2、3 是下游节点
  2. Agent A 发布 GenerationChange 事件到电气岛
  3. Agent B(变压器运维)感知到潮流变化,调整分接头
  4. Agent C(负荷聚合)感知到电压变化,调整负荷分配
impl Agent for DispatchAgent {
    async fn run(&mut self, ctx: &mut AgentContext) -> AgentResult<()> {
        let target_mw = 80.0;

        // 1. 校验自身权限
        ctx.check_permission(Permission::DISPATCH)?;

        // 2. 通过拓扑获取下游节点
        let downstream = ctx.get_downstream_nodes(self.node_id).await?;

        // 3. 发布发电变更事件(拓扑感知广播)
        ctx.publish_to_island(
            self.node_id,
            Event::GenerationChange {
                bus: self.node_id,
                from_mw: self.current_output,
                to_mw: target_mw,
                timestamp: now!(),
            },
        ).await?;

        // 4. 执行发电出力调整
        ctx.set_node_generation(self.node_id, target_mw).await?;

        // 5. 等待下游 Agent 响应(带超时)
        let acks = ctx.wait_for_acks(
            downstream.iter().map(|n| n.node_id).collect(),
            Duration::seconds(1),
        ).await?;

        if acks.failed_count() > 0 {
            log::warn!("部分下游节点未确认: {:?}", acks.failures());
        }

        Ok(())
    }
}

多智能体故障自愈协作

     [F] 故障点

母线A ─── 断路器1 ─── 母线B ─── 断路器2 ─── 母线C
  |                              |                    |
SelfHealingAgent X           SelfHealingAgent Y   EnergyAgent Z

故障自愈流程:

impl Agent for SelfHealingAgent {
    async fn run(&mut self, ctx: &mut AgentContext) -> AgentResult<()> {
        // 监听故障事件
        let fault = ctx.wait_event::<FaultEvent>().await?;

        // 1. 定位故障段
        let fault_section = ctx.locate_fault(&fault).await?;

        // 2. 隔离故障:操作管辖范围内的断路器
        for breaker in self.jurisdiction.breakers_around(fault_section) {
            ctx.open_breaker(breaker).await?;
        }

        // 3. 通过拓扑感知非故障停电区
        let outaged = ctx.find_outaged_areas().await?;

        // 4. 协商上游 Agent 恢复供电
        for area in outaged {
            let upstream = ctx.find_upstream_sources(area).await?;
            for source_node in upstream {
                let restored = ctx.request(
                    source_node,
                    Request::RestoreSupply { area, load_mw: area.load_mw },
                    Duration::seconds(2),
                ).await?;

                if restored.is_ok() {
                    ctx.close_breaker(area.tie_breaker).await?;
                    break;
                }
            }
        }

        Ok(())
    }
}

与通用 AgentOS 对比

维度通用 AgentOSEnerOS Agent-as-Grid-Node
Agent 身份逻辑 ID电网节点 ID
通信方式预定义信道/IP拓扑感知路由
位置感绑定电气节点
权限边界应用层校验内核强制
状态来源自维护内核同步
协作触发显式调用拓扑事件驱动
故障感知外部通知拓扑变更即事件
决策可行性依赖应用校验内核约束保证
横向扩展手动配置拓扑自动发现
一致性模型最终一致拓扑强一致

权限边界

三层权限模型

EnerOS 通过三层权限模型保证 Agent 操作安全:

┌─────────────────────────────────────────┐
│ 1. 节点权限 (Node Permission)            │  ← Agent 绑定时声明
│   · READ / WRITE / CONTROL / DISPATCH   │
├─────────────────────────────────────────┤
│ 2. 管辖权限 (Jurisdiction)               │  ← 内核维护的设备集合
│   · 仅可操作 jurisdiction 内的设备        │
├─────────────────────────────────────────┤
│ 3. 约束权限 (Constraint)                 │  ← 物理约束强制
│   · 即使有权限,违反约束的操作也被拒绝    │
└─────────────────────────────────────────┘
// 权限校验示例
impl AgentContext {
    pub async fn open_breaker(&mut self, breaker_id: DeviceId) -> AgentResult<()> {
        // 1. 节点权限校验
        if !self.binding.permissions.contains(Permission::CONTROL) {
            return Err(AgentError::PermissionDenied("缺少 CONTROL 权限"));
        }

        // 2. 管辖权限校验
        if !self.binding.jurisdiction.contains(&breaker_id) {
            return Err(AgentError::OutOfJurisdiction(breaker_id));
        }

        // 3. 约束校验(内核自动)
        let command = Command::OpenBreaker(breaker_id);
        match self.syscall(ExecuteCommand(command)).await? {
            ExecuteResult::Executed => Ok(()),
            ExecuteResult::Projected(_) => Err(AgentError::CommandProjected),
            ExecuteResult::Rejected(r) => Err(AgentError::ConstraintRejected(r)),
        }
    }
}

节点发现与自动注册

EnerOS 支持基于拓扑的 Agent 自动发现与注册:

use eneros_agent::{AutoDiscovery, AgentFactory};

let discovery = AutoDiscovery::new(&network, &mut registry);

// 监听拓扑变更,自动部署 Agent
discovery.on_new_bus(move |bus_id, bus_info| {
    if bus_info.has_generator() {
        // 新增发电母线 -> 部署 DispatchAgent
        let agent = DispatchAgent::new(NodeBinding::for_bus(bus_id));
        Some(Box::new(agent))
    } else if bus_info.has_load() {
        // 新增负荷母线 -> 部署 EnergyAgent
        let agent = EnergyAgent::new(NodeBinding::for_bus(bus_id));
        Some(Box::new(agent))
    } else {
        None
    }
}).await?;

// 拓扑变更触发 Agent 自动注册/注销
discovery.start().await?;

性能指标

操作延迟吞吐
节点绑定< 1ms-
拓扑感知邻居查询< 10μs100万次/秒
节点间消息传递< 100μs10万消息/秒
管辖范围广播< 500μs-
电气岛发布< 1ms-
权限校验< 1μs1000万次/秒
Agent 上下文切换< 10μs-

限制与权衡

权衡点说明缓解策略
节点耦合Agent 与节点强耦合,迁移困难支持重新绑定 API
单点责任一个节点只能绑定一个主控 Agent支持备份 Agent 热备
拓扑依赖拓扑变更影响 Agent 生命周期自动发现机制平滑过渡
调试复杂跨节点协作链路难追踪内置分布式追踪

下一步