The Short Answer
A blood test result is only meaningful next to the reference range printed beside it, and that range belongs to the laboratory that ran the test. An agent that reads your PDF and compares the number to a range it remembers is comparing it to the wrong range.
TL;DR: Lab reports are PDFs whose layout, units and reference ranges depend on the laboratory. The three things an agent gets wrong are the range (it uses a generic one instead of the lab's), the unit (mg/dL and mmol/L differ by a factor it has to know), and the confidence (it overreads a single value). The fix is structured data: each biomarker with its value, its SI value, and the range the lab itself printed. And once the bloodwork is structured, it can be read against your genotype — which is where a result stops being a number and starts being a question worth asking.
If you have ever handed a lab report to an agent and got back a confident paragraph about your ferritin, this is the article about what happened in between.
A Lab Report Is Not Data Yet
Open one. You will see a table: analyte, result, unit, reference range, maybe a flag. It looks like data, and it is a picture of data.
The same analyte arrives differently from every laboratory. Ferritin is reported in ng/mL by one and µg/L by another (numerically identical, which is a trap of its own), glucose in mg/dL in one country and mmol/L in the next. Column order changes. Some labs print the range as 30 – 400, some as 30-400, some as <400, some as two lines. Sex- and age-specific ranges appear on some reports and not others. Flags — H, L, an asterisk, bold — mean "outside range" in whatever convention that lab chose.
None of this is a problem for the clinician who ordered the test, because the report was designed for a human reading one report from one lab. It is a problem the moment software has to read reports from any lab, and that is exactly what a personal agent is being asked to do.
The Three Things an Agent Gets Wrong
1. The range
This is the serious one. A ferritin of 250 ng/mL is inside one lab's range (30–400) and flagged high by another's (20–200). Both labs are right; they use different assays and different reference populations. The only range that applies to your result is the one printed next to it.
A language model asked "is 250 high?" answers from a range it has seen most often in training. It has no way to know which lab ran your test. It will produce a verdict, and the verdict will be fluent, and often it will be against the wrong range.
2. The unit
Cholesterol at 5.2 is a normal-ish mmol/L reading and an impossible mg/dL one. Vitamin D at 30 is borderline in ng/mL and deficient in nmol/L. A model reading a PDF will usually catch the unit when it is printed clearly. It will not catch it when the unit is in a column header three pages earlier, or abbreviated in a way the lab invented, and it will not tell you which case you are in.
3. The confidence
A single out-of-range value is a prompt for a repeat test far more often than it is a finding. Time of day, fasting, hydration, a cold last week, the assay's own variance — a clinician holds all of that lightly. A model asked to interpret tends to interpret. It is built to answer, and "this probably needs repeating before it means anything" is not the shape of answer it is rewarded for.
What Structured Bloodwork Looks Like
The fix is the same shape as for DNA files: the agent does not read the PDF. It calls a tool that turns the PDF into structured biomarkers, and it reasons over the structure. This is the shape DeepDNA's /bloodwork/parse endpoint is being built to return:
{
"lab": "…",
"report_date": "2026-08-14",
"biomarkers": [
{
"code": "ferritin",
"value": 612, "unit": "ng/mL",
"value_si": 612, "unit_si": "µg/L",
"reference_low": 30, "reference_high": 400,
"reference_source": "lab",
"flag": "high"
}
]
}
Four things in that shape do the work. reference_source: "lab" says the range came from your report, not from a textbook. value_si means the agent never has to convert. flag is computed against that range. And code is a stable identifier, so "ferritin", "Ferritina" and "FERR" all become the same thing.
That endpoint is in private beta: specified, not yet deployed, and designed first for European laboratories. Parsing arbitrary PDFs is genuinely hard, which is why we are not pretending it exists before it does. It is documented in the OpenAPI so that anyone building an agent can design against the contract now.
Where DNA and Bloodwork Meet
Here is the part that makes structured bloodwork worth the trouble.
A genotype tells you what could happen. A biomarker tells you what is happening. Read separately, each is a source of anxiety with no resolution: "you carry a risk" with nothing to check it against, or "this value is high" with no reason why. Read together, they become a specific, answerable question.
Two illustrative examples, with made-up values:
Active. Someone is homozygous for HFE C282Y, the main hereditary haemochromatosis genotype. Most people with that genotype never develop iron-related organ disease; many show raised iron markers, but clinical penetrance is low, which is exactly why the genotype alone is a poor guide. Their ferritin is 612 ng/mL against a lab range of 30–400, and transferrin saturation is 58% against 20–50. The predisposition and the biomarker point the same way. That is a conversation to have with a clinician, and it is concrete.
Compensated. Someone is homozygous for MTHFR C677T. The internet will tell them to worry. Their homocysteine is 8.1 µmol/L against 5–15, folate is mid-range. The predisposition is real and the biomarker says the body is handling it. Nothing in those two numbers calls for action today, and that is a reading a genotype-only view cannot give.
This crossover — genotype against biomarker, with the lab's own ranges — is what DeepDNA's /crossover endpoint is being built to return: which predispositions have biomarkers outside the lab's range and which do not. It depends on both parsers and will be the last of the beta endpoints to open; none has opened yet. It is also the only part of this that no public database can give you, because no public database has your bloodwork.
What to Do Today
Keep your lab PDFs, all of them, with dates. A single value is noise; a trend across three reports is information.
When you ask an agent about a result, give it the range from the report and the unit, not just the number, and tell it to compare against that range and no other. That one instruction removes the most common error.
If a value is out of range, the useful question for an agent is not "what does this mean" but "what could make this a false alarm, and what would confirm it". You will get a more honest answer.
And if you want to know what a marker is — what ferritin measures, why transferrin saturation matters next to it — the knowledge side of this is already public. The gene records at /api/v1/genes/HFE and /api/v1/genes/MTHFR name the biomarkers that matter for each, ferritin and transferrin saturation, homocysteine and folate, and why, with sources.
A Note on Privacy
Blood test results are health data, which under GDPR is special-category data alongside genetic data. The same five questions from the DNA article apply to any tool your agent sends a lab report to: what happens to the file afterwards, where it is processed, under what legal basis, whether anything is trained on it, and what it refuses to say. DeepDNA's parsing endpoints are designed for zero retention — parsed in memory, discarded on response — and the data processing agreement will be published before the beta handles a real report.
Frequently Asked Questions
Can an AI agent read my blood test PDF?
It can extract the text. What it gets wrong is the interpretation: it compares your value to a reference range it remembers instead of the one your lab printed, it can miss unit conversions, and it overreads single values. The reliable pattern is for the agent to call a tool that structures the report and to reason over the structured result.
Why does the reference range differ between laboratories?
Different assays, different instruments and different reference populations. A range is a statement about the lab's method and the people it was calibrated on, not a universal constant. The only range that applies to your result is the one on your report.
Is "in range" the same as "normal" or "optimal"?
No. "In range" means inside the interval the lab defines as typical for its reference population. It does not mean optimal, and a value at the edge of the range is not the same as one in the middle. Anyone — human or agent — who moves from "in range" to "optimal" is adding a claim the report does not make.
What is a DNA and bloodwork crossover?
Reading a genetic predisposition against the biomarker that would show whether it is active. A genotype says what could happen; a biomarker says what is happening. Together they turn "you carry a risk" into "this risk is active" or "this risk is compensated". DeepDNA's /crossover endpoint is being built to do this and is in private beta.
Will this tell me what to do about a result?
No. It structures the report and reads it against your genotype so that you and a clinician have something concrete to look at. It does not diagnose, prescribe or dose.
The Real Answer
Your lab report was written for one reader from one lab. Your agent is reading reports from every lab. The gap between those two is where the errors live, and no amount of model size closes it. Structure the report, keep the lab's own range, convert the unit once, and then — only then — read it against the genome that predicted it.
This article was created with AI assistance and reviewed by the DeepDNA editorial team.
DNA and bloodwork, as an API
DeepDNA is now an API for AI agents and health apps. The knowledge endpoints are live and free, no key. Parsing DNA files and lab reports, and crossing the two, is in private beta. Building something with genetic or lab data? Tell us what.
Read the API docs