Skip to content

Commit 2726832

Browse files
committed
feat: deepeval offline suite
1 parent a3c441e commit 2726832

3 files changed

Lines changed: 18 additions & 7 deletions

File tree

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ COPY app ./app
1717
RUN useradd -m screening-user
1818
USER screening-user
1919

20-
RUN python -c "from app.adapters.guard_classifier import ClassifierGuardrail; ClassifierGuardrail()"
20+
# Presidio recognizers (incl. GLiNER) lazy-load on first `.analyze()` call, not
21+
# at construction, so building the guardrail alone doesn't fetch GLiNER's
22+
# weights. Run an actual scrub so every model — spaCy, GLiNER, the injection
23+
# classifier — is downloaded and cached into the image before HF_HUB_OFFLINE
24+
# is set below; otherwise the first real request fails offline.
25+
RUN python -c "import asyncio; from app.adapters.guard_classifier import ClassifierGuardrail; asyncio.run(ClassifierGuardrail().scrub('warmup'))"
2126
EXPOSE 8000
2227

2328
ENV HF_HUB_OFFLINE=1

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ The **injection** (*manipulation* — text that tries to hijack the model's inst
6161
## Run the evals
6262

6363
```bash
64-
uv run pytest -m "not live and not prod" # deterministic — no model, no network. Run these in CI.
64+
uv run pytest -m "not live and not prod and not quality" # deterministic — no model, no network. Run these in CI.
6565
uv run pytest -m live # hits the real Presidio + GLiNER + injection classifier (+ a live LLM)
6666
uv run pytest -m prod --run-prod # hits the deployed prod endpoint (needs az login; opt-in on purpose)
6767

evals/metrics.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,24 @@
1313

1414
from evals.judge import PortkeyJudge
1515

16+
# One judge shared by every metric below. PortkeyJudge already caches its HTTP
17+
# clients per instance (see evals/judge.py) specifically so they're built once,
18+
# not once per call — instantiating a separate PortkeyJudge per metric would
19+
# undercut that by opening a separate client pool per metric instead.
20+
_JUDGE = PortkeyJudge()
21+
1622
# truthfulness; truthful claims / total claims
1723
# a claim = factual assertion (checked against transcript for truth)
18-
FAITHFULNESS = FaithfulnessMetric(threshold=1.0, model=PortkeyJudge(), async_mode=False)
24+
FAITHFULNESS = FaithfulnessMetric(threshold=1.0, model=_JUDGE, async_mode=False)
1925

2026
# on-topic-ness: relevant statements / total statements
21-
RELEVANCY = AnswerRelevancyMetric(threshold=0.7, model=PortkeyJudge(), async_mode=False)
27+
RELEVANCY = AnswerRelevancyMetric(threshold=0.7, model=_JUDGE, async_mode=False)
2228

2329
# prejudice
24-
BIAS = BiasMetric(threshold=0.0, model=PortkeyJudge(), async_mode=False)
30+
BIAS = BiasMetric(threshold=0.0, model=_JUDGE, async_mode=False)
2531

2632
# judge splits the output into statements scores each one, 1 means nothing leaked
27-
PII = PIILeakageMetric(threshold=1.0, model=PortkeyJudge(), async_mode=False)
33+
PII = PIILeakageMetric(threshold=1.0, model=_JUDGE, async_mode=False)
2834

2935

3036
# Deep Acyclic Graph: decision tree to write.
@@ -55,7 +61,7 @@
5561
# the `_used_to_justify` follow-up decision-dead; 0.5 is what makes it mean
5662
# something — merely mentioning passes, justifying the score with it fails.
5763
threshold=0.5,
58-
model=PortkeyJudge(),
64+
model=_JUDGE,
5965
async_mode=False,
6066
)
6167

0 commit comments

Comments
 (0)