agentscope-ai / agentscope-ai/agentscope-java
[Bug]: Hook message extraction conflict when using long-term memory and RAG together
- 主要语言
- Java
- 星标
- 5.6k
- 派生
- 1.3k
- 平均合并
- 4 天 12 小时
- 30 天内合并 PR
- 77
描述
## Bug Description
When both `StaticLongTermMemoryHook` and `GenericRAGHook` are attached to the same agent, they interfere with each other's message extraction logic. Each hook searches for "the last user message" to use as its query, but since both hooks inject their results as `USER` role messages at the end of the message list, one hook may pick up the other hook's injected message instead of the original user input.
## Root Cause
This is a side effect of previous fixes:
- **PR #1167** (fixing #1164) changed `StaticLongTermMemoryHook` to inject memory as a `USER` message at the **end** of the message list (previously it was `SYSTEM` at the end)
- **PR #941** changed `GenericRAGHook` to inject retrieved knowledge as a `USER` message (previously it was `SYSTEM`)
Both hooks use "find the last `USER` role message" to extract the user's query:
- `StaticLongTermMemoryHook#extractLastUserMessageIndex` — scans from end to start, returns the first `USER` role message
- `GenericRAGHook#extractQueryFromMessages` — scans from end to start, returns the first `USER` role message's text
Since hooks execute in a chain, when the second hook runs, the first hook has already appended its `USER` message. The second hook then picks up that injected message as the "user query", not the actual user input.
**Example flow** (hooks execute by priority; both have priority 50):
1. User sends: `USER: "What is the refund policy?"`
2. `StaticLongTermMemoryHook` runs first:
- `extractLastUserMessageIndex` finds `"What is the refund policy?"` ✓
- Appends `USER (name="long_term_memory"): ...`
3. `GenericRAGHook` runs next:
- `extractQueryFromMessages` finds `...` ✗ — this is the memory hook's output, not the user's query!
- Uses this as the RAG retrieval query, producing irrelevant or incorrect results
The reverse scenario is equally problematic if the RAG hook runs first.
## Steps to Reproduce
1. Configure a `ReActAgent` with both `StaticLongTermMemoryHook` and `GenericRAGHook`
2. Send a user query
3. Observe that the second-executing hook uses the first hook's injected message as its retrieval query
## Expected Behavior
Each hook should extract the **original user input message**, not the other hook's injected context.
## Suggested Fix
Give injected messages distinct `name` identifiers so that each hook can skip them when extracting the user query:
- `StaticLongTermMemoryHook` already uses `name="long_term_memory"` — update `extractLastUserMessageIndex` to skip messages where `name` is `"retrieved_knowledge"`
- `GenericRAGHook` should use `name="retrieved_knowledge"` (instead of the default `"user"`) — update `extractQueryFromMessages` to skip messages where `name` is `"long_term_memory"`
This way each hook only considers genuine user input messages, regardless of execution order.
## Related Issues
- #941 — Changed GenericRAGHook to use user message (introduced `USER` role injection)
- #1164 / #1167 — Changed StaticLongTermMemoryHook to use user message (introduced `USER` role injection at end)
- #1262 — Multiple system messages from StaticLongTermMemoryHook (related but different problem)
贡献指南
评估
这个 Issue 还没有评估数据。