# Anpheros Symptom Engine: methodology

> How free-text symptoms in any language become WHO ICD-10 and ICD-11 concepts: the AI normalizer, presence and experiencer detection, the WHO-checked vocabulary, evaluation results, similar-case matching and limits.

Source: https://developers.anpheros.com/guides/symptom-engine

**The Anpheros Symptom Engine turns what a person writes about how they feel, in their own words and language, into international clinical concepts: a stable Anpheros identifier, a WHO ICD-10 code, a WHO ICD-11 code and a body system, together with whether the symptom is present, resolved, hypothetical or about someone else. It runs in production behind Anpheros Daily, publishes its results as HL7 FHIR R4 Observations on Anpheros Platform, and exposes the same terminology to any application through a REST and FHIR API.** This page describes how it works, how it was checked, what it measures, and where its limits are.

## At a glance

| | |
|---|---|
| Concepts | 86 (70 symptoms, 16 findings), identifiers `SYM-0001`…, never reused |
| Classifications | WHO ICD-10 (Version 2019) and WHO ICD-11 MMS (2025-01), with the equivalence of each mapping |
| Body systems | 13, taken from the ICD-11 chapter 21 blocks (nervous, digestive, respiratory, skin…) |
| Languages | names in 20 languages; free text in the person's own language |
| Warning signs | 32, for 14 concepts, quoted word for word from CDC and NIDDK |
| Normalizer evaluation | 5 languages (Romanian, English, Spanish, German, French): primary code 97.5–100 %, presence and subject 92.5–98 %, negated symptoms reported as present 0 % in every language |
| Clinical review | none yet: `clinical_review: false` on every response |
| Standards | HL7 FHIR R4 (`CodeSystem`, `ValueSet`, `ConceptMap`, `Observation`), ICD-10, ICD-11, LOINC for lab results |

## 1. The pipeline

A symptom goes through four steps. The person's text is never changed; every step adds data next to it.

1. **Capture.** The raw entry is stored as written, with the moment it was noted, the phone's time zone, the language, and optionally intensity (1–10), onset and end. Nothing downstream rewrites it.
2. **Normalization (AI).** A large language model (Google Gemini on Vertex AI) reads the text and returns, for each symptom it mentions: a primary ICD-10 code, optional secondary codes, a short label, and two attributes, *assertion* (present, absent, resolved, hypothetical, uncertain) and *subject* (the person, or someone else). The model may only choose codes from the Anpheros vocabulary; any other answer, an omitted entry or an invalid primary code counts as a failed attempt, never as "unknown symptom".
3. **Concept mapping (deterministic).** The ICD-10 code is mapped to the Anpheros concept and, from it, to ICD-11 and the body system. This step uses fixed tables, not AI, so the same code always gives the same concept.
4. **Publication.** Only symptoms that are **present** and **about the person** become FHIR Observations in the person's record, and only after normalization succeeds. If a later edit or re-normalization changes that, the Observation is withdrawn; the version history stays.

## 2. Presence, time and experiencer

Clinical text often mentions symptoms that the person does not have. Clinical natural-language processing calls this *negation*, *temporality* and *experiencer* detection (the NegEx and ConText family of methods). The engine handles the same three questions with the model's assertion and subject attributes:

| Written | Assertion / subject | Published as the person's symptom? |
|---|---|---|
| "I've had a headache since Tuesday" | present / self | yes |
| "my head doesn't hurt any more" | resolved / self | no |
| "I might get a fever tomorrow" | hypothetical / self | no |
| "my mother has a cough" | present / other | no |

A relative's complaint is never turned into family history automatically.

## 3. The vocabulary and how it was checked

The vocabulary covers ICD-10 chapter XVIII (R00–R94) and, where WHO classifies a symptom in another chapter, the WHO code: constipation K59.0, tinnitus H93.1, double vision H53.2, blurred vision H53.8, itching L29.9, joint pain M25.5, back pain M54, sleep problems G47.

- **ICD-10.** Every code and English title was checked against the WHO ICD-10 Version 2019 browser, including each code's inclusion and exclusion notes. Where the notes moved a symptom elsewhere (for example, R19.4 excludes constipation), the vocabulary followed WHO.
- **ICD-11.** Every concept maps to an ICD-11 MMS 2025-01 code taken from the WHO Simple Tabulation and compared with the official WHO ICD-10 → ICD-11 mapping table. The engine uses the chapter 21 *symptom* code rather than a disease code (headache → MB4D, not 8A8Z "headache disorders"); each of the 21 departures from the WHO statistical table is listed with its reason in the release file. 67 mappings are equivalent, the rest are marked wider, narrower or inexact.
- **Documented choices.** "Migraine" written by a person is coded as headache (R51), and unspecified diarrhoea as R19, because the alternative WHO codes (G43, A09) are diagnoses; the engine records reported symptoms, not diagnoses.
- **Translations.** English names are the WHO titles. Names in 18 more languages are machine translations reviewed term by term, with AI assistance, against the WHO titles (`review: ai_reviewed`); five were rewritten in every language where the meaning did not match the code. No professional medical translator has reviewed them yet.
- **Warning signs.** Quoted word for word, never paraphrased, from public-domain pages of the CDC (stroke, heart attack) and NIDDK (diarrhea, constipation), each with its source, licence and the note that it is not a diagnosis. Where a quote says 9-1-1, the note adds the European 112.

