Qwen2.5-1.5B passage reader for IRS Publication 17 (2025)

This is Qwen/Qwen2.5-1.5B-Instruct, fine-tuned with LoRA (merged into the weights) to answer questions about IRS Publication 17 (Your Federal Income Tax, 2025) from passages you retrieve and put in the prompt. It cites the passages it used, and says it doesn't know when they don't hold the answer. (It writes citations in two formats, [1] and ใ€1โ€ L1-L4ใ€‘; see Limitations.)

For education only. This model is a demonstration of a training method. It is not a tax expert, and it makes no claim to subject-matter expertise. It is not tax, legal or financial advice. It can be wrong, even when it cites a passage. Don't rely on it for any real tax decision: read the publication itself, or ask a qualified professional.

It is a reader, not a knowledge base: without passages it scores 0.18 on its own test set. Use it behind a retriever over Publication 17. It knows nothing about other years, other publications or your situation.

Trained with BrewSLM, a platform for building small language models from your own documents. Every step below (data generation, filtering, training, evaluation, packaging) ran through it. The story behind this model: Teaching a 1.5B model to read Pub 17: two misses, one pass (how this model was built, including the two attempts that didn't clear the bar), which follows the fine-tune lost, retrieval won, and more on the BrewSLM blog. Non-commercial showcase; no warranty.

Result

157 held-out test questions, scored by a local judge model (gemma4:12b) as correct / partial / wrong against an answer key (score = correct + ยฝ partial, averaged). Every arm gets the same retrieval: top-3, 600-character passages, no reranker.

Test score (correct / partial / wrong)
Base Qwen2.5-1.5B-Instruct + passages (the bar) 0.570 (82 / 15 / 60)
This model + passages 0.688 (100 / 16 / 41)
This model, no passages 0.185
Base, no passages 0.073

Compared row by row with the bar on the same 157 questions, this model is better on 32, worse on 12 and the same on 113: +0.118, 95% CI +0.054 to +0.182.

How much to trust that number:

  • The pass rule was written before any model was scored. The test and validation sets were frozen and checksummed first. Three seeds were trained on identical data. The seed with the best validation score is published here (this one, seed 44). The rule required it to beat the bar with a CI lower bound above 0, and at least 2 of the 3 seeds to beat the bar too.

  • All three seeds beat the bar, but by different margins.

    Seed Test score Paired difference vs bar (95% CI) Validation score
    42 0.637 +0.067 (+0.003 to +0.131) 0.710
    43 0.659 +0.089 (+0.026 to +0.152) 0.704
    44 (this model) 0.688 +0.118 (+0.054 to +0.182) 0.723

    Averaged over the three seeds, the gain is +0.091 (CI +0.028 to +0.155). Seed 42 only just cleared the bar. The spread between seeds is about as large as the weakest seed's gain, so expect roughly +0.07 to +0.12, not exactly +0.118.

  • What the claim covers: this model reads retrieved Publication 17 passages better than its base model does, on questions written by the same model family that wrote its training data (see below). It says nothing about general tax competence, or how it does on questions written by people.

  • Retrieval is the ceiling. The retriever found the right passage for 123 of the 157 test questions, the same for every arm. 28 of this model's 41 wrong answers are questions where the passage wasn't retrieved.

  • The judge is one model. gemma4:12b judged everything and also filtered the training answers (below), so its preferences are built into both the data and the score.

How the data was made

Everything was generated locally with open-weight models served by Ollama. No cloud model was used at any step, including the test and validation sets.

  • Source: IRS Publication 17 (2025) PDF, cleaned (page headers and footers removed) and split into 1,064 passages.
  • Questions and reference answers: gpt-oss:120b wrote 3 question / answer pairs per passage (3,187 pairs). Questions that pointed at "the passage" instead of standing alone were rewritten or dropped (60 rewritten, 9 stripped).
  • Test and validation sets: 157 questions each, written by gpt-oss:120b. Each answer had to be quotable from its source passage. No question is shared between train, validation and test, and test and validation share no source passage.
  • Training answers: for each training question, gpt-oss:120b answered from the same top-3 retrieved passages the model sees at inference time. That is why the targets cite passages and sometimes say "I don't know" (272 answers do).
  • Filter: gemma4:12b graded every training answer against its reference answer. Only answers graded correct were kept. Partial answers were dropped as well as wrong ones.
  • Critique and revise: each answer the filter dropped got one revision round. gpt-oss:120b critiqued it, the same model rewrote it, and gemma4:12b re-graded the rewrite and had the final say. Of 628 dropped answers, 242 were fixed and kept. The other 386 stayed out: 317 were still graded partial or wrong, and 69 revisions became "I don't know" answers. Some training answers are therefore revisions written under critique by gpt-oss:120b, not first drafts.
  • Training set: 2,779 passage-prompt rows (question + 3 retrieved passages โ†’ teacher answer), seed 44.

Training

LoRA r 16, alpha 32, dropout 0.05, on all attention and MLP projections. bf16, AdamW, learning rate 2e-4 decaying to 0, effective batch 16, loss on the answer tokens only, max sequence length 2048 (the longest row is 1,919 tokens). 2 epochs, 348 steps, final train loss 0.446, eval loss 0.531. Trained on one NVIDIA GB10. The adapter was merged into the base weights in fp32.

Prompt format

The model was trained on Qwen's chat template. The system message holds the numbered passages and the instruction, and the user message is the question. Keep this layout; other layouts were never trained or tested.

Passages from this project's documents:
[1] (p17-2025.pdf ยท passage 386) <passage text>

[2] (p17-2025.pdf ยท passage 211) <passage text>

[3] (p17-2025.pdf ยท passage 115) <passage text>
Answer the user's next question using only these passages and cite the passage numbers you used, like [1]. If the passages don't contain the answer, say you don't know.
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

repo = "TensorGreed/brewslm-pub17-passage-reader"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo, torch_dtype=torch.bfloat16, device_map="auto")

