> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Learn a User's Preferences From Conversation Alone

> Run a ten-turn consulting conversation in which stated preferences, corrections, and style rules become session guidance without anyone calling a feedback API

You are building an assistant that plans work with a user over a long conversation, and the user keeps changing the brief mid-stream — a constraint you missed, an ordering rule, a switch from two bullet points to four. You would like the assistant to absorb each of those as it happens, without the user ever having to say "remember this."

## What You'll Build

Fifteen sentences about a fictional logistics company — four offices, four projects, audit windows, and the people who lead them — are remembered into an isolated dataset. A single session then runs ten turns of a consulting conversation on top of it, in which the user asks for an audit itinerary and then repeatedly amends the brief: Singapore must come before Toronto, Priya before Mateo, Lisbon can be a video call, answers should now be four bullets instead of two, customer-facing notes should be operational rather than technical. Because `AUTO_FEEDBACK` is on, every answered turn is analyzed for exactly that kind of statement, and whatever the analysis judges durable is written into the session's guidance layer as a gated entry. The script prints the growing list after every turn along with the QA history and which guidance IDs the latest answer used. The run also opens with an `only_context` probe that shows a context read adds no QA entry, and ends by dumping the whole trace as JSON.

The complete runnable script is
[`examples/demos/sessions/live_session_context_feedback_demo.py`](https://github.com/topoteretes/cognee/blob/main/examples/demos/sessions/live_session_context_feedback_demo.py) —
this page walks through its key moments rather than reproducing it.

## Features in Play

* [Remember](/core-concepts/main-operations/remember) — loads the fifteen Northstar Labs facts into the demo dataset in one call
* [Recall](/core-concepts/main-operations/recall) — answers every turn with `GRAPH_COMPLETION` against that dataset
* [Sessions](/guides/sessions) — the shared `session_id` that makes ten separate `recall()` calls one conversation
* [Session-Context Guidance](/core-concepts/sessions-and-caching#session-context-guidance-auto-feedback) — `AUTO_FEEDBACK` is what turns a stated preference or correction into a gated guidance entry on the turn that states it
* [Search Basics](/guides/search-basics#parameters-reference) — `only_context=True` returns the retrieval context instead of an answer, which the probe uses to show that reading context is side-effect-free

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured — ingestion, every answer, and the per-turn feedback detection are all live calls, so answer wording and the learned guidance text vary by model
* Expect the script to set its own environment before importing cognee: it pins `CACHING=true` and `AUTO_FEEDBACK=true` — both already the defaults — switches `CACHE_BACKEND` to `fs` from the default `sqlite`, and defaults `LOG_LEVEL` to `ERROR`. See [Sessions and Caching](/core-concepts/sessions-and-caching#cache-adapters) for what those control
* Run it from a checkout of the cognee repo: it points cognee's data, system, and cache roots at `examples/temp/live_session_context_feedback_demo/` and works only inside that folder
* A full run starts with `cognee.forget(everything=True)` against that isolated root, so it clears its own demo storage rather than memory you want to keep

## How It Works

### Stage 1: Pin the Session Feedback Settings

```python theme={null}
os.environ["CACHING"] = "true"
os.environ["CACHE_BACKEND"] = "fs"
os.environ["AUTO_FEEDBACK"] = "true"
os.environ.setdefault("LOG_LEVEL", "ERROR")
```

These four lines run before `import cognee`, which is what makes them take effect. `CACHING` and `AUTO_FEEDBACK` are both on by default, so setting them here is not what enables the behavior — it pins it, so the demo runs the same way on an instance where either was switched off. `AUTO_FEEDBACK` is the setting behind the per-turn analysis call; with it off, the session would still replay conversation history but would learn nothing from what the user says. `CACHE_BACKEND=fs` is the one real departure from the defaults, putting the session cache in files under the demo's own root instead of the default `sqlite` backend.

### Stage 2: Seed the Northstar Labs Facts

```python theme={null}
async def setup_demo_data():
    await configure_demo_storage(reset_storage=True)
    progress("Clearing previous demo state.")
    await cognee.forget(everything=True)
    progress(f"Ingesting {len(DOCUMENTS)} Northstar Labs facts.")
    await cognee.remember(DOCUMENTS, dataset_name=DATASET_NAME, self_improvement=False)
    progress("Ingestion complete.")
```

One `remember()` builds the permanent graph the conversation will be grounded in: offices, the project each one owns, the data each project consumes, and the audit windows and leads. `self_improvement=False` skips the enrichment pass, because this demo is about what the session learns, not what the graph does. Nothing in these documents states a visit order or a bullet-point preference — those can only come from the conversation. Setup then deletes any previous copy of the demo session, so guidance growth starts from zero and every printed entry is attributable to this run; the closing JSON reports whether it found one as `session_was_deleted`.

### Stage 3: Route Every Question Through One Session

```python theme={null}
async def ask(message: str, *, user, only_context: bool) -> Any:
    return await cognee.recall(
        query_text=message,
        query_type=SearchType.GRAPH_COMPLETION,
        datasets=[DATASET_NAME],
        session_id=SESSION_ID,
        user=user,
        only_context=only_context,
    )
```

Every turn and the probe go through this one helper, so the only thing that differs between them is `only_context`. The shared `SESSION_ID` is what makes ten independent `recall()` calls a single conversation, and pinning `query_type` keeps each turn on the graph-completion path rather than letting the router pick.

### Stage 4: Probe the Context Without Writing to It

```python theme={null}
async def run_context_only_probe(user) -> dict:
    progress("Running context-only probe; this should not register a QA entry.")
    before = await session_evidence(user)
    context = await ask(
        "Which Northstar offices are mentioned?",
        user=user,
        only_context=True,
    )
    after = await session_evidence(user)
```

The probe asks a real question with `only_context=True` and takes an evidence snapshot on either side of it. The QA count should be identical before and after — the probe records that comparison as `qa_was_registered` in its result, which is how the demo shows that reading retrieval context stores no Q\&A turn. The per-turn analysis is skipped for `only_context` calls as well, but the probe runs before the first turn, when the guidance layer is empty either way, so that half is documented behavior rather than something this output demonstrates — see [Session-Context Guidance](/core-concepts/sessions-and-caching#session-context-guidance-auto-feedback).

### Stage 5: Amend the Brief Mid-Conversation

```python theme={null}
    {
        "label": "communication_preference_update",
        "message": (
            "Actually, change my communication preference: I now prefer 4 concise bullet "
            "points instead of 2 informative bullet points."
        ),
    },
    {
        "label": "customer_facing_style_rule",
        "message": (
            "Good. Also remember that customer-facing audit notes should be operational, "
            "not technical."
        ),
    },
```

`TURNS` is a list of ten such messages, and these two are the eighth and ninth: the first supersedes a formatting preference stated back in turn two, the second adds a style rule. Neither is phrased as an instruction to the memory — the labels are narration for the printout, and the session decides on its own what is worth keeping.

### Stage 6: Read Back the Session Evidence

```python theme={null}
async def session_evidence(user) -> dict:
    qa_entries = await cognee.session.get_session(session_id=SESSION_ID, user=user)
    context_entries = await get_session_manager().get_session_context_entries(
        user_id=str(user.id),
        session_id=SESSION_ID,
    )
    return {
        "qa_count": len(qa_entries),
        "latest_qa": serialize_latest_qa(qa_entries),
        "session_context_entries": serialize_context_entries(context_entries),
    }
```

This helper is the instrument the demo reads the session with, and every snapshot in the run is one call to it, drawing on two sources: the stored Q\&A history, and the session's context entries. The script keeps only entries whose `kind` is `context` and prints each one's section, content, and helpful and harmful counts — the running tally that feeds an entry's ranking score alongside its section, confidence, and overlap with the query. Alongside them it prints the latest QA's `used_session_context_ids`, which links an answer back to the guidance entries that shaped it.

### Stage 7: Watch the Guidance Grow, Turn by Turn

```python theme={null}
    for index, turn in enumerate(TURNS, start=1):
        progress(f"Turn {index}: {turn['label']}")
        response = await ask(turn["message"], user=user, only_context=False)
        evidence = await session_evidence(user)
        print_turn_snapshot(
            turn_number=index,
            label=turn["label"],
            user_message=turn["message"],
            response=response,
            evidence=evidence,
        )
        output["turns"].append(
            {
                "turn": index,
                "label": turn["label"],
                "user_message": turn["message"],
                "assistant_response": serialize_response(response),
                "evidence": evidence,
            }
        )
```

Everything above comes together in these twenty lines: answer the turn, immediately re-read the session, print the two side by side, and keep the same pairing in the JSON. Because the snapshot is taken after every turn rather than once at the end, the printed guidance list is a running record of what the conversation taught the session — and the only input to any of it is a user message.

One thing to expect while you watch: the effect arrives one turn later than the statement. The script leaves `SESSION_SEARCH_MODE` at its `concurrent` default, where the analysis runs alongside answer generation, so a new entry lands after the current turn's reply and shapes the next one — turn eight still answers in two bullets, and the switch to four shows up from turn nine. Set `SESSION_SEARCH_MODE=sequential` if you want guidance to reach the same turn that stated it; see [Session-Context Guidance](/core-concepts/sessions-and-caching#session-context-guidance-auto-feedback) for the trade.

## Run It

```bash theme={null}
uv run python examples/demos/sessions/live_session_context_feedback_demo.py
```

Progress lines and per-turn snapshots go to stderr, and one JSON document goes to stdout at the end. Watch the snapshots first: each turn prints the user message, the assistant reply, the running `qa_count`, the latest question with its `used_session_context_ids`, and the session context — `session_context: empty` early on, then a growing bulleted list of entries with their section and helpful/harmful counts as the ordering constraints, the Lisbon video call, the four-bullet preference, and the operational-tone rule are absorbed. Before all of that, the probe logs its QA count before and after, which should be the same number. The closing JSON repeats everything in structured form: the dataset and session IDs, the probe result including `qa_was_registered`, and one entry per turn with the serialized response and the evidence snapshot taken after it. Re-run with `--no-ingest` to keep the ingested dataset and only reset the session.

<Columns cols={2}>
  <Card title="Sessions" icon="message-square" href="/guides/sessions">
    Working with `session_id` for conversational memory.
  </Card>

  <Card title="Sessions and Caching" icon="message-square" href="/core-concepts/sessions-and-caching">
    What `AUTO_FEEDBACK` analyzes on each turn, and when its guidance applies.
  </Card>

  <Card title="Recall" icon="search" href="/core-concepts/main-operations/recall">
    The query path every turn takes, including `only_context`.
  </Card>

  <Card title="Watch a Session Become Permanent Memory" icon="repeat" href="/examples/memory-loop-walkthrough">
    The sibling demo, where session guidance is distilled into the graph.
  </Card>
</Columns>
