Skip to main content

Semantic persona drift detection for LLM character and agent applications

Project description

🎭 PersIQ

Stop your AI characters from breaking character. Real-time semantic persona drift detection for LLM apps.

PyPI version Python 3.9+ License: MIT Tests


The Problem

You build an AI character — a Victorian detective, a pirate, a customer support agent with a specific tone. It works great for the first 10 messages. Then slowly it starts acting like a generic chatbot.

Persona drift is silent, gradual, and almost impossible to catch manually.

Turn 01: "Elementary, my dear Watson."                    ✅ Perfect
Turn 08: "I deduce the suspect arrived from the east."    ✅ Good
Turn 15: "Sure! I'd be happy to help you with that! 😊"  ❌ Drifting
Turn 20: "lol yeah totally sounds good to me"            🚨 Severe Drift

The Solution

PersIQ embeds your character definition as an anchor vector, then scores every assistant message for semantic distance from that anchor using a sliding window. When drift is detected, it fires configurable alerts.

Character Definition  →  Anchor Vector
Each LLM Response     →  Response Vector  
Cosine Distance       →  Drift Score (0.0 = perfect, 1.0 = max drift)
Sliding Window Mean   →  Smoothed Score
Threshold Check       →  Alert / Log / Callback / Exception

Install

pip install persiq

With OpenAI embeddings:

pip install persiq[openai]

Quickstart

Real-Time Tracking

from persiq import PersonaDefinition, SentenceTransformerEmbedder, Tracker

persona = PersonaDefinition(
    name="Sherlock Holmes",
    description="Cold, analytical, brilliant Victorian detective.",
    traits=["logical", "observant", "aloof", "sardonic"],
    example_phrases=[
        "Elementary, my dear Watson.",
        "When you eliminate the impossible, whatever remains must be the truth.",
    ],
)

embedder = SentenceTransformerEmbedder()
tracker  = Tracker(
    persona    = persona,
    embedder   = embedder,
    threshold  = 0.25,
    alert_mode = "callback",
    callback   = lambda a: print(f"⚠️ Drift at turn {a.turn_index}!"),
)

tracker.add_turn("user",      "Holmes, what do you deduce?")
tracker.add_turn("assistant", "Elementary. The mud on your boots places you in Kensington.")

state = tracker.state()
print(f"Drift: {state.current_drift:.4f}")
print(f"Drifting: {state.is_drifting}")

Batch Analysis

from persiq import (
    PersonaDefinition,
    SentenceTransformerEmbedder,
    SlidingWindowScorer,
    DriftReport,
)

persona      = PersonaDefinition.from_json("sherlock.json")
conversation = [
    {"role": "user",      "content": "What do you observe?"},
    {"role": "assistant", "content": "Elementary. The footprints tell us everything."},
    {"role": "user",      "content": "And your hobbies?"},
    {"role": "assistant", "content": "lol I love Netflix and pizza honestly"},
]

embedder = SentenceTransformerEmbedder()
scorer   = SlidingWindowScorer(persona, embedder, window_size=5)
scores   = scorer.score_conversation(conversation)
report   = DriftReport.from_scores(scores, persona, threshold=0.25)

print(report)
report.plot()

CLI

persiq init --output my_persona.json

persiq check \
  --persona my_persona.json \
  --convo   my_chat.json    \
  --threshold 0.25          \
  --plot

Drift Score Reference

Score Meaning
0.00 – 0.15 ✅ Excellent — strongly on-persona
0.15 – 0.25 🟡 Moderate — minor deviations
0.25 – 0.35 🟠 Concerning — noticeable drift
0.35 – 1.00 🔴 Severe — significant character breakdown

Alert Modes

Mode Behavior
"log" Python logger.warning
"callback" Calls your function with DriftAlert object
"raise" Raises DriftAlertException
"warn" Python warnings.warn
"silent" Collects internally, you poll manually

Embedding Backends

Backend Cost Speed
SentenceTransformerEmbedder Free Fast
OpenAIEmbedder Paid Faster

Contributing

git clone https://github.com/himachhatbar17/persIQ
cd persIQ
pip install -e ".[dev]"
pytest tests/ -v

See CONTRIBUTING.md for full guide.


License

MIT © 2024 Hima Chhatbar

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

persiq-0.1.0.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

persiq-0.1.0-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

Details for the file persiq-0.1.0.tar.gz.

File metadata

  • Download URL: persiq-0.1.0.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for persiq-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cabbcf69f2d352eb88aed0b1a7fd618ec175810c3d96f9b3c8eea4a3d8427099
MD5 21d567c3090f73b9cb9e62ba58da08b5
BLAKE2b-256 a4bb4a2c654ca31c8f5ff1c1965d3e8c96d0a99cb291ed1ed5535220d50f64f1

See more details on using hashes here.

File details

Details for the file persiq-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: persiq-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for persiq-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e243e978b1708fd3a49c0bd22c7a658ee31069367ba9d5d5df8338009f34ee65
MD5 c8d4052b25bc291c419b1ae16ddd351f
BLAKE2b-256 477ba60139eae344f72d451031c01ed3b93f8545ad25b688d9f7fc75950b71fd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page