I build AI products end to end, and measure whether they work.

My privacy model for CVoria removes 97% of core personal details before an LLM sees a CV, at about $0.11 per 1,000 CVs.
AI engineer in Sweden, open to full-time, founding and contract roles.

nilsperssonsuorra@gmail.com GitHub ↗ LinkedIn ↗ X ↗

Selected work

CVoria

An AI job-search app I built end to end. My own privacy model removes most personal details before a CV reaches any LLM.

cvoria.com Open ↗
Personal details are removed before an LLM sees the CV.
Uploaded CV What the LLM receives
  • Elin Bergqvist [NAME_1]
  • elin.b@example.se [EMAIL_1]
  • +46 70 000 00 00 [PHONE_1]
  • Storgatan 1 [ADDRESS_1]
  • 19900101-0000 [GOV_ID_1]
  • Senior accountant Senior accountant
  • Excel, IFRS Excel, IFRS

My privacy model removes 97% of core personal details, like names, emails and phone numbers, before an LLM sees the CV, for about $0.11 per 1,000 CVs.

Gemini and GPT left fewer readable (7 and 17 of 757, against my 23) and were more precise, but they see the full CV and cost 8 to 200 times as much. Open-source redactors removed 61 to 86%. Counting every kind of detail, mine removed 93%. 200 fictional CVs in 17 languages.

Personal details removed Est. $ per 1k CVs

Hosted LLMs the full CV goes to the provider

Gemini 3.8 Flash
99.1% $22
GPT-5.6 Luna
97.8% $0.93

Mine self-hosted in Stockholm

CVoria privacy model
97.0% $0.11

Open source runs on your hardware

GLiNER multi PII
85.7% free
LiquidAI LFM2.5 PII
73.7% free
Microsoft Presidio
60.5% free

AI judges preferred my cover letters in 95% of blind comparisons.

57 of 60, judged blind by ChatGPT, Claude and Gemini on 5 Swedish job ads.

One square per comparison won lost
  • B2B sales 12
  • Care work 12
  • Developer 12
  • Digital marketing 9
  • Warehouse work 12

Average score from the judges, out of 10

My letters 7.72
Baseline letters 5.80
How it was built and measured +
  • The model. A 307M-parameter token classifier fine-tuned from mmBERT-base, a multilingual encoder. It tags 13 kinds of personal detail, from names and ID numbers to health data and work-permit status. Trained on about 6,600 generated CVs plus 1,400 reformatted copies, mostly English and Swedish, and no real person’s CV. A detail gets the same placeholder everywhere, and CVoria puts the real one back where the answer needs it, such as a letter signature.
  • Serving. CPU only, on AWS Lambda in Stockholm, about 0.64 s per CV in my run logs. An int8 embedding table halves the file from 1.23 GB to 641 MB with no loss on the benchmark (24 details left readable before, 23 after). If the model can’t be reached, the request is refused rather than sent unredacted.
  • Benchmark. 200 fictional CVs in 17 languages, written by two AI models that each labelled the other’s CVs blind. The answer keys follow CVoria’s own written redaction rules. I locked the test set and scoring with checksums before any system ran. The test set, every system’s outputs and the scoring scripts are public; the model isn’t. Results on real CVs can differ.
  • Where it loses. Names in unusual forms, such as “Kothapalli, V.”, health and religion (27 of 72 left readable) and work-permit status (10 of 21), where both hosted LLMs did much better. 65 of its 1,122 removals (5.8%) weren’t personal details, such as employment dates.
  • Cover letters. 60 blind judgments against standard prompts in ChatGPT, Claude and Gemini and against V1, with an average score of 7.72 against 5.80. All 3 losses came from one marketing job, where my letter was more careful about requirements the CV didn’t back up. V1 used Claude Haiku 4.5 and the current version uses Gemini Flash 3.5, so part of the gain is the model change. Gemini was also the strictest judge, at 18 of 20. It’s a small sample, and it measures judged quality, not interviews.
  • Chrome extension. In development. On an employer’s application form it fills in your details, attaches the CV in the job ad’s language and drafts answers from your CV, asking for a few rough words when the CV doesn’t hold the answer. It handles custom dropdowns, sliders, date pickers and autocomplete fields, and never submits. The clip is a demo form with a fictional applicant.
  • Live interview. In beta. A video interviewer asks questions by voice through Gemini Live while MuseTalk lip-syncs the avatar at 720p on an AWS GPU. The clip shows the next design of the interview screen in a staged session, with the avatar before lip-sync and no voice agent running. Next, the GPU starts when someone begins an interview and shuts itself down when idle, with per-session tokens and a monthly time limit.
  • Cost estimates. From my benchmark run logs: hosted LLMs at list API prices (Gemini 3.8 Flash at its introductory price, about $44 per 1,000 CVs at the 2027 rate) and mine on AWS Lambda at 10 GB of memory. Open-source tools are free to run, and their compute isn’t included.

