October 2026

By Umberto Breglia

PFlash v2: 3x faster processing on long prompts

If you ask questions over long documents, retrieved passages or a whole codebase on one GPU, reading the prompt can be most of the wait before the first token. PFlash sits in front of the model and decides which parts of a long prompt the model actually reads. On six public long-context sets it answers 92 of 124 questions against full prefill's 94, while the model reads a median 27% of the prompt, and on one GPU the first token arrives 3.7× sooner on average.

A long document with a few whole units highlighted in gold, flowing into a short compressed prompt
Document QA on one Radeon AI PRO R9700: 15.7 → 6.2 seconds to the first token, with the same correct answer from both runs.
CodeDebug on one Radeon AI PRO R9700: 132.0 → 28.4 seconds to the first token. Both runs identify the faulty function.
92 / 124questions answered correctly on six public sets, against 94 for full prefill
27%of the prompt reaches the model (median)
3.7×sooner to the first token on average, same sets, one R9700

TL;DR

Why a new PFlash

The first PFlash post showed the compressor on needle-in-a-haystack: hide a sentence in a long filler document, ask for it back, and check that compression kept it. That test is saturated: full prefill, the first PFlash and today's PFlash all score 100 of 100 on our 100-case sweep from 16K to 120K tokens. This release redesigns every stage, and the benchmarks that follow are chosen to be hard in different directions.

How PFlash works

A long prompt is mostly material the answer does not need. PFlash finds the part that matters before the big model sees any of it. A small drafter reads the whole prompt once. Two tiny probes on its activations cut the prompt into units and find the question. A relevance head ranks the units against that question. A budget decides how much to keep, and the kept units go to the target model in their original order.

The PFlash pipeline, old and new, ending at the same target model The old PFlash ran a 0.6 billion parameter drafter with a 32 thousand token window, scored attention mass over every layer, cut the prompt into fixed chunks and kept a fixed fraction of them. The new PFlash runs a 0.8 billion parameter drafter with a 262 thousand token window, a segment probe cuts the prompt into whole units, a request probe finds the request, a learned head scorer ranks the units against it and a length curve sets the budget. Both paths end at the same target model, which prefills what survived. Old PFlash Drafter Qwen3-0.6B 32K window Scorer attention mass over every layer Chunks fixed size, cut anywhere Keep ratio fixed fraction of chunks kept New PFlash Drafter Qwen3.5-0.8B 15 blocks, 262K Segment probe whole units: paragraph, function, record Request probe finds the request wherever it sits Head scorer learned head, ranks the units against it Budget length curve 31.5% → 22.5% of what can go Target prefills what survived

1. Drafter: read the whole prompt

The drafter is Qwen3.5-0.8B with a native 262K-token window, so it can read the longest prompts here in one pass. Only its first fifteen blocks run. They produce the activations that everything after this step works from; the drafter never generates a token.

That shallow pass is most of why PFlash is much faster than full prefill.

2. Segment probe: cut the prompt into whole units

Fixed-size chunks split a function from its signature, a record from its key, an email from its sender. A tiny probe on the drafter's activations predicts where each unit starts instead: a paragraph, a function, a class, a record, a tool call, a chat turn. Cuts fall on line starts, so a unit is always whole lines. The rest of the pipeline keeps or drops whole units, so what reaches the model reads as coherent text.

3. Request probe: find the question

Ranking needs to know what is being asked, and the question is not always at the end. In a RAG prompt it can sit above the retrieved passages; in a chat it may be a short follow-up that only makes sense with the previous turn. A request probe marks the tokens that carry the request, wherever they are.

4. Head scorer: rank the units

A small learned relevance head scores every unit against the request the probe found, using the drafter's activations. It replaces the hand-built attention-mass scorer of the first PFlash and is the largest single quality gain since the first post.

5. Budget: decide how much to keep

The question and the instructions around it are always kept. Of the rest, a length curve sets how much may stay: 31.5% at 16K tokens, tapering to 22.5% at 120K. Units are taken by relevance per token until the budget is full. With the parts that are always kept and the markers for what was left out, the model reads a median 27% of the prompt on the sets below.

6. Target model: answer from the kept units

The kept units go back in their original order, and the target model prefills only them. Where lines were left out, a one-line marker says how many, and a note at the top of the message says it was shortened, so the model knows the text has gaps instead of reading it as complete. Here the target is Qwen3.8-27B. Everything before this step runs on the small drafter, so the expensive prefill shrinks to roughly the size of the kept text.

When PFlash steps aside

