Three AI Agents I Run in Production — and the Pattern Behind Them
Three AI agents I run in production — a natural-language SQL agent, a markdown knowledge assistant, and the agent on this site — and the grounding, safety, and cost decisions behind each.
Most “AI agent” content is a demo: a slick recording, a single happy path, no error handling, no cost ceiling, no plan for when the model is wrong. This isn’t that. Below are three AI-agent systems I run in production — every day, on real data, with real safety rails. Each one replaces work that a person used to do by hand.
The point isn’t “look, AI.” The point is the engineering pattern that turns a model into a system you can actually depend on: ground it in your data, bound what it’s allowed to do, fail gracefully, and keep it cheap.
The three systems
| System | Replaces | Interface | Stack |
|---|---|---|---|
| sql-agent | ”Hey, can you pull this report?” requests to a developer | CLI + Telegram | TypeScript, SQL Database, OpenRouter |
| md-agent | Digging through scattered docs for an answer | Telegram | TypeScript, SQLite FTS5, OpenRouter |
| /api/ai (this site) | Generic “ask about my work” emails | Web (server-side) | Cloudflare Workers AI |
1. sql-agent — natural language to read-only SQL
The problem. Business data lives in a SQL database. The people who need answers — owners, analysts, accountants — don’t write SQL. So every question becomes a ticket: “How many orders came from repeat customers last month?” A developer stops what they’re doing, writes a SELECT, and pastes back a table. It’s repetitive, slow, and blocks both sides.
What it does. sql-agent takes a question in plain English or Russian, generates a read-only SELECT, runs it against the database, and returns the rows — plus an optional plain-language summary.
"How many orders from repeat customers last month?"
↓ (LLM: schema-aware SELECT generation)
SELECT count(*) FROM orders WHERE ...
↓ (read-only execution + row cap)
rows → "412 orders, 38% from repeat customers"
The hard part isn’t the SQL — it’s the safety. A natural-language database agent that can write arbitrary queries is a liability. The decisions that made it safe enough to run unattended:
- Read-only by construction. The agent only ever produces
SELECT. Writes and schema changes are refused before execution. - Query logging. Every generated query is logged with the original question, so anything questionable is auditable after the fact.
- Row caps and timeouts. A generated query that scans 40M rows can’t take the database down — results are capped and aborted.
- The model is swappable; the safety isn’t. It runs on OpenRouter (Claude Sonnet 4 by default, GLM as a fallback), but the read-only guard lives in my code, not the model’s goodwill.
Business analog. This is exactly the system a Shopify store owner or an operations lead needs: ask a question in your own words, get a number, never wait on a developer for a routine report again.
2. md-agent — an LLM grounded in a markdown knowledge base
The problem. Knowledge gets scattered — meeting notes, process docs, decisions, runbooks — across dozens of markdown files. Keyword search finds words, not answers. So people either re-ask questions that were already answered, or give up and make decisions without the context.
What it does. md-agent is a Telegram bot that answers questions grounded in your markdown knowledge base: it retrieves the relevant chunks first (SQLite FTS5 full-text search), then hands them to the LLM to answer. It’s retrieve-then-answer, not free generation.
question → FTS5 retrieve top-k MD chunks → LLM answers FROM those chunks
↓
"no relevant chunks" → honest "I don't know"
The decisions that made it production-grade:
- Grounded, not hallucinated. The answer is constrained to retrieved context. If nothing relevant is in the KB, it says so instead of inventing — the single most important property of a trustworthy knowledge agent.
- Lean hosting. It runs on a 1 CPU / 2 GB RAM VPS. A knowledge-base assistant doesn’t need a GPU or a big server.
- Free-tier models. The default is a free OpenRouter endpoint (DeepSeek V3). The architecture doesn’t depend on any one model or any one bill.
- Git safety net. The knowledge base is version-controlled, so edits are recoverable.
Business analog. Internal knowledge search and support deflection — the same pattern that stops a support team from answering the same five questions forever.
3. The agent on this site
This site has its own small agent at /api/ai. It’s the lightest of the three, and it exists to show the pattern at minimal cost:
- Server-side only. No API keys in the browser. The browser calls a route; the route calls the model.
- Bounded input. Prompts are capped; payloads are size-limited.
- Rate-limited. A per-IP sliding window stops abuse.
- Graceful degradation. If the model binding is absent (e.g. a static deploy), it says so instead of crashing.
- Cheap model. It runs on a small Workers AI model (Llama 3.1 8B) — not because small models are better, but because a portfolio assistant doesn’t need a frontier model, and cost discipline is part of the point.
The pattern behind all three
Strip away the differences and the same five decisions appear in every production agent I ship:
- Ground it. Answers come from your data (retrieved SQL schema, retrieved docs, a curated system prompt) — not the model’s imagination.
- Bound it. Read-only. Capped rows. Capped tokens. Refusal of out-of-scope requests.
- Log and audit. Every action is traceable after the fact.
- Fail gracefully. Model down, binding missing, abusive input — the system degrades, it doesn’t crash or leak internals.
- Keep it cheap. Right-size the model to the job. A knowledge bot doesn’t need a $20/M-token model; a hard reasoning task shouldn’t run on the cheapest one.
A demo skips all five. Production requires all five.
Where this shows up across my work
These aren’t isolated experiments. The same patterns run through everything I build — ak-ops (the live operations platform behind demo.kamensky.dev), ak-blog (this site), and the client case studies. Wherever there’s repetitive, data-bound work, a grounded agent with bounded scope is usually the right tool.
Pros & cons of building vs. buying a SaaS
Build when the workflow is core, the data is sensitive, or the SaaS bill scales with usage in a painful way (the classic Zapier trap). Buy when it’s a commodity integration you’ll never differentiate on.
The three agents above are all “build” — because they touch real business data, the safety model matters, and the per-request cost of a SaaS equivalent adds up fast.
TL;DR
| System | What it proves | Key safety decision |
|---|---|---|
| sql-agent | NL → SQL in production | Read-only by construction |
| md-agent | Grounded KB Q&A on a 2 GB VPS | Retrieve-then-answer; honest “I don’t know” |
| /api/ai | Minimal-cost server-side agent | Bounded input + graceful degradation |
An AI agent is a system around a model, not the model itself. The model is the easy part. The grounding, the safety rails, the cost ceiling, and the graceful failure — that’s the work, and that’s what makes it reliable enough to run every day.
If you have a repetitive, data-bound workflow that a person handles by hand today, that’s exactly where a production agent fits — tell me about it.