Skip to content
XUtilHub

AI-901 courseLesson 8 of 14 · 14 min

Build a Chat App With the Microsoft Foundry SDK in Python (AI-901)

XUtilHub Team ·

Exam skills covered

  • Create a lightweight chat client application by using the Foundry SDK

AI-901 expects you to "create a lightweight chat client application by using the Foundry SDK". This lesson builds one in about 25 lines of Python and explains every line, because exam questions often show code like this and ask what a line does or what's missing.

What you need

  • Python 3.9 or later
  • A Foundry project with a deployed chat model (see the previous lesson)
  • The Azure CLI, signed in with az login
  • Your project endpoint

Install the packages

pip install "azure-ai-projects>=2.0" azure-identity
  • azure-ai-projects is the Foundry SDK. Version 2.x uses the new Foundry projects API.
  • azure-identity provides DefaultAzureCredential for keyless sign-in.

The simplest call

from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient

endpoint = "https://<resource-name>.services.ai.azure.com/api/projects/<project-name>"

project = AIProjectClient(endpoint=endpoint, credential=DefaultAzureCredential())
openai = project.get_openai_client()

response = openai.responses.create(
    model="gpt-5-mini",  # your deployment name
    input="Explain what a token is in one sentence.",
)
print(response.output_text)

Line by line:

  1. AIProjectClient connects to your Foundry project using its endpoint.
  2. DefaultAzureCredential signs in without keys. Locally it uses your Azure CLI login; in Azure it can use a managed identity. No secrets in code.
  3. get_openai_client() returns an OpenAI-compatible client that's already pointed at your project.
  4. responses.create sends the request to the Responses API. model is the deployment name; input is the user prompt.
  5. output_text is the model's reply as plain text.

Add a system prompt and parameters

response = openai.responses.create(
    model="gpt-5-mini",
    instructions="You are a patient tutor. Explain simply, using one example.",
    input="What is an embedding?",
    max_output_tokens=300,
)

instructions is the system prompt. Parameters such as max_output_tokens (and temperature on models that support it) work as described in the parameters lesson.

A multi-turn chat loop

Models are stateless: each request is independent. To hold a conversation you must give the model the history. With the Responses API you can chain responses with previous_response_id, or keep a server-side conversation:

from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient

project = AIProjectClient(
    endpoint="https://<resource-name>.services.ai.azure.com/api/projects/<project-name>",
    credential=DefaultAzureCredential(),
)
openai = project.get_openai_client()

conversation = openai.conversations.create()   # stores the chat history for you

print("Chat with the model. Type 'quit' to exit.")
while True:
    user_text = input("You: ")
    if user_text.lower() == "quit":
        break
    response = openai.responses.create(
        model="gpt-5-mini",
        instructions="You are a helpful, concise assistant.",
        conversation=conversation.id,
        input=user_text,
    )
    print("AI:", response.output_text)

Because every turn is added to the same conversation, the follow-up "And what's its capital?" after "Tell me about France" works as expected.

The older Chat Completions style does the same by sending a growing messages list with system, user and assistant roles:

messages = [{"role": "system", "content": "You are a helpful assistant."}]
messages.append({"role": "user", "content": "Tell me about France"})
completion = openai.chat.completions.create(model="gpt-5-mini", messages=messages)
messages.append({"role": "assistant", "content": completion.choices[0].message.content})

Recognise both patterns: roles (system, user, assistant) and sending the history each time.

Stream the answer

For a chat app, streaming shows text as it's generated:

stream = openai.responses.create(model="gpt-5-mini", input="Write a haiku about clouds", stream=True)
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)

Handle common errors

ErrorLikely cause
401 / 403Not signed in, or your account lacks a role such as Azure AI User on the project
404Wrong endpoint, or a deployment name that doesn't exist
429Rate limit (tokens per minute) exceeded: wait and retry, or raise the deployment's quota
Content filter errorThe prompt or response was blocked by the guardrails

Using keys instead of Entra ID

Some samples use an API key. That works for quick tests, but keys are secrets: never put them in code or source control. Store them in environment variables or Azure Key Vault. Entra ID with DefaultAzureCredential is the recommended approach.

Key takeaways

  • AIProjectClient(endpoint, DefaultAzureCredential()) → get_openai_client() → responses.create(model=<deployment>, input=...) → output_text.
  • instructions = system prompt; input = user prompt.
  • Models are stateless: keep context with conversations, previous_response_id, or a messages history.
  • Prefer keyless Entra ID auth over API keys.

Next lesson: build an AI agent in Foundry.

Check your understanding

Exam-style questions on this lesson. Get them all right to mark the lesson complete.

Question 1

1.Which Python package is the Foundry SDK for working with projects, models and agents?

Question 2

2.Which credential lets the same code sign in with your Azure CLI login locally and a managed identity in Azure?

Question 3

3.What does project.get_openai_client() return?

Question 4

4.How do you keep context across turns in a chat app?

Finished reading?

Tools mentioned in this article

← AI-901 course outline