evals(slm): Axis-A memory-compaction arm on local SLMs
Browse filesCompanion to the Axis-B doc-compaction study: run the memory-compaction
methods (how to compact a GROWING conversation history) on a small local
model forced to compact, using the real app middlewares.
- build_chat_model: add an `ollama` provider that routes through Ollama's
OpenAI-compatible endpoint (ChatOpenAI base_url). Experiments only; default
behavior unchanged. The context window is set on the Ollama side via a
num_ctx Modelfile variant, so full_history overflows a 32k window and every
compaction preset is forced to fire.
- run_slm_axis_a.sh: run the long-context session battery (turn-0 lesson +
questions, retrieval off) under each memory preset (full_history /
sliding_window / summarization_only / prompt_compression /
selective_retention / incontext_history_retrieval / delta_summarization /
hierarchical_summarization) on a num_ctx-capped SLM, then judge vs the
lesson and report. Tracing disabled (local, quota noise).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- app/chat_service.py +16 -1
- evals/run_slm_axis_a.sh +44 -0
|
@@ -759,6 +759,21 @@ def build_chat_model(model_name: str, include_thoughts: bool = False):
|
|
| 759 |
|
| 760 |
if provider == "openai":
|
| 761 |
return ChatOpenAI(model=actual_model, temperature=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 762 |
if provider == "anthropic":
|
| 763 |
try:
|
| 764 |
from langchain_anthropic import ChatAnthropic
|
|
@@ -797,7 +812,7 @@ def build_chat_model(model_name: str, include_thoughts: bool = False):
|
|
| 797 |
)
|
| 798 |
|
| 799 |
raise ValueError(
|
| 800 |
-
"Unsupported model provider. Use openai, anthropic,
|
| 801 |
)
|
| 802 |
|
| 803 |
|
|
|
|
| 759 |
|
| 760 |
if provider == "openai":
|
| 761 |
return ChatOpenAI(model=actual_model, temperature=1)
|
| 762 |
+
if provider == "ollama":
|
| 763 |
+
# Local SLM via Ollama's OpenAI-compatible endpoint (experiments only,
|
| 764 |
+
# e.g. the SLM compaction study). The model's context window is set on
|
| 765 |
+
# the Ollama side (a num_ctx Modelfile variant), not per request.
|
| 766 |
+
return ChatOpenAI(
|
| 767 |
+
model=actual_model,
|
| 768 |
+
temperature=1,
|
| 769 |
+
base_url=os.environ.get(
|
| 770 |
+
"OLLAMA_OPENAI_BASE_URL", "http://localhost:11434/v1"
|
| 771 |
+
),
|
| 772 |
+
api_key=os.environ.get("OLLAMA_API_KEY", "ollama"),
|
| 773 |
+
# Ollama streams usage only when asked; without this the telemetry's
|
| 774 |
+
# usage_metadata is empty and token counts come back as 0.
|
| 775 |
+
stream_usage=True,
|
| 776 |
+
)
|
| 777 |
if provider == "anthropic":
|
| 778 |
try:
|
| 779 |
from langchain_anthropic import ChatAnthropic
|
|
|
|
| 812 |
)
|
| 813 |
|
| 814 |
raise ValueError(
|
| 815 |
+
"Unsupported model provider. Use openai, anthropic, google-genai, or ollama."
|
| 816 |
)
|
| 817 |
|
| 818 |
|
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Axis-A SLM study: the memory-compaction methods (how to compact a GROWING
|
| 3 |
+
# conversation history) on a small local model forced to compact. Companion to
|
| 4 |
+
# the Axis-B doc-compaction study (evals/run_slm_compaction.sh).
|
| 5 |
+
#
|
| 6 |
+
# Setup that makes it a real test:
|
| 7 |
+
# - The long-context session battery: turn 0 loads the ~37.5k-token lesson,
|
| 8 |
+
# turns 1..N ask questions, retrieval OFF (--no-tools) so the agent must
|
| 9 |
+
# answer from whatever the memory preset KEPT in context.
|
| 10 |
+
# - A small window (a num_ctx=32768 Ollama model variant), so full_history
|
| 11 |
+
# overflows and every compaction preset is forced to fire.
|
| 12 |
+
# - Each preset runs the real app middlewares via run_battery, then
|
| 13 |
+
# compaction_study judges each answer vs the lesson (Gemini) and reports.
|
| 14 |
+
#
|
| 15 |
+
# Prereqs: `ollama serve`; build the 32k variant once, e.g.
|
| 16 |
+
# printf 'FROM qwen2.5:7b-instruct\nPARAMETER num_ctx 32768\n' | ollama create qwen2.5-7b-ctx32k -f /dev/stdin
|
| 17 |
+
# Build the battery once: uv run --env-file .env -m evals.compaction_study build --questions 15
|
| 18 |
+
#
|
| 19 |
+
# MODEL=ollama:qwen2.5-7b-ctx32k TAG=qwen2.5-7b bash evals/run_slm_axis_a.sh
|
| 20 |
+
set -u
|
| 21 |
+
cd "$(dirname "$0")/.."
|
| 22 |
+
|
| 23 |
+
# Local experiment: skip LangSmith upload (quota noise; we use context_stats).
|
| 24 |
+
export LANGSMITH_TRACING=false LANGCHAIN_TRACING_V2=false
|
| 25 |
+
|
| 26 |
+
BATTERY="${BATTERY:-data/compaction/longctx_session.jsonl}"
|
| 27 |
+
MODEL="${MODEL:-ollama:qwen2.5-7b-ctx32k}" # a num_ctx Ollama variant
|
| 28 |
+
TAG="${TAG:-qwen2.5-7b}" # short label for out dirs
|
| 29 |
+
# The Axis-A memory-compaction methods (full_history is the keep-all baseline).
|
| 30 |
+
PRESETS="${PRESETS:-full_history sliding_window summarization_only prompt_compression selective_retention incontext_history_retrieval delta_summarization hierarchical_summarization}"
|
| 31 |
+
|
| 32 |
+
for p in $PRESETS; do
|
| 33 |
+
out="runs/axisa_${TAG}_${p}"
|
| 34 |
+
echo "===== preset: $p -> $out ($(date)) ====="
|
| 35 |
+
uv run --env-file .env -m evals.run_battery --battery "$BATTERY" --preset "$p" \
|
| 36 |
+
--model "$MODEL" --no-tools --concurrency 1 --out "$out" > "${out}.log" 2>&1
|
| 37 |
+
echo " exit=$? : $p done ($(date))"
|
| 38 |
+
done
|
| 39 |
+
|
| 40 |
+
echo "===== report ($(date)) ====="
|
| 41 |
+
# Family A only (these ARE the in-context presets); skip the Family-B retrieval join.
|
| 42 |
+
uv run --env-file .env -m evals.compaction_study report \
|
| 43 |
+
--runs "runs/axisa_${TAG}_*" --family-b "" --out "runs/axisa_${TAG}_report"
|
| 44 |
+
echo "===== DONE ($(date)) ====="
|