Agent Architecture (Advanced)
How we built the Ana agent
TextQL has developed a controllable insights agent for tabular data. Achieving this required extensive research and the development of a robust architecture that integrates multiple foundational concepts. This architecture is designed to prioritize reliability while addressing the challenges of context management.
TextQL’s main technology is the Ana (Analyst) agent, which is a chatbot architecture for extracting insights from tabular data. The agent’s capabilities are underpinned by five key technologies:
-
Dakota: A state-machine architecture that manages tool access at runtime. Dakota enables dynamic prompt adjustments and context integration before agent processing.
-
Chat Engine & Cells: A layered architecture for managing data-driven conversations through a cell-based processing system. Four layers (LLM, State, History, Stream) provide model-agnostic AI integration and cross-platform delivery, Cells act as atomic units of conversation, supporting both executable operations (search, metrics, analysis) and interactive elements (clarification, choices, assumptions).
-
Ontology Service (TextQL Semantic Layer): A semantic framework for defining and connecting data areas. Ontology objects are vectorized, allowing the agent to efficiently locate and operate on relevant data within a client’s data warehouse.
-
Sandbox Execution Environment: A secure environment for loading tabular data into memory and executing AI-generated Python scripts for analysis.
-
Textables: A standardized metadata format for tabular data, providing essential information to guide the agent’s analysis.
Architecture Diagram of the TextQL Insights Agent
The following sections provide an in-depth exploration of each component.
Dakota
Dakota is a framework that organizes agent behavior into modes, each representing a state within a dynamic state machine. Modes are designed with specific objectives, associated prompts, accessible tools, and defined transitions to other modes. This structured approach provides robust context management and allows the agent’s flow to align with the requirements of your use case.
Modes should be conceptualized as stages of a project rather than discrete to-do list items. Each mode encapsulates a broader set of actions or analysis phases, making it adaptable to varying workflows.
Example agent flow implemented with the Dakota framework
Why Dakota: Insights from Research and Development:
Dakota emerged as a result of extensive research into agent behavior and the challenges of designing systems for controllable insights. Through this work, we identified several critical requirements for solving complex problems effectively, and we align these requirements with the architecture benefits below:
-
Improved Trajectory Structure: Agents must not simply execute individual steps correctly but must follow an entire workflow reliably. By defining discrete modes and transitions, Dakota ensures the agent’s trajectory is predictable and aligned with desired outcomes.
-
Enhanced Prompt Context in Multi-Step Tasks: Dakota enables tailored advice and guidance for each stage of a task. This approach extends the concept of Retrieval-Augmented Generation (RAG) allowing the agent to advise itself on the appropriate procedure for the task at hand. This approach additionally allows for tying additional context to the modes themselves, enabling targeted actions that facilitate more complex multi-step problems.
Tailoring Dakota to Your Use Case:
The state-machine can be tailored to suit specific workflows, enabling seamless alignment with desired processes. For example:
-
A narrow process can be enforced by configuring the state machine to resemble a linear graph, ensuring a highly controlled and predictable flow.
-
A highly connected graph allows greater flexibility, enabling the agent to rapidly explore options and operate with creativity. This approach prioritizes efficiency but may diverge from rigid workflows.
Agent behavior can be modified and extended in the context of the Dakota framework by (1) adding or removing modes, (2) changing which transitions are possible between modes, or (3) changing prompt context provided with each mode.
Chat Engine
Based on the OSI networking model, our Chat Engine provides a framework for managing conversations while handling data operations consistently.
The system addresses three main requirements:
-
Model Agnosticism: Works with different AI models while maintaining consistent behavior
-
Interaction Format Flexibility: Supports web chat, Slack, and other interfaces
-
Execution Management: Handles data loading and transformation with consistent history tracking
The framework has four layers:
-
LLM Layer: Interfaces with AI providers such as Anthropic and OpenAI. Converts AI responses into the Cell format. Makes it so that the entire system is agnostic to the model provider given a certain level of capability. This layer implements system support for token streaming, function calling, and image recognition.
-
State Layer: Uses a finite state machine (FSM) to manage conversation flow and determine next steps. Manages function calling and execution in a robust manner for a synchronous user experience.
-
History Layer: Tracks conversation context using a directed acyclic graph (DAG) to maintain continuity. Allows for forking and multi-agent operations for certain tasks.
-
Stream Layer: Delivers responses to different client interfaces (TextQL web app, Slack, Teams, embedded deployment) in the appropriate format.
Cells
Cells are the basic units of conversation processing in the Chat Engine. Cells represent both function calling, and non-execution based chat events, such as user and agent messages. Executable cells support both human and agent operations, the inputs and outputs of which can be audited for correctness. Cells also have associated errors specific to them, that are meant to be either presented to the user or agent, as defined at the cell-level.
The system uses several cell types for different data operations:
-
Search Cells: Find relevant data assets in the environment. They can locate dashboards, find values in tables, or identify tables and files needed for analysis. Combines embeddings, conventional NLP (BM25, trigrams, etc.) to surface results. Matched strings for each asset type are customizable. Used when base context is larger than what is productively usable by LLM.
-
Metric Explorer Cells: Handle trend and comparative analysis. They process metric queries with specified breakdowns and filters, converting them to SQL through the ontology service.
-
Object Explorer Cells: Manage queries about population traits, similar to Metric Explorer Cells.
-
Analysis Cells: Run Python operations for tasks like modeling, visualization, and file exports. They operate in sandboxes and can use additional libraries.
To manage agent-user interaction, the system also includes breakpoint cells:
-
Clarification Cells: Ask the user for open-ended feedback, essentially another message
-
Choice Cells: Solicit user feedback on a limited set of options
-
Assumption Cells: Highlight important assumptions to users, for example the choice between two columns
The cells system is designed to support the creation of custom cells, for example a significance test. Additionally, cells are designed to be composable so that users can identify and replicate multi-step workflows in the future, without requiring any additional development.
Python Sandbox
The Sandbox is a persistent Python execution environment designed specifically for data manipulation tasks. It enables flexible operations like statistical analysis, custom visualizations, machine learning model development, and complex data transformations that go beyond the capabilities of SQL and fixed-function libraries. There are four key aspects of the Sandbox:
There are a number of existing solutions for this, but we have implemented a custom sandbox environment and orchestration system oriented for data workloads. This has four key aspects:
-
Arrow-native architecture forms the foundation of our sandbox design. The system uses Apache Arrow as its core data format, with Arrow Flight handling data transfer between components. This provides a consistent, high-performance interface for moving data between the compute engine and analysis tools. DuckDB integration adds efficient handling of flat files and initial data processing, completing the data pipeline.
-
Security and resource management rely on container-based isolation. The orchestrator handles resource allocation, monitoring, and sandbox lifecycle management. Each execution environment runs without network access and with strict resource limits, ensuring both security and consistent performance across analysis runs.
-
The Python environment comes pre-configured for data science workflows. Common libraries like pandas, seaborn, and geopy are available through a dynamic loading system that optimizes memory usage. A custom preprocessing layer improves code quality by optimizing certain function calls and implementing an extensible linting system that guides the agent toward better coding patterns.
-
Data handling capabilities balance flexibility with practical limits. The sandbox interfaces with data through the compute engine using the Textables format and can efficiently process datasets up to several gigabytes, approximately 10 million data points. Built-in validation provides clear feedback when data size exceeds capacity, allowing for query refinement.
The sandbox capabilities can be extended by adding Python libraries for specialized analysis, changing resource allocations such as memory at the orchestrator level, or using custom Python runtimes. We modify common library functions to be more LLM suitable (like what we do for pd.cut) and transparent optimizations in the background. This lets you adapt the environment for specific analysis needs while keeping the security model intact.
Textables
The Textable is a high-performance interface for tabular data, regardless of where it lives. As a unified interface for working with large datasets, it simplifies work by providing a shared format for many purposes:
- Loading datasets to Python sandboxes
- Performing paginated queries for previews
- Performing statistical analysis on large datasets
With the textables format, we’ve created an interface within the platform that ensures the agent is equipped with a common set of tooling across different data tabular data sources. Textables make it so that the amount of additional work to incorporate an additional connection at the data layer is minimal.
TextQL Textables: a high-performance interface for tabular data