Sign inSign up

chiefj/perplexity

By chiefj

•Updated 4 months ago

Perplexity scoring microservice

Image
Developer tools
0

722

chiefj/perplexity repository overview

⁠Perplexity Scorer

Layer 3 perplexity scoring microservice — Score 4 in the LLM Observability composite quality index. Runs on port 8007. Zero GPU required.


⁠Table of Contents

  1. What It Does⁠
  2. Run Locally (Python)⁠
  3. Run with Docker⁠
  4. Run with Docker Compose⁠
  5. API Reference⁠
  6. Skip Conditions⁠
  7. Baselines & Alerting⁠
  8. Composite Weight⁠
  9. Environment Variables⁠
  10. CI / CD⁠
  11. Algorithm⁠

⁠What It Does

Scores the cross-entropy perplexity of an LLM response.

Scorer pathWhen usedCost
Provider logprobs (primary)token_logprobs array providedZero inference
GPT-2 124M ONNX (fallback)No logprobs supplied~25ms on CPU

Returns null (skipped) when skip conditions are met. The composite weight drops to 0.00 automatically.


⁠Run Locally (Python)

cd packages/python/perplexity

pip install -e ".[dev]"

SKIP_CONSOLE_EXPORTER=true SKIP_OTLP_EXPORTER=true \
  pytest tests/ --cov=src -v

Start the server:

PYTHONPATH=src uvicorn api.rest.v1.app:app --host 0.0.0.0 --port 8007 --reload

⁠Run with Docker

⁠Pull and run the published image
docker pull chiefj/perplexity:latest

docker run -d \
  --name perplexity \
  -p 8007:8007 \
  -e SKIP_OTLP_EXPORTER=true \
  chiefj/perplexity:latest
⁠Health check
curl http://localhost:8007/health
# {"status":"ok","scorer":"provider_logprobs"}
⁠Score a response (with provider logprobs)
curl -X POST http://localhost:8007/v1/score/perplexity \
  -H "Content-Type: application/json" \
  -d '{
    "trace_id": "abc123",
    "span_id": "def456",
    "response_text": "The mitochondria is the powerhouse of the cell.",
    "completion_tokens": 12,
    "prompt_type": "chat",
    "token_logprobs": [-1.2, -0.9, -1.5, -2.1, -0.8, -1.3, -1.0, -0.7, -1.4, -2.0, -1.1, -0.6]
  }'

Expected response:

{
  "trace_id": "abc123",
  "span_id": "def456",
  "perplexity": 3.31,
  "score": 0.72,
  "weight": 0.10,
  "skipped": false,
  "skip_reason": null,
  "high_perplexity_flag": false,
  "prompt_type": "chat",
  "scorer_used": "provider_logprobs"
}
⁠Score a response (GPT-2 fallback — no logprobs)
curl -X POST http://localhost:8007/v1/score/perplexity \
  -H "Content-Type: application/json" \
  -d '{
    "trace_id": "xyz789",
    "span_id": "qrs012",
    "response_text": "Paris is the capital of France and a major European city.",
    "completion_tokens": 15,
    "prompt_type": "rag"
  }'
⁠Skipped response (too few tokens)
curl -X POST http://localhost:8007/v1/score/perplexity \
  -H "Content-Type: application/json" \
  -d '{
    "trace_id": "skip1",
    "span_id": "skip2",
    "response_text": "Yes.",
    "completion_tokens": 2,
    "prompt_type": "chat"
  }'
# {"skipped": true, "skip_reason": "completion_tokens_too_few", "weight": 0.0, ...}
⁠Build the image locally
cd packages/python/perplexity

docker build \
  -f build/Dockerfile \
  -t chiefj/perplexity:local \
  .

⁠Run with Docker Compose

cd packages/python/perplexity

docker compose -f deploy/docker/docker-compose.yaml up -d

Stop:

docker compose -f deploy/docker/docker-compose.yaml down

⁠API Reference

Full contract: contracts/openapi/v1.yaml⁠

⁠POST /v1/score/perplexity
FieldTypeRequiredDescription
trace_idstring✅Distributed trace ID
span_idstring✅Parent span ID
response_textstring✅LLM completion text
completion_tokensint✅Token count — < 10 triggers skip
prompt_typeenum✅chat | code | rag | classification
token_logprobsfloat[]❌Provider log-probs (primary path)
finish_reasonstring❌content_filter triggers skip
⁠GET /health

Returns {"status": "ok", "scorer": "<provider_logprobs|gpt2_onnx|unavailable>"}.


⁠Skip Conditions

Conditionskip_reasonweight
completion_tokens < 10completion_tokens_too_few0.00
finish_reason == "content_filter"finish_reason_blocked0.00
No logprobs AND GPT-2 unavailablescorer_unavailable0.00

⁠Baselines & Alerting

prompt_typeExpected perplexityHIGH flag threshold (3 ×)
chat15–35> 105
code8–20> 60
rag12–28> 84
classification6–15> 45

high_perplexity_flag: true indicates the model was likely confused, hallucinating, or output low-quality text.


⁠Composite Weight

Statew_perplexityscore contribution
perplexity available0.101/log(perplexity) → normalized to [0, 1]
perplexity skipped0.00other scorer weights renormalized externally

⁠Environment Variables

VariableDefaultDescription
GPT2_MODEL_PATHgpt2HuggingFace model ID or local path for GPT-2 ONNX
SKIP_CONSOLE_EXPORTERfalseSuppress OTel console span output
SKIP_OTLP_EXPORTERtrueDisable OTLP gRPC/HTTP exporter
OTEL_EXPORTER_OTLP_ENDPOINThttp://localhost:4317OTLP collector endpoint
DEPLOYMENT_ENVdevOTel resource deployment.env attribute

Copy .env.example to .env to configure locally.


⁠CI / CD

The pipeline (perplexity-ci.yml) triggers only when files under packages/python/perplexity/ change and the target branch is main:

EventJobs triggered
Pull request → main (perplexity path)test (Python 3.11 + 3.12)
Push/merge → main (perplexity path)test → build-and-push
⁠GitHub Secrets required

Go to Settings → Secrets → Actions and add:

Secret nameValue
DOCKERHUB_USERNAMEchiefj
DOCKERHUB_TOKENyour Docker Hub access token
⁠Docker Hub tags published on merge to main
chiefj/perplexity:latest
chiefj/perplexity:stable
chiefj/perplexity:v<version>

⁠Algorithm

Primary path (provider logprobs):
  perplexity = exp( -1/N × Σ token_logprobs )

Fallback path (GPT-2 124M ONNX, CPU):
  perplexity = exp( cross_entropy_loss )   # ~25ms / 200 tokens

Normalized score:
  contribution = 1 / log(perplexity)
  score        = clamp((contribution - low) / (high - low), 0, 1)

Tag summary

Content type

Image

Digest

sha256:1790fab76…

Size

109.4 MB

Last updated

4 months ago

docker pull chiefj/perplexity