Skip to content

Split System Prompt & System Reminder to improve context management and avoid hallucination #2653

Description

@Mingholy

Draft Issue: Split System Prompt & System Reminder for Better Context Management

Status: Draft for review - Not yet submitted


What happened?

Currently, Qwen Code conflates two distinct types of system instructions:

  1. System Prompt: Long-lived base instructions (capabilities, constraints, guidelines)
  2. System Reminders: Dynamic, contextual information (subagent availability, plan mode, arena sessions)

Both are processed differently but sent to the LLM in a way that can cause confusion and hallucination:

  • System Prompts are sent as API-level systemInstruction
  • System Reminders are sent as user message content (prepended to user query)

Additionally, the core instruction tells the model that <system-reminder> tags "are NOT part of the user's provided input" — but since reminders are injected into the user message space, the model may not properly distinguish system instructions from user intent.


What did you expect to happen?

A clear separation between:

  1. System Prompt (base instructions): Sent as true system-level instruction

    • Capabilities and constraints
    • User guidelines and preferences
    • Tool usage policies
    • Dynamic examples that only include tools in the active toolset
  2. System Reminder (dynamic context): Also sent at system level

    • Subagent availability
    • Current mode (plan mode, arena)
    • Todo list changes
    • Session state
    • Available tools list to prevent hallucinated tool calls

This would ensure:

  • Clear semantic hierarchy between instructions
  • Better model adherence to system-level guidance
  • Reduced hallucination from instruction confusion (e.g., examples won't reference unavailable tools)
  • More predictable behavior across conversation turns
  • A mechanism to explicitly tell the model which tools ARE available

Why is this needed?

  1. Reduces Hallucination: When system reminders are injected into user message space, the model may treat them as user requests rather than authoritative instructions
  2. Improves Context Clarity: Clear distinction helps the model understand what is system directive vs. contextual information
  3. Better Instruction Hierarchy: Base prompt instructions should take precedence over dynamic reminders — this is harder to ensure when both are in user message space
  4. Debuggability: When something goes wrong, it's easier to trace which instruction type influenced the behavior

Concrete Hallucination Example

The system prompt contains example patterns showing tool usage:

<example>
user: Run the build and fix any type errors
assistant: I'm going to use the ${ToolNames.TODO_WRITE} tool to write the following items...

When a tool like write_file appears in examples but is not registered in coreTools, the LLM may still attempt to call it based on the example pattern. This results in hallucinated tool calls that will never succeed.

The problem:

  1. System prompt includes examples using ${ToolNames.WRITE_FILE}
  2. If write_file is not in the active toolset, the call fails
  3. The model continues trying despite failures
  4. User experience degrades

Root cause: Examples in system prompts don't automatically adapt to the current toolset - they're static text that can mislead the model.


Additional context

Current Architecture

System Prompt Flow:
  Config.getSystemPrompt() / QWEN_SYSTEM_MD
           ↓
  Sent as API systemInstruction

System Reminder Flow:
  In sendMessageStream() - client.ts
           ↓
  Prepended to user message content
           ↓
  Sent as user message (NOT system instruction)

Key Code Location

In packages/core/src/core/client.ts:606-642:

requestToSent = [...systemReminders, ...requestToSent];
// Reminders are added to user message, not system instruction

Example Problem Scenario

  1. System prompt says: "Always confirm with user before executing destructive commands"
  2. A system reminder indicates: "Plan mode is active — do not execute yet"
  3. User says: "Go ahead and delete everything"
  4. Because the reminder is in user message space, the model may deprioritize it over the user's explicit "go ahead"

Labels

  • type/feature-request
  • status/needs-triage
  • area/context-management

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions