Azure-AI_Foundry

Lesson 1: Agent Fundamentals

Learning Objectives

Reference: Azure AI Agent Service Quickstart


Agent Anatomy

An AI agent in Azure AI Foundry consists of five core components:

1. Instructions

The system-level prompt that defines the agent’s persona, behavior, and constraints. Think of this as the agent’s job description.

2. Model

The underlying LLM (e.g., GPT-4o, GPT-4o-mini) that powers the agent’s reasoning.

3. Tools

External capabilities the agent can invoke: Code Interpreter, File Search, function calling, and more.

4. Threads

Persistent conversation sessions that store the full message history. Threads are independent of the agent and can be reused across sessions.

5. Runs

A single execution cycle where the agent processes new messages in a thread. Each run has a lifecycle with defined statuses.


Run Lifecycle

When you create a run, it progresses through these statuses:

queued -> in_progress -> completed
                     -> requires_action (function calling)
                     -> failed / cancelled / expired

Creating Your First Agent: Complete Example

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

# 1. Connect to your AI Foundry project
client = AIProjectClient.from_connection_string(
    credential=DefaultAzureCredential(),
    conn_str="<your-project-connection-string>",
)

# 2. Create an agent with instructions and a model
agent = client.agents.create_agent(
    model="gpt-4o",
    name="research-assistant",
    instructions=(
        "You are a research assistant. Provide concise, well-sourced answers. "
        "When uncertain, say so rather than guessing."
    ),
)
print(f"Agent created: {agent.id}")

# 3. Create a thread (conversation session)
thread = client.agents.create_thread()
print(f"Thread created: {thread.id}")

# 4. Add a user message to the thread
message = client.agents.create_message(
    thread_id=thread.id,
    role="user",
    content="What are the key benefits of retrieval-augmented generation?",
)

# 5. Create a run to process the message
run = client.agents.create_run(thread_id=thread.id, agent_id=agent.id)

# 6. Poll until the run completes
while run.status in ("queued", "in_progress"):
    time.sleep(1)
    run = client.agents.get_run(thread_id=thread.id, run_id=run.id)

if run.status == "completed":
    messages = client.agents.list_messages(thread_id=thread.id)
    for msg in reversed(messages.data):
        print(f"[{msg.role}]: {msg.content[0].text.value}")
elif run.status == "failed":
    print(f"Run failed: {run.last_error}")

# 8. Cleanup
client.agents.delete_agent(agent.id)

Thread Management

Threads are the backbone of agent conversations. Key patterns:

# Continue a conversation by adding more messages
client.agents.create_message(
    thread_id=thread.id,
    role="user",
    content="Can you compare RAG with fine-tuning?",
)

# Create a new run on the same thread
follow_up_run = client.agents.create_run(
    thread_id=thread.id, agent_id=agent.id
)

# List all messages in a thread (paginated)
all_messages = client.agents.list_messages(thread_id=thread.id)
for msg in all_messages.data:
    print(f"{msg.role}: {msg.content[0].text.value[:100]}...")

Tip: Threads persist server-side. You can reconnect to an existing thread by storing the thread.id – no need to replay conversation history.


Using create_and_process_run for Simplicity

For straightforward use cases, the SDK offers a helper that creates a run and polls automatically:

run = client.agents.create_and_process_run(
    thread_id=thread.id, agent_id=agent.id
)
# No manual polling needed -- returns when complete or failed
print(f"Run status: {run.status}")

Best Practices

  1. Keep instructions focused: Avoid dumping everything into instructions. Use tools for dynamic data.
  2. Handle all run statuses: Always check for failed and requires_action, not just completed.
  3. Clean up agents: Delete agents you no longer need to stay within resource limits.
  4. Use meaningful agent names: Names like "finance-analyst" make debugging easier than "agent-1".
  5. Store thread IDs: Persist thread IDs in your application database for multi-session conversations.

Key Takeaways