Serve open alert triage models on Chalk GPUs
This demo shows how to run laya-typed-decisions on a Chalk GPU to score security alerts with identity, asset and analyst context. Select an alert and try the feedback controls, then explore the code to see how it works.
Connect an alert’s context to its triage recommendation
The fictional queue pairs risky alerts with similar benign cases so you can inspect what changes the verdict.
Try this experiment · expected results
1Inspect one arriving alert
Select an alert and compare its input record, recommendation, and contributing facts.
Expected: The explanation links the recommendation to the context the model read.
2Compare a counterfactual
Inspect the contribution analysis showing the alert with one fact changed.
Expected: The comparison separates the detection from the contextual facts that affect triage.
Same alert, different context: compare a risky event with its benign twin. Chalk serves the decision model; the actions below are recommendations for this fictional queue.
Halcyon Freight, its people, hosts and alerts are fictional; every risky alert has a benign twin that differs only in context. The triage is real: each alert is decided live by laya-typed-decisions, a 421M-parameter ModernBERT-large model fine-tuned on security, support, invoice and agent-trace decisions, on one L4. Contributions are counterfactual: the same alert re-asked with one fact changed. The queue action is a stated policy over the calibrated probability: contain when the model says so, investigate at 50% or more, monitor from 30%, close below. Everyone sees the same queue, and feedback expires after 15 minutes. These actions are recommendations in a fictional queue; the demo does not contain hosts or close real alerts. Calibration was fitted on the model benchmark’s security training split, so these scores are not validated probabilities for your alert stream.
Built on Chalk
Chalk builds and hosts the GPU service. The example’s application enriches alerts, recalibrates model scores, compares counterfactual inputs and turns analyst feedback into temporary context.
A model ready to use
Deploy the model and its web app together. Chalk provisions the GPU and returns an HTTPS URL.
Deploy from Python
Define the container and its model weights in Python. Later builds can reuse cached image layers.
Model weights ready at startup
Chalk builds the model weights into the container image. New replicas load them from the image without downloading them again.
Keep the queue in one replica
The deployment pins the ScalingGroup to one replica because the example keeps its queue, windowed counters and analyst feedback in process memory.
Run it on your own
You will need uv and a Chalk environment with NVIDIA L4 capacity. Clone the example, log in to Chalk and run the deploy script. Chalk builds the image with the model weights and returns the service URL.
Replace the fictional signal generator and context directories with your alert sources. The example defines the calibration, counterfactuals and triage thresholds; evaluate those choices on your own alerts before using its recommendations.
import laya
agent = laya.load("michaelfeil/laya-typed-decisions", device="cuda")
# The SIEM alert, enriched by the triage service with directory and stream context.
record = {
"alert": {
"rule": "brute_force",
"description": "many failed authentications followed by a success",
"evidence": "46 failed logins for admin r.batra came from Lagos, NG, followed by "
+ "a successful login after an MFA push was approved. Source 102.89.32.10 is "
+ "not a recognised address. No change window was active.",
},
"context": {
"asset_criticality": "crown_jewel",
"change_window_active": False,
"source_on_allowlist": False,
},
"history": {"prior_alerts_90d": 1, "distinct_countries_30d": 1, "logins_30d": 140},
"principal": {"name": "r.batra", "type": "admin", "mfa_enrolled": True},
}
questions = {
"disposition": {
"type": "choice",
"instructions": "How should this security alert be dispositioned?",
"criteria": {
"close_benign": "Expected, explainable activity; close without analyst time.",
"monitor": "Not clearly malicious, but worth watching for recurrence.",
"investigate": "Warrants an analyst opening an investigation.",
"contain": "Contain the host or account immediately.",
},
},
"true_positive": {
"type": "noul", # a statement; the answer is P(true)
"instructions": "This alert reflects genuinely malicious or unauthorised activity.",
},
}
answers = agent.predict(record, questions)["answers"]
answers["disposition"]["choice"] # "investigate"
answers["true_positive"]["noul"] # raw P(malicious); calibrate before thresholdingBuild alert triage on Chalk
Talk to an engineer about serving decision models with the identity, asset and alert context your security workflow needs.