File size: 11,589 Bytes
1abfa24 20ab5a9 1abfa24 20ab5a9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | ---
license: apache-2.0
language: en
tags:
- finance
- structured-generation
- rule-based
- finir
---
# Model Card: FinIR-Intent (baseline v0.1.0)
**This is a deterministic structured-output baseline, not a trained language model.**
It maps a natural-language financial instruction to the canonical **FinIR Intent
Contract** (a versioned JSON envelope) using a fixed, fully offline rule set. There
are no neural weights in this repository.
## What FinIR is
[FinIR](https://github.com/Olyxee/finir) is a financial intermediate representation
and incremental execution runtime for AI systems: a finance-typed computation graph
that is validated, compiled, and evaluated with dependency-aware incremental reuse.
It is published on PyPI (`pip install finir`, runtime `0.1.0`).
## What FinIR-Intent is
FinIR-Intent is the natural-language layer:
```
natural-language financial request -> FinIR-Intent -> canonical FinIR Intent Contract (v1.0)
```
It performs **no financial computation**. Interpretation and execution are strictly
separated: FinIR-Intent only produces the envelope; the FinIR runtime validates and
executes it (`finir.intent.execute_intent` / `FinancialModel.apply_intent`).
## The problem it solves
Letting an AI system "just compute" a financial what-if invites silently invented
numbers and unit/currency errors. FinIR-Intent constrains the language model's job
to emitting a **typed, validated intent**; the runtime is the single authority on
whether that intent is executable and what it computes. Vague language becomes an
explicit `ambiguous` status instead of a fabricated percentage.
## What it is / is not
- **Is**: a small, dependency-free, offline pattern-matching compiler
(`src/finir_intent/baseline.py`) — no network, no external LLM/API calls, fully
reproducible. It implements the same `finir.intent.IntentCompiler` seam a future
LLM-backed compiler would, so it is a drop-in baseline to measure against.
- **Is not**: a trained/fine-tuned Transformer. Per the workstream brief, "the first
milestone is not model training… only after the baseline is measured should we
decide whether fine-tuning a small open model provides a meaningful improvement."
This baseline exists to make that measurement possible.
## Hugging Face artifact type
Because v0.1.0 ships **code, not weights**, the natural representation is a
**model repository that contains the baseline package plus this card** — a
code/inference repo, not a weight checkpoint. The companion benchmark ships as a
**Datasets** repo, and a **Space** demonstrates the end-to-end flow against the real
runtime. The page makes explicit that this is a baseline compiler, not neural
weights. (See `../release/huggingface/` for the export layout.)
## Schema / runtime compatibility
- **FinIR Intent schema version:** `1.0`
- **Compatible FinIR runtime:** `>=0.1.0,<0.2.0` (verified against the public PyPI
`finir==0.1.0`)
- **FinIR-Intent baseline version:** `0.1.0`
- The canonical contract is owned by the core `finir` package
(`finir.intent.json_schema()`, `schemas/finir-intent-v1.schema.json`). This
package **consumes** it and never redefines it.
## Supported operations
| operation | meaning |
|---|---|
| `relative_change` | `new = current × (1 + value)` (dimensionless decimal; `-0.08` = −8%) |
| `set` | `new = value` (with optional `unit` / `currency`) |
| `absolute_change` | `new = current + value` (with optional `unit` / `currency`) |
| `range` | sweep `target` over `[min, max]` in `steps` (sole op) |
| `scenarios` | named scenarios, each a simultaneous operation set |
## Supported targets
Raw model-input node names (no canonical ontology; alias resolution happens in this
package only, never in the contract): `revenue`, `cogs`, `opex`, `payment_terms`,
`accounts_payable`, `inventory`, `capex`, `debt`, `interest_rate`, `cash`, `price`,
`volume`.
## Ambiguity / unsupported / invalid behavior
- **Ambiguous** — a target with no parseable quantity, or vague language → `status:
"ambiguous"`, empty operations. **No number is ever invented.** Conflicting
operations on one target (e.g. "increase revenue by 5% and also cut revenue by
10%") also map to `ambiguous` rather than silently picking one.
- **Unsupported** — clearly out-of-domain (acquisitions, mergers, hiring/layoffs,
IPOs/going public, litigation, buybacks, bankruptcy) → `status: "unsupported"`.
- **Invalid (semantic)** — a structurally valid but semantically wrong instruction
(a currency the target does not use, a `days` unit on a money target) is
**transcribed faithfully, never "corrected"**; the FinIR runtime rejects it at
execution. This package performs no semantic check itself (no duplicated execution
logic).
## Evaluation methodology
Reproduce (deterministic; no network, no LLM):
```bash
pip install finir==0.1.0
cd finir_intent
pip install -e ".[dev]" # or: PYTHONPATH=src, plus jsonschema
python eval/evaluate.py # writes eval/results/latest.json
```
`eval/evaluate.py` runs the baseline over every
`intentbench/examples/intentbench_v1.jsonl` example, validates each prediction
against `finir.intent.json_schema()` (the canonical schema), scores it against the
paired **ground-truth** expected intent, and — for every executable prediction —
actually executes it against a small reference `FinancialModel`
(`src/finir_intent/reference_model.py`) via the real `finir.intent.execute_intent`.
Every number below is computed from that run; none is hand-typed.
### Benchmark split (anti-leakage)
FinIR-IntentBench is split into **core** (in-distribution phrasing the rule set is
built to support) and a held-out **stress** subset (paraphrases the baseline was
**not** tuned against — unlisted verbs, fractions, magnitude suffixes, idioms). The
baseline was deliberately **not** modified to pass stress cases, so the stress
numbers are an honest measure of the rule set's real coverage gap, not a tuned
score.
## Evaluation results
Produced by an actual run of `python eval/evaluate.py` on
`intentbench_v1.jsonl` (183 examples: 143 core, 40 stress). Full per-example output,
including every prediction and its execution outcome against the real runtime, is in
`eval/results/latest.json`. **Re-run the command above to reproduce** if the code has
changed.
| metric | overall (n=183) | core (n=143) | stress (n=40) |
|---|---|---|---|
| schema validity | 1.0000 | 1.0000 | 1.0000 |
| status accuracy | 0.9344 | 1.0000 | 0.7000 |
| operation accuracy | 0.9515 | 1.0000 | 0.7500 |
| target accuracy | 0.9515 | 1.0000 | 0.7500 |
| value accuracy | 0.9363 | 1.0000 | 0.5833 |
| unit accuracy | 1.0000 | 1.0000 | 1.0000 |
| currency accuracy | 1.0000 | 1.0000 | 1.0000 |
| ambiguity precision | 0.8409 | 1.0000 | 0.5333 |
| ambiguity recall | 0.9737 | 1.0000 | 0.8889 |
| ambiguity F1 | 0.9024 | 1.0000 | 0.6666 |
| multi-operation exact-match | 0.9000 | 1.0000 | 0.0000 |
| scenario exact-match | 1.0000 | 1.0000 | n/a |
| runtime execution success (executable preds) | 1.0000 | 1.0000 | 1.0000 |
| semantic-rejection correctness | 1.0000 | 1.0000 | 1.0000 |
**Do not read the overall numbers as a headline score.** They are a blend of a
saturated core set and a deliberately hard stress set. The core row shows what the
baseline reliably does; the stress row shows where a fixed rule set breaks.
## Known failure cases (from the stress subset)
Every current stress failure is one of two kinds — and **11 of 12 are conservative
refusals, never an invented number**:
- **Refuses (safe):** `valid → ambiguous` on phrasing outside the rule set —
fractions/idioms ("Reduce COGS by a fifth", "Double the unit price", "Halve
inventory"), an unlisted-target reference ("Increase AP by R2,000,000", "Reduce
the wage bill by 6%"), and an unlisted additive idiom ("Add R5,000,000 to opex").
- **Refuses (safe):** `unsupported → ambiguous` on out-of-domain phrasing the
vocabulary does not list ("Spin off the retail division", "Issue new equity",
"Relocate the head office", "Replace the CEO").
- **Value errors (status still valid):** an unlisted direction verb defaults the
sign to positive ("Slash opex by 12%" is parsed as +12%), and a magnitude suffix
on a digit is not expanded ("Increase opex by R5m" is parsed as R5, not R5m).
- **The one genuinely unsafe failure:** "Grow cogs by 4% but also reduce cogs by 2%"
is parsed as a single +4% change because `but also` is not a clause separator, so
the conflicting second operation is dropped instead of triggering `ambiguous`.
This is the only stress case where the baseline commits to a number it should have
refused; it is tracked for a future fix.
## Limitations
This is a fixed rule set — a hand-authored alias table, a small number-word
vocabulary, keyword-anchored regexes — **not** a trained model. Any phrasing outside
what is enumerated in `src/finir_intent/baseline.py` falls back to `ambiguous`
rather than being guessed. It does not handle: fractional/idiomatic magnitudes ("a
fifth", "double", "halve"), magnitude suffixes on digits (`R5m`, `$2m`, `R1.2bn`),
unlisted direction verbs (slash/shave/ramp/shrink…), unlisted target aliases,
period/time scoping (forbidden by the v1.0 contract), or conflicting operations
joined by connectives other than `and`/`,`/`;`. Growing FinIR-IntentBench with new
adversarial paraphrases (as the stress subset does) is the honest way to keep
measuring this gap rather than hide it.
## Fixed parser issues (regression-tested)
- **Word-boundary matching** for direction and unsupported words: naive substring
checks previously false-positived on ordinary English ("up" inside
"supplier"/"group" flipped a decrease's sign; "merge" inside "emergency" and "sue"
inside "issue" misclassified valid instructions as `unsupported`).
- **`set <money-target> to N%`** now refuses (`ambiguous`) instead of silently
becoming a relative change.
- **Spelled-out numbers** ("five percent", "five million rand") parse via a small
fixed number-word vocabulary.
- **`trim`/`trims`** added to the down-direction words ("trim cogs by 4 percent" →
−4%).
- **`boost`/`boosts`, `raises`** added to the up-direction words.
- **Layoff/going-public phrasings with a number or filler between the trigger
words** ("fire 100 employees", "take the company public") are now correctly
`unsupported`, anchored to headcount/listing nouns so "fire up the pipeline" is not
a false positive.
All are covered by unit tests in `tests/test_baseline.py` and by dataset entries.
## License
Apache-2.0, matching the core FinIR repository. The benchmark is entirely synthetic;
no real company or personal data.
## Repository & dependency
- Source & docs: https://github.com/Olyxee/finir (workstream under `finir_intent/`)
- Runtime dependency: `finir>=0.1.0,<0.2.0` — `pip install finir`
- Intent Contract spec: `docs/intent-contract.md`, `docs/huggingface-intent-handoff.md`
## Attribution
The FinIR-Intent Hugging Face workstream (baseline, benchmark, evaluation, Space) was
contributed by **Alisha Fatima** ([@AlishaFatima16](https://github.com/AlishaFatima16)).
The core FinIR runtime and the canonical FinIR Intent Contract are maintained by
Olyxee.
## Links
- **FinIR runtime (PyPI):** https://pypi.org/project/finir/ — `pip install finir`
- **FinIR source (GitHub):** https://github.com/Olyxee/finir
- **FinIR-IntentBench (dataset):** https://huggingface.co/datasets/Olyxee/FinIR-IntentBench
- **FinIR Space (demo):** https://huggingface.co/spaces/Olyxee/FinIR-Intent-Demo
|