Devin Huber
Résumé
n8n · 17 nodes

Metadata Enrichment Agent

Tags incoming news with controlled-vocabulary subject, industry, geography and company codes as it arrives, and decides which articles can publish without an editor.

For a businessClassifies incoming news automatically, so editors spend less time tagging and more time editing, while wrong tags are stopped before they ever reach readers.

Built for
Legal & news information publisher (spec build)
Model
Claude Sonnet via direct HTTP
Stores
n8n Data Tables (controlled vocabulary)
Trigger
Manual run over the ingest queue
Status
Spec build: built to a real brief, tested on an answer key I wrote
Result
Silent errors cut from 27% to 8.6% (worst of three runs) on a 500-article stress test
How it was measured
My open-source evaluation harness, scoring every run against answers written before it ran
Biggest limit
Many articles still go to an editor who didn’t need to see them: the price of the guard
27%→8.6%silent error rate, 500 articles, worst of three runs
7.6%worst run, on articles the guard wasn’t tuned on
500article answer key, every one a trap

01 · Context The problem

The hard part of tagging news at ingest is not the tagging. It is deciding which articles can be trusted to publish with no editor looking — and knowing how often that call is wrong. An LLM can propose codes in seconds, but a wrong code that publishes silently does more damage than a slow correct one.

So the agent had three jobs: tag accurately, prove where every tag came from, and know which articles still need a person.

02 · Pipeline How it works

  1. Load the vocabulary

    The controlled vocabulary lives in a Data Table, so taxonomists can add or retire codes without touching the workflow.

  2. Remove near-duplicates

    Articles are compared with 5-word shingles at Jaccard ≥ 0.50. The canonical copy is picked by source tier, then body length, then date, and duplicates are marked here, then suppressed by the guard after tagging. The run pays to tag them, which the cost figure includes.

  3. Layer 1: match companies

    Word-boundary regex against a 15-record authority file, with a common-noun guard so "shell companies" never matches Shell plc.

  4. Layer 2: LLM tagging

    Claude proposes subject, industry and geography codes. It can only choose companies from the Layer 1 candidates, and labels each one primary or passing mention.

  5. Layer 3: taxonomy guard

    Rejects HALLUCINATED_CODE, FACET_MISMATCH, UNGROUNDED_EVIDENCE (the quoted span must appear word for word), retired codes with no successor, BELOW_CONFIDENCE_FLOOR and FACET_CAP_EXCEEDED. Retired codes with a successor are remapped, and broader terms come from the hierarchy, not the model.

  6. Route every record

    AUTO_PUBLISH, EDITOR_REVIEW, SPECIALIST_REVIEW or DUPLICATE_SUPPRESSED. If the LLM call fails, the record goes to a person.

  7. Score and brief

    Precision, recall, F1 and exact-match rate per facet, plus cost per 1,000 articles. An LLM-written run brief may only cite scorecard figures, and the Word export still ships if the brief call fails.

  8. Export for measurement

    A side branch writes every article in the shape the evaluation harness reads, with its route and the reason for it, so each run can be scored against the answer key without hand work.

Live · Run 49 See it run

The deterministic half of this pipeline — the structural scan and the conformance guard — is plain JavaScript, so it can run anywhere. On 22 September 2026 the workflow processed a 24-article test batch, and what the model returned on each article was recorded.

Those two node bodies are shipped to a page on this site and executed in your browser over that recorded output, so you can pick an article and watch the guard adjudicate every label the model proposed. Replaying it reproduces the recorded run figure for figure — all 56 numbers on its scorecard.

Run 49 is later than the evaluation report, so its numbers are better: silent errors fell from 1 in 6 auto-published records to 0 in 7. Seven records is far too small a base to call a 0% error rate stable, and the run’s own brief says so. Subject recall, at 73.2%, is still the weakest facet, and the review queue is currently covering that gap instead of the model.

03 · Choices Design decisions

Silent error rate is the headline

A tag an editor reviews costs minutes. A wrong tag that auto-publishes costs trust. The number that matters most is auto-published records carrying a wrong tag.

Cues can block, never add

Place names, regulators, industry words and the company's registered industry catch under-tagging. They can stop an article from auto-publishing, but they never add a tag, so they can't introduce errors.

Per-facet confidence floors

Subject 0.85, industry 0.70, geography 0.85. Below 0.60 is rejected, below 0.75 is marked provisional, and each facet is capped at 4 tags.

Secondary tags earn their place

A secondary subject has to clear the same confidence bar as the lead tag, so the model can't pad records with weak extras.

04 · Evidence How I tested it

A 24-article answer key written the way editors would tag, with planted traps: "shell companies," a passing mention, retired-code bait and a renamed-company alias.

Across 5 test runs the error rate fell from 37.5% to 16.7%. Company matching scored 100% precision and recall.

