Toplu ve Geçmişe Dönük Sinyal İşleme: occurred_at ile Backfill

2026-08-25

Bir müşteriyle ilgili elinizde iki yıllık görüşme geçmişi var ve bunu HuMetric'e tek seferde yüklemek istiyorsunuz. Bu bir backfill senaryosu: sinyaller sisteme bugün geliyor ama her biri farklı bir geçmiş tarihte yaşandı. Bu yazı, bunu doğru yapmak için bilmeniz gereken tek alanı (occurred_at) ve o alanın okuma tarafındaki iki uç noktayı nasıl tutarlı tuttuğunu, gerçek curl örnekleriyle anlatıyor.

1. occurred_at: sinyalin kendi tarihi

POST /v1/signals gövdesi şu alanları kabul eder:

{
  "entity_id": "musteri-demo-118",
  "entity_type": "musteri",
  "text": "...üst yönetime bağlanmazsam sosyal medyada şikayet ederim...",
  "occurred_at": "2024-09-15T14:32:00Z"
}

occurred_at boş bırakılırsa (canlı/gerçek zamanlı sinyaller için normal kullanım budur) sistem isteğin geldiği anı kullanır. Ama doldurulduğunda, bu tarih sinyalin gerçek yaşandığı an olarak kaydedilir — API'ye ulaştığı an değil. Backfill'de her zaman doldurun:

curl -X POST https://api.gethumetric.com/v1/signals \
  -H "Authorization: Bearer $HUMETRIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_id": "musteri-demo-118",
    "entity_type": "musteri",
    "text": "...üst yönetime bağlanmazsam sosyal medyada şikayet ederim...",
    "occurred_at": "2024-09-15T14:32:00Z"
  }'

Yanıt hemen döner, işleme arka planda devam eder:

{ "signal_id": "sig_8fa2c1", "status": "queued" }

İşlenip işlenmediğini GET /v1/signals/{signal_id} ile sorgulayabilirsiniz; status alanı queuedcompleted (ya da failed) olur. Bir backfill'i sıraya çok sayıda sinyalle doldururken sinyalleri hangi sırada gönderdiğiniz önemli değildir — her biri kendi occurred_at'i ile damgalanır, sıralama motorun içinde önemsizleşir.

2. Aşınma neye göre hesaplanır

Her metrik iki sayı taşır: kaydedilen ham confidence ve okuma anında hesaplanan effective_confidence. İkincisi zamanla düşer:

effective_confidence = confidence * exp(-λ * yaş_gün)
λ = ln(2) / 365   # güvenin yarı ömrü 1 yıl

yaş_gün, bugün ile occurred_at arasındaki farktir — sinyalin sisteme yüklendiği tarih değil. Yukarıdaki örnekte occurred_at 2024-09-15, bugün 2026-08-25 ise yaş ~710 gün eder ve eskalasyon_riski metriği için ham confidence 0.40 iken effective_confidence0.2605 çıkar. Bu formül her okumada yeniden hesaplanır; kayıtlı ham değer hiç değişmez, bu yüzden denetlenebilir kalır.

3. İki uç nokta, aynı sayı

Bir metriği iki yerden okuyabilirsiniz:

curl https://api.gethumetric.com/v1/entities/musteri-demo-118/metrics \
  -H "Authorization: Bearer $HUMETRIC_API_KEY"
{
  "entity_id": "musteri-demo-118",
  "metrics": [
    {
      "metric_key": "eskalasyon_riski",
      "value": 0.72,
      "confidence": 0.40,
      "effective_confidence": 0.2605,
      "source_count": 1,
      "last_updated": "2024-09-15T14:32:00Z"
    }
  ],
  "metric_count": 1
}
curl https://api.gethumetric.com/v1/entities/musteri-demo-118/metrics/eskalasyon_riski/history \
  -H "Authorization: Bearer $HUMETRIC_API_KEY"
{
  "entity_id": "musteri-demo-118",
  "metric_key": "eskalasyon_riski",
  "points": [
    {
      "recorded_at": "2024-09-15T14:32:00Z",
      "value": 0.72,
      "confidence": 0.40,
      "effective_confidence": 0.2605,
      "source_count": 1
    }
  ],
  "total": 1
}

Dikkat edin: last_updated (güncel metrik ucunda) ile recorded_at (geçmiş ucunda) aynı tarih, ve iki uçtaki effective_confidence aynı sayı. Bu tutarlılık kazara değil — last_updated, o metriğe katkıda bulunan en yeni gerçek gözlemin occurred_at'ini izler, sinyalin sisteme yazıldığı anı değil. Karışık sırayla gelen bir backfill'de bile bu değer geriye gitmez: metriğe daha eski bir occurred_at'li bir sinyal sonradan işlense bile, last_updated en yeni gerçek gözlemde kalır.

4. Uçtan uca bir backfill döngüsü

Elinizde kronolojik olmayan sırada bir transkript arşivi varsa, tipik bir backfill scripti şuna benzer:

import httpx

BASE = "https://api.gethumetric.com/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

for call in call_history:  # herhangi bir sırada olabilir
    httpx.post(f"{BASE}/signals", headers=HEADERS, json={
        "entity_id": call["customer_id"],
        "entity_type": "musteri",
        "text": call["transcript"],
        "occurred_at": call["happened_at"].isoformat(),
    })

Her istek 202 ile hemen döner; sinyaller arka planda sırayla işlenir. Son adım, tüm arşiv işlendikten sonra GET /v1/entities/{id}/metrics ile güncel durumu okumak — artık GET .../history'nin en son noktasıyla birebir aynı effective_confidence'ı görürsünüz.

Referans: kullanılan pack

Yukarıdaki örneklerde eskalasyon_riski dahil yedi metriği tanımlayan çağrı merkezi paketi kullanıldı. Kendi ortamınızda denemek isterseniz:

entity_type: musteri
label: "Çağrı Merkezi Müşterisi"
version: 3
required_fields:
  - key: kanal
    type: str
    label: "Kanal"
metrics:
  - key: memnuniyet
    label: "Memnuniyet"
    type: float
    default_confidence: 0.5
    prompt: "Müşterinin görüşme sırasındaki genel memnuniyeti: ton, şikâyet
             yoğunluğu, teşekkür/övgü ifadeleri. YÜKSEK değer = memnun
             müşteri."
  - key: cozum_basarisi
    label: "İlk Temasta Çözüm"
    type: float
    default_confidence: 0.5
    prompt: "Talebin bu görüşme/mesajlaşma içinde fiilen çözülüp
             çözülmediği: yönlendirme, tekrar arama sözü, açık kalan konu.
             YÜKSEK değer = sorun bu temasta kapandı."
  - key: eskalasyon_riski
    label: "Eskalasyon Riski"
    type: float
    default_confidence: 0.4
    prompt: "Müşterinin üst birime çıkma, iptal/iade talep etme, hukuki veya
             sosyal medya tehdidi savurma eğilimi. YÜKSEK değer = risk
             yüksek (kötü durum, diğer metriklerle ters yönlü)."
  - key: niyet_netligi
    label: "Niyet Netliği"
    type: float
    default_confidence: 0.5
    prompt: "Müşterinin talebini ne kadar net ifade ettiği: tek bir açık
             istek mi, yoksa dağınık/çelişkili birden fazla konu mu.
             YÜKSEK değer = niyet net."
  - key: tekrar_temas_egilimi
    label: "Tekrar Temas Eğilimi"
    type: float
    default_confidence: 0.4
    prompt: "Aynı konuda kısa süre içinde tekrar arama/yazma ihtimali:
             yarım kalan işlem, 'yine ararım' ifadesi, verilen sözün
             belirsizliği. YÜKSEK değer = tekrar temas olası (nötr-kötü
             sinyal, düşük operasyonel verimlilik)."
  - key: yanit_hizi_algisi
    label: "Yanıt Hızı Algısı"
    type: float
    default_confidence: 0.4
    prompt: "Müşterinin bekleme/yanıtlanma hızından duyduğu memnuniyet
             algısı: 'hemen açtınız', 'çok beklettiniz', bekleme
             süresinden şikâyet gibi ifadeler. Ölçülmüş bir süre değil,
             müşterinin ALGISIdır. YÜKSEK değer = hızlı yanıtlandığını
             hissetti."
  - key: saglik_aciliyeti
    label: "Sağlık Aciliyeti"
    type: float
    sensitive: true
    requires_consent_scope: saglik_verisi
    default_confidence: 0.4
    prompt: "Müşterinin anlattığı sağlık durumunun ne kadar acil
             önceliklendirme gerektirdiği. YÜKSEK değer = acil. Bu metrik
             KVKK m.6 anlamında özel nitelikli kişisel veriye dayanır;
             rıza yoksa üretilse bile kaydedilmez."
kvkk:
  sensitive_metrics:
    - saglik_aciliyeti
Occurred_at 2024-09-15 olan bir sinyal, okunduğunda 1.00 değil 0.26 güvenle döner — aşınma sinyalin kendi tarihine göre hesaplanır
Önce history ve metrics uçları farklı güven değeri döndürüyordu (0.26 / 1.00); artık ikisi de aynı sayıyı döner