Skip to content
THE EXAMTOPICS EDITORIAL Explore practice exams

MICROSOFT

Building AI-103 Apps with Python and Microsoft Foundry

Build a Foundry-backed Python agent step by step, with project authentication, conversation handling, tool boundaries and production error checks.

Many Azure AI demonstrations begin after the difficult parts are already solved: someone has provisioned a project, granted permissions, deployed a model, configured a connection and supplied a perfect sample question. The model’s response then looks like the whole application. In production, those surrounding decisions determine whether the application is secure, repeatable and recoverable. Microsoft makes Python and project-level SDK integration explicit in its current AI-103 developer blueprint for precisely that reason.

This article develops a deliberately modest application: a service assistant that answers policy questions and may prepare, but not independently approve, an equipment-return request. The goal is to understand how a Foundry project, agent definition, conversation, tools, data retrieval and monitoring fit together. It extends the architectural concepts behind the AI-103 exam with a practical implementation path and a failure model, while keeping deployment-specific choices clearly separated from what the example can prove without access to your Azure tenant.

Distinguish the project, deployment and agent

A Foundry project is the environment through which an application obtains access to its configured models, connections and agent capabilities. The project endpoint identifies that environment; it is not the same as a generic model endpoint or a legacy hub connection string. A model deployment supplies inference capability. A prompt agent adds a versioned definition of how a model should behave, including its instructions and any configured tools. A conversation can hold the interaction history for one user flow without changing the definition of the agent itself.

These objects should not be collapsed into a single “chatbot” variable. One agent definition may handle many separate conversations. The business request belongs in an application database, not in the agent definition or solely in conversation memory. An authorized tool call can affect an external system, which means it needs stronger validation than an ordinary response. The distinction is central to agent tools, conversations and durable memory and becomes even more important when multiple agents share the same workflow.

Microsoft’s newer Foundry SDK follows the project-endpoint pattern. Older tutorials may show thread/run objects or earlier agents libraries; those examples can describe a valid historical API but should not be mixed casually with current project client calls. Before following an example, check the SDK version, project type, endpoint format and model deployment it assumes. A common debugging mistake is using a perfectly valid credential against a resource or API version for which the code was not written.

Connect from Python without embedding a credential

Begin with a Foundry project and a deployed model suitable for the task. Obtain the project endpoint from the Foundry portal and confirm the project identity has permission to use the deployment. For a local developer, Azure CLI sign-in and DefaultAzureCredential provide an identity-based path. For a deployed application, a correctly scoped managed identity is preferable to a long-lived key stored in source. The endpoint identifies where to call; the identity determines who is calling; the role assignment determines what the caller may do.

Microsoft’s current Python quickstart uses the azure-ai-projects package with azure-identity. Install a version compatible with the chosen Foundry project APIs, for example the current project-client family shown in Microsoft’s documentation, and authenticate using az login during local development. Put the endpoint and deployment name in environment configuration, not inside committed application code:

pip install "azure-ai-projects>=2.3.0" azure-identity
az login
# Supply these via your shell or application configuration:
FOUNDRY_PROJECT_ENDPOINT=https://YOUR-RESOURCE.services.ai.azure.com/api/projects/YOUR-PROJECT
FOUNDRY_MODEL_DEPLOYMENT=YOUR_DEPLOYED_MODEL_NAME
FOUNDRY_AGENT_NAME=equipment-helpdesk

The values above are configuration examples, not commands that create resources or grant roles. The application should fail clearly if an expected value is missing and should avoid printing access tokens or sensitive connection metadata. If authentication succeeds but the model or agent call is denied, inspect project scope, role assignment and runtime identity separately. If the request times out, do not immediately widen permissions; check network path, endpoint resolution, quota and service health first. The deeper distinction between Foundry networking and managed identity matters here because a private endpoint does not grant authorization, and a valid identity does not establish network reachability.

Create a versioned prompt agent and open a conversation