Compressing is a bet that the kept units are enough. PFlash only makes that bet on long content the server has not read yet, and serves everything else as it is.

Benchmarks

TargetQwen3.8-27B, IQ4_XS
PFlashthe release configuration described above (recall threshold θ = 7.5%); the same budget curve on every set
GPUAMD Radeon AI PRO R9700 (32 GB), one request at a time; PFlash on two identical R9700 machines in parallel, full prefill from earlier R9700 runs. Full prefill on LongCodeQA and pflash-bench comes from an earlier run on another GPU, with its time to first token modeled for the R9700 (under 0.6% error on held-out sets).
Decodinggreedy, one seed, thinking off
Output limit2,048 tokens (32 for BRIGHT); an answer that reaches the limit counts as wrong in every arm
Scoringeach benchmark's official metric, unchanged; no LLM judge

The sets are hard in different directions. Document QA is the RAG shape: a question over many retrieved passages, most of them irrelevant (its 15 RULER QA prompts are reported separately as well). LongBench-v2 is a standard long-context suite. NoLiMa hides needles that share no words with the question. CodeDebug is a repository with a planted bug, at 82K to 98K tokens. BRIGHT asks reasoning-heavy questions whose supporting passage shares little wording with them. LongCodeQA asks questions about real repositories at 32K, 64K and 128K tokens, filtered to questions that cannot be answered without the code. pflash-bench is our own private set of real-use prompts: 102 single requests and 12 chat sessions with 68 turns. Its prompts are not published, so its rows are not reproducible from outside.

Quality

Correct answers per set, full prefill against PFlash Share of each set answered correctly, full prefill against PFlash: Document QA 27 and 27 of 30; RULER QA 13 and 13 of 15; LongBench-v2 7 and 4 of 12; NoLiMa 14 and 14 of 24; CodeDebug 23 and 24 of 30; BRIGHT 23 and 23 of 28; LongCodeQA 57 and 59 of 114; pflash-bench 98 and 94 of 102. Full prefill PFlash 0 25 50 75 100% Share of the set answered correctly Document QA 30 cases 27/30 27/30 RULER QA 15, in Doc QA 13/15 13/15 LongBench-v2 12 cases 7/12 4/12 NoLiMa 24 cases 14/24 14/24 CodeDebug 30 cases 23/30 24/30 BRIGHT 28 cases 23/28 23/28 LongCodeQA 114 cases 57/114 59/114 pflash-bench 102 requests 98/102 94/102
Correct answers per set, official metric, greedy decoding, one seed. PFlash: this release on the R9700. Full prefill: earlier R9700 runs; on LongCodeQA and pflash-bench, an earlier run on another GPU. The bar is the share of the set; the label is the raw count. pflash-bench is private.
Correct answers, official metric per set, one R9700. 32K tokens unless noted. The total counts each question once: the 15 RULER QA prompts are also in Document QA. † Full prefill from an earlier run on another GPU (see Benchmarks).
SetFull prefillPFlash
Document QA (30)2727
RULER QA (15, within Document QA)1313
LongBench-v2 (12)74
NoLiMa (24, 16K–32K)1414
CodeDebug (30, 82K–98K)2324
BRIGHT (28)2323
Six public sets (124 unique)9492
LongCodeQA (114, 32K–128K)57†59
pflash-bench, single requests (102, private)98†94
pflash-bench, chat turns (68, private)67†64

PFlash matches full prefill on Document QA, RULER QA, NoLiMa and BRIGHT, gets one more CodeDebug bug and two more LongCodeQA questions, and falls behind on LongBench-v2: 4 of 12 against 7, three questions that full prefill answers and none the other way. In two of those three the drafter's relevance scores were spread almost evenly across the prompt, a sign that no small part of it holds the answer. Over the six public sets PFlash answers 4 questions that full prefill misses and misses 6 that it answers, a net of 2 fewer (95% interval −7 to +3), inside the noise at this size. On our private pflash-bench it answers 94 of 102 against 98.

Time to first token

