integration
Architecture
Studio is a native component of QALITA Platform, not a separate package.
Platform Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Platform Web │ REST │ Platform API │ gRPC │ Worker │
│ (Frontend) │ ←──────→ │ (Backend) │ ←──────→ │ │
│ │ │ │ │ │
│ - Studio UI │ │ - Studio API │ │ - Data Access │
│ - Chat Panel │ │ - LLM Agent │ │ - SQL Queries │
│ - Context Bar │ │ - Data Tools │ │ - File Reads │
└─────────────────┘ └─────────────────┘ └─────────────────┘
React/Next.js FastAPI + LangGraph Python CLI
Component Responsibilities
| Component | Responsibility |
|---|---|
| Frontend | Chat interface, context selection, streaming display |
| Backend Agent | LLM orchestration, tool execution, response generation |
| Backend API | REST endpoints, authentication, data preview |
| Worker | Source connectivity, query execution, data retrieval |
Data Flow
- User sends message → Frontend collects context (issue, source, schema, metrics)
- API receives request → Creates LLM instance from database config
- Agent processes → Invokes LangGraph workflow, may call data tools
- Tools execute → gRPC requests to Worker for data operations
- Response streams → SSE events back to frontend
LLM Configuration
LLM providers are configured through the Platform database, not environment variables or files.
Database Model
LLM configurations are stored in the llm_configuration table:
| Column | Type | Description |
|---|---|---|
id | int | Primary key |
partner_id | int | Organization FK |
name | str | Display name |
provider | str | Provider type |
model_name | str | Model identifier |
api_key | str | Encrypted API key |
endpoint_url | str | Custom endpoint |
is_active | bool | Active configuration |
configuration | json | Additional parameters |
Provider Mapping
The backend maps Platform providers to LangChain providers:
| Platform Provider | LangChain Provider |
|---|---|
openai | openai |
azure_openai | azure_openai |
anthropic | anthropic |
ollama | ollama |
mistral | mistral |
generic | openai (compatible API) |
Creating LLM from Config
The backend uses a factory pattern to create LLM instances:
from backend.agent import create_llm_from_db_config
# Async function to create LLM from active config
llm = await create_llm_from_db_config(
session=db_session,
partner_id=current_user.partner_id,
config_id=None, # Uses active config if None
streaming=True, # Enable streaming
)
Default Models
If no model is specified, defaults are used:
| Provider | Default Model |
|---|---|
| OpenAI | gpt-4o-mini |
| Azure OpenAI | gpt-4o-mini |
| Anthropic | claude-3-haiku-20240307 |
| Ollama | llama3.2 |
| Mistral | mistral-small-latest |
Status & Capabilities
Worker Connection Status
Endpoint: GET /api/v1/studio/status
Returns information about connected Workers for data operations:
{
"connected_workers": [1, 3, 5],
"worker_count": 3
}
Requirements: At least one Worker must be connected for data tools to function.
Agent Capabilities
Endpoint: GET /api/v1/studio/agent/capabilities
Returns agent availability and LLM configuration status:
{
"agent_available": true,
"llm_configured": true,
"active_config": {
"id": 1,
"name": "Production GPT-4o",
"provider": "openai",
"model_name": "gpt-4o",
"endpoint_url": null
}
}
States:
agent_available | llm_configured | Meaning |
|---|---|---|
true | true | Fully operational |
true | false | Agent ready, needs LLM config |
false | * | Install langchain/langgraph |
Visual Indicators
In the Platform frontend, indicators show:
- 🟢 Agent Ready: LLM configured and agent available
- 🟡 Partial: Agent available but no LLM config
- 🔴 Unavailable: Agent module not installed
- ⚪ No Worker: No workers connected for data access
Data Preview Integration
Studio can preview source data through Workers using gRPC.
Preview Architecture
Frontend → Backend API → Worker (gRPC) → Source (DB/File)
↓
DataPreviewManager
↓
Response correlation
Preview Request Flow
- Frontend requests preview for source ID
- Backend verifies source belongs to user's partner
- Backend finds available Worker for partner
- Backend creates gRPC
DataPreviewRequest - Worker reads data from source
- Worker returns
DataPreviewResponsevia gRPC - Backend returns formatted JSON to frontend
Preview Endpoint
GET /api/v1/studio/sources/{source_id}/preview
Parameters:
limit: Max rows (1-10000, default 1000)source_version_id: Specific versionquery: Custom SQL (for database sources)
Response:
{
"ok": true,
"data_type": "table",
"headers": ["id", "name", "email", "created_at"],
"rows": [
{"values": ["1", "John Doe", "john@example.com", "2024-01-15"]},
{"values": ["2", "Jane Smith", "jane@example.com", "2024-01-16"]}
],
"total_rows": 10000
}
Supported Data Types
| Type | Description | Content |
|---|---|---|
table | Structured data | headers, rows |
text | Plain text | content |
json | JSON data | content |
image | Binary image | binary_base64, mime_type |
pdf | PDF document | binary_base64, mime_type |
error | Error state | error |
Source & Issue Context
Studio provides contextual conversation retrieval based on sources and issues.
Context Query
GET /api/v1/studio/conversations/context
Parameters:
source_id: Get conversations from issues linked to sourceissue_id: Get conversations from specific issueproject_id: Get all project conversations
Response:
{
"source_conversations": [...],
"issue_conversations": [...],
"project_conversations": [...],
"total_count": 15
}
Conversation Linking
Conversations are linked to Platform entities:
| Field | Purpose |
|---|---|
issue_id | Link to quality issue |
source_id | Link to data source |
project_id | Link to project |
This enables:
- Retrieving conversation history when reopening an issue
- Seeing related conversations from same source
- Project-wide conversation overview
Data Tools Integration
Studio's agent can execute data operations through Workers.
Tool Architecture
Agent (LangGraph) → Tool Function → gRPC → Worker → Source
↓
AgentActionManager
↓
Response correlation
Available Tools
Tools are created dynamically based on the user's context:
from backend.agent.tools import create_data_tools
# Create tools bound to partner
tools = create_data_tools(
partner_id=current_user.partner_id,
source_id=context.get("source_id")
)
Tool Definitions
| Tool | Input Schema | Action |
|---|---|---|
execute_sql_query | source_id, sql, limit | Run SQL on database |
read_source_data | source_id, limit, table, columns | Read data |
describe_source | source_id, table | Get metadata |
sample_source_data | source_id, n, table | Random sample |
count_rows | source_id, table, condition | Count rows |
filter_data | source_id, condition, limit | Filter data |
aggregate_data | source_id, group_by, agg_func | Aggregate |
gRPC Communication
Tools communicate with Workers via gRPC:
Request:
message AgentActionRequest {
string request_id = 1;
string action_type = 2;
int32 source_id = 3;
string parameters_json = 4;
optional int32 timeout_seconds = 5;
}
Response:
message AgentActionResponse {
string request_id = 1;
bool ok = 2;
string action_type = 3;
optional string error = 4;
optional string result_json = 5;
optional DataPreview data = 6;
optional int64 execution_time_ms = 7;
}
Tool Response Formatting
Results are formatted for LLM consumption:
Execution time: 45ms
Columns: id, name, email, created_at
Rows (20 shown, 1000 total):
id | name | email | created_at
------------------------------------
1 | John Doe | john@ex.com | 2024-01-15
2 | Jane Smith | | 2024-01-16
...
Authentication and Security
Authentication Flow
Studio uses Platform's standard authentication:
1. User logs into Platform
↓
2. JWT token issued by Platform auth
↓
3. Frontend includes token in requests
↓
4. Backend validates token, extracts user/partner
↓
5. Studio endpoints check permissions
Required Permissions
| Endpoint | Required Scope |
|---|---|
/api/v1/studio/status | source:get |
/api/v1/studio/sources/{id}/preview | source:get |
/api/v1/studio/agent/capabilities | source:get |
/api/v1/studio/chat | source:get |
/api/v1/studio/conversations/context | issue:get |
Data Isolation
- Partner Isolation: All queries filter by
partner_id - Source Access: Only sources belonging to partner
- Issue Access: Only issues belonging to partner
- Conversations: Only conversations belonging to partner
API Key Security
LLM API keys are:
- Stored encrypted in database
- Never exposed in API responses
- Only used server-side for LLM calls
🔧 MCP Server Integration
Studio supports Model Context Protocol (MCP) servers for extended tool capabilities.
MCP Architecture
Agent → LangChain Tool → MCPHttpClient → MCP Server
↓
JSON-RPC 2.0
MCP Configuration
MCP servers are configured per partner in the database:
{
"name": "Data Tools Server",
"endpoint_url": "https://mcp.example.com/rpc",
"api_key": "...",
"is_active": true,
"tools_cache": [
{"name": "analyze_csv", "description": "..."},
{"name": "validate_schema", "description": "..."}
]
}
MCP Tool Creation
MCP tools are automatically converted to LangChain tools:
from backend.agent.mcp_client import create_langchain_tools_from_mcp_servers
# Get all active MCP tools for partner
mcp_tools = await create_langchain_tools_from_mcp_servers(
session=db_session,
partner_id=current_user.partner_id
)
# Tools are prefixed with "mcp_" and include server name in description
# e.g., "mcp_analyze_csv" with description "[MCP:DataTools] Analyze CSV file"
Troubleshooting
"Agent module not available"
Cause: LangChain/LangGraph not installed
Solution:
# On the Platform backend server
pip install langchain langgraph langchain-openai langchain-anthropic langchain-ollama
"No LLM configuration found"
Cause: No active LLM config for partner
Solution:
- Go to Settings > AI Configuration
- Create a new configuration
- Set it as Active
"No worker available"
Cause: No Worker connected for data operations
Solution:
# Start a Worker
qalita worker start
Worker timeout
Cause: Worker didn't respond in time
Checks:
- Verify Worker is running and connected
- Check Worker logs for errors
- Verify source connectivity from Worker
- Increase timeout if needed
LLM connection errors
OpenAI:
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer YOUR_KEY"
Ollama:
curl http://localhost:11434/api/tags
Check error details in response:
{
"ok": false,
"error": "Connection to Ollama refused at http://localhost:11434"
}
Monitoring
Backend Logs
Studio operations are logged with loguru:
# In backend logs
INFO | backend.agent.agent:invoke:505 - Invoking agent workflow
INFO | backend.agent.tools.data_tools:execute_query_tool:178 - Executing SQL query on source 456
DEBUG | backend.agent.llm_factory:create_chat_model:120 - Creating LLM with provider=openai, model=gpt-4o-mini
Metrics to Monitor
| Metric | Description |
|---|---|
| Chat request latency | Time from request to response |
| Streaming first byte | Time to first SSE event |
| Tool execution time | Duration of data tool calls |
| Worker response time | gRPC round-trip time |
| LLM token usage | Tokens consumed per request |
Complete Workflow Example
import requests
import json
BASE_URL = "https://your-platform/api/v1"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
# 1. Check agent capabilities
caps = requests.get(f"{BASE_URL}/studio/agent/capabilities", headers=HEADERS).json()
print(f"Agent available: {caps['agent_available']}, LLM configured: {caps['llm_configured']}")
# 2. Check worker status
status = requests.get(f"{BASE_URL}/studio/status", headers=HEADERS).json()
print(f"Workers connected: {status['worker_count']}")
# 3. Preview source data
preview = requests.get(
f"{BASE_URL}/studio/sources/456/preview",
headers=HEADERS,
params={"limit": 100}
).json()
print(f"Columns: {preview['headers']}")
# 4. Chat with context
response = requests.post(
f"{BASE_URL}/studio/chat",
headers=HEADERS,
json={
"message": "Analyze the data quality of this source",
"context": {
"source_id": 456,
"enriched": {
"source": {"id": 456, "name": "customers", "type": "postgresql"},
"dataSample": preview
}
}
}
).json()
print(f"Agent response: {response['response'][:500]}...")
# 5. Get related conversations
convs = requests.get(
f"{BASE_URL}/studio/conversations/context",
headers=HEADERS,
params={"source_id": 456}
).json()
print(f"Related conversations: {convs['total_count']}")
Best Practices
-
LLM Configuration:
- Start with Ollama for development (free, private)
- Use
gpt-4o-minifor cost-effective production - Test configurations before activating
-
Worker Management:
- Ensure at least one Worker per environment
- Monitor Worker connectivity
- Handle Worker unavailability gracefully
-
Context Enrichment:
- Always include relevant context (source, issue)
- Use data samples when asking about data
- Include schema for structure questions
-
Error Handling:
- Check
okfield in responses - Handle streaming errors in SSE
- Implement retry logic for transient failures
- Check
Next Steps
- 🚀 Features - Explore all Studio capabilities
- 💬 Conversation Management - Organize your conversations
- 📖 Configuration - Configure LLM providers