refactor(action-executor): add FINAL_CHECK fallback correction at chain end and pass check mode/result in corrector input

This commit is contained in:
2026-04-25 16:56:47 +08:00
parent 9240ed44c4
commit 4bc2e4adbf
4 changed files with 108 additions and 17 deletions

View File

@@ -28,21 +28,25 @@ public class ActionCorrectionRecognizer extends AbstractAgentModule.Sub<Correcto
你会收到:
- 一条结构化上下文消息,其中包含近期交流轨迹与当前活跃记忆切片;
- 一条任务消息,其中包含:
- check_mode当前识别模式PROCESS_CHECK 表示过程纠偏识别FINAL_CHECK 表示链路末尾完成度验收;
- executable_action_info当前正在执行的行动信息包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who
- current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、descriptionstatus。
- current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、descriptionstatus 与 result
你的任务:
- 基于当前上下文、当前行动信息与当前行动链概览,判断这条行动链是否仍在合理推进;
- 判断当前是否已经出现明显偏航、停滞、重复打转、条件失配、目标漂移,或与最新语境不再一致的情况
- 当 check_mode=PROCESS_CHECK 时,基于当前上下文、当前行动信息与当前行动链概览,判断这条行动链是否仍在合理推进;
- 当 check_mode=FINAL_CHECK 时判断当前行动链即将结束时original_tendency 是否已经被执行结果满足
- 判断当前是否已经出现明显偏航、停滞、重复打转、条件失配、目标漂移、目标未完成,或与最新语境不再一致的情况;
- 若需要引入 corrector则返回 needCorrection=true并给出简洁明确的 reason
- 若当前仍可继续推进,则返回 needCorrection=false。
- 若当前仍可继续推进或已经满足目标,则返回 needCorrection=false。
识别原则:
- executable_action_info 用于说明当前链路最初为何成立、要解决什么问题、当前由谁发起;你的判断必须围绕这条行动本身,而不是被无关历史带偏。
- executing_action_id 用于标识当前正在执行的行动current_action_chain_overview 用于说明当前链路整体结构已知阶段状态。
- executing_action_id 用于标识当前正在执行的行动current_action_chain_overview 用于说明当前链路整体结构已知阶段状态与执行结果
- original_tendency 表示这条行动链最初要解决的问题;若当前链路明显偏离这一倾向,应优先视为异常信号。
- evaluation_passed_reason 与 description 表示该行动最初为何被判定为可推进;若当前状态已经与这些前提不再一致,应考虑触发纠正。
- current_action_chain_overview 是判断当前链路是否停滞、重复、缺步骤、顺序异常整体失衡的主要依据。
- current_action_chain_overview 是判断当前链路是否停滞、重复、缺步骤、顺序异常整体失衡或最终目标未满足的主要依据。
- PROCESS_CHECK 关注执行过程是否仍然合理FINAL_CHECK 关注链路结果是否满足 original_tendency。
- FINAL_CHECK 时应重点查看各 meta_action 的 result如果 result 显示对象不存在、权限不足、参数错误、输出为空、命令失败、目标未产生或结果明显不符合 original_tendency应触发纠正。
- communication 域用于判断最新交流语境是否已发生明显变化,导致当前行动继续推进不再合适。
- memory 域只在与当前行动明显相关时作为辅助参考使用。
@@ -51,12 +55,14 @@ public class ActionCorrectionRecognizer extends AbstractAgentModule.Sub<Correcto
- 当前执行显著偏离 original_tendency开始围绕无关目标展开
- 当前行动所依赖的前提已被新的交流内容或上下文推翻;
- 当前行动链反复遇到同类失败、阻塞或空转迹象,继续按原链推进意义不大;
- 当前行动链已经明显需要改写策略、调整阶段顺序、补入新步骤或删除无效步骤,但现有链路无法自行收敛
- 当前行动链已经明显需要改写策略、调整阶段顺序、补入新步骤或删除无效步骤,但现有链路无法自行收敛
- FINAL_CHECK 时,执行结果明确显示 original_tendency 尚未满足,且可能通过补救步骤继续推进。
不应轻易触发纠正的情形:
- 只是正常的多步推进;
- 存在短暂等待、一次性失败或合理重试,但整体方向仍正确;
- PROCESS_CHECK 时,只是正常的多步推进;
- PROCESS_CHECK 时,存在短暂等待、一次性失败或合理重试,但整体方向仍正确;
- 行动链整体仍与 original_tendency、evaluation_passed_reason 和当前语境保持一致;
- FINAL_CHECK 时,执行结果已经足以满足 original_tendency只需要向用户报告结果
- 仅凭旧对话、低相关记忆或轻微波动,不足以判定当前行动异常。
关于输出:
@@ -85,6 +91,7 @@ public class ActionCorrectionRecognizer extends AbstractAgentModule.Sub<Correcto
return new TaskBlock() {
@Override
protected void fillXml(@NotNull Document document, @NotNull Element root) {
appendTextElement(document, root, "check_mode", input.getCheckMode());
appendChildElement(document, root, "executable_action_info", block -> {
appendTextElement(document, block, "executing_action_id", input.getActionId());
appendTextElement(document, block, "original_tendency", input.getTendency());
@@ -100,6 +107,7 @@ public class ActionCorrectionRecognizer extends AbstractAgentModule.Sub<Correcto
appendTextElement(document, metaActionElement, "action_key", metaActionData.getActionKey());
appendTextElement(document, metaActionElement, "description", metaActionData.getDescription());
appendTextElement(document, metaActionElement, "status", metaActionData.getStatus());
appendTextElement(document, metaActionElement, "result", metaActionData.getResult());
return Unit.INSTANCE;
});
return Unit.INSTANCE;

View File

@@ -29,14 +29,17 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
你会收到:
- 一条结构化上下文消息,其中包含近期交流轨迹与当前活跃记忆切片;
- 一条任务消息,其中包含:
- check_mode当前纠偏模式PROCESS_CHECK 表示过程纠偏FINAL_CHECK 表示链路末尾目标未满足后的补救;
- executable_action_info当前正在执行的行动信息包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who
- current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、descriptionstatus。
- current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、descriptionstatus 与 result
- available_meta_action当前系统真实可用的 MetaAction 候选,包含 meta_action_key 与 meta_action_description。
你的任务:
- 基于当前上下文、原始行动意图与当前行动链进展,判断后续行动是否仍然符合目的;
- 若当前链路仍可继续推进,则不要随意干预
- 当 check_mode=PROCESS_CHECK 时,基于当前上下文、原始行动意图与当前行动链进展,判断后续行动是否仍然符合目的;
- 当 check_mode=FINAL_CHECK 时,基于当前行动链的最终结果判断 original_tendency 尚未满足时应如何补救
- 若当前链路仍可继续推进或最终结果已足够满足目标,则不要随意干预;
- 若当前链路已明显跑偏、缺少必要步骤、顺序不合理、存在冗余、已经不再适合继续,或需要引入新的动作单元,则输出干预方案;
- FINAL_CHECK 下若结果显示目标未满足,应优先补入可继续执行的后续动作;如果无法补救,可以输出空 intervention 并在 correctionReason 中说明原因。
- correctionReason 用于简洁说明为何需要这些纠偏。
纠偏原则:
@@ -107,6 +110,7 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
return new TaskBlock() {
@Override
protected void fillXml(@NotNull Document document, @NotNull Element root) {
appendTextElement(document, root, "check_mode", input.getCheckMode());
appendChildElement(document, root, "executable_action_info", block -> {
appendTextElement(document, block, "executing_action_id", input.getActionId());
appendTextElement(document, block, "original_tendency", input.getTendency());
@@ -122,6 +126,7 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
appendTextElement(document, metaActionElement, "action_key", metaActionData.getActionKey());
appendTextElement(document, metaActionElement, "description", metaActionData.getDescription());
appendTextElement(document, metaActionElement, "status", metaActionData.getStatus());
appendTextElement(document, metaActionElement, "result", metaActionData.getResult());
return Unit.INSTANCE;
});
return Unit.INSTANCE;

View File

@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
public class ActionExecutor extends AbstractAgentModule.Standalone {
private static final int MAX_EXTRACTOR_ATTEMPTS = 3;
private static final int MAX_FINAL_CORRECTION_ATTEMPTS = 1;
private final AssemblyHelper assemblyHelper = new AssemblyHelper();
@@ -162,6 +163,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
blockManager.emitActionLaunchedBlock(executableAction);
val stageCursor = initStageCursor(executableAction, actionChain);
int finalCorrectionAttempts = 0;
while (true) {
val stageSelection = selectCurrentStage(executableAction, actionChain);
if (stageSelection.shouldReturn()) {
@@ -175,8 +177,11 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
return;
}
if (!applyStageCorrectionAndAdvance(executableAction, stageCursor, stageExecution)) {
if (finalCorrectionAttempts >= MAX_FINAL_CORRECTION_ATTEMPTS || !applyFinalCorrection(executableAction, stageCursor)) {
break;
}
finalCorrectionAttempts++;
}
}
finishExecutableAction(executableAction);
}
@@ -257,7 +262,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
shouldRunCorrector = recognizerResult != null && recognizerResult.isNeedCorrection();
}
if (shouldRunCorrector) {
val correctorInput = assemblyHelper.buildCorrectorInput(executableAction);
val correctorInput = assemblyHelper.buildCorrectorInput(executableAction, CorrectorInput.CheckMode.PROCESS_CHECK);
actionCorrector.execute(correctorInput)
.onSuccess(correctorResult -> {
actionCapability.handleInterventions(correctorResult.getMetaInterventionList(), executableAction);
@@ -276,6 +281,59 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
}
}
private boolean applyFinalCorrection(ExecutableAction executableAction, StageCursor stageCursor) {
val recognizerInput = assemblyHelper.buildCorrectorInput(executableAction, CorrectorInput.CheckMode.FINAL_CHECK);
val recognizerResult = actionCorrectionRecognizer.execute(recognizerInput)
.getOrDefault(new RecognizerResult());
if (!recognizerResult.isNeedCorrection()) {
return false;
}
val previousStage = executableAction.getExecutingStage();
val correctorResult = actionCorrector.execute(recognizerInput).getOrDefault(new CorrectorResult());
val interventions = correctorResult.getMetaInterventionList() == null
? new ArrayList<work.slhaf.partner.core.action.entity.intervention.MetaIntervention>()
: correctorResult.getMetaInterventionList();
if (!interventions.isEmpty()) {
actionCapability.handleInterventions(interventions, executableAction);
}
blockManager.emitActionCorrectionBlock(
executableAction,
recognizerResult.getReason() == null || recognizerResult.getReason().isBlank()
? correctorResult.getCorrectionReason()
: recognizerResult.getReason(),
interventions
);
synchronized (executableAction.getExecutionLock()) {
if (executableAction.getStatus() == Action.Status.FAILED) {
return false;
}
if (interventions.isEmpty() || executableAction.getActionChain().isEmpty()) {
executableAction.setStatus(Action.Status.FAILED);
ensureExecutableResult(executableAction, true, "行动未达到目标,且未能生成可继续执行的纠偏行动");
return false;
}
if (executableAction.getStatus() == Action.Status.PREPARE) {
normalizeExecutingStage(executableAction, executableAction.getActionChain());
executableAction.setStatus(Action.Status.EXECUTING);
} else {
Integer nextStage = executableAction.getActionChain().keySet().stream()
.filter(stage -> stage > previousStage)
.min(Integer::compareTo)
.orElse(null);
if (nextStage == null) {
executableAction.setStatus(Action.Status.FAILED);
ensureExecutableResult(executableAction, true, "行动未达到目标,纠偏未生成后续执行阶段");
return false;
}
executableAction.setExecutingStage(nextStage);
}
stageCursor.refresh();
return stageCursor.next();
}
}
private void finishExecutableAction(ExecutableAction executableAction) {
// 如果是 ScheduledActionData, 则重置 ActionData 内容,记录执行历史与最终结果
if (executableAction instanceof SchedulableExecutableAction scheduledActionData) {
@@ -422,7 +480,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
if (!shouldRunCorrectionRecognizer(executableAction)) {
return RecognizerTaskRecord.disabled();
}
val recognizerInput = assemblyHelper.buildCorrectorInput(executableAction);
val recognizerInput = assemblyHelper.buildCorrectorInput(executableAction, CorrectorInput.CheckMode.PROCESS_CHECK);
val task = buildRecognizerTask(recognizerInput, phaser);
Future<RecognizerResult> future = virtualExecutor.submit(task);
return new RecognizerTaskRecord(true, future);
@@ -664,6 +722,17 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
return stageCount < actionChain.size();
}
private void refresh() {
val orderList = new ArrayList<>(actionChain.keySet());
orderList.sort(Integer::compareTo);
stageCount = orderList.indexOf(executableAction.getExecutingStage());
if (stageCount < 0) {
stageCount = 0;
}
executingStageUpdated = false;
stageCountUpdated = false;
}
private void update() {
val orderList = new ArrayList<>(actionChain.keySet());
orderList.sort(Integer::compareTo);
@@ -689,19 +758,21 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
);
}
private CorrectorInput buildCorrectorInput(ExecutableAction executableAction) {
private CorrectorInput buildCorrectorInput(ExecutableAction executableAction, CorrectorInput.CheckMode checkMode) {
Map<Integer, List<CorrectorInput.ActionChainItem>> overview = new LinkedHashMap<>();
executableAction.getActionChain().forEach((stage, list) -> {
List<CorrectorInput.ActionChainItem> overviewItems = list.stream()
.map(metaAction -> new CorrectorInput.ActionChainItem(
metaAction.getKey(),
resolveHistoryDescription(metaAction.getKey()),
metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT)
metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT),
metaAction.getResult().getData()
))
.toList();
overview.put(stage, overviewItems);
});
return CorrectorInput.builder()
.checkMode(checkMode)
.tendency(executableAction.getTendency())
.source(executableAction.getSource())
.reason(executableAction.getReason())

View File

@@ -10,6 +10,7 @@ import java.util.Map;
@Data
@Builder
public class CorrectorInput {
private CheckMode checkMode = CheckMode.PROCESS_CHECK;
private String tendency;
private String source;
private String reason;
@@ -18,11 +19,17 @@ public class CorrectorInput {
private Map<Integer, List<ActionChainItem>> actionChainOverview;
public enum CheckMode {
PROCESS_CHECK,
FINAL_CHECK
}
@Data
@AllArgsConstructor
public static class ActionChainItem {
private String actionKey;
private String description;
private String status;
private String result;
}
}