feat: add findings on DeepSeek-V4-Flash performance and memory strategies
Browse files
evals.md
CHANGED
|
@@ -168,14 +168,18 @@ Numbered findings; each states what it was tested on. Convention: entries are ne
|
|
| 168 |
|
| 169 |
- **F24 (2026-06-19) β F3's "0 clears" was a blind-signal artifact: `cleared_tool_outputs` cannot observe `ClearToolUsesEdit`, which fires but invisibly.** `ContextEditingMiddleware.wrap_model_call` applies the clear to a `deepcopy` of the per-call message view and returns it via `request.override(messages=...)` (`langchain/agents/middleware/context_editing.py:251-255`) β it never writes the placeholder back to the checkpoint, but `telemetry.context_window_stats` counts placeholders in the *checkpointed* `state_messages` (`chat_service.py:1876`). So the counter reads **0 for every preset including `aggressive`** across all `runs/`, regardless of whether clearing fired β "0 clears" is structural, not evidence of absence. The real effect lands in input tokens: on sessions `clear_retrieval_kb` cut mean input **145.6kβ120.5k (~17%, $0.229β$0.203/turn)** vs `prod` by clearing the retrieval payloads `prod` exempts, while on single-turn it **backfired to 308k/$0.477** (re-retrieval churn to recover what it cut β the `aggressive`/F19 pathology). So clearing is real and *mixed* (session win, single-turn loss), not absent. **Supersedes F3's "clearing never fires" reading; F3's structural point stands** β `prod`'s `exclude_tools=("retrieve_tutor_context",)` provably leaves the dominant retrieval payloads in place by construction, so prod-clearing still can't touch the big tokens. Caveats: the session token saving is 1-trial screen n; library clearing stays telemetry-invisible (the probe gate survives only because summarization, which *does* persist, co-fires in these arms β a clearing-only arm would false-fail `check_triggers`). Detect clearing via input-token deltas, not `cleared_tool_outputs`.
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
**Screen winners β promotion candidates:** `incontext_history_retrieval` (needs the long-session test), `retrieval_budget_30k` and `clear_retrieval_kb` (cheap Axis-B wins; clear_retrieval_kb is cheaper than prod with similar memory + better recall/key-points), anchored by `full_history`. **Drop:** `context_reset`, `observation_truncation`, `selective_retention`.
|
| 172 |
|
| 173 |
**Part C β what remains (beyond the workshop).** The screen answered the core question; everything below *hardens* or *extends* it and is **gated on a spend or data decision from Omar** β none is required for the workshop.
|
| 174 |
|
| 175 |
1. **Promotion (rigor, not new findings).** Re-run the 2-3 winners (+ 1-2 combos) on the full batteries (60 single-turn + 32 sessions + 30 replay) Γ 3 trials, with paired statistical tests and per-variant failure-taxonomy diffs, to turn the screen's coarse n=12 rankings into confident numbers; optionally an Anthropic (Haiku) re-run of the prefix-rewriting arms (`prompt_compression`, `context_reset`, `aggressive`) to test whether explicit caching flips F2's cost ranking. **~$1,300-1,800 at corrected pricing** (the old "$300-400" was at pre-correction prices; Γ the 4.4 fix β estimate precisely before running, since the per-turn cost is now ~$0.25).
|
| 176 |
-
2. **Finish the v2 contradiction tier β the highest-value new dataset (already built and partially run; see the V2 execution note below).** Moderate sessions: plant A, update to Aβ², then probe after prod compaction has evicted A from the kept-recent window. This is the one correctness regime where `full_history` itself might lose (it sees both A and Aβ² and must choose the current one) β yet the partial run so far shows the opposite (`full_history` contradiction **2/2** vs `prod` **0/3**), so that regime has not actually appeared. What remains is finishing Tier 1 (the missing `full_history` session, then Tier-1 `profile_memory` and optionally `incontext_history_retrieval`) and adding trials, not building the dataset.
|
| 177 |
-
3. **The `incontext_history_retrieval` long-session cost test β principled but less product-critical.** The screen showed `incontext` works (83%, F16) but couldn't show a cost benefit on β€13-turn sessions. Whether retrieve-old-turns beats `full_history` *once sessions get genuinely long* needs a token-calibrated long-session v2 tier; useful for the workshop argument, but gated by whether that regime matters in real tutor telemetry.
|
| 178 |
-
4. **Conditional builds.** Build `temporal_graph_memory` only if `full_history` fails contradictions, `delta_summarization` only if the long-horizon cost tier shows room to beat full history, and `entity_memory` only if multi-project probes show fact bleed. `collection_memory` is a separate cheap v1/product follow-up for verbatim fact storage (F22 tested the current profile write-back, not that). `hierarchical_summarization` and `sleeptime_consolidation` are deferred. The step-by-step v2 plan is in `evals_part_c_plan.md` β "Battery v2".
|
| 179 |
|
| 180 |
**Deliberately not pursued.** *Stretch (heavier, likely later):* sub-agent isolation, reframed as a tool-output-token play β keep noisy `run_kb_command` output out of the main context (ties to F1); temporal-graph memory is already the conditional build in item 4 above. *Dropped as low-information given the findings:* the skills / lazy-prompt-loading family (only a ~458-token win β see the talk-outline correction below), procedural memory, GraphRAG, and multi-agent / parallel-research agents. Context for the `kb_off` arm (F17/F23): the KB is the dominant grounding tool β β89% of Part B turns, ~7.7 KB vs ~0.9 retrieval calls/turn over 1,088 turns β so disabling it forces the 100k-token retrieval fallback, which is why it raised cost/latency.
|
| 181 |
|
|
@@ -219,3 +223,4 @@ Golden cases as a CI gate (5β10 critical-path cases with deterministic asserti
|
|
| 219 |
- `data/eval/README.md` β battery schemas + glossary of terms; `review_log_v1.md` β dataset audit trail.
|
| 220 |
- `evals/` β the harness code; `app/memory_presets.py`, `app/telemetry.py` β the app-side hooks.
|
| 221 |
- `runs/b_report/`, `runs/c_report/` β generated tables, token curves, blinded grading workbook (Part B and the Part C screen). Re-grade / follow-up reports: `runs/kbfair_report/` (F23 KB-fair recall), `runs/d_report_profile_memory_active/` (F22 profile rerun), `runs/e2_v2_partial_report/` (v2 partial).
|
|
|
|
|
|
| 168 |
|
| 169 |
- **F24 (2026-06-19) β F3's "0 clears" was a blind-signal artifact: `cleared_tool_outputs` cannot observe `ClearToolUsesEdit`, which fires but invisibly.** `ContextEditingMiddleware.wrap_model_call` applies the clear to a `deepcopy` of the per-call message view and returns it via `request.override(messages=...)` (`langchain/agents/middleware/context_editing.py:251-255`) β it never writes the placeholder back to the checkpoint, but `telemetry.context_window_stats` counts placeholders in the *checkpointed* `state_messages` (`chat_service.py:1876`). So the counter reads **0 for every preset including `aggressive`** across all `runs/`, regardless of whether clearing fired β "0 clears" is structural, not evidence of absence. The real effect lands in input tokens: on sessions `clear_retrieval_kb` cut mean input **145.6kβ120.5k (~17%, $0.229β$0.203/turn)** vs `prod` by clearing the retrieval payloads `prod` exempts, while on single-turn it **backfired to 308k/$0.477** (re-retrieval churn to recover what it cut β the `aggressive`/F19 pathology). So clearing is real and *mixed* (session win, single-turn loss), not absent. **Supersedes F3's "clearing never fires" reading; F3's structural point stands** β `prod`'s `exclude_tools=("retrieve_tutor_context",)` provably leaves the dominant retrieval payloads in place by construction, so prod-clearing still can't touch the big tokens. Caveats: the session token saving is 1-trial screen n; library clearing stays telemetry-invisible (the probe gate survives only because summarization, which *does* persist, co-fires in these arms β a clearing-only arm would false-fail `check_triggers`). Detect clearing via input-token deltas, not `cleared_tool_outputs`.
|
| 170 |
|
| 171 |
+
- **F25 (2026-06-19) β DeepSeek-V4-Flash replicates F9/F10 and extends them to long horizon: `full_history` is cheapest AND best-memory on every tier, so the cost crossover never appears.** A full Part-C-style v2 matrix re-run on **DeepSeek-V4-Flash (first-party API, not Gemini)** β 12 arms, 840 turns, 0 errors; Tier 1 contradiction (3Γ22-turn) + Tier 2 long-horizon (2Γ36-turn); reports `runs/ds_v2_t{1,2}_report/`, raw on HF `eval_runs/part_f_deepseek_v2`. `full_history` is the **cheapest** arm on both tiers (**$0.0069/turn** at 22t, **$0.0101/turn** at 36t), undercutting every compaction arm β while billing the *most* tokens (1.78M input tok/turn at long horizon) because ~**97% are cache-hit**. DeepSeek's ~50Γ cache discount ($0.14 cache-miss vs $0.0028 cache-hit input) makes the enormous *cached* prefix cheaper than any compaction's cache-breaking rewrite, so the summarization arms are priciest (`prod` $0.0336, `selective_retention` $0.0357). F9's inversion therefore holds **even at 36 turns**, and harder than on Gemini (10Γ discount β crossover would appear sooner; DeepSeek's 50Γ pushes it past every length tested). Per-turn cost is ~10-15Γ below Gemini on the comparable tier. **Provider caveat:** `incontext_history_retrieval` does *not* beat `full_history` on cost here ($0.0147 vs $0.0101) β the opposite of a teammate's OpenRouter run, where fallback routing fragments the prefix cache; cost comparisons must hold the provider/caching path constant (first-party single-endpoint caching verified live, `cache_read` non-zero). Caveats: thin n (Tier 1 n=3, Tier 2 n=2 per arm, 1 trial) β coarse rankings.
|
| 172 |
+
|
| 173 |
+
- **F26 (2026-06-19) β The v2 contradiction question (Q2) is answered on DeepSeek: `full_history` resolves contradictions, compaction loses them, so no temporal memory is needed.** Same matrix, judge-graded via the validated **subagent path** (28 probes, blind, `judge.py` rubric β F14). `full_history` scores **3/3 contradiction** and **2/2 long-horizon recall** β perfect memory on both tiers, including the regime where it could in theory lose (it carries both A and Aβ² raw and must pick the current Aβ²). `prod` summarization **fails contradictions 0/3** (evicts the updated fact β F10 confirmed and sharpened) and 1/2 long-horizon. `incontext_history_retrieval` matches `full_history` (3/3, 2/2) by retrieving the old turns, but costs more (F25); `profile_memory` partially rescues contradictions (2/3) via its store (the F22 pattern). Among long-horizon compaction arms, `prompt_compression` is least-bad (2/2 β shrinks text, drops no facts) and `context_reset` is dominated (0/2). Validity: compaction fired at **100% of probes** for every compaction arm, **0%** for `full_history` (gate passed). **Resolves item 4's conditional β `temporal_graph_memory` is not triggered**, since `full_history` did not fail contradictions. Caveats: thin n (3/2 per arm, 1 trial); the judge is reproducibility-validated (F14), not independent-human.
|
| 174 |
+
|
| 175 |
**Screen winners β promotion candidates:** `incontext_history_retrieval` (needs the long-session test), `retrieval_budget_30k` and `clear_retrieval_kb` (cheap Axis-B wins; clear_retrieval_kb is cheaper than prod with similar memory + better recall/key-points), anchored by `full_history`. **Drop:** `context_reset`, `observation_truncation`, `selective_retention`.
|
| 176 |
|
| 177 |
**Part C β what remains (beyond the workshop).** The screen answered the core question; everything below *hardens* or *extends* it and is **gated on a spend or data decision from Omar** β none is required for the workshop.
|
| 178 |
|
| 179 |
1. **Promotion (rigor, not new findings).** Re-run the 2-3 winners (+ 1-2 combos) on the full batteries (60 single-turn + 32 sessions + 30 replay) Γ 3 trials, with paired statistical tests and per-variant failure-taxonomy diffs, to turn the screen's coarse n=12 rankings into confident numbers; optionally an Anthropic (Haiku) re-run of the prefix-rewriting arms (`prompt_compression`, `context_reset`, `aggressive`) to test whether explicit caching flips F2's cost ranking. **~$1,300-1,800 at corrected pricing** (the old "$300-400" was at pre-correction prices; Γ the 4.4 fix β estimate precisely before running, since the per-turn cost is now ~$0.25).
|
| 180 |
+
2. **Finish the v2 contradiction tier β the highest-value new dataset (already built and partially run; see the V2 execution note below).** Moderate sessions: plant A, update to Aβ², then probe after prod compaction has evicted A from the kept-recent window. This is the one correctness regime where `full_history` itself might lose (it sees both A and Aβ² and must choose the current one) β yet the partial run so far shows the opposite (`full_history` contradiction **2/2** vs `prod` **0/3**), so that regime has not actually appeared. What remains is finishing Tier 1 (the missing `full_history` session, then Tier-1 `profile_memory` and optionally `incontext_history_retrieval`) and adding trials, not building the dataset. **(2026-06-19 β now run in full on DeepSeek-V4-Flash rather than Gemini: F26 confirms `full_history` 3/3 contradiction vs `prod` 0/3, so the regime did not appear on a second model either; the Gemini Tier-1 finish is now optional cross-model confirmation.)**
|
| 181 |
+
3. **The `incontext_history_retrieval` long-session cost test β principled but less product-critical.** The screen showed `incontext` works (83%, F16) but couldn't show a cost benefit on β€13-turn sessions. Whether retrieve-old-turns beats `full_history` *once sessions get genuinely long* needs a token-calibrated long-session v2 tier; useful for the workshop argument, but gated by whether that regime matters in real tutor telemetry. **(2026-06-19 β run on DeepSeek (F25) at 36 turns: `full_history` stays cheapest and `incontext` works but does not beat it on cost under first-party caching; whether the answer flips on a 10Γ cache provider like Gemini/Anthropic is still open.)**
|
| 182 |
+
4. **Conditional builds.** Build `temporal_graph_memory` only if `full_history` fails contradictions (F26: it did **not** on DeepSeek β 3/3 β so this stays unbuilt), `delta_summarization` only if the long-horizon cost tier shows room to beat full history (F25: `full_history` still cheapest at 36t on DeepSeek, so no room there β though a 10Γ cache provider is untested), and `entity_memory` only if multi-project probes show fact bleed. `collection_memory` is a separate cheap v1/product follow-up for verbatim fact storage (F22 tested the current profile write-back, not that). `hierarchical_summarization` and `sleeptime_consolidation` are deferred. The step-by-step v2 plan is in `evals_part_c_plan.md` β "Battery v2".
|
| 183 |
|
| 184 |
**Deliberately not pursued.** *Stretch (heavier, likely later):* sub-agent isolation, reframed as a tool-output-token play β keep noisy `run_kb_command` output out of the main context (ties to F1); temporal-graph memory is already the conditional build in item 4 above. *Dropped as low-information given the findings:* the skills / lazy-prompt-loading family (only a ~458-token win β see the talk-outline correction below), procedural memory, GraphRAG, and multi-agent / parallel-research agents. Context for the `kb_off` arm (F17/F23): the KB is the dominant grounding tool β β89% of Part B turns, ~7.7 KB vs ~0.9 retrieval calls/turn over 1,088 turns β so disabling it forces the 100k-token retrieval fallback, which is why it raised cost/latency.
|
| 185 |
|
|
|
|
| 223 |
- `data/eval/README.md` β battery schemas + glossary of terms; `review_log_v1.md` β dataset audit trail.
|
| 224 |
- `evals/` β the harness code; `app/memory_presets.py`, `app/telemetry.py` β the app-side hooks.
|
| 225 |
- `runs/b_report/`, `runs/c_report/` β generated tables, token curves, blinded grading workbook (Part B and the Part C screen). Re-grade / follow-up reports: `runs/kbfair_report/` (F23 KB-fair recall), `runs/d_report_profile_memory_active/` (F22 profile rerun), `runs/e2_v2_partial_report/` (v2 partial).
|
| 226 |
+
- `runs/ds_v2_t1_report/`, `runs/ds_v2_t2_report/` β **DeepSeek-V4-Flash** v2 matrix (F25/F26: cost + contradiction + long-horizon), graded via the subagent path (`runs/ds_judge/`). Shared on HF as `eval_runs/part_f_deepseek_v2/` (the standard `mv eval_runs/part_*/* runs/` download restores them). Provider added in `app/chat_service.py` (`deepseek` / `openrouter`), pricing in `app/telemetry.py`.
|