Last quarter, our growth team came to me with a familiar problem: we were leaving money on the table. Our product had clear upgrade paths, but our sales team couldn’t keep up with the sheer volume of users hitting feature limits or showing strong engagement with premium features. They wanted a system that could identify these “upsell-ready” users and trigger personalized outreach, automatically. The buzz around AI agents was loud, so the directive was clear: build something with AI for automating SaaS upsell strategies.
I’ve shipped enough AI agents to know the difference between a demo and a production system. The promise of an autonomous agent identifying high-value users, crafting tailored messages, and even scheduling calls sounds fantastic on a whiteboard. The reality, though, is a messy tangle of data pipelines, opaque LLM behavior, and debugging sessions that make you question your life choices. We weren’t just building a script; we were trying to create a system that could directly impact revenue, which meant the stakes were high for silent failures or costly loops.
The Data Foundation: Knowing Who to Talk To
Before any AI agent can do its magic, it needs data. Lots of it. For upsell automation, this means a deep understanding of user behavior and account status. We pulled data from our CRM, our billing system, and crucially, our product analytics platform. This is where the choice between tools like PostHog and Amplitude really matters. PostHog gives you incredible flexibility with event capture and self-hosting options, which is great for data sovereignty and cost control if you have the engineering bandwidth. But for sheer ease of use and powerful out-of-the-box segmentation, Amplitude often wins. We used Amplitude for this project because its cohorting features made it simpler to define “power users” or “feature-blocked users” without writing complex SQL queries every time. It just works, and when you’re trying to move fast, that’s a huge win.
Defining an upsell-ready user isn’t just about hitting a usage threshold. It’s about intent. Are they repeatedly trying to access a locked feature? Have they invited a certain number of team members, indicating team growth? Are they engaging with a specific set of features that are part of a higher tier? These signals are often scattered across different data sources, and stitching them together reliably is the first major hurdle. We spent weeks just on data normalization and creating a unified user profile, which, yes, is annoying but absolutely essential. Without clean, real-time data, your AI agent is just guessing.
Building the Agent: Frameworks and Frustrations
Once we had our data flowing, it was time to build the agent itself. We looked at a few frameworks: LangGraph, CrewAI, and AutoGen. Each has its strengths. CrewAI is great for orchestrating multiple agents with defined roles, making it feel like you’re building a small team. LangGraph, built on top of LangChain, offers a more explicit state machine approach, which I prefer for critical workflows because it makes debugging easier. You can visualize the flow and see exactly where an agent got stuck or made a bad decision. AutoGen is powerful for multi-agent conversations, but for a direct upsell flow, I found it a bit overkill.
We settled on LangGraph. Our agent’s job was to:
- Identify a user from the “upsell-ready” cohort.
- Fetch their recent activity and account details.
- Determine the most relevant upsell offer (e.g., more seats, a specific premium feature, a higher usage tier).
- Draft a personalized email or in-app message.
- Log the interaction and, if appropriate, trigger a follow-up task for a human sales rep.
This sounds straightforward. It isn’t. The initial drafts of the agent’s “reasoning” often produced generic, unconvincing messages. We had to fine-tune the prompts extensively, giving the LLM specific examples of good upsell copy and clear instructions on tone and call-to-action. We also had to build guardrails. What if the agent tried to upsell someone who just downgraded? Or a user who had an open support ticket? These edge cases are where agents silently fail, burning customer trust and wasting LLM tokens.
One concrete gripe I have with these frameworks is the lack of built-in, production-grade observability. You can get basic logs, but understanding why an agent chose a particular path or generated a specific output often requires digging through raw LLM traces. Tools like LangSmith and Langfuse are essential here. LangSmith, in particular, became our lifeline for debugging. It lets you visualize the entire chain of thought, the inputs, the outputs, and the tools called. Without it, you’re flying blind, especially when an agent starts looping or hallucinating. Honestly, LangSmith’s tracing capabilities are the only way I’d actually deploy a complex agent to production today. The free tier is enough for solo work, but for a team, the paid plans are a necessity, and frankly, they’re worth every penny to avoid costly production incidents.