From 281984bb054b5a569ad8524b53dd424673713867 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Thu, 16 Apr 2026 21:38:11 +0800 Subject: [PATCH] feat(action): redefine structure of evaluator result to support json schema of openai sdk, and create system prompt for sub-modules of ActionPlanner --- .../module/action/planner/ActionPlanner.java | 50 ++++++++--------- .../planner/evaluator/ActionEvaluator.java | 53 +++++++++++++++++++ .../evaluator/entity/EvaluatorResult.java | 30 +++++++++-- .../planner/extractor/ActionExtractor.java | 26 +++++++++ 4 files changed, 128 insertions(+), 31 deletions(-) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/ActionPlanner.java b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/ActionPlanner.java index 992e80a0..25b71976 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/ActionPlanner.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/ActionPlanner.java @@ -71,9 +71,7 @@ public class ActionPlanner extends AbstractAgentModule.Running result = actionExtractor.execute(input) - .onFailure(exp -> { - ExceptionReporterHandler.INSTANCE.report(exp, ContextExceptionReporter.REPORTER_NAME); - }); + .onFailure(exp -> ExceptionReporterHandler.INSTANCE.report(exp, ContextExceptionReporter.REPORTER_NAME)); if (result.exceptionOrNull() != null) { return; } @@ -82,17 +80,16 @@ public class ActionPlanner extends AbstractAgentModule.Running tendencies, String input) { - input = trimInput(input); + private void appendTendencyBlock(List tendencies) { String datetime = ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); cognitionCapability.contextWorkspace().register(new ContextBlock( buildTendenciesEvaluatingFullBlock(tendencies), - buildTendenciesEvaluatingCompactBlock(tendencies, datetime, input), - buildTendenciesEvaluatingAbstractBlock(tendencies, datetime, input), + buildTendenciesEvaluatingCompactBlock(tendencies, datetime), + buildTendenciesEvaluatingAbstractBlock(tendencies, datetime), Set.of(ContextBlock.FocusedDomain.ACTION), 60, 18, @@ -100,25 +97,24 @@ public class ActionPlanner extends AbstractAgentModule.Running tendencies, String datetime, String input) { + private @NotNull BlockContent buildTendenciesEvaluatingAbstractBlock(List tendencies, String datetime) { return new BlockContent(TENDENCIES_EVALUATING_BLOCK_NAME, getModuleName(), BlockContent.Urgency.HIGH) { @Override protected void fillXml(@NotNull Document document, @NotNull Element root) { appendTextElement(document, root, "datetime", datetime); - appendTextElement(document, root, "related_input", input); appendTextElement(document, root, "abstract", "There are " + tendencies.size() + " related tendencies in evaluating."); } }; } - private @NotNull BlockContent buildTendenciesEvaluatingCompactBlock(List tendencies, String datetime, String input) { + private @NotNull BlockContent buildTendenciesEvaluatingCompactBlock(List tendencies, String datetime) { return new BlockContent(TENDENCIES_EVALUATING_BLOCK_NAME, getModuleName(), BlockContent.Urgency.HIGH) { @Override protected void fillXml(@NotNull Document document, @NotNull Element root) { int size = tendencies.size(); boolean num = size > 3; appendTextElement(document, root, "datetime", datetime); - appendTextElement(document, root, "related_input", input); + appendTextElement(document, root, "state", "Partner is considering whether to do these"); appendTextElement(document, root, "tendencies_count", size); appendListElement(document, root, num ? "tendencies_truncated" : "tendencies", "tendency", num ? tendencies.subList(0, 3) : tendencies); } @@ -126,10 +122,11 @@ public class ActionPlanner extends AbstractAgentModule.Running tendencies) { - return new CommunicationBlockContent(TENDENCIES_EVALUATING_BLOCK_NAME, getModuleName(), BlockContent.Urgency.HIGH, CommunicationBlockContent.Projection.SUPPLY) { + return new BlockContent(TENDENCIES_EVALUATING_BLOCK_NAME, getModuleName(), BlockContent.Urgency.HIGH) { @Override protected void fillXml(@NotNull Document document, @NotNull Element root) { - appendRepeatedElements(document, root, "tendency", tendencies); + appendTextElement(document, root, "state", "Partner is considering whether to do these"); + appendListElement(document, root, "tendencies", "tendency", tendencies); } }; } @@ -216,20 +213,19 @@ public class ActionPlanner extends AbstractAgentModule.Running> primaryActionChain = evaluatorResult.getPrimaryActionChain(); + Map> primaryActionChain = evaluatorResult.getPrimaryActionChainAsMap(); if (primaryActionChain == null || primaryActionChain.isEmpty()) { return; } @@ -253,10 +249,10 @@ public class ActionPlanner extends AbstractAgentModule.Running new ImmediateExecutableAction( evaluatorResult.getTendency(), @@ -381,7 +377,7 @@ public class ActionPlanner extends AbstractAgentModule.Running> getActionChain(EvaluatorResult evaluatorResult) { Map> actionChain = new HashMap<>(); - Map> primaryActionChain = evaluatorResult.getPrimaryActionChain(); + Map> primaryActionChain = evaluatorResult.getPrimaryActionChainAsMap(); if (!fixDependencies(primaryActionChain)) { return null; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/ActionEvaluator.java b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/ActionEvaluator.java index 7113fef3..97391605 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/ActionEvaluator.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/ActionEvaluator.java @@ -25,6 +25,53 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; public class ActionEvaluator extends AbstractAgentModule.Sub> implements ActivateModel { + private static final String MODULE_PROMPT = """ + 你负责评估单条行动倾向,并判断它是否值得进入后续行动链。 + + 你会收到: + - 一条结构化上下文消息,其中可能包含当前活跃的行动相关状态、近期交流轨迹、认知相关上下文、以及当前活跃记忆切片; + - 一组 ,表示当前可用的 MetaAction 候选; + - 一条最新的 user message,其内容就是当前需要评估的单条 tendency。 + + 你的任务: + - 判断该 tendency 是否成立、是否值得推进; + - 判断它更适合立即执行,还是先进入规划; + - 判断是否需要先向用户确认; + - 若可推进,则基于 available_meta_actions 生成 primaryActionChain; + - 若当前 tendency 与某个待处理 pending 明确对应,且本轮已完成承接或推进,应正确填写 resolvedPending; + - 若当前 tendency 明确包含可调度语义,再填写 scheduleData。 + + 评估原则: + - 结合上下文理解当前 tendency 与近期交流、当前行动状态、活跃记忆之间的关系。 + - 若 tendency 与已有正在执行、等待确认、或已明确覆盖的行动完全等价,通常不应重复建立新的行动链。 + - 若 tendency 是对已有待确认行动的确认、拒绝、补充条件、修改要求或继续推进,则应优先视为对原有行动状态的承接,而不是无关新任务。 + - 若 action 相关上下文中存在等待确认的 block,且当前 tendency 明显与其相关,则必须显式承接这一点,不要因为其已存在于上下文中而省略。 + - 只有在 tendency 明确具有可执行意义时,才返回 ok=true。 + - 若 tendency 更适合直接交流回应,或尚不足以形成行动推进,则返回 ok=false。 + - primaryActionChain 中只能使用 available_meta_actions 内出现的 action_key,不要编造不存在的动作。 + - 不要输出完整执行细节、自然语言计划正文或额外解释,只输出 EvaluatorResult 对应结构。 + + 关于字段: + - ok 表示该 tendency 是否值得进入后续行动推进。 + - needConfirm 表示在真正推进前是否必须先得到用户确认。 + - type: + - IMMEDIATE: 可直接进入即时执行链; + - PLANNING: 需要先形成或进入规划链,再决定后续执行。 + - primaryActionChain 表示按 order 分组的候选动作链,每个元素包含: + - order: 执行顺序 + - actionKeys: 该顺序下的 action_key 列表 + - reason 用于说明你为何做出该判断,应简洁明确。 + - description 用于概括本次行动评估结果,应能帮助后续模块快速理解该 tendency 的推进方向。 + - scheduleData 仅在该 tendency 明确包含可调度语义时填写;否则留空。 + - scheduleData.type: 一次性计划或周期性计划 + - scheduleData.content: 符合 Quartz 标准的 Cron 表达式 + - resolvedPending 仅在你能明确判断当前 tendency 已承接某个 pending block 时填写;否则留空。 + - 当 ok=false 时,type、primaryActionChain、scheduleData、resolvedPending 通常应留空或保持无效默认值,不要强行填充。 + + 输出要求: + - 严格按照 EvaluatorResult 对应结构输出。 + - 不要输出结构之外的解释、注释或额外文本。 + """; @InjectCapability private ActionCapability actionCapability; @@ -107,6 +154,12 @@ public class ActionEvaluator extends AbstractAgentModule.Sub modulePrompt() { + return List.of(new Message(Message.Character.SYSTEM, MODULE_PROMPT)); + } + @NotNull @Override public String modelKey() { diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/entity/EvaluatorResult.java b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/entity/EvaluatorResult.java index a5fc130c..c9c0e495 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/entity/EvaluatorResult.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/evaluator/entity/EvaluatorResult.java @@ -1,10 +1,12 @@ package work.slhaf.partner.module.action.planner.evaluator.entity; import lombok.Data; -import work.slhaf.partner.core.action.entity.SchedulableExecutableAction; +import work.slhaf.partner.core.action.entity.Schedulable; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Data public class EvaluatorResult { @@ -12,9 +14,8 @@ public class EvaluatorResult { private boolean needConfirm; private ResolvedPending resolvedPending; private ActionType type; - private String scheduleContent; - private SchedulableExecutableAction.ScheduleType scheduleType; - private Map> primaryActionChain; + private ScheduleData scheduleData; + private List primaryActionChain; private String tendency; private String reason; private String description; @@ -28,4 +29,25 @@ public class EvaluatorResult { private String blockName; private String source; } + + public Map> getPrimaryActionChainAsMap() { + return primaryActionChain.stream().collect(Collectors.toMap( + ChainElement::getOrder, + ChainElement::getActionKeys, + (oldValue, newValue) -> newValue, + LinkedHashMap::new + )); + } + + @Data + public static class ScheduleData { + private String content; + private Schedulable.ScheduleType type; + } + + @Data + public static class ChainElement { + private Integer order; + private List actionKeys; + } } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/extractor/ActionExtractor.java b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/extractor/ActionExtractor.java index 5063fb35..8c81ccd1 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/extractor/ActionExtractor.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/action/planner/extractor/ActionExtractor.java @@ -16,6 +16,26 @@ import java.util.List; public class ActionExtractor extends AbstractAgentModule.Sub> implements ActivateModel { + private static final String MODULE_PROMPT = """ + 你负责从当前输入中提取可能的行动倾向,供后续模块继续评估。 + + 你会收到: + - 一条结构化上下文消息,主要包含 communication 域与 action 域内容; + - 一条最新输入,作为本轮重点分析对象。 + + 规则: + - communication 域主要用于理解当前会话语境、主题延续与用户意图。 + - action 域主要用于判断相关行动是否已经在执行、等待确认,或已被覆盖。 + - 只提取“可能值得进入后续评估的行动倾向”,不要输出完整行动计划、执行步骤或工具细节。 + - 若某个倾向已经明显处于执行中,且当前输入没有带来新的推进信息、修正信息或条件变化,应避免重复提出。 + - 若 action 域中存在等待确认的 block,且当前输入与其相关,则必须提取出对应的行动倾向;不要因为其已存在于上下文中而省略。 + - 若当前输入没有明显行动倾向,可返回空结果。 + + 输出要求: + - 严格按照 ExtractorResult 对应结构输出。 + - 不要输出结构之外的解释或额外文本。 + """; + @InjectCapability private CognitionCapability cognitionCapability; @@ -39,6 +59,12 @@ public class ActionExtractor extends AbstractAgentModule.Sub modulePrompt() { + return List.of(new Message(Message.Character.SYSTEM, MODULE_PROMPT)); + } + @NotNull @Override public String modelKey() {