Prompt Engineering for Spec Generation and Validation
Once you understand spec decomposition and task creation, the next frontier is using AI to automate spec authoring and validation. Well-crafted prompts enable AI to extract formal specifications from vague requirements, generate executable specs in JSON Schema or OpenAPI, and then verify that code satisfies those specs. This article covers the specific prompting patterns that work best for spec-driven workflows.
The Role of Prompts in Spec-Driven Development
In traditional development, prompts ask AI to "write code." In spec-driven development, prompts have three jobs:
- Generate specs from requirements. Convert prose into OpenAPI, JSON Schema, or state machine definitions.
- Refine specs interactively. Use multi-turn conversations to clarify ambiguities and add edge cases.
- Validate code against specs. Confirm that generated code satisfies the spec, and identify gaps.
Each job requires a different prompt structure.
Prompt Pattern 1: Spec Generation from Requirements
When you have vague requirements, a well-structured prompt can guide AI to produce a formal spec.
# Task: Generate a Formal API Specification
You are an expert API designer. Given loose requirements, produce
a detailed OpenAPI 3.1.0 specification.
## Requirements:
A REST API for an online store must support:
- Customers can view a catalog of products
- Customers can add items to a shopping cart
- Customers can place orders and pay via credit card
- Admins can add/remove products and set inventory
- All endpoints require authentication except GET /products
## Output Instructions:
1. Produce a valid OpenAPI 3.1.0 YAML spec
2. Include all endpoints (GET, POST, PATCH, DELETE as needed)
3. For each endpoint, specify:
- Summary and description
- Request body schema (if applicable)
- Response schema for success (200-level) and errors (400/401/500)
- Authentication requirements
4. Define reusable schemas (Product, Order, Customer) in components
5. Include sensible validation rules (min/max lengths, formats, enums)
6. For enum fields, list all valid values
7. Include 2-3 example requests and responses per endpoint
Output ONLY the OpenAPI YAML, no explanations.
This prompt forces several key outputs:
- Reusable schemas (preventing duplication)
- Validation rules (preventing invalid requests from being generated)
- Clear error codes (so code knows what to return)
- Examples (so AI verifying code can check behavior)
The AI produces:
openapi: 3.1.0
info:
title: Online Store API
version: 1.0.0
servers:
- url: https://api.store.example.com/v1
components:
schemas:
Product:
type: object
properties:
id:
type: string
pattern: '^prod_[a-z0-9]{12}$'
name:
type: string
minLength: 1
maxLength: 200
price:
type: number
minimum: 0.01
maximum: 999999.99
inventory:
type: integer
minimum: 0
required: [id, name, price, inventory]
# ... (more schemas)
paths:
/products:
get:
summary: List all products
parameters:
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: Products retrieved
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/Product'
total:
type: integer
# ... (more endpoints)
This spec is now machine-readable and can be used to generate code and tests.
Prompt Pattern 2: Refining Specs Interactively
A single prompt rarely produces a perfect spec. Use multi-turn conversations to refine:
# Turn 1: Initial spec generation
[Use Prompt Pattern 1 above]
# Turn 2: Refinement
The spec you generated is helpful, but I need to add:
1. Rate limiting: 100 requests per minute per API key
2. Webhooks: OrderCreated, OrderShipped, OrderCancelled
3. Idempotency: All POST endpoints must support Idempotency-Key header
Please update the OpenAPI spec to include:
- Rate-Limit-Remaining, Rate-Limit-Reset headers in all responses
- Webhook schema definition and delivery details
- Idempotency-Key as a required header for POST endpoints
- A 409 Conflict response for duplicate idempotency keys
Output only the updated YAML.
The AI refines the spec iteratively. After a few turns, you have a spec that reflects all nuances.
Prompt Pattern 3: Code Generation from Spec
Once you have a formal spec, use it to prompt AI to generate code:
# Task: Generate Python FastAPI Implementation
You are an expert Python backend engineer. Given an OpenAPI spec,
produce a production-ready FastAPI implementation.
## Specification:
[PASTE THE OPENAPI SPEC FROM PREVIOUS TURN]
## Implementation Instructions:
1. Create a FastAPI app with routes for each endpoint
2. Validate all request inputs according to the spec schemas
3. Return responses with the exact schema defined in the spec
4. Implement authentication using JWT Bearer tokens
5. Return appropriate HTTP status codes (200, 400, 401, 404, 409, 500)
6. Use dependency injection for database connections
7. Log all requests and errors
8. Use type hints throughout
9. Include docstrings for all functions
## Code Organization:
- main.py: FastAPI app definition and route registration
- schemas.py: Pydantic models matching OpenAPI schemas
- crud.py: Database operations
- auth.py: JWT token generation and validation
## Error Handling:
- Catch and log all exceptions
- Return 500 with generic error message (never expose internals)
- Return 400 for validation errors with field-level detail
Output complete, runnable code for each file. No explanations.
The AI produces code that provably matches the spec because the spec was provided as input.
Prompt Pattern 4: Spec Validation Against Code
To verify that code satisfies a spec, use a validation prompt:
# Task: Validate Code Against OpenAPI Specification
You are a code reviewer expert in API compliance. Your job is to
validate that the given Python code matches the provided OpenAPI spec.
## Specification:
[PASTE THE OPENAPI SPEC]
## Code:
[PASTE THE PYTHON CODE]
## Validation Checklist:
For each endpoint in the spec, verify:
1. Endpoint exists with correct method and path
2. Request validation matches schema (required fields, types, constraints)
3. Response status codes and schemas match spec
4. Authentication is enforced per spec
5. All error cases are handled (400, 401, 404, 409, 500)
## Output Format:
Report findings as JSON:
{
"endpoints": [
{
"endpoint": "GET /products",
"status": "compliant|non_compliant",
"findings": [
{
"type": "error|warning",
"description": "..."
}
]
}
],
"summary": {
"compliant_endpoints": 5,
"non_compliant_endpoints": 1,
"critical_issues": 1,
"overall_verdict": "pass|fail"
}
}
Output only the JSON, no explanations.
The AI audits code against the spec and reports:
{
"endpoints": [
{
"endpoint": "GET /products",
"status": "compliant",
"findings": []
},
{
"endpoint": "POST /orders",
"status": "non_compliant",
"findings": [
{
"type": "error",
"description": "Code returns 200 on success; spec requires 201 Created"
},
{
"type": "warning",
"description": "Code does not validate customerId format per spec"
}
]
}
],
"summary": {
"compliant_endpoints": 8,
"non_compliant_endpoints": 1,
"critical_issues": 1,
"overall_verdict": "fail"
}
}
Prompt Pattern 5: Test Generation from Spec
A spec also enables automatic test generation:
# Task: Generate pytest Test Cases from OpenAPI Spec
You are an expert Python test engineer. Given an OpenAPI spec,
generate comprehensive pytest test cases.
## Specification:
[PASTE THE OPENAPI SPEC]
## Test Generation Instructions:
1. For each endpoint, generate tests for:
- Happy path (valid inputs, 200/201 response)
- Validation errors (invalid inputs, 400 response)
- Authentication failure (missing/invalid token, 401)
- Not found errors (missing resource, 404)
- Conflict errors (duplicate, 409)
2. Use pytest fixtures for setup/teardown
3. Use parameterized tests for multiple scenarios
4. Mock external services (payment processor, email)
5. Use examples from the spec as test data
6. Assert response schema matches spec
## Code Structure:
- tests/test_products.py
- tests/test_orders.py
- tests/conftest.py (fixtures and mocks)
Output complete, executable pytest code.
The AI generates tests directly from the spec:
import pytest
from fastapi.testclient import TestClient
from app import app
client = TestClient(app)
@pytest.fixture
def valid_product():
return {
"name": "Widget",
"price": 19.99,
"inventory": 100
}
def test_list_products_success():
response = client.get("/products?page=1&limit=20")
assert response.status_code == 200
data = response.json()
assert "items" in data
assert "total" in data
assert isinstance(data["items"], list)
def test_list_products_invalid_limit():
response = client.get("/products?page=1&limit=1000")
assert response.status_code == 400
def test_create_product_unauthorized():
response = client.post("/products", json={"name": "Widget", "price": 19.99, "inventory": 100})
assert response.status_code == 401
# ... (more tests)
Best Practices for Spec-Generation Prompts
Chain of thought: Ask AI to reason about requirements before generating the spec. This reduces errors.
Before generating the OpenAPI spec, answer these questions:
1. What are the core entities? (Product, Order, Customer, etc.)
2. What operations does each entity support? (CRUD, custom actions)
3. What authentication is required for each operation?
4. What validation rules apply to each field?
5. What error cases must we handle?
Iterate in small steps: Rather than ask for a full implementation in one prompt, ask for spec → code → tests in separate prompts.
Provide context: Include team conventions, coding standards, and existing APIs. AI will match the style and avoid inconsistencies.
Validate the output: Always review AI-generated specs. Check for:
- Missing endpoints or fields
- Unrealistic constraints (limit: 100 max on unbounded input)
- Incomplete error cases
- Inconsistent naming (camelCase vs snake_case)
Comparison Table: Prompting Strategies
| Strategy | Use Case | Accuracy | Iteration |
|---|---|---|---|
| Single prompt (full spec) | Simple APIs | 70–80% | Low |
| Iterative refinement | Complex domains | 90–95% | High |
| Spec + code validation loop | Production code | 95%+ | Medium |
| Prompt chaining (spec → code → tests) | End-to-end | 95%+ | High |
Key Takeaways
- Spec-generation prompts must be structured, with clear output format (YAML, JSON) and validation rules.
- Iterative refinement (multi-turn conversations) produces better specs than single prompts.
- Specs enable downstream automation: code generation, test generation, and validation.
- Always validate AI-generated specs by humans; AI can miss domain nuances and edge cases.
- Chaining prompts (spec → code → tests) reduces errors and accelerates development.
Frequently Asked Questions
Can AI generate better specs than humans?
No. AI can extract structure from prose and ensure formal correctness, but AI lacks domain expertise and business context. Use AI to formalize specs, then have domain experts review them.
How do I prevent AI from generating incomplete specs?
Provide detailed requirements or examples of similar APIs. Use checklists in prompts. Validate output against a spec template (e.g., "every endpoint must include error responses").
What if the generated spec doesn't match my team's conventions?
Include team style guidance in the prompt. For example, "Use snake_case for field names" or "Include operationId for every endpoint" or "Use Bearer token authentication."
Can I use AI-generated specs in production immediately?
Not recommended. AI-generated specs are a good starting point, but humans must review for completeness, correctness, and alignment with business requirements. Treat them as drafts.