CrucibleFeedback

CrucibleFeedback Logo

Production feedback loop for ML systems: telemetry ingestion, quality assessment, drift detection, curation, retraining triggers, and export

Hex VersionHex DocsLicense


Features

Installation

# mix.exs
{:crucible_feedback, "~> 0.2.0"}

Configuration

Database Configuration (Oban Pattern)

CrucibleFeedback uses dynamic repo injection - your host application provides the Repo:

# config/config.exs
config :crucible_feedback,
  repo: MyApp.Repo,  # Required when using Ecto storage
  storage: CrucibleFeedback.Storage.Ecto,
  embedding_client: CrucibleFeedback.EmbeddingClient.Noop,
  start_ingestion: true,
  ingestion: [
    flush_interval: :timer.seconds(5),
    max_batch_size: 1_000
  ],
  sanitizer: [
    pii_patterns: []
  ],
  quality: [
    min_length: 20,
    max_length: 4_000
  ],
  triggers: [
    drift_threshold: 0.2,
    quality_threshold: 0.7,
    data_count_threshold: 1_000,
    schedule_interval_seconds: 86_400
  ],
  export: [
    output_dir: "exports"
  ],
  curation: [
    limit: 1_000,
    min_quality_score: 0.8,
    max_hard_quality: 0.5
  ]

# Your host app's Repo configuration
config :my_app, MyApp.Repo,
  database: "my_app_dev",
  username: "postgres",
  password: "postgres",
  hostname: "localhost"

Then start your Repo in your application's supervision tree:

# lib/my_app/application.ex
children = [
  MyApp.Repo,
  # ... other children
]

Migrations

Copy migrations from deps/crucible_feedback/priv/repo/migrations/ or run:

mix crucible_feedback.install

Legacy Mode

For backwards compatibility, set start_repo: true to auto-start internal Repo:

config :crucible_feedback,
  start_repo: true,
  ecto_repos: [CrucibleFeedback.Repo]

config :crucible_feedback, CrucibleFeedback.Repo,
  database: "crucible_feedback_dev",
  username: "postgres",
  password: "postgres",
  hostname: "localhost"

Usage

Ingest Events

CrucibleFeedback.log_inference(%{
  deployment_id: "deploy-1",
  model_version_id: "model-1",
  user_id: "user-123",
  prompt: "What is 2+2?",
  response: "4",
  latency_ms: 120,
  token_count: 42,
  metadata: %{source: "api"}
})

Record Signals

CrucibleFeedback.record_signal("inference-id", :thumbs_up, %{source: "ui"})
CrucibleFeedback.record_user_edit("inference-id", "User edited response")

Quality Assessment

CrucibleFeedback.assess_quality(%{response: "{\"ok\": true}"})
CrucibleFeedback.get_quality_stats("deploy-1")

Drift Detection

CrucibleFeedback.detect_drift("deploy-1", window_size: 1_000)

Curation and Export

CrucibleFeedback.curate("deploy-1", persist: true)
CrucibleFeedback.export("deploy-1", format: :jsonl, output_path: "exports/feedback.jsonl")
CrucibleFeedback.export_preference_pairs("deploy-1")

Retraining Triggers

CrucibleFeedback.check_triggers("deploy-1")

Feedback Stages

This package provides Crucible stages for feedback loop management:

All stages implement the Crucible.Stage behaviour with full describe/1 schemas.

Options (Export Feedback)

Options (Check Triggers)

Stage Usage

CrucibleFeedback.Stages.ExportFeedback.run(context, format: :jsonl)
CrucibleFeedback.Stages.CheckTriggers.run(context, [])

Storage Backends

Migrations

mix ecto.create
mix ecto.migrate

Testing

mix test

Notes