## 4. Evaluation

The normalizer is evaluated on a fixed set of 100 synthetic cases written in Romanian (the language of most current users), each with the expected primary code, assertion and subject. 32 of the cases are deliberately not present: negated, resolved, hypothetical, uncertain or about another person. Results with the current prompt (version 3, 15 October 2026):

| Metric | Result | Target |
|---|---|---|
| Primary code correct | 100 % | ≥ 85 % |
| Assertion and subject both correct | 98 % | — |
| Negated symptoms reported as present | 0 % | ≤ 3 % |

The two errors were administrative entries ("an appointment with the cardiologist on Tuesday", "I want to lose 5 kg") classified as hypothetical instead of present; neither is a symptom. The test set has not been reviewed by a clinician, so the scores are indicative.

**Other languages (16 October 2026).** 40 of the cases, covering every category, were translated into English, Spanish, German and French, with the same expected answers; the informal cases were rewritten in each language's own informal style. The instructions to the model stayed the same.

| Language | Cases | Primary code | Presence and subject | Negated reported as present |
|---|---|---|---|---|
| Romanian | 100 | 100 % | 98 % | 0 % |
| English | 40 | 100 % | 97.5 % | 0 % |
| Spanish | 40 | 97.5 % | 92.5 % | 0 % |
| German | 40 | 100 % | 97.5 % | 0 % |
| French | 40 | 100 % | 95 % | 0 % |

Most remaining errors are the same administrative entries ("cardiologist appointment on Tuesday", "check-up, all fine") or a choice between two non-present states ("no fever today" as resolved rather than absent); none of them publishes a symptom. The one coding difference was Spanish "escalofríos y malestar" (chills and malaise) coded as malaise (R53) with chills (R68) as a secondary code, rather than the reverse.

Names shown to people follow their language: the app displays the concept name in the user's language (lay name first) and the presence note ("resolved", "someone else") in the app's 20 languages.

**In production (16 October 2026)**, after the vocabulary was checked against WHO, every stored symptom was re-normalized. On the records of real users: all symptoms normalized, 0 present symptoms left as "unclear", and 0 symptoms that are not present published as the person's own (independent audit of the published Observations).

## 5. Similar cases (in development)

The next component compares people by their symptoms and abnormal lab results, to suggest, only with explicit consent, people who report something very similar.

- **Profile.** Present, self-reported symptoms of the last 90 days by Anpheros concept, and lab results of the last 180 days outside the reference range printed by the laboratory, by LOINC code. Profiles are independent of language and country: a lab report in Romanian and one in English map to the same LOINC code.
- **Score.** A weighted Jaccard index: shared signs over all signs of both people. Very common symptoms (headache, abdominal pain, fatigue, fever, cough, dizziness…) weigh 0.25, specific symptoms 1, an abnormal lab result 1.5. From 50 participants, weights are also scaled by how rare a sign is in the population (inverse document frequency). Two different signs in the same body system earn partial credit.
- **Rule.** A pair is only considered with at least three shared specific symptoms, or two plus a shared abnormal lab result: common complaints alone never make two people "similar". An invitation is offered from a score of 0.70; the person sees similar cases from 0.80.
- **Privacy.** Adult account holders only, explicit consent (GDPR Art. 9), revocable at any time with immediate deletion. A person sees counts and the shared signs, never who the others are.

It does not suggest a diagnosis or a disease.

## 6. How applications use it

- **Anpheros Daily** (iOS, Android, Mac, web): every symptom a person notes goes through the pipeline above; the person can see and correct the result.
- **Anpheros Platform**: symptoms are stored as FHIR `Observation`s with category `urn:anpheros:observation-category|symptom`, both codes and the person's own text. Any application with the person's consent can read them.
- **Your application**: search concepts with `GET /v1/terminology/symptoms`, expand the FHIR `ValueSet`, translate codes with the `ConceptMap`s to ICD-10 and ICD-11, and validate Observations against the `anpheros-symptom` profile. See [Symptom data API](https://developers.anpheros.com/guides/symptom-data-api) for requests and responses.
- **AI assistants and agents** read the same structured data through the [Context API](https://developers.anpheros.com/guides/ai-agents-medical-data) instead of free text, so their answers can cite codes.

## 7. Limits

- The engine names and codes symptoms; it does not diagnose, rank causes or link symptoms to diseases.
- No clinician has reviewed the vocabulary, the translations or the warning signs yet.
- The evaluation sets are synthetic; 15 of the 20 languages have no evaluation set yet.
- ICD-11 is licensed by WHO under CC BY-ND 3.0 IGO; codes and titles are reproduced unchanged.

## Related

- [Symptom data API](https://developers.anpheros.com/guides/symptom-data-api): concepts, FHIR terminology and patient-reported symptoms
- [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems)
- [Longitudinal patient data API](https://developers.anpheros.com/guides/longitudinal-patient-data-api)
