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
DefaultAzureCredentialfor 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:
AIProjectClientconnects to your Foundry project using its endpoint.DefaultAzureCredentialsigns in without keys. Locally it uses your Azure CLI login; in Azure it can use a managed identity. No secrets in code.get_openai_client()returns an OpenAI-compatible client that's already pointed at your project.responses.createsends the request to the Responses API.modelis the deployment name;inputis the user prompt.output_textis 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
| Error | Likely cause |
|---|---|
| 401 / 403 | Not signed in, or your account lacks a role such as Azure AI User on the project |
| 404 | Wrong endpoint, or a deployment name that doesn't exist |
| 429 | Rate limit (tokens per minute) exceeded: wait and retry, or raise the deployment's quota |
| Content filter error | The 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.
Finished reading?
Tools mentioned in this article
JSON Formatter
Format and beautify JSON online. Pretty-print with 2 or 4 space indentation, validate syntax and copy or download the result. Free and private.
JSON to PythonNEW
Convert JSON to Python dataclasses with from_dict, Pydantic v2 models with aliases, or TypedDicts. Snake_case names, optional fields and nested models included.