5 min readAI
How I built a 16-agent AI newsroom in production: architecture and failure modes
The architecture behind Unlok Insights: 16 agents and 9 workflows writing market briefs, with editors in the loop, versioned prompts and costs per feature.
Unlok Insights writes plain-English market briefs for retail investors every trading day. When I left, sixteen agents in nine workflows were doing the writing. What makes it work in production isn't the agents. It's what surrounds them: fresh, checked sources, an editor who can change or pull any piece, prompts versioned like code, and the cost of every model call tracked by feature.
I was the project lead and primary engineer on it at Kupa, the company behind Unlok. This post stays at the level of the public case study: the shape of the system and the lessons, not Kupa's prompts or numbers.
What the newsroom writes
- Pre-market and post-market briefs: what moved, why, and what to watch.
- Top movers, with the news that caused each move.
- Short 'What happened' explainers for the day's biggest moves.
- Earnings and events previews, and the stories behind them.
The architecture, step by step
- ScheduleRuns start at set times around the US trading day, from the exchange calendar, so nothing runs on a market holiday or writes about a session that never happened.
- GatherMarket data and news from the last day only, ranked, with the full article fetched rather than a headline. Symbols that are hard to report on reliably, like OTC listings and warrants, are left out before any model sees them.
- WriteOne agent call per item, run in parallel, so a slow or failed item doesn't hold up the rest of the brief.
- CheckClaims are checked against the sources the agent was given. A move with no clear cause gets no invented one: it's left out.
- ReviewEverything lands in a newsroom-style CMS where editors can edit, regenerate or archive any piece before or after it goes out.
- MeasureEvery model call is logged with the feature it served, the model, the tokens and the cost.
Workflows with agents inside, not agents all the way down
An agent decides its own next step. A workflow has fixed steps. Most of the newsroom is workflows, with agents inside the steps that need judgement, like choosing which story explains a move, and writing. Fixed steps are easier to test, retry and budget for, and when something goes wrong you know which step it was.
The agents run on Mastra, a TypeScript framework, with models on Azure OpenAI and AWS Bedrock. Before settling on it I compared LangChain, LangGraph, the OpenAI tooling, n8n and AgentScope. Long-running jobs elsewhere in the company run on Temporal, which I took from a proof of concept to company-wide.
Failure modes I had to design for
- Old news presented as newA model has no sense of today unless you give it one. So every run got the current date and time, and only sources from the window it was writing about.
- A confident cause that isn’t in the sourcesThe most dangerous error in financial writing. The check step compares claims with the sources, and an editor sees the result.
- The same story twiceSeveral sources report the same event in different words. Without deduplication, a brief repeats itself, or a thread fills with near-copies.
- Runs nobody readsRefreshing everything on a timer spends money on content no one opens. Moving refreshes closer to when people actually look cut the waste.
- A prompt change that breaks something elsePrompts are code. A small wording change can shift tone, length or facts across a whole feature, so prompt changes go through the same review as code changes.
Guardrails and cost tracking
- Prompts live in the CMS, with versioned migrations that a person promotes from development to production.
- A prompt playground runs a draft prompt on real inputs before it ships, next to the current one.
- The model is chosen per feature, not once for the whole system.
- Editors can regenerate or archive any piece, and that is part of the design, not an emergency button.
- Every model call is tagged with its feature, so cost can be read per feature, per model and per day.
The cost part is less work than it sounds. A sketch of the idea, not the production code:
type Usage = { inputTokens: number; outputTokens: number };
/** Wraps a model call so every call is recorded against the feature it served. */
export async function tracked<T>(
feature: string,
model: string,
call: () => Promise<{ result: T; usage: Usage }>,
): Promise<T> {
const started = Date.now();
const { result, usage } = await call();
await db.insert(aiCalls).values({
feature, // "movers.what-happened", "brief.pre-market", ...
model,
inputTokens: usage.inputTokens,
outputTokens: usage.outputTokens,
ms: Date.now() - started,
});
return result;
}Price the tokens from the provider's price list when you read the table, not when you write it, so a price change doesn't rewrite history. You won't find cost figures here: they belong to Kupa. What I can say is that having cost by feature from the first week is what made it possible to decide which features earned their model calls.
What I'd tell a team starting out
- Start with one workflow and one feature, and run it for real before adding agents.
- Give the model less to decide. Every decision you can make in code is one the model can’t get wrong.
- Put a person where a mistake would be public or costly. Here is how I design those gates.
- Track cost per feature from the first call.
- Version prompts like code, with a way to compare a new one with the old one on the same inputs.
If your team has repeat work that could run like this, this is how I plan and build AI automation.
Questions people ask
- How many AI agents does a business need?
- Usually fewer than it thinks. Most reliable systems are fixed workflows with an agent inside the few steps that need judgement. Start with one workflow, measure it, then add.
- Which framework do you use for AI agents in production?
- At Kupa I used Mastra for agents and workflows, and Temporal for long-running jobs. I compared LangChain, LangGraph, the OpenAI tooling, n8n and AgentScope first. The right choice depends on your stack and how long your jobs run.
- How do you stop an AI from making things up in financial content?
- Give it only fresh, relevant sources, check its claims against them, leave out what has no source, and keep an editor who can change or pull any piece. No single step is enough on its own.
- How do you track LLM costs per feature?
- Wrap every model call so it records the feature, the model and the tokens used, then price the tokens when you report. It takes a day to set up and answers the question every later decision depends on.