Back to Blog
5 min read

Azure AI Foundry Deep Dive: Building Enterprise AI Applications

Azure AI Foundry represents Microsoft’s vision for a unified AI development platform. Let’s explore how to build production-ready AI applications using this new framework.

Setting Up Your First AI Foundry Project

from azure.ai.foundry import AIFoundryClient
from azure.ai.foundry.projects import Project
from azure.identity import DefaultAzureCredential

# Initialize the client
credential = DefaultAzureCredential()
client = AIFoundryClient(
    credential=credential,
    subscription_id="your-subscription-id"
)

# Create a new project
project = client.projects.create(
    name="data-analytics-assistant",
    resource_group="rg-ai-production",
    location="eastus2",
    description="AI assistant for data analytics tasks",
    tags={"environment": "production", "team": "data-engineering"}
)

print(f"Project created: {project.name}")
print(f"Project ID: {project.id}")

The AI Foundry Project Structure

my-ai-project/
├── .ai/
│   ├── config.yaml           # Project configuration
│   └── connections.yaml      # Data and service connections
├── src/
│   ├── agents/               # AI agent definitions
│   ├── prompts/              # Prompt templates
│   ├── tools/                # Custom tools
│   └── flows/                # Orchestration flows
├── evaluations/
│   ├── test_cases.jsonl      # Test data
│   └── metrics.py            # Custom evaluation metrics
├── deployments/
│   └── production.yaml       # Deployment configuration
└── ai-foundry.yaml           # Project manifest

Configuring Connections

# .ai/connections.yaml
connections:
  - name: azure-openai-prod
    type: azure_openai
    endpoint: ${AZURE_OPENAI_ENDPOINT}
    api_key: ${AZURE_OPENAI_KEY}
    api_version: "2024-10-01"

  - name: fabric-lakehouse
    type: azure_data
    connection_string: ${FABRIC_CONNECTION_STRING}

  - name: cognitive-search
    type: azure_search
    endpoint: ${SEARCH_ENDPOINT}
    api_key: ${SEARCH_KEY}

Building a Data Analysis Agent

from azure.ai.foundry.agents import Agent, Tool, AgentConfig
from azure.ai.foundry import AIFoundryClient

# Define tools for the agent
class FabricQueryTool(Tool):
    name = "fabric_query"
    description = "Execute SQL queries against Microsoft Fabric Lakehouse"

    def __init__(self, connection_name: str):
        self.connection = connection_name

    async def execute(self, query: str) -> dict:
        """Execute SQL query and return results."""
        from azure.ai.foundry.connections import get_connection

        conn = get_connection(self.connection)
        result = await conn.execute_query(query)

        return {
            "columns": result.columns,
            "rows": result.rows[:100],  # Limit for context
            "row_count": len(result.rows),
            "truncated": len(result.rows) > 100
        }

class ChartGeneratorTool(Tool):
    name = "generate_chart"
    description = "Generate a chart from data"

    async def execute(self, data: dict, chart_type: str, title: str) -> str:
        """Generate chart and return URL."""
        import matplotlib.pyplot as plt
        import io
        import base64

        fig, ax = plt.subplots(figsize=(10, 6))

        if chart_type == "bar":
            ax.bar(data["labels"], data["values"])
        elif chart_type == "line":
            ax.plot(data["labels"], data["values"])
        elif chart_type == "pie":
            ax.pie(data["values"], labels=data["labels"], autopct='%1.1f%%')

        ax.set_title(title)

        buffer = io.BytesIO()
        plt.savefig(buffer, format='png')
        buffer.seek(0)
        image_base64 = base64.b64encode(buffer.getvalue()).decode()

        return f"data:image/png;base64,{image_base64}"

# Create the agent
data_analyst = Agent(
    name="DataAnalyst",
    model="gpt-4o",
    config=AgentConfig(
        temperature=0.1,
        max_tokens=4000
    ),
    instructions="""You are a data analyst assistant with access to a Microsoft Fabric Lakehouse.

Your capabilities:
1. Query data using SQL via the fabric_query tool
2. Create visualizations using the generate_chart tool
3. Provide insights and recommendations based on data

When answering questions:
1. First understand what data is needed
2. Write and execute appropriate SQL queries
3. Analyze the results
4. Create visualizations when helpful
5. Provide clear, actionable insights

Always explain your reasoning and methodology.""",
    tools=[
        FabricQueryTool("fabric-lakehouse"),
        ChartGeneratorTool()
    ]
)

Running the Agent

from azure.ai.foundry.agents import AgentRuntime

