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 绑定到电网的一个具体节点,赋予其:
- 位置:明确绑定到母线、变电站或设备
- 连接:通过电网拓扑与其他 Agent 通信
- 状态:感知并维护所在节点的运行状态
- 行为:能在权限范围内对所在节点执行控制
- 边界:物理与逻辑的权限边界由内核强制
Agent 节点模型
节点属性
每个 Agent 节点包含以下内核维护的属性:
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
node_id | NodeId | 绑定的电气节点 ID | BusId(1) / DeviceId(“tr-001”) |
node_type | NodeType | 节点类型 | Bus / Device / Switch / Substation |
electrical_position | ElectricalPos | 电气位置(电压等级/区域) | 110kV / 华东区 |
jurisdiction | Jurisdiction | 管辖范围(设备集合) | [Breaker-1, Breaker-2, Tr-1] |
permissions | PermissionSet | 权限位掩码 | READ | WRITE | CONTROL |
priority | Priority | 调度优先级 | Normal / High / Critical |
liveness | Liveness | 生命周期状态 | 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(®istry);
// 注册并激活
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 调整发电出力时:
- Agent A 通过拓扑感知到母线 2、3 是下游节点
- Agent A 发布
GenerationChange事件到电气岛 - Agent B(变压器运维)感知到潮流变化,调整分接头
- 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 对比
| 维度 | 通用 AgentOS | EnerOS 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μs | 100万次/秒 |
| 节点间消息传递 | < 100μs | 10万消息/秒 |
| 管辖范围广播 | < 500μs | - |
| 电气岛发布 | < 1ms | - |
| 权限校验 | < 1μs | 1000万次/秒 |
| Agent 上下文切换 | < 10μs | - |
限制与权衡
| 权衡点 | 说明 | 缓解策略 |
|---|---|---|
| 节点耦合 | Agent 与节点强耦合,迁移困难 | 支持重新绑定 API |
| 单点责任 | 一个节点只能绑定一个主控 Agent | 支持备份 Agent 热备 |
| 拓扑依赖 | 拓扑变更影响 Agent 生命周期 | 自动发现机制平滑过渡 |
| 调试复杂 | 跨节点协作链路难追踪 | 内置分布式追踪 |
下一步
- Power-Native First - 电力原生优先设计哲学
- 约束即法律 - 权限边界的底层保障
- 多智能体协作 - Agent 协作机制详解
- 实时确定性 - 节点调度的实时保证