Skip to content

Commit e2310ce

Browse files
authored
Merge pull request #1 from eosho/feature/visualizer-tool
Release 12-29-2025
2 parents 4f2ccc9 + fc34f57 commit e2310ce

24 files changed

Lines changed: 1311 additions & 552 deletions

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ BIGQUERY_DATASET=your-dataset
8787
BIGQUERY_LOCATION=US
8888
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
8989
BIGQUERY_CREDENTIALS_JSON=
90+
91+
# =============================================================================
92+
# Visualization (Optional)
93+
# Requires Azure Container Apps Dynamic Sessions for secure code execution.
94+
# See docs/CONFIGURATION.md for setup instructions.
95+
# =============================================================================
96+
AZURE_SESSIONS_POOL_ENDPOINT=https://eastus.dynamicsessions.io/subscriptions/xxx/resourceGroups/xxx/sessionPools/xxx

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Built on top of LangChain's [`SQLDatabase`](https://docs.langchain.com/oss/pytho
2828
- **Intent Detection**: Automatically routes queries to the correct data agent based on question context
2929
- **Multi-Turn Conversations**: Follow-up questions with context awareness (e.g., "What's the average?" after a query)
3030
- **SQL Validation**: Safe query execution with sqlglot-based validation across all dialects
31+
- **Data Visualization**: Generate charts and graphs from query results using natural language (e.g., "show me a bar chart")
3132
- **Configurable Agents**: YAML-based configuration for adding new data sources
3233
- **A2A Protocol**: Agent-to-Agent interoperability for integration with other A2A-compliant systems
3334

@@ -49,6 +50,7 @@ Generates, validates, and executes SQL queries with retry logic.
4950

5051
- [Database Setup](docs/DATABASE_SETUP.md)
5152
- [Configuration](docs/CONFIGURATION.md)
53+
- [Data Visualization](docs/VISUALIZATION.md)
5254
- [A2A Protocol](docs/A2A.md)
5355

5456
## Quick Start
@@ -163,6 +165,7 @@ data-agent chat -c adventure_works
163165
1. What are the total deposits by customer segment?
164166
2. Show me all high-severity fraud alerts from the past week
165167
3. Who are the top 5 customers by transaction volume?
168+
4. Show me a bar chart of transactions by type
166169

167170
```bash
168171
data-agent query "What are the total deposits by customer segment?" -c amex

docs/CONFIGURATION.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ data_agents:
3535
blocked_functions:
3636
- pg_sleep
3737
- pg_read_file
38+
code_interpreter:
39+
enabled: true
3840
system_prompt: |
3941
You are an SQL assistant...
4042
{schema_context}
@@ -54,6 +56,25 @@ data_agents:
5456
answer: "There are 1,234 users."
5557
```
5658
59+
## Code Interpreter (Data Visualization)
60+
61+
Enable the code interpreter to generate charts and visualizations from query results. When enabled, the LLM can detect visualization intent (e.g., "show me a chart", "visualize", "plot") and generate matplotlib code to create charts.
62+
63+
```yaml
64+
code_interpreter:
65+
enabled: true
66+
azure_sessions_endpoint: ${AZURE_SESSIONS_POOL_ENDPOINT}
67+
```
68+
69+
| Setting | Description | Default |
70+
|---------|-------------|---------|
71+
| `enabled` | Enable/disable visualization generation | `false` |
72+
| `azure_sessions_endpoint` | Azure Container Apps session pool management endpoint URL | - |
73+
74+
**Note:** Visualization requires Azure Container Apps Dynamic Sessions for secure, isolated code execution.
75+
76+
See [VISUALIZATION.md](VISUALIZATION.md) for complete setup instructions, architecture details, and troubleshooting.
77+
5778
## SQL Validation
5879

5980
Each data agent can configure SQL validation settings to control query safety:

