perficient/build
← all archetypes

structured extraction

Fill {{SCENARIO}} and {{DOMAIN}}, copy, paste into your coding agent.

# Kickoff — Structured Extraction Pipeline

Paste everything below into your coding agent after filling {{SCENARIO}} and {{DOMAIN}}.

---

You are working in this repo: Next.js 16 App Router + TypeScript + Tailwind, Clerk auth
(wired), Drizzle + Neon Postgres (schema `perficient`, `runs` + `documents` tables exist),
Anthropic SDK with `ANTHROPIC_API_KEY` in env. Deployed on Vercel; keep it deployable.

Build a structured-extraction pipeline for this scenario: {{SCENARIO}} (domain: {{DOMAIN}}).

## The bar: extraction is only "AI doing real work" if it survives messy input and
## proves its accuracy. Schema + validation + eval, not a demo of JSON.parse.

1. **Synthetic messy inputs.** Script: one Claude call generates 12-15 realistic raw
   {{DOMAIN}} documents (emails / reports / invoices / intake forms — whatever fits) as
   plain text, DELIBERATELY messy: inconsistent formats, missing fields, typos, two docs
   with conflicting info, one irrelevant document. Store in `documents`.
2. **Target schema.** `lib/extract/schema.ts`: a zod schema for the structured record
   (6-10 fields: strings, enums, numbers, dates, at least one array). Every field
   nullable — "not present" must be expressible, or the model will invent values.
   Mirror as a JSON Schema for the API's structured output.
3. **Extractor.** `app/api/extract/route.ts` (model `claude-sonnet-4-6`):
   - Structured output constrained to the JSON Schema.
   - System prompt: extract ONLY what is stated; null for absent fields — never guess;
     for each extracted field include a short `evidence` quote from the source.
   - zod-validate the response; on failure retry ONCE feeding the zod error back; second
     failure → row flagged `needs_review`, never silently dropped.
   - Add a `confidence` enum (high|medium|low) per record, reasoning-first field order.
4. **Batch run + review UI** at `/app`: table of all documents → extracted records,
   evidence quotes on hover/expand, `needs_review` rows highlighted, per-field null counts
   at the top. A human-review lane for low-confidence rows is the production story told in
   UI form. Log each extraction to `runs` (archetype "extraction") with token usage.
5. **Eval with known truth.** Because inputs are generated, generate the GROUND TRUTH
   alongside them (same call, separate field). `scripts/eval.ts`: field-level precision —
   % of extracted values matching truth, % of absent fields correctly null (the
   hallucination rate for extraction), and the conflict doc surfaced as `needs_review`.
   Print the table; run it live.

## Constraints
- Milestone after each step. The evidence-quote requirement is non-negotiable — it's the
  citation story in extraction form.
- All model calls through `lib/ai.ts`. Streaming for the batch endpoint or chunk the batch
  to stay inside serverless timeouts.