Skip to content

Commit fe956b3

Browse files
authored
Adding fine-tuning samples and tests (#44003)
1 parent ee70841 commit fe956b3

32 files changed

+2218
-161
lines changed

sdk/ai/azure-ai-projects/.env.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ AZURE_AI_MODEL_DEPLOYMENT_NAME=
2020
AGENT_NAME=
2121
CONVERSATION_ID=
2222
CONNECTION_NAME=
23+
AZURE_AI_PROJECTS_AZURE_SUBSCRIPTION_ID=
24+
AZURE_AI_PROJECTS_AZURE_RESOURCE_GROUP=
25+
AZURE_AI_PROJECTS_AZURE_AOAI_ACCOUNT=
2326

2427
#######################################################################
2528
#

sdk/ai/azure-ai-projects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
### Bugs Fixed
1313

1414
### Sample updates
15+
* Added `finetuning` samples for operations create, retrieve, list, list_events, list_checkpoints, cancel, pause and resume. Also, these samples includes various finetuning techniques like Supervised (SFT), Reinforcement (RFT) and Direct performance optimization (DPO).
1516

1617
## 2.0.0b1 (2025-11-11)
1718

sdk/ai/azure-ai-projects/README.md

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -716,57 +716,127 @@ with open(file_path, "rb") as f:
716716
uploaded_file = openai_client.files.create(file=f, purpose="fine-tune")
717717
print(uploaded_file)
718718

719-
print(f"Retrieving file metadata with ID: {uploaded_file.id}")
720-
retrieved_file = openai_client.files.retrieve(uploaded_file.id)
719+
print("Waits for the given file to be processed, default timeout is 30 mins")
720+
processed_file = openai_client.files.wait_for_processing(uploaded_file.id)
721+
print(processed_file)
722+
723+
print(f"Retrieving file metadata with ID: {processed_file.id}")
724+
retrieved_file = openai_client.files.retrieve(processed_file.id)
721725
print(retrieved_file)
722726

723-
print(f"Retrieving file content with ID: {uploaded_file.id}")
724-
file_content = openai_client.files.content(uploaded_file.id)
727+
print(f"Retrieving file content with ID: {processed_file.id}")
728+
file_content = openai_client.files.content(processed_file.id)
725729
print(file_content.content)
726730

727731
print("Listing all files:")
728732
for file in openai_client.files.list():
729733
print(file)
730734

731-
print(f"Deleting file with ID: {uploaded_file.id}")
732-
deleted_file = openai_client.files.delete(uploaded_file.id)
735+
print(f"Deleting file with ID: {processed_file.id}")
736+
deleted_file = openai_client.files.delete(processed_file.id)
733737
print(f"Successfully deleted file: {deleted_file.id}")
734738
```
735739

736740
<!-- END SNIPPET -->
737741

738-
## Tracing
742+
### Fine-tuning operations
739743

740-
**Note:** Tracing functionality is in preliminary preview and is subject to change. Spans, attributes, and events may be modified in future versions.
744+
The code below shows Fine-tuning operations using the OpenAI client, which allow you to create, retrieve, list, cancel, pause, resume, and manage fine-tuning jobs. These operations support various fine-tuning techniques like Supervised Fine-Tuning (SFT), Reinforcement Fine-Tuning (RFT), and Direct Performance Optimization (DPO). Full samples can be found under the "finetuning" folder in the [package samples][samples].
741745

742-
You can add an Application Insights Azure resource to your Microsoft Foundry project. See the Tracing tab in your AI Foundry project. If one was enabled, you can get the Application Insights connection string, configure your AI Projects client, and observe traces in Azure Monitor. Typically, you might want to start tracing before you create a client or Agent.
746+
<!-- SNIPPET:sample_finetuning_supervised_job.finetuning_supervised_job_sample-->
743747

744-
### Installation
748+
```python
749+
print("Uploading training file...")
750+
with open(training_file_path, "rb") as f:
751+
train_file = openai_client.files.create(file=f, purpose="fine-tune")
752+
print(f"Uploaded training file with ID: {train_file.id}")
753+
754+
print("Uploading validation file...")
755+
with open(validation_file_path, "rb") as f:
756+
validation_file = openai_client.files.create(file=f, purpose="fine-tune")
757+
print(f"Uploaded validation file with ID: {validation_file.id}")
758+
759+
# For OpenAI model supervised fine-tuning jobs, "Standard" is the default training type.
760+
# To use global standard training, uncomment the extra_body parameter below.
761+
print("Creating supervised fine-tuning job")
762+
fine_tuning_job = openai_client.fine_tuning.jobs.create(
763+
training_file=train_file.id,
764+
validation_file=validation_file.id,
765+
model=model_name,
766+
method={
767+
"type": "supervised",
768+
"supervised": {"hyperparameters": {"n_epochs": 3, "batch_size": 1, "learning_rate_multiplier": 1.0}},
769+
},
770+
# extra_body={"trainingType":"GlobalStandard"}
771+
)
772+
print(fine_tuning_job)
745773

746-
Make sure to install OpenTelemetry and the Azure SDK tracing plugin via
774+
print(f"Getting fine-tuning job with ID: {fine_tuning_job.id}")
775+
retrieved_job = openai_client.fine_tuning.jobs.retrieve(fine_tuning_job.id)
776+
print(retrieved_job)
747777

748-
```bash
749-
pip install azure-ai-projects azure-identity opentelemetry-sdk azure-core-tracing-opentelemetry
750-
```
778+
print("Listing all fine-tuning jobs:")
779+
for job in openai_client.fine_tuning.jobs.list():
780+
print(job)
751781

752-
You will also need an exporter to send telemetry to your observability backend. You can print traces to the console or use a local viewer such as [Aspire Dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone?tabs=bash).
782+
print("Listing only 10 fine-tuning jobs:")
783+
for job in openai_client.fine_tuning.jobs.list(limit=10):
784+
print(job)
753785

754-
To connect to Aspire Dashboard or another OpenTelemetry compatible backend, install OTLP exporter:
786+
print(f"Pausing fine-tuning job with ID: {fine_tuning_job.id}")
787+
paused_job = openai_client.fine_tuning.jobs.pause(fine_tuning_job.id)
788+
print(paused_job)
755789

756-
```bash
757-
pip install opentelemetry-exporter-otlp
758-
```
790+
print(f"Resuming fine-tuning job with ID: {fine_tuning_job.id}")
791+
resumed_job = openai_client.fine_tuning.jobs.resume(fine_tuning_job.id)
792+
print(resumed_job)
759793

760-
### How to enable tracing
794+
print(f"Listing events of fine-tuning job: {fine_tuning_job.id}")
795+
for event in openai_client.fine_tuning.jobs.list_events(fine_tuning_job.id):
796+
print(event)
761797

762-
Here is a code sample that shows how to enable Azure Monitor tracing:
798+
# Note that to retrieve the checkpoints, job needs to be in terminal state.
799+
print(f"Listing checkpoints of fine-tuning job: {fine_tuning_job.id}")
800+
for checkpoint in openai_client.fine_tuning.jobs.checkpoints.list(fine_tuning_job.id):
801+
print(checkpoint)
763802

764-
<!-- SNIPPET:sample_agent_basic_with_azure_monitor_tracing.setup_azure_monitor_tracing -->
803+
print(f"Cancelling fine-tuning job with ID: {fine_tuning_job.id}")
804+
cancelled_job = openai_client.fine_tuning.jobs.cancel(fine_tuning_job.id)
805+
print(f"Successfully cancelled fine-tuning job: {cancelled_job.id}, Status: {cancelled_job.status}")
765806

766-
```python
767-
# Enable Azure Monitor tracing
768-
application_insights_connection_string = project_client.telemetry.get_application_insights_connection_string()
769-
configure_azure_monitor(connection_string=application_insights_connection_string)
807+
# Deploy model (using Azure Management SDK - azure-mgmt-cognitiveservices)
808+
# Note: Deployment can only be started after the fine-tuning job completes successfully.
809+
print(f"Getting fine-tuning job with ID: {fine_tuning_job.id}")
810+
fine_tuned_model_name = openai_client.fine_tuning.jobs.retrieve(fine_tuning_job.id).fine_tuned_model
811+
deployment_name = "gpt-4-1-fine-tuned"
812+
813+
with CognitiveServicesManagementClient(credential=credential, subscription_id=subscription_id) as cogsvc_client:
814+
815+
deployment_model = DeploymentModel(format="OpenAI", name=fine_tuned_model_name, version="1")
816+
817+
deployment_properties = DeploymentProperties(model=deployment_model)
818+
819+
deployment_sku = Sku(name="GlobalStandard", capacity=100)
820+
821+
deployment_config = Deployment(properties=deployment_properties, sku=deployment_sku)
822+
823+
deployment = cogsvc_client.deployments.begin_create_or_update(
824+
resource_group_name=resource_group,
825+
account_name=account_name,
826+
deployment_name=deployment_name,
827+
deployment=deployment_config,
828+
)
829+
830+
while deployment.status() not in ["Succeeded", "Failed"]:
831+
time.sleep(30)
832+
print(f"Status: {deployment.status()}")
833+
834+
print(f"Testing fine-tuned model via deployment: {deployment_name}")
835+
836+
response = openai_client.responses.create(
837+
model=deployment_name, input=[{"role": "user", "content": "Who invented the telephone?"}]
838+
)
839+
print(f"Model response: {response.output_text}")
770840
```
771841

772842
<!-- END SNIPPET -->

sdk/ai/azure-ai-projects/cspell.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"fstring",
2020
"aiprojectclient",
2121
"Tadmaq",
22-
"Udbk"
22+
"Udbk",
23+
"Ministral",
24+
"cogsvc"
2325
],
2426
"ignorePaths": [
2527
"*.csv",

sdk/ai/azure-ai-projects/dev_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ openai
88
opentelemetry-sdk
99
azure-core-tracing-opentelemetry
1010
azure-monitor-opentelemetry
11+
azure-mgmt-cognitiveservices
1112

sdk/ai/azure-ai-projects/samples/files/sample_files.py

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
"""
88
DESCRIPTION:
99
Given an AIProjectClient, this sample demonstrates how to use the synchronous
10-
file operations using the OpenAI client: create, retrieve, content, list, and delete.
10+
file operations using the OpenAI client: create, wait_for_processing, retrieve, content, list, and delete.
1111
1212
USAGE:
1313
python sample_files.py
1414
1515
Before running the sample:
1616
17-
pip install azure-ai-projects azure-identity openai python-dotenv
17+
pip install azure-ai-projects>=2.0.0b1 azure-identity openai python-dotenv
1818
1919
Set these environment variables with your own values:
20-
1) PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your
21-
Microsoft Foundry project.
20+
1) AZURE_AI_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your
21+
Microsoft Foundry portal.
2222
2) FILE_PATH - Optional. Path to the file to upload. Defaults to the `data` folder.
2323
"""
2424

@@ -34,31 +34,34 @@
3434
script_dir = Path(__file__).parent
3535
file_path = os.environ.get("FILE_PATH", os.path.join(script_dir, "data", "test_file.jsonl"))
3636

37-
with DefaultAzureCredential(exclude_interactive_browser_credential=False) as credential:
38-
39-
with AIProjectClient(endpoint=endpoint, credential=credential) as project_client:
40-
41-
with project_client.get_openai_client() as openai_client:
42-
43-
# [START files_sample]
44-
print("Uploading file")
45-
with open(file_path, "rb") as f:
46-
uploaded_file = openai_client.files.create(file=f, purpose="fine-tune")
47-
print(uploaded_file)
48-
49-
print(f"Retrieving file metadata with ID: {uploaded_file.id}")
50-
retrieved_file = openai_client.files.retrieve(uploaded_file.id)
51-
print(retrieved_file)
52-
53-
print(f"Retrieving file content with ID: {uploaded_file.id}")
54-
file_content = openai_client.files.content(uploaded_file.id)
55-
print(file_content.content)
56-
57-
print("Listing all files:")
58-
for file in openai_client.files.list():
59-
print(file)
60-
61-
print(f"Deleting file with ID: {uploaded_file.id}")
62-
deleted_file = openai_client.files.delete(uploaded_file.id)
63-
print(f"Successfully deleted file: {deleted_file.id}")
64-
# [END files_sample]
37+
with (
38+
DefaultAzureCredential(exclude_interactive_browser_credential=False) as credential,
39+
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
40+
project_client.get_openai_client() as openai_client,
41+
):
42+
# [START files_sample]
43+
print("Uploading file")
44+
with open(file_path, "rb") as f:
45+
uploaded_file = openai_client.files.create(file=f, purpose="fine-tune")
46+
print(uploaded_file)
47+
48+
print("Waits for the given file to be processed, default timeout is 30 mins")
49+
processed_file = openai_client.files.wait_for_processing(uploaded_file.id)
50+
print(processed_file)
51+
52+
print(f"Retrieving file metadata with ID: {processed_file.id}")
53+
retrieved_file = openai_client.files.retrieve(processed_file.id)
54+
print(retrieved_file)
55+
56+
print(f"Retrieving file content with ID: {processed_file.id}")
57+
file_content = openai_client.files.content(processed_file.id)
58+
print(file_content.content)
59+
60+
print("Listing all files:")
61+
for file in openai_client.files.list():
62+
print(file)
63+
64+
print(f"Deleting file with ID: {processed_file.id}")
65+
deleted_file = openai_client.files.delete(processed_file.id)
66+
print(f"Successfully deleted file: {deleted_file.id}")
67+
# [END files_sample]

sdk/ai/azure-ai-projects/samples/files/sample_files_async.py

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
"""
88
DESCRIPTION:
99
Given an AIProjectClient, this sample demonstrates how to use the asynchronous
10-
file operations using the OpenAI client: create, retrieve, content, list, and delete.
10+
file operations using the OpenAI client: create, wait_for_processing, retrieve, content, list, and delete.
1111
1212
USAGE:
1313
python sample_files_async.py
1414
1515
Before running the sample:
1616
17-
pip install azure-ai-projects azure-identity openai python-dotenv aiohttp
17+
pip install azure-ai-projects>=2.0.0b1 azure-identity openai python-dotenv aiohttp
1818
1919
Set these environment variables with your own values:
20-
1) PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your
21-
Microsoft Foundry project.
20+
1) AZURE_AI_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your
21+
Microsoft Foundry portal.
2222
2) FILE_PATH - Optional. Path to the file to upload. Defaults to the `data` folder.
2323
"""
2424

@@ -31,41 +31,47 @@
3131

3232
load_dotenv()
3333

34+
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
35+
script_dir = Path(__file__).parent
36+
file_path = os.environ.get("FILE_PATH", os.path.join(script_dir, "data", "test_file.jsonl"))
37+
3438

3539
async def main() -> None:
3640

37-
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
38-
script_dir = Path(__file__).parent
39-
file_path = os.environ.get("FILE_PATH", os.path.join(script_dir, "data", "test_file.jsonl"))
41+
credential = DefaultAzureCredential()
42+
43+
async with credential:
44+
45+
project_client = AIProjectClient(endpoint=endpoint, credential=credential)
4046

41-
async with DefaultAzureCredential(exclude_interactive_browser_credential=False) as credential:
47+
async with project_client:
4248

43-
async with AIProjectClient(endpoint=endpoint, credential=credential) as project_client:
49+
openai_client = project_client.get_openai_client()
4450

45-
async with project_client.get_openai_client() as openai_client:
51+
print("Uploading file")
52+
with open(file_path, "rb") as f:
53+
uploaded_file = await openai_client.files.create(file=f, purpose="fine-tune")
54+
print(uploaded_file)
4655

47-
# [START files_async_sample]
48-
print("Uploading file")
49-
with open(file_path, "rb") as f:
50-
uploaded_file = await openai_client.files.create(file=f, purpose="fine-tune")
51-
print(uploaded_file)
56+
print("Waits for the given file to be processed, default timeout is 30 mins")
57+
processed_file = await openai_client.files.wait_for_processing(uploaded_file.id)
58+
print(processed_file)
5259

53-
print(f"Retrieving file metadata with ID: {uploaded_file.id}")
54-
retrieved_file = await openai_client.files.retrieve(uploaded_file.id)
55-
print(retrieved_file)
60+
print(f"Retrieving file metadata with ID: {processed_file.id}")
61+
retrieved_file = await openai_client.files.retrieve(processed_file.id)
62+
print(retrieved_file)
5663

57-
print(f"Retrieving file content with ID: {uploaded_file.id}")
58-
file_content = await openai_client.files.content(uploaded_file.id)
59-
print(file_content.content)
64+
print(f"Retrieving file content with ID: {processed_file.id}")
65+
file_content = await openai_client.files.content(processed_file.id)
66+
print(file_content.content)
6067

61-
print("Listing all files:")
62-
async for file in openai_client.files.list():
63-
print(file)
68+
print("Listing all files:")
69+
async for file in openai_client.files.list():
70+
print(file)
6471

65-
print(f"Deleting file with ID: {uploaded_file.id}")
66-
deleted_file = await openai_client.files.delete(uploaded_file.id)
67-
print(f"Successfully deleted file: {deleted_file.id}")
68-
# [END files_async_sample]
72+
print(f"Deleting file with ID: {processed_file.id}")
73+
deleted_file = await openai_client.files.delete(processed_file.id)
74+
print(f"Successfully deleted file: {deleted_file.id}")
6975

7076

7177
if __name__ == "__main__":

0 commit comments

Comments
 (0)