feat(agent): include progress-ledger snapshot in limit-exceeded wrap-up

This commit is contained in:
matevip 2026-05-24 23:00:49 +08:00
parent 59d090ebb5
commit 7f45b95432
3 changed files with 39 additions and 3 deletions

View File

@ -710,7 +710,8 @@ public class AgentGraphBuilder {
ObservationProcessor observationProcessor = new ObservationProcessor(graphObservationProperties);
ObservationNode observationNode = new ObservationNode(observationProcessor, streamTracker);
SummarizingNode summarizingNode = new SummarizingNode(chatModel, streamingHelper, streamTracker);
LimitExceededNode limitExceededNode = new LimitExceededNode(chatModel, observationProcessor, streamingHelper, i18nService);
LimitExceededNode limitExceededNode = new LimitExceededNode(
chatModel, observationProcessor, streamingHelper, i18nService, progressLedgerService);
FinalAnswerNode finalAnswerNode = new FinalAnswerNode(generatedFileCache);
KeyStrategyFactory keyStrategyFactory = KeyStrategy.builder()

View File

@ -47,18 +47,33 @@ public class LimitExceededNode implements NodeAction {
private final NodeStreamingChatHelper streamingHelper;
/** Optional i18n service; nullable so legacy/tests without Spring context still work. */
private final I18nService i18n;
/**
* Optional ledger loader. When set, the conversation's progress snapshot
* (done / in-progress / pending) is appended to the LLM's context so the
* "graceful wrap-up" answer can be honest about which steps actually
* finished and which were still pending when the iteration cap hit.
* Null in legacy/test constructors the wrap behaves as before.
*/
private final vip.mate.agent.progress.ProgressLedgerService progressLedgerService;
public LimitExceededNode(ChatModel chatModel, ObservationProcessor observationProcessor,
NodeStreamingChatHelper streamingHelper) {
this(chatModel, observationProcessor, streamingHelper, null);
this(chatModel, observationProcessor, streamingHelper, null, null);
}
public LimitExceededNode(ChatModel chatModel, ObservationProcessor observationProcessor,
NodeStreamingChatHelper streamingHelper, I18nService i18n) {
this(chatModel, observationProcessor, streamingHelper, i18n, null);
}
public LimitExceededNode(ChatModel chatModel, ObservationProcessor observationProcessor,
NodeStreamingChatHelper streamingHelper, I18nService i18n,
vip.mate.agent.progress.ProgressLedgerService progressLedgerService) {
this.chatModel = chatModel;
this.observationProcessor = observationProcessor;
this.streamingHelper = streamingHelper;
this.i18n = i18n;
this.progressLedgerService = progressLedgerService;
}
/**
@ -66,7 +81,7 @@ public class LimitExceededNode implements NodeAction {
*/
@Deprecated
public LimitExceededNode(ChatModel chatModel, ObservationProcessor observationProcessor) {
this(chatModel, observationProcessor, null, null);
this(chatModel, observationProcessor, null, null, null);
}
@Override
@ -100,6 +115,25 @@ public class LimitExceededNode implements NodeAction {
contextForLLM = i18n != null ? i18n.msg("agent.limit_exceeded.empty_context") : "(no tool results)";
}
// Prepend the conversation's progress ledger snapshot when available
// so the wrap-up answer can be honest about partial completion ("4/10
// models researched, 6 still pending") rather than vaguely describing
// "what I tried". Without this, hitting the iteration cap on a
// 10-step task produces a useless catch-all message observed in
// round-4 of the LLM-review smoke test.
String ledgerSnapshot = null;
if (progressLedgerService != null && conversationId != null && !conversationId.isBlank()) {
try {
ledgerSnapshot = progressLedgerService.load(conversationId).renderSnapshot();
} catch (Exception e) {
log.warn("[LimitExceededNode] Failed to load progress ledger for {}: {}",
conversationId, e.getMessage());
}
}
if (ledgerSnapshot != null) {
contextForLLM = ledgerSnapshot + "\n\n---\n\n" + contextForLLM;
}
// 构建 prompt
String systemPrompt = SYSTEM_TEMPLATE.replace("{maxIterations}", String.valueOf(maxIterations));
String userPrompt = USER_TEMPLATE

View File

@ -5,6 +5,7 @@
1. 给出简洁、诚实、可执行的回答
2. 若信息不足以完全回答,明确说明哪些部分还不确定
2.1. 若所依据的数据被截断或不完整(含"已截断/TRUNCATED/preview/INCOMPLETE"等标记),明确告知用户数据不完整并指出缺口,**绝不编造、补全或重新编号缺失的数据条目**,也不要把明细列表缩减为范围表述
2.2. 如果上下文里出现"## 当前任务进度"账本,**以账本为权威完成度** —— done 的步骤真的做完了pending / in_progress 的步骤明确告诉用户"未完成",并把这些条目列出来作为下一步建议
3. 如果还有未完成的方向,简要列出建议的下一步
4. **不要为「未完成」道歉,不要提及「推理步数」「迭代次数」「工具调用上限」这类技术细节** —— 直接给结论
5. 保持输出简洁,避免重复已知内容