Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
"""
DESCRIPTION:
Given an AIProjectClient, this sample demonstrates how to create an agent
optimization job and manually poll it to completion.
optimization job and poll its standard LRO to completion.

Agent optimization automatically improves an agent's system prompt, model
choice, or tool definitions by running candidate variants against your
training dataset and scoring them with the evaluators you specify.

USAGE:
python sample_optimization_job_basic_polling.py
python sample_optimization_job_advanced_app_polling.py

Before running the sample:

Expand All @@ -40,9 +40,9 @@
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
JobStatus,
OptimizationAgentIdentifier as AgentIdentifier,
OptimizationEvaluatorRef as EvaluatorRef,
JobStatus,
OptimizationJob,
OptimizationJobInputs,
OptimizationOptions,
Expand All @@ -60,7 +60,7 @@
eval_model = os.environ.get("EVAL_MODEL", "gpt-4o")
optimization_model = os.environ.get("OPTIMIZATION_MODEL", "gpt-5.1")

terminal_statuses = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED}
TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED}

with (
DefaultAzureCredential() as credential,
Expand All @@ -73,40 +73,48 @@
print("Creating optimization job...")
created_jobs: list[OptimizationJob] = []

def capture_created_job(response):
def raw_response_hook(response):
# Since `polling=False` is set below, it is guaranteed that `raw_response_hook` will be
# invoked once on the initial "201 Created" response, and `response` is of type `OptimizationJob`.
response.http_response.read()
created_jobs.append(OptimizationJob(response.http_response.json()))

job = OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
)
)

project_client.beta.agents.begin_create_optimization_job(
job=OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
)
),
job=job,
polling=False,
raw_response_hook=capture_created_job,
raw_response_hook=raw_response_hook,
)
if not created_jobs:
raise RuntimeError("The create operation did not return an optimization job.")
job = created_jobs[0]
print(f"Created job: id={job.id}, status={job.status}")

# ------------------------------------------------------------------
# 2. Poll the job to completion.
# 2. Poll until the job reaches a terminal state.
# ------------------------------------------------------------------
while job.status not in terminal_statuses:
print(f"Polling job `{job.id}` to completion...", end="", flush=True)
while job.status not in TERMINAL_STATUSES:
time.sleep(poll_interval)
job = project_client.beta.agents.get_optimization_job(job_id=job.id)
print(f"Job status: {job.status}")
print(".", end="", flush=True)
print()
print(f"Final job status: `{job.status}`.")

if job.warnings:
for warning in job.warnings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
"""
DESCRIPTION:
Given an async AIProjectClient, this sample demonstrates how to create an
agent optimization job and manually poll it to completion.
agent optimization job and poll it to completion.

Agent optimization automatically improves an agent's system prompt, model
choice, or tool definitions by running candidate variants against your
training dataset and scoring them with the evaluators you specify.

USAGE:
python sample_optimization_job_basic_polling_async.py
python sample_optimization_job_advanced_app_polling_async.py

Before running the sample:

pip install "azure-ai-projects>=2.4.0" azure-identity python-dotenv
pip install "azure-ai-projects>=2.4.0" azure-identity python-dotenv aiohttp

