Skip to content

[BUG] MessagesModelHook 跳转控制逻辑异常 #4421

@wangliuliu1115

Description

@wangliuliu1115

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

问题描述

在 MessagesModelHook 中,当重写 canJumpTo() 方法返回 List.of(JumpTo.end) 后,无论 beforeModel 方法返回的是否是带跳转的 AgentCommand,流程都会提前结束,不会执行后续的 Hook。

代码示例

@Slf4j
@RequiredArgsConstructor
@HookPositions({HookPosition.BEFORE_MODEL})
public class SemanticCacheHook extends MessagesModelHook {

    private final SemanticCacheService semanticCacheService;

    public static final String CACHE_HIT_KEY = "cache_hit";

    @Override
    public String getName() {
        return "semantic_cache_check";
    }

    @Override
    public List<JumpTo> canJumpTo() {
        return List.of(JumpTo.end);
    }

    @Override
    public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {

            // 使用 QueryEnhancementHook 生成的增强查询
            String queryToSearch = config.metadata()
                    .flatMap(m -> Optional.ofNullable((String) m.get(ENHANCED_QUERY_KEY)))
                    .orElse(null);

            // 如果没有增强查询, fallback 到列表中最后一条用户消息
            if (queryToSearch == null || queryToSearch.isBlank()) {
                for (int i = previousMessages.size() - 1; i >= 0; i--) {
                    Message msg = previousMessages.get(i);
                    if (msg.getMessageType() == MessageType.USER) {
                        queryToSearch = msg.getText();
                        break;
                    }
                }
            }

            if (queryToSearch == null || queryToSearch.isBlank()) {
                return new AgentCommand(previousMessages); // 无查询,继续流程
            }

            // 执行向量搜索 (Redis)
            String cache = semanticCacheService.getIfPresent(queryToSearch);
            if (cache != null && !cache.isBlank()) {
                // 元数据中增加内容结果,并结束流程
                config.metadata().ifPresent(meta -> meta.put(CACHE_HIT_KEY, cache));
                return new AgentCommand(JumpTo.end, previousMessages);
            }

            return new AgentCommand(previousMessages);

    }
}

预期行为

  • 命中缓存时 (cache != null):返回 new AgentCommand(JumpTo.end, previousMessages)流程结束,不执行后续 Hook
  • 未命中缓存时 (cache == null):返回 new AgentCommand(previousMessages)流程继续,执行下一个 Hook

实际行为

  • 只要重写了 canJumpTo() 并返回 List.of(JumpTo.end)或者包含它,无论 beforeModel 返回什么(即使是 new AgentCommand(previousMessages)),流程都会结束,后续 Hook 永远不会执行。

环境信息

  • Spring AI Alibaba Version: [1.1.2.0、1.1.0.0-RC2]
  • Java Version: [21]

参考资料

官方文档示例([Hooks 和 Interceptors | Spring AI Alibaba](https://java2ai.com/docs/frameworks/agent-framework/tutorials/hooks#messagesmodelhook))中展示了这种用法:

@Override
public List<JumpTo> canJumpTo() {
    return List.of(JumpTo.end);
}

@Override
public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
    // 检查某些条件,如果满足则提前退出
    if (shouldExit(previousMessages)) {
        return new AgentCommand(JumpTo.end, previousMessages);
    }
    return new AgentCommand(previousMessages);  // 这里应该继续,但实际上会结束
}

但实际行为与文档描述不符。

Expected Behavior

同上

Steps To Reproduce

同上

Environment

Spring AI Alibaba version(s):1.1.2.0、1.1.0.0-RC2均有此问题

Debug logs

No response

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions