Kevin
Zou

17, San Francisco, CA

ch2 · flexor carpi radialis · surface emg · 250 hz
Ditto AI

Product Lead & Member of Technical Staff at Ditto, a $10M venture-backed AI matchmaker that lives in your messages. Under the product, it's a data problem: every conversation and every choice is behavioral signal, and the hard part is turning that messy, subjective data into calibrated decisions about who to match. I own that pipeline end to end: capturing the signal, banking rich per-user feature vectors, and building the models that score and decide on top of them, plus the messaging backend that delivers the agent.

Recognition

Selected for Y Combinator's in-person AI Startup School at Chase Center, SF.

Y Combinator AI Startup School admit-one ticket, Kevin Zou

Invited to YC's Startup Internship Expo for Summer 2027.

YC Startup Internship Expo admit-one ticket, Kevin Zou
Selected work
[01]

Electromyography

surface emg · hardware + ml · stanford research
EMG snap electrodes in hand beside the OpenBCI board and a laptop running the multi-channel signal GUI
the rig: electrodes → OpenBCI → live signal
  • EMG silent-speech research at Stanford: a wearable that reads muscle activity off the skin and decodes words said silently. Electrodes → signal → decoder, on a 16-channel OpenBCI Cyton+Daisy rig, with an MCP server so an LLM agent can operate the hardware itself and a real-time labeled-recording pipeline behind a from-scratch decoder.

Machine Learning & Data Modeling

  • Built the decoder's modeling stack: EMG-specific data augmentation (channel dropout, time-warping, amplitude jitter, electrode-shift simulation) and vector-quantized tokenization (learned codebooks over the raw signal, HuBERT-style) that turns continuous EMG into discrete units a sequence model can decode.
  • Held to a strict leak-free protocol: VQ / SSL tokenization only ties the strong raw-feature baseline rather than beating it, so the real ceiling is sensing, not modeling (125 Hz sits below this signal's Nyquist floor), and the next gain comes from the sensor.
  • Current bet: noisy-channel decoding with an LLM prior. Partial EMG evidence × P(words | context) → open-vocabulary intent, not a fixed menu of gestures.
Bar chart of VQ codebook size (4, 8, 16) versus gesture decode accuracy (78.2%, 94.7%, 97.5%), with a dashed raw-feature baseline the largest codebook only ties
VQ codebook size vs. decode accuracy · richer codebooks recover the raw baseline (dashed), they don't beat it · my OpenBCI runs
[02]

Benchmark · Meta emg2qwerty

surface-emg decoding · leak-free eval
  • Benchmarked the from-scratch decoder against Meta's emg2qwerty, their open surface-EMG decoding baseline, on a strict leak-free, subject-held-out split, with no train/test contamination, so the comparison holds up rather than being cherry-picked.
  • It outperforms the baseline, reaching 95% on a working command set.
  • The edge is the modeling stack, not scale: EMG-specific augmentation, VQ tokenization, and eval discipline on a narrow, high-value task.
[03]

Preference Engine · Attractiveness Scoring

ditto research · multimodal LLM judge · face + embedding pipeline
  • A matchmaking engine needs a calibrated per-user scalar for physical attractiveness: subjective, fine-grained, and only comparable within a gender×ethnicity bucket (8 supported). Gold labels come from a per-user Elo fit on 6,231 human pairwise comparisons, with 887 men scored at ≥8 duels each.
  • Naive scoring fails: the deployed holistic rubric correlates with human Elo at only ρ = 0.315. A multimodal LLM asked for an absolute rating collapses onto a few round numbers.
  • The fix is anchored pointwise scoring: show the judge six human-calibrated anchor faces from the same bucket, then ask for one rating on the gold Elo scale. That reaches ρ = 0.62–0.64, beating every compare-then-aggregate scheme (adaptive Bradley–Terry tops out at 0.50) at ~1/17 the model calls.
  • Blending in an identity-embedding Bradley–Terry head, trained on raw duels over 512-d ArcFace / AuraFace embeddings, lifts correlation to ρ = 0.698 on a 523-user held-out set: the embeddings carry within-bucket signal the language pathway can't verbalize.
  • We hit a hard perceptual resolution ceiling: the judge emits only 112 distinct scores across 538 users, and on near-equal faces it agrees with humans at 53.6% (chance). On a subjective attribute, perception caps the judge, not prompting.
  • My part, the face + embedding pipeline underneath: SCRFD / AuraFace detection, owner-isolation blurring so only the right face in a group photo is scored (947 of 1,013 cohort photos retain a usable face), face-gating, and the identity-embedding infra the Bradley–Terry head runs on. Bias handled as a constraint: per-bucket calibration, no cross-bucket comparison, and equity gaps tracked where the data is too sparse to be decision-grade.

research at Ditto

[04]

Messaging Infrastructure

unified send API · channel adapters · backend at scale
  • The product is messages in and messages out, so the backend is a messaging system first. One unified send API sits in front of every channel (iMessage, Instagram DMs), so product code calls a single interface and never talks to a network directly.
  • Inbound. Platform webhooks hit a normalizer that flattens each provider's payload into one internal event shape, resolves it to a conversation, and hands it to the agent, with idempotency keys so a retried or duplicated webhook never double-fires.
  • Outbound routing. A routing layer spreads sends across a pool of senders with per-sender queues, capacity scoring, rate-limit tracking, and health checks, so traffic flows to the healthiest sender and one degraded path is isolated instead of taking the funnel down with it.
  • Real endpoints at scale. Delivery runs on a managed fleet of phone numbers / SIMs across Mac-based workers and modems, each with its own session, health, and rate-limit isolation, so the agent sends from real endpoints across iMessage and SMS without any single number becoming a bottleneck or a point of failure.
  • Delivery. Retries with backoff, durable session/conversation state, and worker pools; replies stream out as multiple |||-delimited bubbles, first bubble in a few hundred ms, so a thread reads like a person typing, not a wall of text.
  • Correctness under concurrency. A wrong conversation-to-identity mapping would route one person's message to another, so identity resolution and state transitions run atomically: a single DB transaction, no unsafe fallbacks.
Stack
LanguagesTypeScript · Python · SQL
BackendNode.js · Prisma · Postgres · MongoDB · webhook & queue infrastructure
FrontendReact · Tailwind
ML / DataPyTorch · NumPy · ArcFace / AuraFace embeddings
Othercellular / SIM / eUICC · EMG
Contact