guides/07_llm_and_dspy_workflows.md

# LLM and DSPy Workflows

Exdantic includes explicit support for structured-output workflows targeting providers like OpenAI and Anthropic, plus DSPy-style validation patterns.

## Building an LLM Output Contract

You can define output contracts with either compile-time or runtime schemas.

Compile-time example:

```elixir
defmodule LLMOutput do
  use Exdantic

  schema "Structured LLM output" do
    field :answer, :string do
      required()
      min_length(1)
    end

    field :confidence, :float do
      required()
      gteq(0.0)
      lteq(1.0)
    end

    field :sources, {:array, :string} do
      optional()
    end

    config do
      strict(true)
    end
  end
end
```

## Validate and Generate Provider Schema in One Flow

Use `Exdantic.EnhancedValidator` for integrated pipelines:

```elixir
{:ok, validated, provider_schema} =
  Exdantic.EnhancedValidator.validate_for_llm(
    LLMOutput,
    %{
      answer: "42",
      confidence: 0.93,
      sources: ["paper-a", "paper-b"]
    },
    :openai
  )
```

## Provider Optimization APIs

Use JSON Schema resolver utilities directly:

```elixir
base = Exdantic.JsonSchema.from_schema(LLMOutput)
openai = Exdantic.JsonSchema.Resolver.enforce_structured_output(base, provider: :openai)
anthropic = Exdantic.JsonSchema.Resolver.enforce_structured_output(base, provider: :anthropic)
```

For higher-level metadata and optimization:

```elixir
enhanced =
  Exdantic.JsonSchema.EnhancedResolver.resolve_enhanced(
    LLMOutput,
    optimize_for_provider: :openai,
    flatten_for_llm: true
  )
```

## DSPy-Oriented Metadata

Field metadata can carry DSPy-style annotations with `extra/2`:

```elixir
field :question, :string do
  extra("__dspy_field_type", "input")
  extra("prefix", "Question:")
end

field :answer, :string do
  extra("__dspy_field_type", "output")
  extra("prefix", "Answer:")
end
```

This metadata is useful when adapting Exdantic schemas into DSPy-style prompt/signature tooling.

## DSPy Optimization API

Use:

```elixir
dspy_schema =
  Exdantic.JsonSchema.EnhancedResolver.optimize_for_dspy(
    LLMOutput,
    signature_mode: true,
    strict_types: true,
    field_descriptions: true
  )
```

Common effects:

- flattening and strictness for predictable output parsing
- additional DSPy metadata flags
- optional computed-field removal for input contracts

## End-to-End Validation Reporting

For deployment checks and diagnostics:

```elixir
report =
  Exdantic.EnhancedValidator.comprehensive_validation_report(
    LLMOutput,
    %{answer: "x", confidence: 0.8},
    test_providers: [:openai, :anthropic],
    include_performance_analysis: true,
    include_dspy_analysis: true
  )
```

Report includes validation result, generated schema, provider compatibility, performance metrics, and recommendations.

## Runtime Contracts for Multi-Stage LLM Pipelines

When stage outputs change dynamically, use runtime schemas:

```elixir
stage_schema = Exdantic.Runtime.create_schema(fields, strict: true)
{:ok, validated} = Exdantic.Runtime.validate(stage_output, stage_schema)
```

Or use enhanced runtime schemas for staged transforms and computed enrichment.

## Recommended Production Pattern

1. Define strict schema contracts (`strict(true)` or strict runtime config)
2. Validate raw model output before business logic
3. Generate provider-specific schema in CI checks
4. Keep provider optimization deterministic and versioned
5. Use comprehensive reports to monitor contract drift

## Next Guides

- `guides/08_configuration_and_settings.md`
- `guides/09_errors_reports_and_operations.md`