Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,25 @@ uv run hf download google/gemma-3-4b-it \
--local-dir /path/to/models/hf_models/google/gemma-3-4b-it
```

If you enable the finance **GroundingVerifier** stage, pre-stage its two public
models at the pinned revisions used by the workflow:

```bash
# Claim-to-evidence routing model
uv run hf download sentence-transformers/all-MiniLM-L6-v2 \
config.json model.safetensors special_tokens_map.json \
tokenizer.json tokenizer_config.json vocab.txt \
--revision 1110a243fdf4706b3f48f1d95db1a4f5529b4d41 \
--local-dir /path/to/models/hf_models/sentence-transformers/all-MiniLM-L6-v2

# Natural-language-inference model
uv run hf download MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli \
added_tokens.json config.json model.safetensors special_tokens_map.json \
spm.model tokenizer.json tokenizer_config.json \
--revision 6f5cf0a2b59cabb106aca4c287eed12e357e90eb \
--local-dir /path/to/models/hf_models/MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli
```

**Storage location:** Models should go in your mounted HuggingFace models directory (see cluster config `mounts` section).

### Mount Path in Cluster Config
Expand All @@ -191,13 +210,15 @@ stage_kwargs:
<details>
<summary><strong>Which models does each workflow need?</strong></summary>

| Model | Demo SDG | Demo SFT | Demo GRPO | Demo Eval | Production GRPO |
|-------|:--------:|:--------:|:---------:|:---------:|:---------------:|
| `Qwen/Qwen3-4B` | | ✓ | ✓ | ✓ | |
| `openai/gpt-oss-20b` | ✓ | | | ✓ | |
| `google/gemma-3-4b-it` | | | | ✓ | |
| `openai/gpt-oss-120b` | | | ✓ | | ✓ |
| `Qwen/Qwen3-30B-A3B` | | | | | ✓ |
| Model | Demo SDG | Demo SFT | Demo GRPO | Demo Eval | Production GRPO | GroundingVerifier |
|-------|:--------:|:--------:|:---------:|:---------:|:---------------:|:-----------------:|
| `Qwen/Qwen3-4B` | | ✓ | ✓ | ✓ | | |
| `openai/gpt-oss-20b` | ✓ | | | ✓ | | |
| `google/gemma-3-4b-it` | | | | ✓ | | |
| `openai/gpt-oss-120b` | | | ✓ | | ✓ | |
| `Qwen/Qwen3-30B-A3B` | | | | | ✓ | |
| `sentence-transformers/all-MiniLM-L6-v2` | | | | | | ✓ |
| `MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli` | | | | | | ✓ |

**Tip:** Download commonly used models once and reuse across all workflows.
</details>
Expand Down
2 changes: 2 additions & 0 deletions docs/recipes/finance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ Detailed technical specifications for each stage:
- **[SFT Stages](stages/sft.md)** - 6 stages
- **[Eval Stages](stages/eval.md)** - 7 stages
- **[GRPO Stages](stages/grpo.md)** - 10 stages
- **[GroundingVerifier](grounding-verifier/README.md)** - Finance integration,
evaluation protocol, and held-out results

## Quick Command Reference

Expand Down
122 changes: 122 additions & 0 deletions docs/recipes/finance/grounding-verifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# GroundingVerifier for finance
Comment thread
psgundecha-nv marked this conversation as resolved.

GroundingVerifier evaluates completed `finance_agent` rollouts against the SEC
evidence preserved in their native tool-call history. It writes a separate
sidecar and does not modify the original rollout, reward, or training data.

The evaluator:

1. deterministically splits the submitted answer into claims;
2. routes each claim to retrieved evidence with
`sentence-transformers/all-MiniLM-L6-v2`;
3. checks entailment with
`MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli`; and
4. verifies SEC attribution, entities, metrics, dates, protected values,
calculations, comparisons, and evidence-scoped refusals.

Both public model revisions can be pinned. Incomplete attribution or model
failure produces `unavailable`; unsupported or conflicting claims are blocked.
Evidence is limited to `retrieve_information` excerpts retained by the rollout.

## Air-gapped setup

NVFlow workers run with Hugging Face and Transformers offline flags enabled, so
the two public models must be staged before submitting `evaluate_grounding`.
From a connected host, download the pinned revisions into the cluster directory
mounted as `/hf_models`:

```bash
uv run hf download sentence-transformers/all-MiniLM-L6-v2 \
config.json model.safetensors special_tokens_map.json \
tokenizer.json tokenizer_config.json vocab.txt \
--revision 1110a243fdf4706b3f48f1d95db1a4f5529b4d41 \
--local-dir /path/to/models/hf_models/sentence-transformers/all-MiniLM-L6-v2