NextChapterBench

Can a model write the next chapter of a novel? 24 models each get a real chapter and a twist on what happens next, so they can’t copy the book. An AI judge I tested before trusting grades the result. Early results: 10 of 24 planned items have run.

nextchapterbench.com Open ↗

Claude Haiku 5.5 scores within 4.5 points of the leader for 6% of the price.

$0.18 against $3.07 to write the whole benchmark. Best setting per model. Early results: 10 of 24 planned items so far.

Score Cost
  1. 1Claude Opus 5 · xhigh 79.2 $3.07
  2. 2Claude Sonnet 5.5 · xhigh 78.3 $3.15
  3. 3Claude Opus 5.5 · xhigh 77.4 $5.12
  4. 4Fable 5.1 · xhigh 76.8 $14.49
  5. 5Fable 5 · xhigh 75.2 $8.83
  6. 6Claude Haiku 5.5 · xhigh 74.7 $0.18
  7. 7GPT-6 Astra · high 73.0 $3.84
  8. 8GLM-5.3 Flash · default 71.0 $0.07
  9. 9GPT-5.6 Sol · medium 66.7 $1.42
  10. 10GPT-6.1 Sol · medium 66.1 $0.75

Score out of 100: how closely the chapter follows the brief, times how well it’s written, graded by an AI judge beside the author’s real chapter. Lines show ± one standard error. Rows within about 2 points are a tie.

I auditioned three AI judges before trusting one. The one I kept was harsher on its own company’s models, not kinder.

Points given to its own family’s chapters, compared with the other two judges.

← harsher on its own kinder to its own →

Claude Sonnet 5 · kept · judging Anthropic models −7.5

GPT-5.6 Sol · not kept · judging OpenAI models +11.8

One judge can’t fully cancel this house effect, and the site says so.

How it was built and measured +
  • Judge chosen by audition. Sonnet 5’s rankings correlated 0.84 and 0.73 with the two other candidate judges, which correlated 0.75 with each other. It ranked the real author above every model on both audition items, where Gemini 3.1 Pro gave a model 99 and Wilkie Collins 74.
  • Bias measured, not assumed. The judge scored its own model family 7.5 points lower than the other judges did. A GPT judge favoured OpenAI by 11.8 points.
  • Noise quantified. A repeat judge call moves a chapter’s score by about 3 points, and a model’s ten-item average by about 1. Generation noise is larger: when the leading model wrote its ten chapters a second time, single chapters moved by up to 7 points. I pinned the judge’s CLI build after a newer build shifted the reference score by about 6 points.
  • Five hidden continuity traps per brief, which count double, plus a verbatim n-gram check that caught the top model copying 30 consecutive words of Austen in the pilot. The longest copied run so far is 157 words; it’s reported, not yet penalised. The briefs are drafted by an Anthropic model and approved item by item by hand, which may suit Anthropic models.
  • Findings. More reasoning effort isn’t free. Under the earlier three-judge panel, Fable 5.1 gained a clear step only at xhigh, at about 2.5 times the cost of high, while GPT-6 Astra gained nothing measurable from any setting. 10 of 24 planned items have been run so far.

nearlossless-context

A Python library that lets an AI model read long texts with a fixed amount of memory, choosing what to keep before it knows the question.

Minutes from the Bergen office, spring planning. The team reviewed the roadmap for the coming quarter and agreed to move the launch by two weeks. Most of the talk was about hiring and the travel budget. Marta raised the old servers again, and everyone agreed to replace them before summer. The archive room will be cleared in May. The vault code is KX-4417. Please keep it inside the team. After lunch the group went through the customer survey, which was mostly positive, and argued about whether the newsletter should go out monthly or every other month. Nobody could agree, so it was left for the next meeting.

Illustration. Crossed out = dropped. Memory holds words.

When the question comes after the text, the model still finds the hidden fact in 14 of 15 tests, against 5 of 15 when it keeps what attention picks.

Synthetic tests: a fact is hidden in a long text and each method keeps an eighth of it. The attention-based one is my own SnapKV-style version; told the question first, it nearly matches the full text.

Each square is one test Found the fact

Attention-based · keeps what attention picks

5 / 15

nearlossless-context · keeps what stands out in the text

14 / 15

Perfect knowledge · told in advance where the fact is

15 / 15
60 real LongBench questions Answer score (F1)
Full text 0.28
nearlossless-context 0.19
Attention-based 0.18

Questions asked after the text. Both still fall short of the full text. Measured before a later fix.

About

I build products on my own, from the idea to the launch.

Since June 2025 I’ve shipped 10+ projects, from live products to a Python package with a preprint. I build with Claude Code and Codex in T3 Code, and ship on Vercel and AWS.

Portrait of Nils Persson Suorra

Nils Persson Suorra
AI engineer · Sweden
Swedish · English

1,647 GitHub contributions in the last year.

Per month, across the projects on this page and others.