Why I don't ship AI without citations
A client once asked me, watching a demo of AI generation: "how do I know this is true?" Good question, and the only one that matters when you put an LLM in the hands of a salesperson about to send it to a prospect. Fluent, wrong text, signed with the client's company name, isn't a feature. It's a liability.
The problem demos don't show
Generative AI demos are impressive because they show the best case: coherent, well-turned text that sounds informed. What they don't show is the one time in ten when the model claims a company "just raised funding" when nothing of the sort exists in the available data. In B2B, that kind of error goes out under the sender's name and spends their credibility. The problem isn't that LLMs get things wrong (that's expected, it's the nature of the tool), it's that they get things wrong with exactly the same confidence as when they're right. Nothing in the output distinguishes a verified claim from a plausible hallucination.
What I built in Project A
Project A generates outreach sequences: emails and messages aimed at decision-makers, built from real signals (a LinkedIn post, a company news item, a role change). The architecture I put in place treats generation not as a black box but as a three-stage pipeline.
First, generation itself: the model drafts the message using the sources retrieved for that prospect. Then an attribution pass: every sentence in the generated text is checked against the available sources to see whether it can be tied back to one. Finally, display: sourced sentences carry a clickable footnote pointing to the real source, unsourced sentences are visually flagged, and a counter shows something like "1/2 sentences sourced" so the user sees the message's reliability at a glance.
Here's a simplified version of the data shape behind this logic:
type SourceRef = {
url: string
label: string
}
type GroundedSentence = {
text: string
source?: SourceRef
}
function verify(sentences: GroundedSentence[]) {
const sourced = sentences.filter((s) => s.source).length
return { sourced, total: sentences.length }
}
When the user clicks "Regenerate (grounded)", it isn't the same generation with a different seed. It's a constrained generation: the prompt is rewritten to only allow claims directly backed by retrieved sources, even if that means a shorter, more cautious message that is fully verifiable.
The trade-offs, without hiding them
This system has a cost. The attribution pass adds latency: you can't just stream the model's text straight to the screen anymore, you have to verify before showing each sentence's status. There's also a recall versus precision trade-off: an attribution system that's too strict flags correct sentences as unsourced (frustrating), one that's too lenient lets approximations through (dangerous). I chose to lean strict: better a message that admits it's incomplete than one that sounds confident and is wrong.
And there's the case where nothing is sourceable at all: no recent signal, no news, no post. In that case the system doesn't force a creative generation to fill the gap. It says so, and falls back to a more generic message, presented as such rather than disguised as personalization.
What it means for a client
A salesperson sending an AI-generated message is putting their reputation and their company's on the line. Being able to see, at a glance, what's proven and what isn't turns AI from an anxiety-inducing text generator into a working tool whose limits are understood. It's also a matter of legal safety: a false claim about a prospect (a figure, an event) creates liability for whoever sends it. Traceability isn't a nice-to-have, it's a condition for adoption: sales teams only keep using an AI tool long-term if they can trust it without re-reading every line each time.
That's the conviction behind how I integrate AI into the products I build: generation is only useful if it's verifiable. If you have a product where AI needs to produce text that represents your company or your clients, this is exactly the kind of guardrail I build in from the architecture up.