For a scenario with a stable purpose and recurring interactions, a managed prompt agent is a useful starting point. It defines a behavior once, while conversations retain the history of individual interactions. The following condensed example follows the current Foundry project-client pattern; replace deployment configuration with names that actually exist in the account. Its job is intentionally read-only: it should provide information or ask for missing evidence, not change the business database.

import os
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
model = os.environ["FOUNDRY_MODEL_DEPLOYMENT"]
agent_name = os.environ.get("FOUNDRY_AGENT_NAME", "equipment-helpdesk")
project = AIProjectClient(
    endpoint=endpoint,
    credential=DefaultAzureCredential(),
)
agent_version = project.agents.create_version(
    agent_name=agent_name,
    definition=PromptAgentDefinition(
        model=model,
        instructions=(
            "Explain equipment-return policy using approved evidence. "
            "When evidence is missing, say what needs verification. "
            "Never claim a return request was submitted."
        ),
    ),
)
agent_client = project.get_openai_client(agent_name=agent_name)
conversation = agent_client.conversations.create()
reply = agent_client.responses.create(
    conversation=conversation.id,
    input="What happens if my laptop was purchased by my department?",
)
print(reply.output_text)

This code illustrates the principal objects rather than every production concern. Microsoft Foundry APIs and supported packages change, so test the exact installed SDK and deployment pair before shipping. Creating a new agent version is a lifecycle operation; production code normally does not create a fresh version for every customer request. Provision or update the agent through a controlled deployment process, then let the application invoke the approved version. Persist conversation identifiers only in a user-scoped application store, and validate ownership before a user resumes a conversation.

For an ephemeral agent whose instructions and tool wiring should live entirely with application source, Microsoft’s project-scoped Responses API is another supported pattern. It is a different lifecycle choice from a managed, versioned prompt agent. Do not blend both patterns in one example without explaining who owns the agent definition and how it is deployed. What matters for AI-103 is recognizing when managed identity, reusable agent versions, local orchestration or a direct model response is appropriate for the requirements.

Put real evidence and business actions behind separate interfaces

The service assistant needs current policy documents. That is a retrieval problem, not a reason to append every internal procedure to the system prompt. A practical ingestion pipeline parses source content, retains effective dates and department boundaries, applies access metadata, and indexes suitable passages for retrieval. At query time, the retrieval service should enforce the user’s eligible document set before any passage reaches the model. The decision between lexical, vector, hybrid and agentic retrieval depends on the corpus and the question, as explained in the dedicated RAG and grounding discussion.

For an equipment-return workflow, a retrieved policy may state that a manager must approve a request. The agent may explain the requirement or prepare a draft, but the act of submission belongs to a different tool with a narrower contract. Design that tool as an ordinary application API: validated arguments, authenticated actor, idempotency key, stored approval state, explicit error types and an audit record. The model should never be the final judge of whether a user has sufficient privilege.

The application might accept a proposed return request with employee ID, asset ID, reason and an approval reference. Each field should be validated against authoritative systems before any write. “Approved” written in chat is not a valid approval reference. A safer pattern keeps the submission endpoint disabled until the application can verify an independent authorization record. If the tool returns a timeout after receiving the request, the caller should reconcile the operation’s idempotency key or server-side status before attempting another write.

A narrow tool also makes evaluation clearer. It should be possible to test that the agent chooses a lookup when a policy question is asked, chooses a draft action when the request has enough information, and never chooses the final submission step without verified permission. If the agent misuses a tool, inspect the description and proposed parameters, but do not rely on stronger prompt wording to replace an API-side control.

Treat failures as first-class application states

An AI call can fail before the model produces a word. Missing environment configuration, expired identity, incorrect project scope, regional model availability, quota exhaustion and private-network DNS errors all deserve distinct diagnostics. Once a response begins, retrieval might be empty, a tool may return invalid data, or the generated output may violate a schema. These failures should not all become “something went wrong,” because operators need to locate the component that owns the repair.