passages = ["...", "...", "..."]  # top-3 retrieved Publication 17 passages, ~600 characters each
system = "Passages from this project's documents:\n" + "\n\n".join(
    f"[{i}] (p17-2025.pdf ยท passage {i}) {p}" for i, p in enumerate(passages, 1)
) + ("\nAnswer the user's next question using only these passages and cite the passage numbers you used, "
     "like [1]. If the passages don't contain the answer, say you don't know.")
messages = [{"role": "system", "content": system},
            {"role": "user", "content": "Who must file a 2025 return?"}]
inputs = tok.apply_chat_template(messages, add_generation_prompt=True, return_dict=True,
                                 return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=256, do_sample=False)
print(tok.decode(out[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True))

Limitations

  • Trained and tested on one document. Publication 17 for 2025 only; tax rules change every year.
  • Training and test questions come from the same generator (gpt-oss:120b), so the test measures in-distribution reading, not robustness to how people phrase things.
  • It can still misread a passage that holds the answer: 13 of its 41 wrong test answers.
  • Two citation formats. 505 of the 2,779 training answers kept the teacher model's own citation style, ใ€1โ€ L1-L4ใ€‘ (passage 1, lines 1-4), because the cleanup step missed that form. The model copied it on 73 of 157 test answers, and 66 use [1]. The number is the passage number either way. If you parse citations, accept both, e.g. re.findall(r"[\[ใ€](\d+)", answer). The scores aren't affected: the judge grades facts, not citation format.
  • Educational demonstration only, with no claim to tax expertise. Not tax, legal or financial advice. Check answers against the publication itself, or ask a qualified professional.

Citation

Trained and evaluated with BrewSLM. The full story is in the build write-up on the BrewSLM blog. If you reuse the method, a link back is appreciated.

License

Apache 2.0, the base model's license. IRS Publication 17 is a work of the U.S. government and in the public domain.

Downloads last month
31
Safetensors
Model size
2B params
Tensor type
BF16
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for TensorGreed/brewslm-pub17-passage-reader

Adapter
(1647)
this model