Skip to content

[Feature] Add Azure OpenAI provider for enterprise deployments #174

Description

@mimran-khan

Summary

Many enterprise organizations use Azure OpenAI Service rather than the public OpenAI API. Azure OpenAI has a fundamentally different authentication model — it uses Azure AD tokens or API keys scoped to a resource endpoint, and models are referenced by deployment name rather than model ID.

Today, SkillSpector's openai provider assumes stock OpenAI conventions (OPENAI_API_KEY + model IDs like gpt-5.4). While OPENAI_BASE_URL can point to an Azure endpoint, Azure requires an api-version query parameter and uses deployment-based routing that ChatOpenAI doesn't handle correctly. LangChain provides a dedicated AzureChatOpenAI class for this.

Why This Matters

Scenario: Enterprise security team behind Azure-only policy

A company's infosec policy routes all AI traffic through their Azure OpenAI resource. They have GPT-4o deployed as security-gpt4o. They try:

export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY=<azure-key>
export OPENAI_BASE_URL=https://myorg.openai.azure.com/
export SKILLSPECTOR_MODEL=security-gpt4o

skillspector scan ./agent-skill/

This fails because:

  1. Azure requires api-version in the URL (e.g., 2024-06-01)
  2. The deployment name security-gpt4o is not a valid OpenAI model ID
  3. Azure endpoints use a different path structure (/openai/deployments/{name}/chat/completions)

They're forced to either skip LLM analysis entirely or set up a proxy that translates between OpenAI and Azure formats.

Proposed Implementation

providers/
  azure_openai/
    __init__.py
    provider.py
    model_registry.yaml

Environment variables:

Variable Required Description
AZURE_OPENAI_ENDPOINT Yes Azure resource endpoint (e.g., https://myorg.openai.azure.com/)
AZURE_OPENAI_API_KEY Yes* Azure API key (*or use Azure AD via AZURE_OPENAI_AD_TOKEN)
AZURE_OPENAI_DEPLOYMENT Yes Deployment name (used as azure_deployment in LangChain)
AZURE_OPENAI_API_VERSION No API version (default: 2024-06-01)

provider.py:

from langchain_openai import AzureChatOpenAI

class AzureOpenAIProvider:
    DEFAULT_MODEL = "gpt-4o"
    SLOT_DEFAULTS: dict[str, str] = {}

    def resolve_credentials(self) -> tuple[str, str | None] | None:
        api_key = os.environ.get("AZURE_OPENAI_API_KEY", "").strip()
        endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT", "").strip()
        if not api_key or not endpoint:
            return None
        return api_key, endpoint

    def create_chat_model(self, model, *, max_tokens, timeout=120):
        creds = self.resolve_credentials()
        if creds is None:
            return None
        api_key, endpoint = creds
        deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT", model).strip()
        api_version = os.environ.get("AZURE_OPENAI_API_VERSION", "2024-06-01").strip()
        return AzureChatOpenAI(
            azure_endpoint=endpoint,
            azure_deployment=deployment,
            api_key=api_key,
            api_version=api_version,
            max_tokens=max_tokens,
            timeout=timeout,
        )

Selection:

export SKILLSPECTOR_PROVIDER=azure_openai
export AZURE_OPENAI_ENDPOINT=https://myorg.openai.azure.com/
export AZURE_OPENAI_API_KEY=<key>
export AZURE_OPENAI_DEPLOYMENT=security-gpt4o

skillspector scan ./my-skill/

Scope

  • New providers/azure_openai/ subpackage (~60 lines)
  • Registration in providers/__init__.py (~5 lines)
  • Tests: credential resolution, deployment name mapping, API version defaults
  • Documentation: add Azure to README provider table and .env.example

Dependency

langchain-openai already ships AzureChatOpenAI — no new dependency needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions