Download pfbmax/diligent.py from rasynai/rasyn-iris: direct link, hf CLI and curl.
- Browser
- Download file 5.45 kB
-
https://huggingface.co/rasynai/rasyn-iris/resolve/main/pfbmax/diligent.py
- Command line
-
hf download hf://rasynai/rasyn-iris/pfbmax/diligent.py
-
curl -L -o diligent.py https://huggingface.co/rasynai/rasyn-iris/resolve/main/pfbmax/diligent.py
5.45 kB
| """Second retrieval round seeded by JUDGE-CONFIRMED papers. | |
| Everything measured here says the remaining loss is in two places: papers we | |
| never retrieve at all, and selection accuracy. Blind widening does not fix | |
| the first -- a wider fanout raises pool recall (0.533 -> 0.644) yet measured | |
| NEUTRAL-to-negative end to end, because the extra candidates dilute the | |
| window the selector can afford to look at. | |
| The difference here is WHERE we widen. After the pool judge runs, we know which | |
| papers it scored as perfectly relevant. Their citation neighbourhood is not a | |
| blind widening: a paper cited by, or citing, a confirmed-relevant paper is | |
| drawn from a distribution far denser in golds than another BM25 page. So this | |
| round expands only around confirmed hits, then judges the newcomers with the | |
| same cheap selector before letting any of them into the submission. | |
| That is what Ai2's own "diligent" mode buys with its long search budget, in a | |
| shape that stays cheap here: corpus calls are inexpensive compared to LLM | |
| calls, so the whole expansion costs wall-clock time plus one extra judge pass | |
| over the NEW papers only. | |
| Integrity: seeds come from the judge's scores on retrieved text, never from | |
| gold ids; emitted evidence is the paper's own verbatim abstract. | |
| Env: PFBMAX_DILIGENT=1 enables, PFBMAX_DILIGENT_SEEDS (default 8), | |
| PFBMAX_DILIGENT_PER_SEED (default 60), PFBMAX_DILIGENT_JUDGE (default 200). | |
| """ | |
| from __future__ import annotations | |
| import os | |
| DOC_CHARS = 1500 | |
| def _envi(name, default): | |
| raw = (os.environ.get(name) or "").strip() | |
| try: | |
| return int(raw) if raw else default | |
| except ValueError: | |
| return default | |
| def _cid(paper): | |
| for attr in ("corpusId", "corpus_id"): | |
| v = getattr(paper, attr, None) | |
| if v: | |
| return str(v) | |
| return None | |
| def expand(query, criteria, pool, client, inserted_before, judge, | |
| trace=None): | |
| """Return [(cid, evidence, score)] triples of NEW papers the judge rates | |
| highly. | |
| The score is included so the caller can merge by QUALITY. An | |
| earlier version appended newcomers to the TAIL: recall@FULL rose | |
| (0.1998 -> 0.2078, so the expansion really does find new golds) but the | |
| score FELL 0.0427, because tail papers cannot reach the top-K window while | |
| still joining the judged set and dragging nDCG down. Position is the whole | |
| game when the scored window is K ~ 2P. | |
| ``judge`` is criterion_judge; it is called only on the newcomers, so the | |
| marginal cost is one judge pass over ``PFBMAX_DILIGENT_JUDGE`` papers. | |
| """ | |
| tr = trace if trace is not None else {} | |
| order = list(pool.ranked()) | |
| if not order: | |
| return [] | |
| n_seeds = _envi("PFBMAX_DILIGENT_SEEDS", 8) | |
| per_seed = _envi("PFBMAX_DILIGENT_PER_SEED", 60) | |
| n_judge = _envi("PFBMAX_DILIGENT_JUDGE", 200) | |
| seen = set(order) | |
| seeds = order[:n_seeds] # pool is judge-sorted at this point | |
| fresh = {} | |
| for seed in seeds: | |
| for direction in ("references", "citations"): | |
| try: | |
| papers = client.get_citations( | |
| seed, direction=direction, limit=per_seed, | |
| fields="corpusId,title,abstract,year") or [] | |
| except Exception: | |
| papers = [] | |
| for p in papers: | |
| c = _cid(p) | |
| if not c or c in seen or c in fresh: | |
| continue | |
| abstract = (getattr(p, "abstract", "") or "").strip() | |
| title = (getattr(p, "title", "") or "").strip() | |
| if not abstract: | |
| continue # no verbatim text -> cannot furnish evidence | |
| fresh[c] = (title, abstract) | |
| tr["diligent_fresh"] = len(fresh) | |
| if not fresh: | |
| return [] | |
| items = list(fresh.items())[:n_judge] | |
| docs = [(c, (t + ". " + a)[:DOC_CHARS]) for c, (t, a) in items] | |
| # score each newcomer with the SAME replicated-grader scale the pool was | |
| # ranked on, so the caller can merge by quality instead of by arrival. | |
| # Parallel: 200 sequential judge calls is ~5 minutes a query, which makes | |
| # the round untestable regardless of whether it helps. | |
| from concurrent.futures import ThreadPoolExecutor | |
| model = os.environ.get("PFBMAX_CJ_MODEL", "gpt-4o-mini") | |
| workers = _envi("PFBMAX_CJ_WORKERS", 8) | |
| def _one(item): | |
| cid, text = item | |
| try: | |
| return cid, judge.score_paper(query, criteria, text, model) | |
| except Exception: | |
| return cid, None | |
| scored = {} | |
| with ThreadPoolExecutor(max_workers=max(1, workers)) as ex: | |
| for cid, v in ex.map(_one, docs): | |
| if v is not None: | |
| scored[cid] = v | |
| lookup = dict(items) | |
| try: | |
| gate = float(os.environ.get("PFBMAX_DILIGENT_GATE") or 0.66) | |
| except ValueError: | |
| gate = 0.66 | |
| keep = _envi("PFBMAX_DILIGENT_KEEP", 60) | |
| out = [] | |
| for cid in sorted(scored, key=lambda c: -scored[c])[:keep]: | |
| if scored[cid] < gate: | |
| break # below the grader's own "highly relevant" threshold: not worth a slot | |
| t, a = lookup.get(cid, ("", "")) | |
| ev = (a or t)[:1200] | |
| if ev: | |
| out.append((cid, ev, scored[cid])) | |
| tr["diligent_kept"] = len(out) | |
| tr["diligent_judged"] = len(scored) | |
| return out | |