uv run hf download MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli \
added_tokens.json config.json model.safetensors special_tokens_map.json \
spm.model tokenizer.json tokenizer_config.json \
--revision 6f5cf0a2b59cabb106aca4c287eed12e357e90eb \
--local-dir /path/to/models/hf_models/MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli
```

The workflow loads `/hf_models/sentence-transformers/all-MiniLM-L6-v2` and
`/hf_models/MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli`. See [INSTALL.md →
Download Models](../../../../INSTALL.md#download-models) for the mount
configuration and general model-staging procedure.

## NVFlow integration

Add `evaluate_grounding` after `collect_rollouts` in a finance GRPO workflow.
The stage reads completed `output-rs*.jsonl` files and writes matching
`grounding-verifier-rs*.jsonl` sidecars.

```yaml
pipeline_stages:
- collect_rollouts
- evaluate_grounding
```

## Repeated feature acceptance

Every GroundingVerifier feature can define a native acceptance profile with a
fixed number of finance-agent seeds. The first profile covers the air-gapped
model setup and runs one prepared `finance_sec_search` task three times:

```bash
uv run nflow run-all \
--config nvflow/recipes/finance/workflows/grpo/feature_gates/grounding_airgap.yaml \
-e finance_sec_search
```

Change `feature_runs` in the profile to increase the repetition count. The
profile always regenerates its dedicated rollouts, evaluates every row, and
then fails unless all expected files and completion markers exist, every
sidecar matches its rollout fingerprint, the offline model contract holds, and
the unavailable rate stays within the configured limit. Its compact summary is
written beside the sidecars as `feature-gate-grounding_airgap.json`.

This native profile requires the demo `prepare_data` output and SEC cache from
the quick-start workflow. Ordinary CI tests validate the gate logic without a
GPU; executing the finance agent itself requires the configured NVFlow Slurm
environment. `allow` and `block` are both valid execution outcomes because an
unsupported agent answer should be blocked. Detection efficacy remains covered
by the pinned public-model benchmark below.

## Public-model benchmark

The controlled benchmark uses eight FY2024 facts from Amazon, Alphabet, Meta,
and Tesla, which were held out from the earlier AAPL/MSFT/NVDA development set.
Each fixed evidence trace is evaluated once with its grounded answer and against
six mutations: numeric fabrication, entity conflation, metric fabrication,
temporal conflation, accession conflation, and an unsupported claim. This gives
eight grounded and 48 adversarial cases.

```bash
uv sync
uv run python -m nvflow.recipes.finance.utils.rl.grounding_benchmark \
--output-dir artifacts/grounding-verifier-benchmark \
--routing-model-revision 1110a243fdf4706b3f48f1d95db1a4f5529b4d41 \
--nli-model-revision 6f5cf0a2b59cabb106aca4c287eed12e357e90eb
```

The command writes `cases.jsonl`, `results.jsonl`, and `summary.json`. It also
records latency, throughput, memory use, model revisions, and host details.
It succeeds only when grounded acceptance and attack rejection are each at
least 90% and the unavailable rate is at most 5%.

The same public-model gate and native rollout-to-sidecar check can be run with:

```bash
GROUNDING_VERIFIER_RUN_MODELS=1 uv run pytest -q \
tests/test_grounding_benchmark.py -k pinned_public_models --no-cov
```

For the native held-out study, see the [frozen evaluation
protocol](evaluation-protocol.md) and [results](evaluation-results.md).

## Scope

This integration verifies whether a submitted answer is supported by the
retrieval excerpts and SEC metadata preserved in an NVFlow rollout. It does not
independently re-verify the complete SEC filing or establish unrestricted
production hallucination detection.
57 changes: 57 additions & 0 deletions docs/recipes/finance/grounding-verifier/evaluation-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Native finance evaluation protocol
Comment thread
psgundecha-nv marked this conversation as resolved.

The confirmation protocol was frozen before task generation, rollout
collection, or GroundingVerifier evaluation.

## Separation

- All 60 issuers were excluded from development and three earlier studies.
- GroundingVerifier was not used for task generation, rollout collection,
eligibility, labeling, or adversarial-answer creation.
- Evaluation inputs and labels were frozen before the one-shot guard run.

## Trace generation

An independent generator used official SEC ticker, submissions, filing, and
XBRL Company Facts data to select a 10-K and establish its company, metric,
year, value, and unit. Each task supplied the target filing date, canonical SEC
URL, and bounded retrieval range.

A pinned, locally hosted `Qwen3-4B-Instruct-2507` policy then executed the native
NVFlow `finance_agent` path:

```text
sec_filing_search -> parse_html_page -> retrieve_information -> submit_final_result
```

The tasks covered year-over-year calculations, cross-issuer comparisons, and
closed-world evidence-based refusals. This design tests evidence use and answer
verification, not autonomous discovery of an unknown filing.

## Eligibility and freezing

A calculation or comparison was eligible only when every retrieved
company/metric/year/value/unit tuple agreed with the independent SEC/XBRL
reference. A refusal was eligible only when its bounded evidence contained a
valid coverage fact but omitted the requested metric.

We collected 180 native rollouts and selected 120 eligible traces by task-ID
hash, balanced as 40 calculations, 40 comparisons, and 40 refusals. Selection
did not use GroundingVerifier outcomes.

Each trace contributed one grounded answer and one independently assigned
adversarial answer. Attacks covered numeric fabrication; entity, metric,
temporal, and source conflation; wrong or contradictory comparison winners;
and unsupported refusal claims.

## Success criteria

The preregistered GO gate required:

- at least 95% grounded acceptance and attack rejection;
- Wilson 95% lower bounds of at least 90%;
- at least 90% accuracy in every task category; and
- zero adversarial `allow` decisions.

Intervals used two-sided Wilson estimates and 20,000 issuer-cluster bootstrap
resamples with seed `26081432`.
58 changes: 58 additions & 0 deletions docs/recipes/finance/grounding-verifier/evaluation-results.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Native finance evaluation results

## Verdict

The frozen confirmation passed its preregistered GO criteria.

| Endpoint | Correct | Rate | Wilson 95% interval |
|---|---:|---:|---:|
| Grounded acceptance | 119/120 | 99.17% | 95.43-99.85% |
| Adversarial rejection | 120/120 | 100% | 96.90-100% |

- Calculations: 80/80 paired decisions correct.
- Comparisons: 80/80 paired decisions correct.
- Refusals: 79/80 paired decisions correct.
- False allows: 0.
- Exact two-sided McNemar comparison with an accept-all baseline:
`p = 9.18e-35`.

All attacks were blocked. They included numeric fabrication; entity, metric,
temporal, and source conflation; wrong or contradictory comparison winners;
and unsupported refusal detail or assertion.

## Collection and validation

- Native collection: 180 rollouts in 1:46:40.
- Frozen evaluation: 120 independent traces from 60 unseen issuers.
- Guard evaluation: 240 paired rows in 33.60 seconds.
- Native exclusions: 40 missing or incorrect source-bound tuples, nine
unexpected retrieval counts, one unpaired submission, and ten eligible
reserve traces. Exclusions did not use guard outcomes.
- Repository tests: 385 passed and one skipped.
- Pinned-public-model integration test, Ruff, `uv lock --check`, and
`git diff --check`: passed.

## Residual error

The only false block was a grounded refusal for a company ending in `N.V.`.
The deterministic decomposer split the legal suffix into an incomplete clause,
which the NLI model classified as contradiction. The candidate was not changed
after observing the confirmation result.

## Public models

```text
sentence-transformers/all-MiniLM-L6-v2
revision 1110a243fdf4706b3f48f1d95db1a4f5529b4d41

MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli
revision 6f5cf0a2b59cabb106aca4c287eed12e357e90eb
```

## Claim boundary

These results demonstrate source-bound detection on controlled, issuer-held-out
retrieval excerpts preserved in native NVFlow finance traces. They do not
independently validate complete SEC documents, estimate production failure
prevalence, prove unrestricted hallucination detection, or demonstrate an
NVIDIA Slurm deployment.
15 changes: 15 additions & 0 deletions nvflow/grounding_verifier/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Evidence-based provenance decisions for NVFlow agent outputs."""
Loading
Loading