agentscope-ai / agentscope-ai/QwenPaw

[Feature]: Separate auto memory search from manual memory_search: compact coarse-filter injection + explicit deep-search guidance

Offen
#7,019 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
enhancement
Vorherrschende Sprache
Python
Sterne
34.9k
Forks
3.1k
Ø Merge
1 T. 15 Std.
Gemergte PRs (30 T.)
225

Beschreibung

## Summary

Improve QwenPaw's memory **retrieval** side: separate auto memory search from the manual `memory_search` tool, give auto search a compact coarse-filter injection with explicit guidance ("this is only a rough scan — dig deeper if anything looks relevant"), and add concrete search guidance to the system prompt so agents actually use memory instead of treating it as a one-shot dead end.

## Component(s) Affected

- [x] Core / Backend (app, agents, config, providers, utils, local_models)
- [ ] Console (frontend web UI)
- [ ] Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
- [ ] Skills
- [ ] CLI
- [ ] Documentation (website)
- [ ] Tests
- [ ] CI/CD
- [ ] Scripts / Deploy

## Problem / Motivation

QwenPaw has a strong memory **storage** pipeline (auto_memory → memory/ → auto_dream → digest), but the **retrieval** side is weak, and in practice agents are passive about memory:

1. **Auto memory search is a silent dead end.** Every turn, `MemoryMiddleware` injects a *simulated completed* `memory_search` tool call (ToolCallBlock FINISHED + ToolResultBlock SUCCESS) with the text `"I'll check memory for relevant context before answering."` (`AUTO_MEMORY_SEARCH_TEXT` in `constant.py`). The model sees a successful tool call and reasonably concludes "memory was already searched, nothing more to do" — so it never calls `memory_search` again, even when the auto result is empty or irrelevant.

2. **Auto search returns too few, too long results.** `AutoMemorySearchConfig.max_results` defaults to **2** (`config/config.py`), and each result is the **full raw answer text** (the whole `response.answer` is injected, no truncation/summary). So the injected context is both low-recall and high-cost: relevant items get excluded, and the 2 items that do come back eat a lot of tokens.

3. **Auto search queries with the raw user input.** The query is built from the user's message directly, with no query rewriting, so recall is inherently low — and with max_results=2, borderline-relevant matches are cut off entirely.

4. **Manual `memory_search` guidance is vague.** `MEMORY_GUIDANCE` (in `agents/memory/prompts.py`) only says "when a question involves past facts/preferences, first use `memory_search`". It does not say *how* to search (query rewriting, multi-query, pseudo-answer search, backing off one step) or *when auto results are insufficient*. Combined with #1, the model has little reason to ever search.

Net effect: for a system with a rich memory layer, agents behave as if memory doesn't exist unless a relevant snippet happens to surface in the auto injection.

## Proposed Solution

### 1. Separate the two search paths (auto vs manual)

- Keep the injected auto search as a **distinct, lightweight** signal — e.g. an `auto`-prefixed tool (`auto_memory_search`) or a clearly-labeled injected message — so the model can tell "this was a system-side coarse scan" apart from "I explicitly searched".
- The manual `memory_search` tool remains the full-depth path and is what the model should call when it needs real recall.

### 2. Make auto search a compact coarse filter

- **More results, shorter items**: raise the auto `max_results` default (e.g. 5–8), but inject **truncated/summarized snippets** (e.g. first N chars per item, or a per-item summary) instead of the full answer text. This flips the current "2 long blobs" trade-off into "several short hints" — better recall signal at similar or lower token cost.
- Optionally rewrite/expand the auto query (the infra already over-fetches with a reranker; a query-expansion step would help even without a reranker).

### 3. Explicit guidance text on the auto injection

Replace/annotate the injected message so the model understands the semantics, e.g.:

> "An automatic coarse memory scan was performed for this turn (low recall by design). If any snippet seems even partially relevant — or if the task relies on past facts/preferences/decisions — call `memory_search` yourself with a refined query (rewrite the user's words, try multiple angles, or search for a likely answer) to confirm and get full context. Do not treat this auto scan as a complete search."

The point is to make the model feel *invited* to search deeper instead of feeling *done*.

### 4. Strengthen manual `memory_search` guidance in the system prompt

Add concrete, short search techniques to `MEMORY_GUIDANCE` (zh + en):

- When a query returns nothing or only weak hits: **rewrite the query** — multi-angle variants, or a **pseudo-answer (HyDE)** — "search with a likely answer instead of the question".
- **Back off one step**: if the detail query fails, search the underlying concept first.
- Do **not** trust a single empty auto result; absence of evidence needs a second attempt with different phrasing.

These are compact (a few lines), high-leverage prompts that make the existing memory infrastructure actually reachable.

## Alternatives Considered

- **Just raise `max_results`**: would increase token cost per turn (full-text blobs × more items), and without guidance the model still treats the injection as "done". Rejected as insufficient.
- **Remove auto search entirely and rely on the model calling `memory_search`**: regresses recall for cases where the model doesn't know it should search (which is the current failure mode). Rejected.
- **Teach this only via agent persona files (AGENTS.md)**: our own agents already carry notes like "the auto injection is a shallow hint, not a full retrieval — search yourself" (see our AGENTS.md), and it helps, but it's per-agent boilerplate that shouldn't be needed; a platform-level fix benefits all agents. Proposed as a complementary stopgap, not the fix.

## Additional Context

Code references (v2.1.0):

- `agents/middlewares.py` — `MemoryMiddleware.on_model_call` injects the simulated search each turn.
- `agents/memory/base_memory_manager.py:132` — `_build_auto_memory_search_msg` builds the synthetic ToolCallBlock(ToolCallState.FINISHED) + ToolResultBlock(ToolResultState.SUCCESS).
- `constant.py:150` — `AUTO_MEMORY_SEARCH_TEXT = "I'll check memory for relevant context before answering."`
- `config/config.py:623` — `AutoMemorySearchConfig.max_results` default = 2.
- `agents/memory/prompts.py` — `MEMORY_GUIDANCE` (zh/en), the only manual-search guidance.
- `agents/memory/reme_light_memory_manager.py:1077` — `auto_memory_search` builds the query from raw user messages.

Real-world symptom: with `auto_memory_search.enabled=true`, an agent answered a question about a past event from weeks ago with "no memory of it" while the relevant note existed in `memory/` — because the auto scan (raw query, 2 results) missed it and the model never tried a second search.

## Willing to Contribute

- [ ] I am willing to open a PR for this feature (after discussion).

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.