Median time to first token, full prefill against PFlash Median seconds to the first token, full prefill against PFlash, on one AMD Radeon AI PRO R9700: Document QA 29.8 and 9.6; LongBench-v2 27.5 and 8.8; NoLiMa 15.2 and 15.1; BRIGHT 35.5 and 10.6; LongCodeQA 42.5 and 12.7; CodeDebug 140.7 and 29.8. Full prefill PFlash 0 25 50 75 100 125 150 s Median time to first token, seconds Document QA 32K 29.8 s 9.6 s LongBench-v2 32K 27.5 s 8.8 s NoLiMa 16K–32K 15.2 s 15.1 s BRIGHT 32K 35.5 s 10.6 s LongCodeQA 32K–128K, full modeled 42.5 s 12.7 s CodeDebug 82K–98K 140.7 s 29.8 s
Median time to first token on one R9700, same runs as the quality table. PFlash includes scoring and the requests it served unshortened. LongCodeQA’s full prefill is modeled for the R9700.
Median time to first token, seconds, one R9700, from the same runs as the quality table. † Modeled for the R9700 (see Benchmarks).
SetFull prefillPFlashSpeed-up
Document QA29.8 s9.6 s3.1×
LongBench-v227.5 s8.8 s3.1×
NoLiMa (16K–32K)15.2 s15.1 s1.0×
BRIGHT35.5 s10.6 s3.3×
LongCodeQA (32K–128K)42.5 s†12.7 s3.4×
CodeDebug (82K–98K)140.7 s29.8 s4.7×

The gain grows with the prompt: the target's prefill grows faster than linearly with length, while PFlash hands it a fraction of the prompt. On short prompts there is little to win. NoLiMa shows where PFlash starts: 13 of its 24 prompts are around 16K tokens, too short for PFlash to act, so they are served whole in the same 15.2 seconds as full prefill and set the median, while its 32K prompts drop from 35.4 to 11.4 seconds.

Median time to first token by prompt length

Full prefillPFlash
Full prefill
16,384 prompt tokens: 15.2 s; 32,768 prompt tokens: 29.8 s; 92,160 prompt tokens: 140.7 s; 131,072 prompt tokens: 251.1 s
PFlash
16,384 prompt tokens: 15.1 s; 32,768 prompt tokens: 9.6 s; 92,160 prompt tokens: 29.8 s; 131,072 prompt tokens: 43.8 s
Median time to first token on one R9700, same runs as the table: NoLiMa at 16K, served whole by PFlash, Document QA at 32K, CodeDebug at 82K–98K (plotted at 90K), and at 128K the two LongCodeQA prompts that full prefill also ran on the R9700. Only the four marked points were measured; the lines only connect them.

Multi-turn chat

A chat is where the cache rules matter most. A long document arrives in one turn, and every later turn resends it along with the conversation so far. PFlash handles a chat one message at a time and never rewrites what the cache already holds.

We measure this on MTRAG, IBM's multi-turn RAG benchmark, in a variant where a long document arrives in the middle of the chat: 32 conversations and 255 turns, with about 44K tokens of documents in the first turn and another 44K pasted at the third. The model's own answers are fed back as the conversation, as a chat client would do; greedy decoding, thinking off, up to 1,024 output tokens, prefix cache on. The prefix cache keeps each turn up to its last message, so with full prefill a follow-up reads only what is new. MTRAG's reference answers are free-form, so a judge (Codex Sol 6.1, blind to the arm) compares each answer with the reference.

MTRAG with a pasted document, 32 conversations and 255 turns, one R9700. Time to first token is the median for each kind of turn; the whole chat is the sum of a conversation's times to first token, median over conversations. † Full prefill was not run on the R9700: its times are modeled from each turn's prefilled tokens with the measured R9700 prefill speed.
Full prefill†PFlash
Correct answers197189
First turn, 44K53.1 s14.7 s
Pasted turn, 44K new93.7 s25.9 s
Follow-ups2.5 s5.4 s
Whole chat160 s85 s

PFlash wins on the long turns: the first answer comes in 14.7 seconds instead of 53.1, and the answer to the pasted document in 25.9 instead of 93.7. Follow-ups cost more, 5.4 against 2.5 seconds, because PFlash scores each new question on the drafter and prefills what recall brings back, yet over a whole chat it comes out well ahead, a median 85 seconds of waiting against 160. Quality is close but not level: 189 of 255 turns right against 197, a difference inside the noise at this size (95% interval −18 to +2 turns), with PFlash ahead over the first four turns and behind from the fifth on, where late questions reach further back. How much a follow-up recalls is set by θ, chosen once on a development replay outside every benchmark here; a lower value recalls more and may answer better on long chats, at some cost in follow-up time.

Agent sessions

An agent session follows the same rule as a chat: PFlash shortens only new long content, and everything the server has already read is reused as it is.

Limits and what's next

Resources


Related

Ask your own documents, on your own box

Open-source engine. The compressor sits in front of the model you already run.

GitHub First PFlash post Discord