Set these environment variables with your own values:
1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found
Expand All @@ -33,19 +33,16 @@
"""

import asyncio
import json
import os

from dotenv import load_dotenv

from azure.core.pipeline import PipelineResponse
from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest
from azure.identity.aio import DefaultAzureCredential
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import (
JobStatus,
OptimizationAgentIdentifier as AgentIdentifier,
OptimizationEvaluatorRef as EvaluatorRef,
JobStatus,
OptimizationJob,
OptimizationJobInputs,
OptimizationOptions,
Expand All @@ -63,7 +60,7 @@
eval_model = os.environ.get("EVAL_MODEL", "gpt-4o")
optimization_model = os.environ.get("OPTIMIZATION_MODEL", "gpt-5.1")

terminal_statuses = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED}
TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED}


async def main() -> None:
Expand All @@ -76,44 +73,52 @@ async def main() -> None:
# 1. Create an optimization job without SDK polling.
# ------------------------------------------------------------------
print("Creating optimization job...")
initial_responses: list[PipelineResponse[HttpRequest, AsyncHttpResponse]] = []

def capture_created_job_response(
response: PipelineResponse[HttpRequest, AsyncHttpResponse],
) -> None:
initial_responses.append(response)
pipeline_responses = []

def raw_response_hook(response):
# The raw_response_hook is called synchronously before the generated LRO method
# awaits read() on the initial response. Capture the pipeline response object here
# and parse the body afterwards, when read() has already been awaited.
pipeline_responses.append(response)

job = OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
)
)

await project_client.beta.agents.begin_create_optimization_job(
job=OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
)
),
job=job,
polling=False,
raw_response_hook=capture_created_job_response,
raw_response_hook=raw_response_hook,
)
if not initial_responses:
# Alternatively, have the SDK handle polling by removing `polling=False`, assigning the awaited call
# to a poller, and then awaiting `poller.result()`.
if not pipeline_responses:
raise RuntimeError("The create operation did not return an optimization job.")
job = OptimizationJob(json.loads(initial_responses[0].http_response.text()))
job = OptimizationJob(pipeline_responses[0].http_response.json())
print(f"Created job: id={job.id}, status={job.status}")

# ------------------------------------------------------------------
# 2. Poll the job to completion.
# 2. Poll until the job reaches a terminal state.
# ------------------------------------------------------------------
while job.status not in terminal_statuses:
print(f"Polling job `{job.id}` to completion...", end="", flush=True)
while job.status not in TERMINAL_STATUSES:
await asyncio.sleep(poll_interval)
job = await project_client.beta.agents.get_optimization_job(job_id=job.id)
print(f"Job status: {job.status}")
print(".", end="", flush=True)
print()
print(f"Final job status: `{job.status}`.")

if job.warnings:
for warning in job.warnings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
"""
DESCRIPTION:
Given an AIProjectClient, this sample demonstrates how to create an agent
optimization job, poll it to completion, and read the results.
optimization job, observe the SDK poller until it is done, and then get
the result.

Agent optimization automatically improves an agent's system prompt, model
choice, or tool definitions by running candidate variants against your
training dataset and scoring them with the evaluators you specify.

USAGE:
python sample_optimization_job_basic.py
python sample_optimization_job_app_polling.py

Before running the sample:

Expand All @@ -23,16 +24,17 @@
Set these environment variables with your own values:
1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found
in the overview page of your Microsoft Foundry portal.
2) FOUNDRY_AGENT_NAME - Required. The name of the agent to optimize.
3) DATASET_NAME - Required. The name of the registered training dataset.
4) EVALUATOR_NAME - Required. The name of a registered project evaluator.
5) DATASET_VERSION - Optional. Version of the training dataset. Defaults to "1".
6) POLL_INTERVAL_SECONDS - Optional. Seconds between status polls. Defaults to 10.
7) EVAL_MODEL - Optional. The model used for evaluation. Defaults to "gpt-4o".
8) OPTIMIZATION_MODEL - Optional. The model used for optimization. Defaults to "gpt-5.1".
2) FOUNDRY_AGENT_NAME - Required. The name of the agent to optimize.
3) DATASET_NAME - Required. The name of the registered training dataset.
4) EVALUATOR_NAME - Required. The name of a registered project evaluator.
5) DATASET_VERSION - Optional. Version of the training dataset. Defaults to "1".
6) POLL_INTERVAL_SECONDS - Optional. Seconds between status polls. Defaults to 10.
7) EVAL_MODEL - Optional. The model used for evaluation. Defaults to "gpt-4o".
8) OPTIMIZATION_MODEL - Optional. The model used for optimization. Defaults to "gpt-5.1".
"""

import os
import time

from dotenv import load_dotenv

Expand Down Expand Up @@ -64,28 +66,39 @@
):

# ------------------------------------------------------------------
# 1. Create an optimization job.
# 1. Create an optimization job and observe the SDK-managed poller.
# ------------------------------------------------------------------
print("Creating optimization job...")
result = project_client.beta.agents.begin_create_optimization_job(
job=OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
)
job = OptimizationJob(
inputs=OptimizationJobInputs(
agent=AgentIdentifier(agent_name=agent_name),
train_dataset=ReferenceDatasetInput(
name=dataset_name,
version=dataset_version,
),
evaluators=[EvaluatorRef(name=evaluator_name)],
options=OptimizationOptions(
max_candidates=3,
eval_model=eval_model,
optimization_model=optimization_model,
),
),
)

print("Begin creating an agent optimization job.")
poller = project_client.beta.agents.begin_create_optimization_job(
job=job,
polling_interval=poll_interval,
).result()
print("Optimization job completed.")
)

print("Optional: While SDK is polling, periodically print the job status until the job is complete")
while not poller.done():
time.sleep(poll_interval)
print(f"status=`{poller.status()}`")

# Since done() is true, result() returns the final deserialized job result without
# waiting further. It also propagates any LRO polling exception.
result = poller.result()
print(f"Final LRO status: `{poller.status()}`.")

# ------------------------------------------------------------------
# 2. Inspect the results.
Expand Down
Loading
Loading