Agent overview
About the Clinical Trial Matcher
An experimental, evidence-grounded agent that screens a synthetic, de-identified oncology profile against a fictional clinical-trial catalog — with a dedicated evaluation API so the whole run can be inspected end to end.
What it does
A single request turns a free-text, de-identified oncology profile into a criterion-by-criterion comparison against each candidate trial. Three cooperating agents extract the facts, review eligibility with cited evidence, and verify the assembled package; a deterministic rule — not the model — decides each trial's overall status. The service is stateless: nothing is written to disk, and the browser downloads the report locally.
Business requirements
De-identified input only
Direct identifiers (email, phone, SSN, record numbers, explicit names) are rejected before any model call.
Evidence-grounded
Every criterion is judged met, not met, or unknown, and decisive judgements must cite fields from the profile.
Deterministic eligibility
Overall status follows a fixed precedence rule in code, so the model never invents an eligibility verdict.
Independent verification
A verifier audits the assembled package for structural consistency before results are returned.
Fictional catalog
All studies are demonstration data with DEMO- identifiers — never real registry entries.
Stateless & private
No profile is persisted; the report is downloaded client-side and tracing of input text is disabled.
Evaluable end to end
A dedicated API returns the answer plus every tool, context, and metadata value for external eval.
Not medical advice
Results never establish clinical eligibility and always carry an explicit safety notice.
How it works
- Safety gateReject the request if the text contains direct identifiers.
- Profile extractionAn agent copies only the facts explicitly present into a structured, de-identified profile.
- Catalog searchA deterministic lookup selects candidate trials by condition and location.
- Eligibility reviewOne agent turn per candidate trial (run concurrently) assesses each criterion with cited evidence.
- Deterministic scoringCode derives each trial's overall status and the met / unknown / not-met counts.
- Evidence verificationA verifier audits the package; the ranked report is then returned.
The agents
| Agent | Purpose | Structured output | Tools |
|---|---|---|---|
| Synthetic profile extractor | Extract explicit facts; never infer. | PatientProfile |
None (structured output) |
| Eligibility evidence reviewer | Assess one trial's criteria with cited evidence. | EligibilityReview |
None (structured output) |
| Screening evidence verifier | Audit the package for structural consistency. | VerificationResult |
None (structured output) |
All three agents run on the model named by OPENAI_MODEL (default
gpt-5-mini). They use structured outputs rather than function tools, so the
evaluation trace reports an empty tool list for each — the deterministic catalog search is
surfaced as its own operation step instead.
Authentication
The screening endpoints are protected. First exchange your operator credentials
(configured with AUTH_USERNAME / AUTH_PASSWORD) for a bearer
token, then send it as an Authorization: Bearer <token> header on
/api/match and /api/eval. Tokens are short-lived JWTs; missing or
expired tokens are rejected with 401. /api/health and the UI stay
public.
curl -X POST http://localhost:8014/api/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "changeme"}'
# → {"access_token": "eyJ…", "token_type": "bearer", "expires_in": 3600}
Evaluation API
POST /api/eval runs the same workflow as /api/match but returns a
full trace built for evaluation harnesses: the final answer, plus every step's agent,
model, input context, output, available tools, tool calls, guardrail outcomes, response
ids, token usage, and timing. Unlike /api/match, it does not fail when the
verifier rejects the package — it reports the outcome in metadata.verified so
you can score the complete run.
Call it from Postman
- Method
POST, URLhttp://localhost:8014/api/eval - Header
Content-Type: application/json - Header
Authorization: Bearer <token>(from/api/login) - Body (raw JSON) as below
{
"profile_text": "Synthetic de-identified profile: 54-year-old female with stage III HER2-negative breast cancer, ECOG 1, located in Berlin."
}
Or with curl (reusing the token from /api/login):
curl -X POST http://localhost:8014/api/eval \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"profile_text": "Synthetic de-identified profile: 54-year-old female with stage III HER2-negative breast cancer, ECOG 1, located in Berlin."}'
Response shape
{
"request_id": "…",
"input": { "profile_text": "…" },
"final_output": { /* same object /api/match returns: profile, matches, verification */ },
"trace": [
{
"index": 1,
"kind": "agent",
"name": "profile_extraction",
"agent_name": "Synthetic profile extractor",
"model": "gpt-5-mini",
"input": "…profile text…",
"output": { /* structured agent output */ },
"available_tools": [],
"tool_calls": [],
"messages": ["…"],
"guardrails": [{ "name": "deidentified_profile_guardrail", "tripwire_triggered": false }],
"response_ids": ["…"],
"usage": { "requests": 1, "input_tokens": 0, "output_tokens": 0, "total_tokens": 0 },
"duration_ms": 0.0,
"error": null
}
/* … catalog_search (operation), one eligibility_review per trial, evidence_verification … */
],
"metadata": {
"model": "gpt-5-mini",
"candidate_trial_ids": ["DEMO-BRCA-001", "…"],
"verified": true,
"overall_statuses": ["potentially_eligible", "…"],
"step_count": 6,
"duration_ms": 0.0,
"usage": { "requests": 0, "input_tokens": 0, "output_tokens": 0, "total_tokens": 0 }
}
}
The interactive schema for every field is available at /docs (import /openapi.json into Postman to generate a collection automatically).