Prompt Lab
Interactive prompt testing, the RTIO format, and the reusable prompt library.
What it is
Prompt Lab is the interactive workspace for designing, testing, and saving AI prompts. You test an extraction prompt against a real document, optionally define a structured JSON output schema, switch between models (Vertex AI, OpenAI, Anthropic), let AI enhance the prompt into RTIO structure, and save the result to the prompt library for reuse by tasks, agents, and squads.
Two related surfaces work together:
- Prompt Lab — the synchronous test-and-tune surface. It runs a single prompt against one document and returns the structured result immediately so you can iterate.
- Prompt Library — the persistent store of reusable prompts (the
promptcontent type). An agent references a saved prompt by its title viaprompt_title; an extraction task node references one the same way.
Prompt Lab is where you author and validate. The library is where you store and reuse. A prompt is not available to agents or workflows until you have saved it to the library.
When to use it
Use Prompt Lab whenever you are authoring or tuning a prompt before wiring it into an extraction task or an agent. It is where you iterate on prompt quality against real inputs instead of guessing — refine the wording, tighten the output schema, and compare models side by side until the extraction is reliable.
RTIO — Role, Task, Input, Output
RTIO is TurfAI's structured prompt format. Rather than one free-form blob of instructions, a prompt is organised into clear sections so the model knows who it is, what to do, what it is looking at, and how to answer:
- Role — the persona/expertise the model adopts ("You are an expert document extraction
assistant…"). Stored as the
systementry in the prompt'sroles. - Task — what to extract, in plain language. Stored as the
userentry inroles, plus the discrete steps intasks. - Input — the document content. At run time the platform injects it; enhanced prompts use a
{{document_content}}placeholder in the user role. - Output — the required answer shape:
outputFormat(text/json/markdown/structured) plus the output schema andexampleOutputthat pin the JSON structure.
Structuring a prompt this way reduces ambiguity, which is what makes extraction repeatable across documents.
AI-powered RTIO enhancement
Prompt Lab can turn a rough prompt into polished RTIO automatically. You provide a title, your
draft prompt, and (optionally) an output schema; the platform calls the LLM with a prompt-engineer
meta-prompt and returns a structured { roles, tasks, instructions } object you can review and
edit before saving.
There are two distinct generation paths in the platform:
- Enhance RTIO (
POST /api/prompt-lab/enhance-rtio) — interactive polishing inside Prompt Lab. Takes yourprompt,output_schema,title,description; returnsroles(system + user with a{{document_content}}placeholder),tasks(3–5 steps), andinstructions(3–5 formatting/accuracy rules). - RTIO generation from classification — an automated pipeline task that builds a full prompt
(
title,description,section,roles,tasks,instructions,outputFormat,exampleOutput) from a document plus its classification result. Generated prompts are stampedlevel: "user"andversion: "1.0.0"with a default confidence of ~0.85.
The exact RTIO enhancement / meta-prompt algorithm and confidence-scoring internals are an implementation detail of the processor and are not yet documented here. Treat the enhanced output as a draft to review, not a guaranteed-correct prompt.
RTIO also shows up elsewhere: the agent prompt_title field (see Agents)
and extraction nodes in the Node catalog both resolve a saved RTIO prompt by
title.
How it works
Process flow — iterate then save:
Call flow — a structured test run. With an output schema, the controller wraps your prompt in an RTIO template (Role / Task / Output Format / Rules) before sending it; without one it sends the prompt as free-form:
Sub-features
- Interactive testing against a real document, returning the result synchronously.
- Output schema — supply a JSON shape; the prompt is wrapped in a structured RTIO template.
- Free-form mode — omit the schema to send the prompt as-is for exploratory extraction.
- Multi-model support — Vertex AI (
vertex, default), OpenAI, Anthropic. - AI enhancement — auto-polish a draft into RTIO
{ roles, tasks, instructions }. - Save to library — convert a tested prompt into a reusable library entry.
- Prompt library — system (shared) vs user (private) prompts, with title, description, section, tags, and versioning.
Configuration parameters
Prompt Lab test run (/api/prompt-lab/execute)
| Field | Type | Default | Description |
|---|---|---|---|
document_id | number | — (required) | The document to run the prompt against. |
prompt | string | — (required) | Natural-language extraction instructions. |
output_schema | object | {} | Expected JSON shape. When non-empty, the prompt is wrapped in a structured RTIO template; otherwise the run is free-form. |
model_type | string | vertex | LLM provider: vertex, openai, or anthropic. |
RTIO enhancement (/api/prompt-lab/enhance-rtio) takes prompt (required), title (required),
description, and output_schema, and returns roles, tasks, and instructions.
Saved prompt (the prompt library entry)
Reconciled against the prompt content-type schema. These are the fields a saved library entry
carries:
| Field | Type | Default | Description |
|---|---|---|---|
title | string | — (required) | Prompt name; agents/nodes reference it by this title. |
slug | uid (from title) | auto | URL-safe identifier derived from the title. |
description | text | — | What the prompt extracts. |
section | string | — | Grouping/category for organising the library. |
roles | json | system/user/developer/assistant entries | RTIO role prompts; each entry is { role, prompt }. |
tasks | json | [] | Ordered list of extraction steps. |
instructions | json | [] | Formatting / accuracy / missing-data rules. |
outputFormat | enum | text | One of text, json, markdown, structured. |
exampleOutput | json | {} | A sample of the expected output (your output schema lives here in practice). |
version | string | 1.0 | Prompt version string. |
level | enum | user | Library visibility: system (shared) or user (private). |
owner | relation → user | — | Owning user (drives user-level visibility). |
review_status | enum | draft | draft → in_review → published / rejected (Wave 2 governance). draft is blocked from agent/workflow execution. |
reviewed_by / reviewed_at | relation / datetime | — | Server-stamped on review transition. |
review_notes | text | — | Reviewer notes, visible to the owner (esp. on reject). |
lint_violations | json | — | Prompt-injection lint findings recorded on a publish attempt; empty array means it passed. |
pack_slug / pack_version / solution_pack | string / relation | null | Set when the prompt ships inside a solution pack. |
forked_from | string | null | Source prompt when this entry was forked. |
The legacy "category / tags" labels in earlier docs map onto the schema's section field and
pack/relation metadata. There is no free-form tags array on the current prompt content type —
use section to group, and level to control visibility.
Tips & best practices
- Write the Task before the Role. Decide exactly which fields you need, then add a Role that primes the model for that domain. A vague Role ("you are helpful") adds nothing; a specific one ("expert AP invoice analyst") measurably improves field accuracy.
- Always define an output schema for extraction. Without it the run is free-form and the model
may return prose. With a schema, the controller wraps your prompt with explicit rules: return
only valid JSON, use
nullfor missing fields, use[]for empty arrays. - Match field names in the prompt to the schema. If the schema key is
invoice_total, say "invoice total" in the Task — divergent wording is the most common cause of empty fields. - System vs user roles. Put stable, reusable framing (persona, global rules) in the
systemrole; put the document-specific extraction ask in theuserrole. Enhanced prompts place a{{document_content}}placeholder in the user role. - Library visibility:
level. Keep work-in-progress prompts atlevel: user(private to the owner). Promote tolevel: systemonly once a prompt is stable and meant to be shared — a system prompt is visible to everyone, so churn there is disruptive. - Versioning. Bump
versionwhen you change extraction behaviour rather than overwriting silently, so agents/nodes referencing the prompt by title have a traceable history. Useforked_fromwhen branching an existing prompt instead of editing a shared one. - Mind the review gate. A
draftprompt is blocked from agent/workflow execution; move it throughin_reviewtopublishedbefore depending on it in production.
Concrete examples
An output schema for invoice extraction — supply this as output_schema on the test run:
{
"vendor_name": "string",
"invoice_number": "string",
"invoice_date": "string (YYYY-MM-DD)",
"due_date": "string (YYYY-MM-DD)",
"currency": "string",
"line_items": [
{ "description": "string", "quantity": "number", "unit_price": "number", "amount": "number" }
],
"subtotal": "number",
"tax": "number",
"total": "number"
}A system + user prompt pair (RTIO roles) as stored on a saved prompt:
{
"title": "Extract Invoice Details",
"section": "Accounts Payable",
"outputFormat": "json",
"roles": [
{
"role": "system",
"prompt": "You are an expert accounts-payable analyst. You extract structured data from invoices precisely and never invent values."
},
{
"role": "user",
"prompt": "Extract the vendor, invoice number, dates, line items, and totals from the invoice below.\n\n{{document_content}}"
}
],
"tasks": [
"Identify the vendor and invoice number",
"Extract invoice date and due date",
"Extract each line item with quantity, unit price, and amount",
"Extract subtotal, tax, and total"
],
"instructions": [
"Return only valid JSON matching the output schema",
"Use null for any field you cannot find",
"Return an empty array for line_items if none are present",
"Match numbers exactly as printed; do not recalculate"
]
}A Prompt Lab test request (structured run against document 42 on Anthropic):
POST /api/prompt-lab/execute
{
"document_id": 42,
"prompt": "Extract the vendor, invoice number, dates, line items and totals.",
"output_schema": { "vendor_name": "string", "total": "number", "invoice_date": "string" },
"model_type": "anthropic"
}The response includes result (the structured content), tokens_used, latency_ms, model, and
the document it ran against.
Dependencies
- DMS prompt-lab API —
executeandenhance-rtiocontrollers; enforces document ownership/visibility before running. - DMS prompt service — library CRUD,
level-based visibility, and the review/lint governance fields. - LLM service — runs the extraction at
/api/v1/extractacross the selected provider. - Document management — supplies the test document (the controller passes the document's GCS URL straight to the model, which handles OCR for scanned files internally).
Limitations
- Quality is prompt-dependent; complex extraction schemas may need several iterations.
- Provider availability depends on which LLM credentials the deployment has configured.
- The extraction call has a long timeout (up to ~10 minutes) for large documents — a single test run is not instantaneous on big files.
- The internal RTIO enhancement meta-prompt and confidence-scoring logic are not yet documented; treat enhanced output as a reviewable draft.
- Batch testing (running a prompt across many documents at once) is coming soon — it is not part of the current synchronous single-document Prompt Lab.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Extraction returns empty fields | Schema key names don't match the wording in the prompt/document, or the field genuinely isn't on the page. | Align the Task wording with the schema keys; confirm the field exists in the test document; per the wrap rules, missing fields correctly come back as null. |
| Extraction returns wrong values | Vague Role/Task, or the model is recalculating instead of reading. | Tighten the Role to the domain; add an instruction to "match values exactly as printed; do not recalculate"; add an exampleOutput. |
| Output is prose, not JSON | No output_schema was supplied, so the run is free-form. | Provide an output_schema so the prompt is wrapped in the structured RTIO template with the "return only valid JSON" rule. |
| Different models give different results | Providers vary in extraction behaviour and JSON adherence. | Compare vertex / openai / anthropic on the same document and schema; pick the one that's most consistent for your document type. |
| RTIO enhancement fails ("invalid RTIO structure") | The model returned malformed JSON or omitted roles / tasks / instructions. | Re-run enhancement; provide a clearer title and a non-empty output schema so the meta-prompt has more to work with. |
| Prompt not appearing in the library for teammates | Saved at level: user (private to owner), or still review_status: draft. | Promote to level: system to share; move the prompt through review to published. |
| Agent/node can't find the prompt | prompt_title doesn't match the saved title, or the prompt is still draft (blocked from execution). | Match the title exactly; publish the prompt before referencing it. See Agents. |
How to test
- Create a draft prompt. In Prompt Lab, give it a title (e.g. Extract Invoice Details) and write a plain-language Task describing the fields you need.
- Add an output schema. Paste the invoice schema above so the run is structured rather than free-form.
- Test against a sample document. Pick a sample invoice and run
POST /prompt-lab/executewith yourprompt,output_schema, and amodel_type. Inspect the returned JSON. - Refine. Where fields come back empty or wrong, adjust wording and re-run; switch
model_typeto compare providers on the same document. - (Optional) Enhance. Call
enhance-rtioto polish the draft into structuredroles/tasks/instructions, then review the result. - Save to the library. Persist the tuned prompt; set
level(userwhile iterating,systemonce shared) and bumpversionon later changes. - Reference it. Point an agent's
prompt_titleor an extraction task node at the saved title, and confirm the workflow produces the same structured output as your Prompt Lab run.
Related
- Agents — consume saved prompts via
prompt_title. - Node catalog — extraction nodes reference library prompts.
- Task Node Mechanics — how nodes resolve inputs and prompts.
- Solution Packs — bundle prompts (
pack_slug/solution_pack). - Agentic automation and Governance — where prompts fit in the platform and the review gate.
Roadmap
- Batch testing across multiple documents — coming soon.
- Documented RTIO enhancement algorithm and confidence scoring — not yet documented.
APIs used
| Method | Path | Purpose |
|---|---|---|
POST | /api/prompt-lab/execute | Run a prompt against a document (structured or free-form). |
POST | /api/prompt-lab/enhance-rtio | AI-polish a draft prompt into RTIO structure. |
GET / POST | /api/prompts | List / create library prompts. |