async def analyze_sales_data():
    runtime = AgentRuntime(client)

    # Start a conversation
    conversation = await runtime.create_conversation(
        agent=data_analyst,
        metadata={"user_id": "analyst-001", "department": "sales"}
    )

    # First query
    response = await conversation.send_message(
        "What were our top 10 products by revenue last quarter?"
    )
    print(f"Agent: {response.content}")

    # Follow-up
    response = await conversation.send_message(
        "Show me a bar chart of those results"
    )
    print(f"Agent: {response.content}")

    # Check tool usage
    for tool_call in response.tool_calls:
        print(f"Tool used: {tool_call.tool_name}")
        print(f"Input: {tool_call.input}")
        print(f"Output: {tool_call.output}")

    return conversation.id

# Run the analysis
conversation_id = await analyze_sales_data()

Implementing Evaluation

from azure.ai.foundry.evaluation import Evaluator, EvalMetric
from typing import List

class SQLAccuracyMetric(EvalMetric):
    """Custom metric for SQL query accuracy."""
    name = "sql_accuracy"

    async def compute(self, prediction: str, reference: str) -> float:
        # Compare SQL structure and results
        pred_normalized = self.normalize_sql(prediction)
        ref_normalized = self.normalize_sql(reference)

        if pred_normalized == ref_normalized:
            return 1.0

        # Partial credit for correct structure
        pred_parts = set(pred_normalized.split())
        ref_parts = set(ref_normalized.split())
        overlap = len(pred_parts & ref_parts) / len(ref_parts)

        return overlap

    def normalize_sql(self, sql: str) -> str:
        import re
        sql = sql.upper()
        sql = re.sub(r'\s+', ' ', sql)
        sql = sql.strip()
        return sql

# Run evaluation
evaluator = Evaluator(
    client=client,
    metrics=[
        "relevance",        # Built-in
        "coherence",        # Built-in
        "groundedness",     # Built-in
        SQLAccuracyMetric() # Custom
    ]
)

test_cases = [
    {
        "input": "What is our total revenue this year?",
        "expected_sql": "SELECT SUM(revenue) FROM sales WHERE YEAR(sale_date) = 2024",
        "expected_answer_contains": ["revenue", "total", "2024"]
    },
    {
        "input": "Show me customer count by region",
        "expected_sql": "SELECT region, COUNT(*) FROM customers GROUP BY region",
        "expected_answer_contains": ["region", "customers", "count"]
    }
]

results = await evaluator.evaluate(
    agent=data_analyst,
    test_cases=test_cases,
    num_runs=3  # Average over multiple runs
)

print(f"Overall Score: {results.overall_score:.2f}")
for metric, score in results.metric_scores.items():
    print(f"  {metric}: {score:.2f}")

Deploying to Production

# deployments/production.yaml
deployment:
  name: data-analyst-production
  agent: DataAnalyst

  compute:
    type: managed
    sku: Standard_D4s_v3
    min_instances: 2
    max_instances: 10

  scaling:
    metric: requests_per_second
    target: 100
    scale_up_threshold: 80
    scale_down_threshold: 20

  monitoring:
    application_insights: true
    custom_metrics:
      - query_latency
      - token_usage
      - error_rate

  security:
    authentication: azure_ad
    allowed_origins:
      - "https://app.contoso.com"
    rate_limiting:
      requests_per_minute: 100
      tokens_per_minute: 50000
# Deploy using SDK
deployment = client.deployments.create(
    project_name="data-analytics-assistant",
    config_path="deployments/production.yaml"
)

print(f"Deployment URL: {deployment.endpoint}")
print(f"Status: {deployment.status}")

Monitoring and Observability

from azure.ai.foundry.monitoring import Dashboard, Alert

# Create monitoring dashboard
dashboard = Dashboard(
    name="data-analyst-monitoring",
    project="data-analytics-assistant",
    panels=[
        {"type": "time_series", "metric": "request_count", "title": "Requests"},
        {"type": "time_series", "metric": "latency_p95", "title": "P95 Latency"},
        {"type": "pie_chart", "metric": "tool_usage", "title": "Tool Distribution"},
        {"type": "table", "metric": "error_logs", "title": "Recent Errors"}
    ]
)

# Set up alerts
alert = Alert(
    name="high-error-rate",
    condition="error_rate > 0.05",
    window_minutes=5,
    action="email",
    recipients=["oncall@company.com"]
)

client.monitoring.create_dashboard(dashboard)
client.monitoring.create_alert(alert)

Azure AI Foundry provides the foundation for building enterprise-grade AI applications with proper tooling, evaluation, and monitoring. The platform continues to evolve rapidly with new capabilities announced at Ignite 2024.

Resources

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.