An LLM will not read your logs for you. It cannot, at least not the way vendors imply: a single busy host emits millions of lines a day, and no model context window or API budget survives that volume. The teams getting value from large language models in log analysis are the ones who reduce the data with deterministic tooling first, then point the model at the language-heavy remainder.
Here is the split that works, the tools to use, and where it breaks.
Reduce Before You Reason
The first mistake is treating the model as the parser. It is the last step, not the first. Before an LLM sees anything, collapse the raw stream into a small set of representatives.
For high-volume structured-ish logs (auth, web, firewall), mine templates with Drain3. It groups lines by their fixed skeleton and treats the variable parts as parameters, with no training required. Millions of lines become a few hundred templates.
from drain3 import TemplateMiner
miner = TemplateMiner()
with open("/var/log/auth.log") as f:
for line in f:
miner.add_log_message(line.strip())
# A few hundred templates instead of millions of raw lines
for cluster in sorted(miner.drain.clusters, key=lambda c: c.size, reverse=True):
print(cluster.size, cluster.get_template())
Now you have something a model can actually work with: send the templates, their counts, and a few example lines, and ask the model to label each cluster, flag which ones are security-relevant, and group them by activity. You are spending tokens on a few hundred patterns, not tens of millions of events.
Force Structured Output on the Messy Tail
Drain3 and Grok patterns handle the regular logs cheaply. The long tail is where the model earns its keep: free-text error messages, vendor appliance logs with no schema, application exceptions that never look the same twice.
Do not ask for prose back. Force a schema, the same way you would for any other enrichment callout. On the Anthropic Messages API, tool use doubles as a structured-output contract:
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
extract_tool = {
"name": "extract_log_fields",
"description": "Extract normalized fields from a single unstructured log line.",
"input_schema": {
"type": "object",
"properties": {
"event_type": {"type": "string"},
"src_ip": {"type": "string"},
"username": {"type": "string"},
"outcome": {"type": "string", "enum": ["success", "failure", "unknown"]},
"severity": {"type": "string", "enum": ["info", "low", "medium", "high"]},
},
"required": ["event_type", "outcome"],
},
}
resp = client.messages.create(
model="claude-haiku-4-5-20251001", # cheap model for high-volume work
max_tokens=512,
tools=[extract_tool],
tool_choice={"type": "tool", "name": "extract_log_fields"},
system="Extract only fields present in the line. Do not invent values.",
messages=[{"role": "user", "content": raw_line}],
)
fields = next(b.input for b in resp.content if b.type == "tool_use")
The enum constraints stop the model from inventing a new severity, and you validate every returned src_ip against an IPv4/IPv6 format before it enters your store. Route this high-volume extraction to a cheap model like Claude Haiku 4.5 (claude-haiku-4-5-20251001); save the expensive models for the investigations a human already cares about. The same routing-by-severity logic applies here as in a full SOC integration.
Cluster With Embeddings, Not Prompts
Two log lines can describe the same event with completely different wording. Embeddings catch that where string matching does not. Embed each message with a small local sentence-transformer, then cluster the vectors.
from sentence_transformers import SentenceTransformer
from sklearn.cluster import DBSCAN
model = SentenceTransformer("all-MiniLM-L6-v2") # runs locally, no data leaves
vectors = model.encode(log_messages, normalize_embeddings=True)
labels = DBSCAN(eps=0.25, min_samples=5, metric="cosine").fit_predict(vectors)
# label == -1 marks the outliers worth an analyst's attention
Run the embedding model locally with sentence-transformers so you are not paying per token or exporting logs to analyze them. Store the vectors in pgvector and you get “show me logs similar to this one” during an investigation. The -1 outliers from DBSCAN are the rare events; hand only those to the LLM for explanation. This is the same feature-then-model discipline covered in feature engineering for security data.
Draft Queries, Do Not Run Them
Turning an analyst’s plain-English intent into first-draft Splunk SPL, KQL, or a Sigma rule is a real win. Generating a query and running it unattended is not. Models invent field names that do not exist in your schema, botch time-window boundaries, and write queries that look correct while matching the wrong events.
Give the model your actual field list so it stops guessing, and treat the output like generated code: review it, run it against a bounded time range, and sanity-check the hit count before it becomes a scheduled detection. A generated query that returns zero results or ten million both mean the same thing: read it before you trust it. This is the reverse of the SIEM-to-Jupyter workflow, where the analyst writes the logic and the notebook keeps it reproducible.
Where It Breaks
Plan for these from the first prototype:
- Aggregation belongs in SQL. Counting failed logins per user across a week is a
GROUP BY, not a prompt. Models cannot count reliably at scale and will confidently give you a wrong total. - Log fields are attacker-controlled. A User-Agent, a filename, an HTTP path can carry an indirect prompt injection (OWASP LLM01, MITRE ATLAS AML.T0054). Keep the model read-only and gate everything it returns.
- Hallucinated fields reach your store. A model may return a plausible
src_ipthat was never in the line. Validate format and cross-check against the raw event before writing anything. - Non-determinism defeats detection. The same line can parse two ways on two runs. Anything feeding a detection rule needs a deterministic path or a validation gate, not a raw model output.
- Cost scales with volume. Send representatives, not raw streams. If your token bill scales linearly with log volume, the architecture is wrong.
Where to Learn This
The hard part is not prompting. It is knowing which step is deterministic (templating, aggregation, format validation) and which is a language task (labeling clusters, explaining an anomaly, drafting a query), then wiring them so the model never sits where a wrong answer causes damage. Teams that get value here already understood their log schemas and detection logic; the model amplifies that engineering, it does not supply it.
GTK Cyber’s Applied Data Science and AI for Cybersecurity course is built for security practitioners who want to connect these pieces on real data, with the judgment to keep the model where it helps. The generative AI in security operations post covers the same split for the broader SOC.