File size: 9,069 Bytes
ceb5715 86e4690 ceb5715 c271e5e 86e4690 ceb5715 86e4690 ceb5715 c271e5e ceb5715 86e4690 ceb5715 86e4690 ceb5715 86e4690 ceb5715 86e4690 ceb5715 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | ---
license: apache-2.0
language:
- en
pipeline_tag: text-ranking
tags:
- context-compression
- prompt-compression
- agents
- coding-agents
- gradient-boosted-trees
- lightgbm
- extractive
---
# trim-1
trim-1 is a small model that decides which lines of a context an AI agent
needs for its current ask, and drops the rest.
Give it a context (a tool result, a file, a log, a long chat) and the current
query. It returns the context's own lines, in their original order, with a
short marker wherever lines were removed. It never rewrites or summarizes a
line, so identifiers, paths and error text come through exactly as they were.
- **1.2 MB.** 712 gradient-boosted trees, not a neural network.
- **Milliseconds on one CPU core.** No GPU, no network call, no extra model request.
- **Deterministic.** No sampling and no randomness: the same context and query give the same output.
- **Verbatim.** Every kept line is a line of the input.
It saves the most on long-document retrieval, where it removes most of the
input and keeps the evidence. On short coding-agent tool outputs it saves
little by design. See [Which setting to use](#which-setting-to-use).
trim-1 is the model inside [Caveman](https://github.com/JuliusBrussee/caveman).
The code is at [caveman-ai/trim-1](https://github.com/caveman-ai/trim-1).
## How it works
1. The context is split into lines.
2. Each line gets 67 numeric features, computed against the query:
- **Lexical match:** BM25 against the query, query-term coverage, shared
bigrams and trigrams, compound identifier hits.
- **Line kind:** whether the line reads as an error, a test result, a path,
a heading, a diff header, a function signature, a JSON key or a stack frame.
- **Position and shape:** where the line sits, its length, its indent and
how the indent changes.
- **Neighbours:** how the lines around it, and its enclosing header, score.
3. The trees turn each feature row into a keep probability.
4. An operating point turns the probabilities into a selection. It keeps every
line scoring above a share of the best line's score, the top few lines
regardless, one line of context on each side, and the enclosing block header.
Three operating points ship:
| point | floor (share of best line's score) | use |
|---|---:|---|
| `conservative` | 0.0035 | cut least |
| `balanced` (default) | 0.008 | the default |
| `aggressive` | 0.035 | cut most |
trim-1 fails closed. It returns the context unchanged when the query is blank,
the context is under 2,000 bytes, the context is over 8 MiB or 200,000
lines, or the cut would remove less than 10% of the bytes.
## Results
One run on 2026-10-11, on frozen holdout splits of public suites. Operating
points were chosen on dev splits and holdout was scored once.
**Evidence kept.** A case passes when every piece of labelled evidence is still
in the output. Cut is the share of tokens removed (`cl100k_base`, counted
locally).
| suite | cases | what must survive | point | pass rate | token cut |
|---|---:|---|---|---:|---:|
| agent traces | 200 | strings a coding agent used in its next turns | balanced | 100.0% | 1.9% |
| code context | 150 | the lines the gold patch edits, inside retrieved code | balanced | 90.7% | 21.8% |
| code context | 150 | | aggressive | 56.7% | 66.9% |
| multi-hop QA | 300 | human-marked supporting facts | balanced | 100.0% | 1.7% |
| multi-hop QA, long (8k-32k tokens) | 90 | | balanced | 94.4% | 88.9% |
| haystack (10k-50k tokens) | 60 | 1-3 hop facts in logs, JSON, code and prose | balanced | 75.0% | 54.4% |
**Answers kept.** A reader model answers from the output and a judge model
grades the answer. "Full" is the reader given the uncompressed context.
| suite | cases | full | balanced | aggressive |
|---|---:|---:|---:|---:|
| agent traces | 100 | 100% | 99% | 98% |
| multi-hop QA, long | 90 | 88.9% | 85.6% | 76.7% |
| multi-hop QA | 100 | 85.0% | 85.0% | 77.0% |
| haystack | 60 | 91.7% | 70.0% | 48.3% |
**Speed and memory.** Ten real inputs per size, one call at a time after a
warm-up, on one CPU core while other jobs ran on the machine.
| input tokens | p50 latency | memory (RSS) |
|---:|---:|---:|
| 700 | 1.1 ms | 24 MB |
| 5,000 | 7.2 ms | 28 MB |
| 20,000 | 22 ms | 31 MB |
| 60,000 | 63 ms | 39 MB |
## Which setting to use
The setting decides how hard trim-1 cuts, and cutting harder costs quality.
Every line it removes is a line the model can no longer read, so a higher
setting saves more tokens and loses more of what the task needed.
How much you can cut before quality drops depends on the context:
| context | setting | token cut | evidence kept |
|---|---|---:|---:|
| coding-agent tool outputs | `balanced` | 1.9% | 100.0% |
| coding-agent tool outputs | floor 0.06 (between `balanced` and `aggressive`) | 27.1% | 92.0% |
| retrieved code | `balanced` | 21.8% | 90.7% |
| retrieved code | `aggressive` | 66.9% | 56.7% |
| long documents (8k-32k tokens) | `balanced` | 88.9% | 94.4% |
**Coding-agent tool outputs: use a low setting.** Stay at `balanced` or
`conservative`. A tool output is short and dense: most of its lines are things
the agent uses in its next turns. At `balanced` trim-1 keeps all of it and
saves about 2%. Pushed to a 27% cut, 8% of cases lose something the agent went
on to use. Expect small savings here, and do not raise the setting to get more.
**Long-document retrieval: this is what trim-1 is for.** A long document holds
a few lines that answer the query and a lot that do not. At `balanced` trim-1
removes 89% of the tokens and keeps the supporting evidence in 94% of cases,
and a reader model answers 85.6% of questions from the output against 88.9%
from the full document. `aggressive` drops that to 76.7%, so `balanced` is the
setting to use here too.
**Retrieved code sits in between.** `balanced` cuts 22% and keeps the lines the
fix touches in 91% of cases. `aggressive` cuts 67% and keeps them in 57%, which
is too lossy for most uses.
## Limits
- **Entity chains.** trim-1 drops later hops that share no words with the
query. This is the main cause of its haystack losses.
- **It needs a query.** With no query it does nothing.
- **Line-level only.** It keeps or drops whole lines; it does not shorten a
long line.
- **English.** Training and evaluation data are English text and source code.
- **One run.** The numbers above come from a single run. Suites are clustered
by session, repository or conversation, so per-case intervals understate the
uncertainty. The judge model was not validated against human labels.
- **In-distribution QA.** The multi-hop QA suites use the validation split of a
dataset whose train split is in the training data.
- **Not a savings claim.** Token cuts are local token counts on benchmark
cases, not measured provider billing.
## Training data
trim-1 was trained on public, commercially licensed data only. Labels are the
ones each source provides: human-marked spans and supporting facts, the lines a
gold patch edits, the element a person acted on, and what a coding agent used
in its next turns. No language model wrote a label.
Sources fall into four groups:
- **Agent trajectories:** public coding-agent runs, labelled by what the agent
used next.
- **Code context:** issue-and-patch datasets over permissively licensed
repositories.
- **Documents and chat:** question answering, contract, finance and meeting
datasets with human evidence labels.
- **Structured output:** web pages, tool catalogs and API responses, SQL
schemas, tables and CI logs.
Non-commercial and unlicensed datasets, and code from copyleft or unlicensed
repositories, were left out. Every training
context was checked against the evaluation contexts and repositories and
removed on a match. No private session data is in the model.
## Files
| file | what it is |
|---|---|
| `model.bin` | the trees, 1,245,358 bytes, sha256 `75478721d9992c3cbe6a1874ddf363ae6d78935a1fa526fb6fac1d0f6f3cdc2d` |
| `LICENSE` | Apache-2.0 |
`model.bin` layout, little endian:
```
"KEEP" 4 bytes
version uint32 (1)
features, trees, nodes, leaves uint32 each (67, 712, 44144, 44856)
feature names each: uint16 length + bytes
tree roots []int32
node feature []int32
node threshold []float64
node left, node right []int32 each
leaf values []float64
```
A child or root below zero is the leaf `^index`. A node sends a row left when
`row[feature] <= threshold`. A line's score is the sigmoid of the summed leaf
values.
## Use
The code is on GitHub: [caveman-ai/trim-1](https://github.com/caveman-ai/trim-1).
It is pure Go with no dependencies, and the model is embedded.
```bash
go install github.com/caveman-ai/trim-1/cmd/trim@latest
trim --query "why does the build fail" build.log
```
From Go:
```go
import trim "github.com/caveman-ai/trim-1"
res := trim.Compress(context, query, trim.Options{Point: "balanced"})
fmt.Print(res.Output)
```
## License
Apache-2.0.
|