Keep the error boundary around each stage. An authorization denial is not a transient event to retry with a more privileged identity. A rate limit may justify bounded backoff if the operation is safe to repeat. A failed retrieval may call for a clearer no-answer response. A business action with uncertain commit status requires readback or reconciliation, not blind resubmission. This makes the difference between a credible developer implementation and a demonstration that only handles ideal inputs.

Even successful model responses should be checked before downstream use. Parse any required structured output, validate its fields, reject invented business identifiers, and preserve evidence references. An unsupported response can be readable and persuasive while still being unsuitable for automation. For safety-sensitive work, the guardrail and approval design must operate across input, retrieval, tool execution and final output rather than appearing as one instruction to “be responsible.”

Make evaluation and tracing part of the application

A trace should explain the steps that actually ran: model invocation, search query, retrieval identifiers, tool calls, timing, retry decisions and outcome. An operator investigating a wrong answer should be able to distinguish a failed policy lookup from an error in the model’s final wording. Link trace IDs to a sanitized evaluation record rather than storing every raw employee message indefinitely. Privacy rules still apply to generated content and telemetry.

Before deploying a prompt-agent change, create a small evaluation set with normal policy questions, contradictory documents, unanswerable requests, forged approval text and a malformed tool response. Track groundedness, task completion, correct tool selection and explicit denial of unauthorized actions separately. A system that improves average response quality but starts creating requests without approval has failed. The core methods of tracing and AI evaluation give each failure a measurable owner.

Evaluation should not stop after launch. Deployments, prompt instructions, tool schemas, model versions and search indexes change independently. Record which set of versions handled a response, watch for rising latency or unsupported answers, and add real sanitized failures to the regression set. One control might be improved while another becomes weaker; separating metrics is the only way to make those trade-offs visible.

Security monitoring adds a second lens. A successful tool call may still be a policy violation if the wrong principal was allowed to reach it. Record the authorized actor, resource scope and action identifier where appropriate, but never expose secret tokens in traces. The application should reveal when a control blocked an operation and should treat repeated authorization failures as signals requiring investigation, not prompts for automatic privilege expansion.

Release the project as versioned software, not a saved playground state

A repeatable release includes application code, installed SDK versions, agent definition, model deployment reference, prompt version, tool schema, search configuration and evaluation threshold. Separate sensitive credentials from those artifacts. A change to a tool parameter can break the agent without changing the application endpoint; a retrieval index can lose a required access field while the model remains healthy. Build release checks around those contracts.

Use a controlled path from development to test and production. In test, verify project identity under production-like permission restrictions and use a representative search index rather than only toy documents. Check that the generated agent version is the one the application intends to invoke. A staged release or canary can reveal increased latency, poor grounding or unsafe tool selection before the entire user base is affected. Keep a rollback plan that restores not only code but the behavioral configuration and compatible retrieval schema.

The broader GenAIOps lifecycle connects these decisions to automated tests and production ownership. If the organization cannot identify which agent version processed a request, or cannot restore the earlier tool contract after a regression, it lacks an operationally complete implementation no matter how impressive the model’s answer sounds.

Use the implementation to reason about exam scenarios

An AI-103 question may describe a Python client that receives a permission error after a successful local test. The first investigation is which identity the deployed process actually uses and what role it has at the project and data-plane resources. Another may describe answers that are accurate in development but stale in production; this points toward index freshness, retrieval filters and source lifecycle, not simply a different model. A third may describe an agent issuing duplicate orders after a network timeout; the right fix belongs in idempotent business tooling and readback rather than a prompt that asks the model to “be careful.”

Finally, be able to distinguish a managed prompt agent from an ephemeral Responses API agent, and a conversation identifier from authoritative business state. Those are implementation details with real consequences for versioning, security and recovery. Someone who has built this modest assistant, tested denial paths and traced one failed request will recognize those consequences much faster than someone who has memorized an SDK method list without using it.

The value of a Foundry project is not that it makes application architecture disappear. It provides a defined surface through which models, agents, identity and tools can be combined. The developer’s responsibility is to choose useful boundaries, enforce them in ordinary software and show with evidence that the composed system behaves as intended.

Continue exploring the technologies and certification concepts that matter most to you.