|
Download README.md from localangle/cite: direct link, hf CLI and curl.
- Browser
- Download file 8.78 kB
-
https://huggingface.co/localangle/cite/resolve/main/README.md
- Command line
-
hf download hf://localangle/cite/README.md
-
curl -L -o README.md https://huggingface.co/localangle/cite/resolve/main/README.md
8.78 kB
| license: mit | |
| language: | |
| - en | |
| library_name: cite | |
| tags: | |
| - cite | |
| - paragraph-citation | |
| - retrieval | |
| - question-answering | |
| - news | |
| - encoder | |
| - modernbert | |
| - on-device | |
| pipeline_tag: text-ranking | |
| base_model: jhu-clsp/ettin-encoder-32m | |
| # Cite | |
| Which paragraphs answer the question. | |
| A small encoder that, given a question and ordered paragraph texts, returns a | |
| calibrated probability per paragraph and two thresholds (`needed`, | |
| `contributing`). | |
| | | | | |
| | --- | --- | | |
| | **Task** | Paragraph citation / needed-blocks | | |
| | **Size** | ~42 MB weights (trimmed vocab, int8 embeddings, fp16 rest); a larger 68M build is under [`68m/`](https://huggingface.co/localangle/cite/tree/main/68m) | | |
| | **Runtime** | CPU (PyTorch); browser (ONNX Runtime WASM) | | |
| | **Weights** | [v0.3.0](https://huggingface.co/localangle/cite/tree/v0.3.0) · [`web/`](https://huggingface.co/localangle/cite/tree/main/web) for WASM | | |
| | **Demo** | [localangle/cite-demo](https://huggingface.co/spaces/localangle/cite-demo) (in-browser) | | |
| Cite does **not** write an answer. It ranks the paragraphs you already have and | |
| flags which ones are needed to answer the question. | |
| > Question: *Who voted against the library renovation?* | |
| > → Cite highlights the paragraph naming Paulsen and Chen. | |
| ## Try it | |
| - **Live demo:** [localangle/cite-demo](https://huggingface.co/spaces/localangle/cite-demo) — paste an article, ask a question, see which paragraphs Cite cites. | |
| - **Local playground:** from the [cite](https://github.com/localangle/cite) repo, `uv run python deploy/cite_playground.py`. | |
| ## Install | |
| ```bash | |
| pip install "cite @ git+https://github.com/localangle/cite.git" | |
| # or, from a checkout: | |
| uv sync | |
| ``` | |
| Python ≥ 3.12. Needs `torch`, `transformers`, `safetensors`, `huggingface_hub`. | |
| ## Usage | |
| ```python | |
| from cite import CitePackage | |
| cite = CitePackage.from_pretrained("localangle/cite") | |
| paragraphs = [ | |
| "The council approved a $4.2 million library renovation.", | |
| "Paulsen and Chen voted against the measure.", | |
| "Construction starts in March.", | |
| ] | |
| scores = cite.predict("Who voted against the renovation?", paragraphs) | |
| for score in scores: | |
| if score.needed: | |
| print(score.index, score.probability, paragraphs[score.index]) | |
| ``` | |
| `score.needed` uses the packaged threshold (0.76). `score.contributing` is a | |
| looser relatedness cut (0.17). Logits are Platt-scaled to probabilities at load | |
| time; you do not fit thresholds yourself for the published package. | |
| Load a local folder the same way: | |
| ```python | |
| cite = CitePackage.load("path/to/package") # or from_pretrained("./path") | |
| ``` | |
| ## Files | |
| | File | Contents | | |
| | --- | --- | | |
| | `cite.json` | Format, Platt scaling, thresholds, source metadata | | |
| | `weights.safetensors` | Trimmed encoder + head (int8 token embeddings, fp16 elsewhere) | | |
| | `encoder/` | ModernBERT/Ettin config for the trimmed vocabulary | | |
| | `tokenizer/` | Tokenizer with `[MASK]` as the block marker | | |
| | `web/` | Browser package: `model.onnx` (~36 MB int8), `vocab_map.bin`, `cite-web.json`, `tokenizer/` | | |
| | `68m/` | The 68M build as a full Python package (same layout as the repo root; ~107 MB weights) | | |
| | `web-68m/` | Browser package for the 68M build (`model.onnx` ~88 MB int8) | | |
| PyTorch weights expand to fp32 at load; only storage is compressed. The `web/` | |
| ONNX graph is what the static demo runs in WASM (soft cap 2048 tokens). | |
| ## Accuracy | |
| On a held-out real-news needed-blocks eval (v59, 1,800 questions over local | |
| news outlets; threshold chosen on a separate calibration split): | |
| | Metric | Cite-32M package | | |
| | --- | --- | | |
| | Coverage | 0.692 | | |
| | Exact set match | 0.725 | | |
| | Empty-set accuracy | 0.897 | | |
| | Any-extra rate | 0.066 | | |
| The browser ONNX build on the same eval: exact 0.722, coverage 0.687, empty 0.902. | |
| ### Broad and abstract questions | |
| The eval above uses specific fact-lookup questions. Later versions add training so that broad | |
| questions ("How will the library change as a result of the renovations?") score the paragraph | |
| that answers them instead of washing out. | |
| - **v0.2.0** fine-tuned on LLM-written broad rewrites of real training questions. | |
| - **v0.3.0** adds synthetic short articles where nearly every paragraph shares the topic word, | |
| with hard negatives, then averages the weights 0.75/0.25 with v0.2.0 to keep the specific-question | |
| operating point. | |
| On a 117-item hand-written probe (specific question vs. an abstract rewrite of it; 92 items after | |
| removing 25 where several paragraphs plausibly answer the rewrite), abstract-question results: | |
| | Abstract question | v0.1.0 | v0.2.0 | v0.3.0 | | |
| | --- | --- | --- | --- | | |
| | Top-1 (all 117) | 0.650 | 0.744 | 0.752 | | |
| | Needed recall (all 117) | 0.402 | 0.752 | 0.761 | | |
| | Top-1 (92 audited) | 0.826 | 0.848 | 0.859 | | |
| | Top-3 (92 audited) | n/a | 0.957 | 0.978 | | |
| Packaged-model numbers for v0.2.0 and v0.3.0; v0.1.0 from the fp32 student. Specific-question probe | |
| top-1 is 0.949 (v0.2.0) and 0.966 (v0.3.0). The probe is small and written by one author; | |
| treat it as a regression check, not a benchmark. | |
| On a short, topic-saturated example article, v0.3.0 improves but does not solve the hardest | |
| case: for "What specific improvements will be made...?" the improvements paragraph moves from | |
| rank 4 (18%) to rank 2 (60%), still behind a funding paragraph that repeats the word | |
| "renovation". See `experiments/107-cite-abstract-probe`, `experiments/108-cite-broad-consistency` | |
| and `experiments/109-cite-hard-negatives`. | |
| ## Cite 68M | |
| A larger build, distilled from the same teacher with the same data and training steps, on | |
| [Ettin-68M](https://huggingface.co/jhu-clsp/ettin-encoder-68m). It is more accurate, especially on broad | |
| and abstract questions, and about 3x slower. The 32M build above stays the default. | |
| ```python | |
| cite = CitePackage.from_pretrained("localangle/cite", subfolder="68m") | |
| ``` | |
| The [demo](https://huggingface.co/spaces/localangle/cite-demo) has a model switch; the 68M build downloads | |
| about 88 MB on first use and is cached after that. Packaged thresholds: needed 0.79, contributing 0.17. | |
| | | Cite 32M (v0.3.0) | Cite 68M | | |
| | --- | --- | --- | | |
| | Weights (package) | 41.8 MB | 107.0 MB | | |
| | Browser `model.onnx` | 36.3 MB | 88.3 MB | | |
| | v59 eval: coverage / exact / empty-set / any-extra rate | 0.692 / 0.725 / 0.897 / 0.066 | 0.729 / 0.763 / 0.923 / 0.042 | | |
| | Abstract probe, 92 audited items: top-1 / needed recall | 0.859 / 0.859 | 0.902 / 0.891 | | |
| | Abstract probe, all 117: top-1 | 0.752 | 0.786 | | |
| | Browser (WASM, 1 thread): 7 paragraphs / 44 paragraphs | 185 ms / 1.4 s | 547 ms / 4.2 s | | |
| On the short example article, for "What specific improvements will be made to the library as a result of the | |
| renovation?", the improvements paragraph scores 93.5% on 68M (60% on 32M, behind a funding paragraph). | |
| The same caveats apply: one run per size, a small hand-written probe, and browser timings from a single | |
| machine. See `experiments/110-cite-68m`. | |
| ## Latency | |
| Batch-1, CPU, AMD EPYC (HF `cpu-upgrade`, 8 vCPU) for the related ONNX int8 | |
| form: about 44 ms p50 at 5–12 paragraphs and 268 ms at 33–60. The portable | |
| PyTorch package this repo ships is the accuracy-matched serving artifact; long | |
| documents are dominated by attention cost. | |
| ## How it works | |
| Cite is a fine-tuned [Ettin](https://huggingface.co/jhu-clsp/ettin-encoder-32m) | |
| encoder (ModernBERT family). The question and each paragraph are packed into | |
| one sequence with a `[MASK]` marker before every paragraph; the head reads the | |
| marker states. A 400M teacher labeled real news; the 32M student was distilled | |
| then fine-tuned on LLM-written broad rewrites of its training questions | |
| (consistency distillation) and on synthetic hard-negative articles, and compressed (trimmed vocabulary, int8 | |
| embeddings, fp16 weights). | |
| ## Limitations | |
| - Cite ranks paragraphs; it does not generate answers or quote spans inside a | |
| paragraph. | |
| - Lexical overlap still matters: "big 10" and "Big Ten" can score differently. | |
| Scores for a paragraph also drift down in very long articles. | |
| - Eval is English news-style text. Other domains are unmeasured. | |
| - Empty-set accuracy drops a few points from calibration to eval; treat the | |
| packaged threshold as a starting point for a new domain. | |
| - Documents longer than `max_tokens` (7999) drop trailing paragraphs. | |
| - Training used private teacher labels and news text that is not redistributed | |
| here. | |
| ## Built on | |
| - [Ettin encoder 32M](https://huggingface.co/jhu-clsp/ettin-encoder-32m) (MIT) | |
| by JHU CLSP. Fine-tuned and compressed for Cite; see | |
| `THIRD_PARTY_NOTICES.md`. | |
| ## License | |
| MIT for the Cite code and this package's weights, subject to the Ettin MIT | |
| notice above. | |
| ## Citation | |
| ```bibtex | |
| @software{cite_2026, | |
| title = {Cite: Which paragraphs answer the question}, | |
| author = {Local Angle}, | |
| year = {2026}, | |
| url = {https://huggingface.co/localangle/cite}, | |
| } | |
| ``` | |