docs/VISUALIZATION.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# Data Visualization
2+
3+
This guide covers the code interpreter feature for generating charts and visualizations from query results.
4+
5+
## Overview
6+
7+
When enabled, the data agent can detect visualization intent in user queries (e.g., "show me a chart", "plot the data") and generate matplotlib code to create charts. The code runs in a secure, isolated environment using Azure Container Apps Dynamic Sessions.
8+
9+
**Key features:**
10+
- Automatic detection of visualization requests
11+
- LLM-generated matplotlib code
12+
- Secure sandboxed execution with Hyper-V isolation
13+
- Native image capture (no file storage)
14+
- Support for bar charts, line charts, pie charts, scatter plots, and more
15+
16+
## Requirements
17+
18+
Visualization requires Azure Container Apps Dynamic Sessions. This provides:
19+
20+
| Feature | Benefit |
21+
|---------|---------|
22+
| **Hyper-V isolation** | Each execution runs in a dedicated VM |
23+
| **Pre-installed packages** | NumPy, Pandas, Matplotlib ready to use |
24+
| **Native image capture** | `plt.show()` output captured automatically |
25+
| **Automatic cleanup** | Sessions terminate after idle timeout |
26+
| **No host access** | Code cannot access host filesystem or network |
27+
28+
## Azure Setup
29+
30+
### 1. Create a Container Apps Environment
31+
32+
If you don't already have one:
33+
34+
```bash
35+
az containerapp env create \
36+
--name aca-env \
37+
--resource-group rg-data-agent \
38+
--location eastus
39+
```
40+
41+
### 2. Create the Session Pool
42+
43+
```bash
44+
az containerapp sessionpool create \
45+
--name session-pool-viz \
46+
--resource-group rg-data-agent \
47+
--container-type PythonLTS \
48+
--max-sessions 100 \
49+
--cooldown-period 300 \
50+
--location eastus
51+
```
52+
53+
**Parameters:**
54+
- `--container-type PythonLTS`: Python runtime with common data science packages
55+
- `--max-sessions`: Maximum concurrent sessions
56+
- `--cooldown-period`: Seconds before idle session is terminated
57+
58+
### 3. Get the Pool Management Endpoint
59+
60+
```bash
61+
az containerapp sessionpool show \
62+
--name session-pool-viz \
63+
--resource-group rg-data-agent \
64+
--query "properties.poolManagementEndpoint" -o tsv
65+
```
66+
67+
This returns a URL like:
68+
```
69+
https://eastus.dynamicsessions.io/subscriptions/<sub>/resourceGroups/<rg>/sessionPools/<pool>
70+
```
71+
72+
### 4. Assign the Executor Role
73+
74+
Grant your identity permission to execute code in the session pool:
75+
76+
```bash
77+
# Get your user ID
78+
USER_ID=$(az ad signed-in-user show --query id -o tsv)
79+
80+
# Get the session pool resource ID
81+
POOL_ID=$(az containerapp sessionpool show \
82+
--name session-pool-viz \
83+
--resource-group rg-data-agent \
84+
--query id -o tsv)
85+
86+
# Assign the role
87+
az role assignment create \
88+
--role "Azure ContainerApps Session Executor" \
89+
--assignee $USER_ID \
90+
--scope $POOL_ID
91+
```
92+
93+
**Note:** For service principals or managed identities, replace `$USER_ID` with the appropriate object ID.
94+
95+
### 5. Install the SDK
96+
97+
```bash
98+
pip install langchain-azure-dynamic-sessions
99+
```
100+
101+
Or add to your `pyproject.toml`:
102+
```toml
103+
dependencies = [
104+
"langchain-azure-dynamic-sessions>=0.1.0",
105+
]
106+
```
107+
108+
## Configuration
109+
110+
### Environment Variable
111+
112+
Set the pool endpoint:
113+
114+
```bash
115+
export AZURE_SESSIONS_POOL_ENDPOINT="https://eastus.dynamicsessions.io/subscriptions/.../sessionPools/..."
116+
```
117+
118+
Or in `.env`:
119+
```bash
120+
AZURE_SESSIONS_POOL_ENDPOINT=https://eastus.dynamicsessions.io/subscriptions/.../sessionPools/...
121+
```
122+
123+
### YAML Configuration
124+
125+
Enable visualization in your agent config:
126+
127+
```yaml
128+
data_agents:
129+
- name: "sales_agent"
130+
# ... other config ...
131+
code_interpreter:
132+
enabled: true
133+
azure_sessions_endpoint: ${AZURE_SESSIONS_POOL_ENDPOINT}
134+
```
135+
136+
| Setting | Description | Default |
137+
|---------|-------------|---------|
138+
| `enabled` | Enable/disable visualization | `false` |
139+
| `azure_sessions_endpoint` | Session pool management endpoint URL | - |
140+
141+
### System Prompt
142+
143+
To enable visualization detection, include `visualization_requested` in your response format:
144+
145+
```yaml
146+
system_prompt: |
147+
You are a SQL expert for the sales database.
148+
149+
{schema_context}
150+
151+
## Response Format
152+
153+
Provide your response as JSON with these fields:
154+
- "thinking": Step-by-step reasoning about the query
155+
- "sql_query": The generated SQL query
156+
- "explanation": Brief explanation of what the query does
157+
- "visualization_requested": Set to true if the user asks for a chart, graph, plot, or visualization
158+
```
159+
160+
## How It Works
161+
162+
```
163+
┌─────────────────────────────────────────────────────────────────┐
164+
│ User Query │
165+
│ "Show me a bar chart of sales by region" │
166+
└─────────────────────────────────────────┬───────────────────────┘
167+
168+
169+
┌─────────────────────────────────────────────────────────────────┐
170+
│ SQL Generation LLM │
171+
│ Generates SQL + sets visualization_requested: true │
172+
└─────────────────────────────────────────┬───────────────────────┘
173+
174+
175+
┌─────────────────────────────────────────────────────────────────┐
176+
│ Database Query │
177+
│ Execute SQL, return result rows │
178+
└─────────────────────────────────────────┬───────────────────────┘
179+
180+
181+
┌─────────────────────────────────────────────────────────────────┐
182+
│ Visualization LLM │
183+
│ Generates matplotlib code based on data + user question │
184+
└─────────────────────────────────────────┬───────────────────────┘
185+
186+
187+
┌─────────────────────────────────────────────────────────────────┐
188+
│ Azure Container Apps Dynamic Sessions │
189+
│ • Code executed in Hyper-V isolated container │
190+
│ • plt.show() output captured automatically │
191+
│ • Image returned as base64 PNG │
192+
└─────────────────────────────────────────┬───────────────────────┘
193+
194+
195+
┌─────────────────────────────────────────────────────────────────┐
196+
│ Response │
197+
│ Text explanation + embedded chart image │
198+
└─────────────────────────────────────────────────────────────────┘
199+
```
200+
201+
### Execution Flow
202+
203+
1. **Intent Detection**: The SQL LLM sets `visualization_requested: true` when it detects chart/graph/plot intent
204+
2. **SQL Execution**: Query runs against the database, returning structured data
205+
3. **Code Generation**: A second LLM call generates matplotlib code tailored to the data and question
206+
4. **Sandboxed Execution**: Code runs in Azure Sessions with automatic image capture
207+
5. **Response Assembly**: Text response and chart image are combined for display
208+
209+
## Example Queries
210+
211+
These prompts trigger visualization:
212+
213+
| Query | Chart Type |
214+
|-------|------------|
215+
| "Show me a bar chart of sales by region" | Bar chart |
216+
| "Visualize the top 10 customers by revenue" | Horizontal bar |
217+
| "Plot monthly revenue trends for 2024" | Line chart |
218+
| "Create a pie chart of transaction types" | Pie chart |
219+
| "Graph the distribution of order values" | Histogram |
220+
| "Compare Q1 vs Q2 performance" | Grouped bar |
221+
222+
## Further Reading
223+
224+
- [Azure Container Apps Dynamic Sessions](https://learn.microsoft.com/azure/container-apps/sessions)
225+
- [Session Pool Management](https://learn.microsoft.com/azure/container-apps/sessions-code-interpreter)
226+
- [LangChain Azure Dynamic Sessions](https://python.langchain.com/docs/integrations/tools/azure_dynamic_sessions)

docs/data_agent_graph.png

13.6 KB
Loading

pyproject.toml

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,11 @@ dependencies = [
2222
"pyyaml>=6.0",
2323
"python-dotenv>=1.2.1",
2424
"databricks-sql-connector>=4.2.2",
25-
"asyncpg>=0.29.0",
2625
"psycopg[binary]>=3.1.0",
27-
"nest-asyncio>=1.6.0",
2826
"azure-cosmos>=4.7.0",
29-
"aiohttp>=3.9.0",
3027
"structlog>=24.0.0",
3128
"typing-extensions>=4.12",
3229
"azure-identity>=1.25.1",
33-
"azure-keyvault-secrets>=4.10.0",
3430
"langgraph-cli[inmem]>=0.4.10",
3531
"langgraph-api>=0.5.42",
3632
"pyodbc>=5.3.0",
@@ -41,14 +37,15 @@ dependencies = [
4137
"rich>=14.0.0",
4238
"chainlit>=2.0.0",
4339
"pandas>=2.0.0",
44-
"tabulate>=0.9.0",
4540
"a2a-sdk[http-server]>=0.3.22",
4641
"httpx>=0.27.0",
4742
"sqlalchemy>=2.0.45",
4843
"sqlalchemy-bigquery>=1.16.0",
4944
"databricks-sqlalchemy>=2.0.8",
5045
"google-cloud-bigquery-storage>=2.36.0",
5146
"psycopg2>=2.9.11",
47+
"langchain-azure-dynamic-sessions>=0.2.0",
48+
"matplotlib>=3.10.8",
5249
]
5350

5451
[project.scripts]
@@ -72,15 +69,6 @@ dev = [
7269
"isort>=7.0.0",
7370
]
7471

75-
# Azure AI Foundry hosting dependencies
76-
foundry = [
77-
"azure-ai-agentserver-langgraph>=0.1.0",
78-
"azure-ai-projects>=1.0.0",
79-
"azure-identity>=1.25.1",
80-
"opentelemetry-api>=1.20.0",
81-
"opentelemetry-sdk>=1.20.0",
82-
]
83-
8472
[tool.setuptools.packages.find]
8573
where = ["src"]
8674
include = ["data_agent*"]

src/data_agent/agent.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ async def run(
561561
datasource_name=result.get("datasource_name", ""),
562562
rewritten_question=result.get("rewritten_question", ""),
563563
messages=result.get("messages", []),
564+
visualization_image=result.get("visualization_image"),
565+
visualization_code=result.get("visualization_code"),
566+
visualization_error=result.get("visualization_error"),
564567
)
565568

566569
def get_agent_names(self) -> list[str]:

0 commit comments

Comments
 (0)