Three fresh runs on those 24 articles published 7, 8 and 8 with no editor, the same 8 articles each time, and no silent errors, and I reported the ceiling with it: zero errors in 8 is still consistent with a true rate up to 32%. Then the answer key grew to 500 articles, 34 of them duplicates of another, each built as a trap. Scored by the evaluation harness, the same pipeline’s silent error rate was 27% (54 of 200). The small set was not representative, and a likely range covers chance, not a test set that leaves out the hard cases.

Most of those 54 were one gap: 36 were missing a regulation or litigation subject beside the main one. A prompt revision took subject recall from 82.8% to 94.7% and the rate to 11.6%. A new guard rung then took it to 6.5%, 6.3% and 8.6% across three runs of identical code, a drop bigger than the spread between them. The worst run, 8.6% (18 of 210, likely 5.5–13.1%), is the one to quote: the runs send out the same articles again, so adding them together (44 of 615) would claim a narrower range than the evidence holds.

The new rung’s threshold was chosen on half the articles and checked on the other half, where the three runs gave 5.4%, 6.6% and 7.6% (worst: 8 of 105, likely 3.9–14.3%). Duplicates held up at scale: 33 or 34 of the 34 suppressed in every run, and no real article ever suppressed.

05 · Production readiness What it would take to run at scale

What the build already does, and what I would add before it carried real volume. The second column is a plan, not a claim.

Monitoring

In place

Every run writes a scorecard (routing split, per-facet precision and recall, cost per 1,000) and a compact export the evaluation harness scores against the answer key.

Before 100× volume

An editor-audited sample of auto-published articles each week, scored by the harness, with an alert when the silent error rate leaves its range or straight-through moves outside its normal band.

Failures and retries

In place

A failed model call sends the article to a specialist, never to publish. After two concurrent 500-record runs overloaded the API, the test copy sends model calls two at a time.

Before 100× volume

Retries with backoff on refused calls, a cap on the share of failed calls per run that pauses publishing, and a queue of failed articles to rerun.

Drift

In place

The answer key is frozen and fingerprinted; a run stops if any row changed. Changes are judged against the spread of three identical runs, not one.

Before 100× volume

Rerun the golden set on every prompt, model or vocabulary change, and fail the release when the harness says the change is worse beyond noise.

Cost at 100×

In place

$9.21 per 1,000 articles: the tokens the original pipeline used on a measured run, costed at Claude Sonnet 5’s price today of $2 / $10 per million tokens, including duplicates it paid to tag before suppressing them.

Before 100× volume

Skip the model call for copies already marked as duplicates, and cache the fixed vocabulary part of the prompt. Both cut cost without touching routing.

06 · Security Untrusted input and what the model can touch

  • Article text reaches the model, so it is treated as untrusted. The model can only return codes from the controlled vocabulary and companies from the candidates the rule layer found; anything else is rejected as an invented code.
  • Every tag must quote its evidence word for word from the article, or the guard rejects it. An instruction hidden in an article cannot add a tag the vocabulary and the text do not support.
  • The exported workflow carries no credentials, webhook IDs or internal URLs; the build that produced the public copy fails on a match.

07 · Iteration Tuning log

  1. Run 42
    Dropped the industry floor to 0.70. Straight-through rose from 20.8% to 45.8%, but silent errors went from 1 of 5 to 3 of 11. Reverted.
  2. Later run
    Re-applied the 0.70 floor once completeness cues were in place. Straight-through settled at 33.3%.
  3. Prompt change
    Merging two prompt rules into one cost 16 points of subject recall.
  4. Gate change
    Gating on the lowest-confidence tag instead of the lead tag sent 87.5% of clean records to review.
  5. Golden 500
    Scored on a 500-article answer key: 27% silent error rate, where the 24-article key had shown none in the same 8 articles three times.
  6. Prompt v2
    Said what a broader term is, and when a regulation or litigation subject is tagged beside the main one. 27% to 11.6%.
  7. Guard v3
    An article goes to an editor when the model proposed a code at 0.40 or more that the 0.60 floor set aside. 8.6% in the worst of three runs; 7.6% or less on the half its threshold wasn’t tuned on.

08 · Honest notes Known limits

  • The price of the guard is reviews: about 41% of articles now publish with no editor, down from 47% with the revised prompt alone (40% originally), and more than half of the reviews are ones an editor did not need.
  • Five articles are silent errors in every run of the current version. They are the next place to look.
  • The prompt and guard changes were made in a test copy scored on the 500. The demo replays the original pipeline’s run.
  • The company authority file holds 15 records; production would need the full list.
  • The scorecard includes a 90-day rollout plan for moving from test set to live ingest.

Want to see this one run?

I'll screen-share the workflow, the test set and the results, including what didn't work.

Get in touch