Skip to content
Embabel 文档版本 0.3.0-SNAPSHOT 源快照 d092338d 更新于 2026-09-29

49 · 附录:规划模块(Planning Module)

摘要(Abstract)

用于规划与调度的低层模块,供 Embabel Agent Platform 使用。

A* GOAP 规划算法概览

A* GOAP(Goal-Oriented Action Planning,目标导向动作规划)规划器是 A* 搜索算法的一种实现, 专门用于规划达成指定目标的动作序列。 该算法通过探索潜在的动作序列并最小化总体成本,高效地从初始世界状态找到通往目标状态的最优路径。

核心算法组件

  • A* 搜索:通过探索状态空间找出最优动作序列;
  • 前向规划(Forward Planning):从起始状态向目标模拟动作;
  • 后向规划(Backward Planning):从目标反向推导,以优化计划;
  • 计划仿真(Plan Simulation):验证计划确实达成了预期目标;
  • 剪枝(Pruning):移除无关动作,产出高效的计划;
  • 未知条件处理(Unknown Condition Handling):管理不完整的世界状态信息。

A* 搜索算法

A* 搜索算法通过维护以下结构运作:

  • Open List(开放列表):待探索状态的优先队列,按 f-score 排序;
  • Closed Set(封闭集):已完全探索过的状态;
  • g-score:到达某状态已累积的成本;
  • h-score:到达目标剩余成本的启发式估计;
  • f-score:总估计成本(g-score + h-score)。

处理流程(Process Flow)

1. 初始化

  • 把起始状态放入开放列表;
  • 将其 g-score 置为 0,并计算其 h-score。

2. 主循环

当开放列表非空时:

  • 从开放列表选出 f-score 最低的状态;
  • 如果该状态满足目标,构造并返回计划;
  • 否则把该状态标记为已处理(加入封闭集);
  • 对每一个适用动作,生成下一个状态;若它优于已有路径,则加入开放列表。

3. 路径重建

找到目标状态时,沿着前驱指针回溯重建路径,产出一个由动作序列构成的计划。

参考:AStarGoapPlanner.kt → AStarGoapPlanner:planToGoalFrom:

前向与后向规划的优化

规划器实现了两趟(two-pass)优化策略,用来消除不必要的动作。

后向规划优化

这一趟从目标条件反向推导,只保留对达成目标有贡献的动作。

参考:AStarGoapPlanner.kt → _backwardPlanningOptimization

前向规划优化

这一趟从起始状态模拟整个计划,移除那些并未朝目标推进的动作。

参考:AStarGoapPlanner.kt → _forwardPlanningOptimization

计划仿真(Plan Simulation)

计划仿真按顺序执行动作,以验证计划的正确性。

参考:函数 simulatePlan(startState, actions)

对规划系统剪枝(Pruning Planning Systems)

规划器可以对整个规划系统剪枝,移除无关动作:

java
PlanningSystem prune(PlanningSystem planningSystem) {
    // 取出通往所有目标的所有计划
    List<Plan> allPlans = plansToGoals(planningSystem);
    // 只保留至少出现在一个计划中的动作
    Set<Action> filteredActions = planningSystem.getActions().stream()
            .filter(action -> allPlans.stream()
                    .anyMatch(plan -> plan.getActions().contains(action)))
            .collect(Collectors.toSet());
    return planningSystem.withActions(filteredActions);
}

启发函数(Heuristic Function)

启发函数用于估计"从给定状态到达目标的成本"。

完整规划流程

  • 用起始状态、动作与目标条件进行初始化;
  • 运行 A* 搜索,找出初始动作序列;
  • 应用后向规划优化消除不必要的动作;
  • 应用前向规划优化进一步精炼计划;
  • 通过仿真验证计划;
  • 返回优化后的动作序列;若不存在合法计划则返回 null。

Agent 剪枝流程(Agent Pruning Process)

当为特定目标对某个 Agent 剪枝时:

  • 识别规划系统中所有已知条件;
  • 基于输入条件设置初始状态;
  • 找出通往每个目标的所有可能计划;
  • 只保留至少出现在一个计划中的动作;
  • 用剪枝后的动作集合创建新的 Agent。

这种周全的做法确保 Agent 只包含达成其既定目标所必需的动作, 从而提升效率,并防止动作在不同 Agent 之间"泄漏"。

A* GOAP 规划中的"进展判定"逻辑

方法 forwardPlanningOptimization 中的进展判定逻辑是 A* GOAP 算法前向规划优化的关键部分。 该逻辑确保只有真正让状态朝目标推进的动作才会被纳入最终计划。

进展判定表达式

java
boolean progressMade = !nextState.equals(currentState) &&
        action.getEffects().entrySet().stream().anyMatch(entry -> {
            String key = entry.getKey();
            Object value = entry.getValue();
            return goal.getPreconditions().containsKey(key) &&
                    !Objects.equals(currentState.get(key), goal.getPreconditions().get(key)) &&
                    (Objects.equals(value, goal.getPreconditions().get(key)) || !nextState.containsKey(key));
        });

逐项解释

该表达式仅当动作对达成目标状态产生了有意义的推进时才为 true。逐项拆解:

  • nextState != currentState —— 验证该动作确实改变了世界状态,防止把无效果的动作算进来。
  • action.effects.any { ... } —— 检查该动作产生的每一个效果;只要有任意一个效果满足内部条件就返回 true。
  • goal.preconditions.containsKey(key) —— 确保只考虑与目标所要求的条件相关的效果,忽略那些修改与目标无关条件的动作。
  • currentState[key] != goal.preconditions[key] —— 检查当前条件值与目标要求是否不同;只有当我们在改变一个"需要被改变"的条件时才算作进展。
  • (value == goal.preconditions[key] || key not in nextState) —— 检查动作产生进展的两种可能方式:
    • value == goal.preconditions[key]:动作把该条件改成与目标要求完全一致 —— 这是对目标达成的直接推进;
    • key not in nextState:动作把该条件从状态中彻底移除 —— 如果该条件此前处于不正确的状态,这被视为进展; 它也允许"清除障碍或重置条件"这类动作。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。