
I recently embarked on a fun experiment: building a self-service assistant for Adobe Customer Journey Analytics (CJA). The goal was simple but ambitious — create an assistant that could answer questions about projects, dimensions, metrics, or even general CJA concepts, without requiring technical know-how or deep familiarity with the interface.
The idea came from a very practical need. When maintaining a clean and well-structured CJA setup, you often find yourself double-checking whether certain dimensions or metrics are still necessary — and whether you can safely remove them without breaking anything. These housekeeping tasks may sound simple, but they often require digging through multiple projects or data views to see where components are still in use.
As a technical analyst, I can do that with a few API calls or scripts. But isn’t there a simpler way? Something more intuitive — where even non-technical users could just ask a question like, “Is this dimension still used anywhere?” and instantly get a clear, friendly answer? That’s exactly the kind of idea that inspired me to experiment with a small AI assistant for Adobe CJA.
The experiment
For this prototype, I experimented with a hybrid approach combining several tools:
- Ollama (Local LLM): This acts as the reasoning engine behind the assistant. For prototyping, I didn’t want to spend money on public LLM APIs — so I ran everything locally on my laptop using Ollama. The downside: performance and response quality aren’t perfect, and sometimes the model needs a few seconds (or minutes) to think. But for quick experimentation and proof-of-concept work, it’s absolutely enough. Plus, running it locally keeps all data private, which is a nice bonus when working with internal analytics setups.
- LangChain: This orchestrates queries and connects the LLM to different data sources as “tools”.
- Chainlit: Provides a simple chat interface where users can ask questions and receive responses as if they were talking to a colleague.
The assistant draws information from multiple sources:
- cjapy: Fetches projects, dimensions, and metrics directly from Adobe CJA via the brilliant cjapy wrapper.
- CSV exports: I used CSV exports as a workaround for my internal Confluence documentation. In my daily work, I maintain several structured files — FAQs, SDRs, the shared components matrix, and other CJA-related documentation. Ideally, I’d connect directly to our internal Confluence space, but since that’s not (yet) possible, CSVs gave me a lightweight and flexible way to simulate structured data access. It’s not fancy, but it works surprisingly well for prototyping.
- URLs (Experience League): Integrated knowledge allows the assistant to answer conceptual questions like “What is a session?” or “How do I build a simple freeform table?”

By combining these sources, the assistant can support beginners who don’t know APIs or the CJA config interface, while still offering value to advanced users who want a conversational entry point to their data.
How it works
When someone asks a question—whether it’s something factual like “What is a session?” or something data-specific like “List all projects”– the assistant first decides which data source or tool to use.
If the question requires structured data, it pulls the information directly from a CSV export or through the cjapy API. Once the raw data is retrieved, the LLM (Large Language Model) takes over — it interprets the question, analyzes the data, and generates a clear, human-friendly answer.
Using LangChain makes defining these “tools” very straightforward. A tool is basically a Python function wrapped with metadata that tells the LLM when and how to use it. For example:
Tool(
name="ListProjects",
func=list_projects,
description=(
"Use this tool when the user asks about available projects in Adobe Customer Journey Analytics. "
"It returns a list of project names, owners, descriptions, creation dates, and last modified timestamps. "
"Only use this when the question clearly relates to projects, dashboards, or reports."
)
)
What’s interesting is that this description isn’t just a comment for developers — it’s actually passed to the LLM as part of its reasoning context.
That means the better and more specific the description, the smarter the assistant becomes at choosing the right tool and responding accurately.
For example, asking “Is there a project called myCSS?” triggers the assistant to look through the connected tools. The LLM then responds with the information found via cjapy getProjects(). Of course, the answer isn’t perfect, but for prototyping enough. Here is the example query:

Use cases I explored
Even in this prototype stage, the assistant can handle a variety of queries:
- Project lookup: “Which projects exist in CJA?”
- Shared dimension search: “Which dimensions are shared with the data view xy?”
- Data view mapping: “Which metrics are available in data view 1 or data view 2?”
- Conceptual guidance: “What is a session?” or “How do I build a simple freeform table?”

These capabilities make the assistant approachable for beginners, while still providing quick insights for experienced users.

Lessons learned
Some key takeaways from this experiment:
- Performance matters: Running Ollama locally works for small datasets, but larger queries can overload the system. Scaling to better hardware or cloud models would make responses nearly instantaneous.
- Structured data is essential: The LLM struggles with raw CJAPy outputs. Preprocessing into CSV or JSON ensures accurate, readable answers.
- Hybrid approach is effective: Separating data retrieval from natural language reasoning keeps the assistant responsive and accurate.
Conclusion
In the end, this was a fun and insightful experiment. It showed me that with today’s open-source tools, it’s absolutely possible to build a simple AI assistant that can interact with Adobe Customer Journey Analytics in a natural, conversational way.
Of course, the setup I used was just a prototype — running locally with limited hardware and smaller models. To really scale this idea, you’d need more powerful infrastructure, more refined prompts, and especially better-defined “tools” in Langchain. Getting those tool descriptions right is key: they help the model understand exactly what it can do, and prevent it from becoming a time waster instead of a helper.
For now, this project remains an experiment — a proof of concept to show what’s possible. My hope is that Adobe themselves continue to evolve their own AI assistants, because they’re in the best position to connect all the dots: internal documentation, CJA metadata, and product-specific context.
At the same time, this whole exercise also reinforced how crucial good documentation is for any analytics setup. A clean, well-structured description of your dimensions, metrics, and projects — paired with outputs like SDRs or component usage matrices via cjapy — can make all the difference between chaos and clarity, both for humans and for AI.