Skip to content

Step 1 - Microsoft Foundry + LangChain

Goal

By the end of this step you will have:

  • a working uv-managed Python environment,
  • a .env pointing at your Microsoft Foundry project,
  • and a working Typer CLI that can call chat, agent, embedding, and vector-store flows against a Foundry-hosted model.

Why this step exists

Microsoft Foundry exposes models behind two endpoint shapes:

  • a project endpoint (https://<resource>.services.ai.azure.com/api/projects/<project>) used for chat completions, agents, and most APIs,
  • a resource-level OpenAI v1 endpoint (https://<resource>.services.ai.azure.com/openai/v1) required for embeddings (the project-scoped path does not currently serve embeddings - this nuance is encoded in scripts/microsoft_foundry/vanilla.py.

LangChain ships first-class integrations through langchain-azure-ai, so we standardise on that package and keep our code thin.

sequenceDiagram
    autonumber
    actor Dev as Developer
    participant CLI as Typer CLI
    participant Cred as DefaultAzureCredential
    participant LC as LangChain (langchain-azure-ai)
    participant Foundry as Foundry project endpoint
    participant Model as Deployed model (gpt-5)

    Dev->>CLI: uv run python scripts/microsoft_foundry/vanilla.py hello-world
    CLI->>Cred: get token
    Cred-->>CLI: AAD token
    CLI->>LC: init_chat_model("azure_ai:gpt-5")
    LC->>Foundry: POST /chat/completions (Bearer token)
    Foundry->>Model: forward prompt
    Model-->>Foundry: completion
    Foundry-->>LC: response
    LC-->>CLI: AIMessage
    CLI-->>Dev: pretty-printed answer

Prerequisites checklist

  • You completed the Overview prerequisites.
  • You have run az login and selected the subscription that owns the Foundry project.
  • At least one chat model is deployed in your Foundry project.

Steps

1.1 Clone and bootstrap

git clone https://github.com/ks6088ts-labs/concierge.git
cd concierge

# Installs runtime + dev + docs groups into .venv via uv
make install-deps-dev

# Creates a local environment file from the repository template
cp .env.template .env

make install-deps-dev runs uv sync --all-groups and installs the pre-commit hooks. After this you have an isolated .venv containing langchain, langgraph, langchain-azure-ai, azure-identity, and the rest of pyproject.toml.

1.2 Configure environment variables

Open the .env file you copied from .env.template. The required Foundry value comes from your project overview page (Microsoft Foundry → your project → OverviewProject details).

# .env
AZURE_AI_PROJECT_ENDPOINT=https://<your-resource>.services.ai.azure.com/api/projects/<your-project>

The endpoint is bound to a typed settings class in concierge/settings/microsoft_foundry.py:

class MicrosoftFoundrySettings(BaseSettings):
    azure_ai_project_endpoint: str = ""

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

Why Pydantic Settings?

Reading config through pydantic-settings gives us a single typed entry point that works the same way for local .env files, CI secrets, and container environment variables - no os.environ scattered across the code.

1.3 Run your first chat call

uv run python scripts/microsoft_foundry/vanilla.py hello-world \
    --query "Hello, how are you doing today?"

What happens under the hood:

# scripts/microsoft_foundry/vanilla.py (simplified)
from langchain.chat_models import init_chat_model

chat_model = init_chat_model("azure_ai:gpt-5")
response = chat_model.invoke(query)
response.pretty_print()

init_chat_model accepts the "<provider>:<model>" shorthand and resolves azure_ai to the langchain-azure-ai integration. The script loads .env before Typer runs, so AZURE_AI_PROJECT_ENDPOINT is available to the provider integration. Commands that build clients directly (direct-client, tracing, and embeddings) also read the same value through get_microsoft_foundry_settings().

Use deployment names

The --model values in the examples are deployment names. Keep the defaults if your Foundry project uses gpt-5 and text-embedding-3-small; otherwise replace them with the names shown under Models + endpoints in your project.

1.4 Explore the other CLI commands

List every subcommand:

uv run python scripts/microsoft_foundry/vanilla.py --help
Subcommand What it demonstrates Upstream docs
hello-world Plain chat call with init_chat_model Use chat models
configurable Pass temperature and switch model at call time Configurable models
direct-client Build AzureAIOpenAIApiChatModel directly Configure clients directly
async-call ainvoke with the async DefaultAzureCredential Run asynchronous calls
reasoning Stream reasoning content blocks (use a reasoning-capable model) Reasoning
server-side-tools Bind built-in WebSearchTool to the model Server-side tools
use-in-agents Wrap the model in a langchain.agents.create_agent agent Use Foundry models in agents
embeddings Call an embedding model via init_embeddings Use embedding models
embeddings-direct Same flow with AzureAIOpenAIApiEmbeddingsModel Use embedding models
vector-store-search End-to-end embed + similarity search with InMemoryVectorStore Run similarity search with a vector store

A few worth running now:

uv run python scripts/microsoft_foundry/vanilla.py configurable \
    --model gpt-5 --temperature 0.2 \
    --query "Summarise LangGraph in one sentence."
uv run python scripts/microsoft_foundry/vanilla.py reasoning \
    --model azure_ai:DeepSeek-R1-0528
uv run python scripts/microsoft_foundry/vanilla.py embeddings \
    --text "The quick brown fox jumps over the lazy dog."

uv run python scripts/microsoft_foundry/vanilla.py vector-store-search \
    --query thud --k 1

Embeddings need the resource-level endpoint

The helper _resource_openai_v1_endpoint() in scripts/microsoft_foundry/vanilla.py strips /api/projects/<project> off your AZURE_AI_PROJECT_ENDPOINT and replaces it with /openai/v1. You do not need to set a second env var, but you do need a text-embedding-* deployment on the same resource.

Verify

A successful run looks like this (output truncated):

================================== Ai Message ==================================

Hello! I'm doing well, thanks for asking. ...

If you see AIMessage content printed via pretty_print, the model wiring is correct.

Troubleshooting

DefaultAzureCredential failed to retrieve a token

Run az login again, or set AZURE_TENANT_ID / AZURE_CLIENT_ID / AZURE_CLIENT_SECRET if you must use a service principal. See DefaultAzureCredential docs.

DeploymentNotFound or 404 model_not_found

The string passed to init_chat_model (e.g. azure_ai:gpt-5) must match a deployment name in your Foundry project, not the model name. Open Foundry → Models + endpoints to check.

Embeddings call returns 404

Confirm that an embedding model (e.g. text-embedding-3-small) is deployed on the resource that backs the project, and that the _resource_openai_v1_endpoint() URL is reachable from your machine.

What's next

You can talk to Foundry models, but you cannot yet see what is happening inside each call. The next step adds observability so you can debug prompts, latency, and token usage end-to-end.

Continue with Step 2 - Observability (Tracing & MLflow).