Most AI document drafting tools for life sciences treat compliance as an afterthought. They generate fluent prose, cite a few sources if you are lucky, and hand you a blob of text that a QA specialist then has to reverse-engineer into something audit-ready. The AI gets credit for speed. The quality team absorbs the risk.

We built something different. GxP-RAG is an open-source document drafting system where the compliance architecture is the foundation, not a feature flag. Every procedural step cites its source. Every electronic signature produces a SHA-256 digest. Every audit record is cryptographically chained to its predecessor. The ALCOA+ evaluation engine scores drafts before they ever reach a human reviewer.

This is not a chatbot with a regulatory prompt. It is a structured drafting pipeline with guardrails at every layer.

The Architecture: Five Layers, One Constraint

The system has a hard constraint: no AI-generated content reaches an approved state without human review, cryptographic provenance, and compliance verification. Every architectural decision flows from that constraint.

┌─────────────────────────────────────────────────────────────────┐
│                      GxP-RAG Architecture                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐      │
│  │  PDF / DOCX  │    │   Markdown   │    │    JSON      │      │
│  │  Upload      │    │   / Text     │    │   Structured │      │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘      │
│         │                   │                   │               │
│         └───────────────────┼───────────────────┘               │
│                             ▼                                   │
│               ┌─────────────────────────┐                       │
│               │   GxP Document Parser   │                       │
│               │  (auto-classify doc     │                       │
│               │   type, extract ID,     │                       │
│               │   detect sections)      │                       │
│               └────────────┬────────────┘                       │
│                            ▼                                    │
│               ┌─────────────────────────┐                       │
│               │  Hierarchical Chunker   │                       │
│               │  (section-aware, 600w,  │                       │
│               │   100w overlap)         │                       │
│               └────────────┬────────────┘                       │
│                            ▼                                    │
│               ┌─────────────────────────┐                       │
│               │  FastEmbed (local)      │                       │
│               │  BAAI/bge-small-en-v1.5 │                       │
│               └────────────┬────────────┘                       │
│                            ▼                                    │
│               ┌─────────────────────────┐                       │
│               │   Qdrant Vector DB      │                       │
│               │  (payload indexing +    │                       │
│               │   metadata filtering)   │                       │
│               └────────────┬────────────┘                       │
│                            │                                    │
│         ┌──────────────────┼──────────────────┐                 │
│         ▼                  ▼                  ▼                 │
│  ┌─────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ Pydantic AI │  │  Compliance  │  │   HITL       │           │
│  │ Agent       │  │  Engine      │  │   Approval   │           │
│  │ (typed out) │  │  (ALCOA+     │  │   Workflow   │           │
│  └─────────────┘  │   scoring)   │  │  (e-sig +    │           │
│                   └──────────────┘  │   SHA-256)   │           │
│                                     └──────────────┘           │
│                            │                                    │
│                            ▼                                    │
│               ┌─────────────────────────┐                       │
│               │  Tamper-Evident Audit   │                       │
│               │  Trail (JSONL + SHA-256 │                       │
│               │   hash chain)           │                       │
│               └─────────────────────────┘                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Six layers. Each one exists because a regulator, auditor, or quality manager would ask a question the previous layer could not answer.

Layer 1: The RAG Pipeline — Why Local Embeddings Matter

The retrieval pipeline uses Qdrant as the vector database with FastEmbed generating embeddings locally via BAAI/bge-small-en-v1.5. This was a deliberate choice over API-based embedding services.

The reasoning: In a regulated environment, every external API call is a potential data leakage vector and a dependency that must be validated. When you embed a deviation report about a contamination event, that text leaves your network if you use an external embedding API. With FastEmbed, the 384-dimensional vectors are generated on-premise with zero latency and zero data egress. The model is 130MB. It runs on CPU.

The chunker is not a naive sliding window. It is section-aware — it splits on GxP document headers (numbered sections like ### 1.0 Purpose, ## 7.0 Procedure) and falls back to paragraph splitting only when no standard headings are found. Each chunk is prepended with a contextual header:

Document: SOP-MFG-014 - Cleanroom Sanitization (Type: SOP, Dept: Manufacturing)
Section: 7.2 Surface Disinfection

7.2.1 Unidirectional Overlapping Wiping Technique...

This contextual prefix dramatically improves retrieval quality because the embedding model sees the document identity and section heading alongside the content, not just the raw paragraph text.

The document parser auto-classifies incoming documents into nine GxP categories — SOP, Work Instruction, Deviation Report, Validation Protocol, CAPA, Change Control, Batch Production Record, Analytical Test Method, and Regulatory Guideline — using keyword heuristics on the first 2,000 characters and the filename. It extracts the document ID from standard patterns (SOP-XYZ-123, DEV-2024-001, CAPA-2024-012), the title from markdown headers or Title: fields, and the version from Version: or Rev. markers. This means you can drop a folder of mixed GxP documents onto the system and it will correctly categorize, tag, and index each one without manual metadata entry.

Layer 2: Pydantic AI — Why Structured Output Is Non-Negotiable

The drafting agent is built on Pydantic AI, not LangChain, not a raw API wrapper. The reason is simple: the output schema is a Pydantic model (GxPDocumentDraft), and every field is typed, validated, and documented.

class GxPDocumentDraft(BaseModel):
    doc_id: str
    title: str
    doc_type: DocumentType
    version: str
    department: str
    purpose: str
    scope: str
    regulatory_standards: List[str]
    responsibilities: Dict[str, str]
    procedure_sections: List[GxPSection]
    citations: List[Citation]
    # ... 20+ more typed fields

Each ProceduralStep inside a GxPSection carries:

  • step_number — hierarchical numbering (e.g., 5.1.2)
  • role_responsible — the specific authorized role (not “responsible party”)
  • critical_parameters — CPPs like "Temperature: 2-8°C", "Agitation: 150 RPM"
  • acceptance_criteria — observable pass/fail conditions
  • verification_method — how the step is documented ("Initial in batch record", "Automated SCADA log")
  • citations — per-step source provenance back to the knowledge base

This is the difference between an LLM generating “Ensure the temperature is within acceptable limits” and generating “Verify autoclave chamber temperature is 121.0°C ± 0.5°C for a minimum hold time of 15.0 minutes (QC Analyst). Acceptance Criteria: All thermocouple readings within 120.5°C – 121.5°C. Verification: SCADA data log exported and attached as Annex A.”

The system prompt enforces five fundamental rules:

  1. Grounded provenance — always query the knowledge base before drafting; every critical limit must cite its source document, section, and exact quote.
  2. Imperative voice — active, unambiguous instructions assigned to specific roles.
  3. Critical Process Parameters — every operation specifies pass/fail criteria with quantified tolerances.
  4. ALCOA+ data integrity — contemporaneous recording instructions and deviation handling protocols.
  5. Structural completeness — Purpose, Scope, Responsibilities, Procedures, Acceptance Criteria, Citations, Sign-off requirements.

The agent has three tools: search_gxp_knowledge_base (semantic search with metadata filtering), retrieve_document_details (full-chunk retrieval by document ID), and validate_gxp_structure (self-check against GxP structural requirements). The agent is instructed to search first, draft second, and validate third.

Layer 3: The ALCOA+ Compliance Engine

After the agent produces a draft, the compliance engine runs a deterministic evaluation against ALCOA+ principles. This is not an LLM call. It is a rules-based scorer that inspects the structured output.

ALCOA+ Principle What It Checks Score Impact
Attributable Every procedural step has a role_responsible -15% if steps lack roles
Contemporaneous Real-time recording instructions present Always passes (enforced by prompt)
Accurate Acceptance criteria defined with quantifiable criteria -20% if no criteria found
Complete Purpose, Scope, and Procedure sections populated -10% per missing section, -30% if no procedures

The engine produces a compliance score (0–100%), flags critical deficiencies, generates risk items for any step with Critical Process Parameters, and evaluates against four regulatory standards: FDA 21 CFR Part 211, FDA 21 CFR Part 11, EU Annex 11, and ISPE GAMP 5.

A draft scoring below 80% or containing critical deficiencies is flagged as non-compliant. This is the first gate before any human sees the document.

Layer 4: HITL Approval with 21 CFR Part 11 Electronic Signatures

The approval workflow is the most critical layer. It implements the core requirements of 21 CFR Part 11 for electronic records and electronic signatures.

The workflow states:

DRAFT → PENDING_APPROVAL → APPROVED / REJECTED / REVISION_REQUESTED

When a draft is submitted for approval, the system creates an ApprovalRequest with:

  • Required reviewer roles (default: SME Reviewer + QA Specialist)
  • A frozen document snapshot
  • An audit trail entry

When a reviewer approves, they execute an Electronic Signature containing:

  • Printed name — the signer’s full legal name
  • User ID — unique identification
  • Signer role — authorized GxP role (QA Specialist, QA Manager, SME Reviewer, Regulatory Affairs)
  • Signature meaning — a formal declaration (default: “I confirm that I have reviewed this GxP document and approve its scientific, technical, and regulatory compliance”)
  • Contemporaneous UTC timestamp — recorded at the moment of signing
  • SHA-256 signature digest — computed from {user_id}:{signer_name}:{role}:{meaning}:{timestamp}:{document_content}

The signature digest is a cryptographic commitment to the exact content that was signed. If anyone modifies the document after signing, the digest will not match. This is not a checkbox. It is a legally binding electronic signature with cryptographic proof.

Layer 5: The Tamper-Evident Audit Trail

Every event in the system — document creation, knowledge base queries, approval requests, signatures, rejections — is logged to a JSONL audit trail. Each record contains:

{
  "event_id": "uuid",
  "timestamp": "2026-08-17T07:00:00+00:00",
  "event_type": "APPROVAL_GRANTED",
  "doc_id": "SOP-MFG-042",
  "user_id": "qa_lead_01",
  "user_role": "QA_SPECIALIST",
  "action_details": { "request_id": "APP-A1B2C3D4", "comments": "..." },
  "signature": { "signer_name": "...", "signature_digest": "a3f2..." },
  "previous_record_hash": "b7e1...",
  "record_hash": "c9d4..."
}

The previous_record_hash field links each record to its predecessor. The record_hash is a SHA-256 digest of the entire record (including the previous hash). This creates a cryptographic chain — identical in concept to a blockchain but stored as a simple append-only JSONL file.

The audit-verify CLI command walks the entire chain and validates:

  1. Every previous_record_hash matches the actual hash of the prior record.
  2. Every record_hash matches a fresh computation of the record’s contents.

If any record was modified, deleted, or inserted, the chain breaks and the verification fails. This is what “tamper-evident” means in the context of 21 CFR Part 11 — you cannot silently alter audit history.

Multi-LLM Provider Architecture

The system supports five LLM provider families through a factory pattern:

Provider Models Use Case
OpenAI GPT-4o, o3-mini, GPT-4.5-preview Frontier quality, reasoning
Anthropic Claude 3.7 Sonnet, Claude 3.5 Sonnet, Claude 3 Opus Complex regulatory reasoning
Google Gemini 2.0 Flash, Gemini 1.5 Pro Cost-effective generation
Ollama / Local Llama 3.3, Qwen 2.5 72B, DeepSeek R1 Air-gapped, zero data egress
TestModel Deterministic test output CI/CD, automated testing

The FallbackModel from Pydantic AI enables automatic provider failover — if OpenAI is down, the system falls back to Anthropic or a local model without manual intervention.

Why this matters for regulated environments: No single vendor lock-in. If your primary LLM provider changes their terms, raises prices, or has an outage during a critical document drafting cycle, you switch providers with a single environment variable change. The structured Pydantic output schema ensures the document format is identical regardless of which model generated it.

Observability: Langfuse Integration

Every drafting session is traced in Langfuse with a typed observation hierarchy:

  • Agent span — the root drafting session (input prompt, model, user context)
  • Retriever span — Qdrant semantic search (query, filters, result count, scores)
  • Generation span — Pydantic AI model execution (model name, input/output)
  • Guardrail span — ALCOA+ compliance evaluation (score, deficiencies)
  • Event — 21 CFR Part 11 electronic signature execution (SHA-256 digest)

Quality scores are automatically recorded: gxp-compliance-score (0.0–1.0) and alcoa-data-integrity-pass (0 or 1) on every trace. This gives you a dashboard of compliance quality over time — you can track whether your drafts are improving, which models produce the highest compliance scores, and where the RAG retrieval is finding (or missing) relevant source documents.

The CLI and Web Studio

The system ships with two interfaces:

CLI (gxp-rag) — for scripting, CI/CD integration, and batch operations:

gxp-rag ingest ./sample_data          # Parse, chunk, embed, index
gxp-rag search "autoclave validation"  # Semantic search
gxp-rag draft "Draft an SOP for..." --type SOP --model openai:gpt-4o
gxp-rag approvals sign APP-A1B2C3D4 --name "Jane Smith" --role QA_SPECIALIST
gxp-rag audit-verify                   # Verify SHA-256 chain integrity

Web Studio (gxp-rag serve) — a FastAPI application with:

  • Drafting Studio with model selection and real-time structured output
  • Knowledge Base manager with drag-and-drop document upload
  • Human Approval center with side-by-side citation review and e-signature dialog
  • Audit Trail viewer with real-time cryptographic chain verification

What’s Included as Sample Data

The repository ships with six realistic GxP documents covering different document types:

  • SOP-MFG-014 — Cleanroom Sanitization and Microbial Disinfection (ISO Class 5/7 cleanrooms, disinfectant rotation schedules, contact plate acceptance criteria)
  • CAPA-2024-012 — Corrective Action for Bioburden Excursion in Purified Water System (Burkholderia cepacia investigation, deadleg remediation, ozone sanitization)
  • SOP-LAB-XXX — HPLC System Suitability Testing
  • VAL-XXX — Autoclave IQ/OQ Validation Protocol
  • WI-XXX — Pipette Calibration Work Instruction
  • DEV-XXX — Cold Room Temperature Excursion Deviation Report

These are realistic enough to demonstrate the full pipeline — auto-classification, section-aware chunking, semantic retrieval, structured drafting, and compliance scoring — without requiring a production document management system.

Getting Started

git clone https://github.com/saram-io/gxp-rag.git
cd gxp-rag
uv venv --python python3.12
source .venv/bin/activate
uv pip install -e ".[dev]"

# Ingest sample documents
gxp-rag ingest ./sample_data

# Draft a document
gxp-rag draft "Draft an SOP for Cleanroom Disinfection after microbial excursion in ISO Class 5 filling suite" --type SOP --model openai:gpt-4o

# Run the test suite
pytest -v

The test suite covers 16 scenarios: Pydantic AI agent tool calls, structured output validation, Qdrant RAG ingestion and semantic search, 21 CFR Part 11 electronic signature generation, SHA-256 hash chaining, multi-provider model resolution, and FastAPI endpoint rendering.

The Bottom Line

Building AI for regulated environments is not about making the LLM smarter. It is about building infrastructure around the LLM that enforces compliance structurally. The model generates. The schema validates. The compliance engine scores. The human approves with a cryptographic signature. The audit trail proves no one tampered with anything.

GxP-RAG is the reference architecture for that stack. It is open source, it runs locally, and it takes the regulatory requirements seriously enough that a QA auditor can trace every claim in a generated document back to a specific source document, section, and exact quote — verified by SHA-256.

The repo: github.com/saram-io/gxp-rag