1+ # pylint: disable=line-too-long,useless-suppression
2+ # ------------------------------------
3+ # Copyright (c) Microsoft Corporation.
4+ # Licensed under the MIT License.
5+ # ------------------------------------
6+
7+ """
8+ DESCRIPTION:
9+ Given an AIProjectClient, this sample demonstrates how to use the synchronous
10+ `openai.evals.*` methods to create, get and list eval group and and eval runs
11+ using inline dataset content.
12+
13+ USAGE:
14+ python sample_coherence.py
15+
16+ Before running the sample:
17+
18+ pip install azure-ai-projects azure-identity
19+
20+ Set these environment variables with your own values:
21+ 1) PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your
22+ Azure AI Foundry project. It has the form: https://<account_name>.services.ai.azure.com/api/projects/<project_name>.
23+ 2) MODEL_DEPLOYMENT_NAME - Required. The name of the model deployment to use for evaluation.
24+ """
25+
26+ import os
27+ import json
28+ import time
29+
30+ from azure .identity import DefaultAzureCredential
31+ from azure .ai .projects import AIProjectClient
32+ from openai .types .evals .create_eval_jsonl_run_data_source_param import (
33+ CreateEvalJSONLRunDataSourceParam ,
34+ SourceFileContent ,
35+ SourceFileContentContent
36+ )
37+
38+ def main () -> None :
39+ endpoint = os .environ [
40+ "PROJECT_ENDPOINT"
41+ ] # Sample : https://<account_name>.services.ai.azure.com/api/projects/<project_name>
42+ model_deployment_name = os .environ .get ("MODEL_DEPLOYMENT_NAME" , "" ) # Sample : gpt-4o-mini
43+
44+ with DefaultAzureCredential () as credential :
45+ with AIProjectClient (endpoint = endpoint , credential = credential , api_version = "2025-11-15-preview" ) as project_client :
46+ print ("Creating an OpenAI client from the AI Project client" )
47+
48+ client = project_client .get_openai_client ()
49+ client ._custom_query = {"api-version" : "2025-11-15-preview" }
50+
51+ data_source_config = {
52+ "type" : "custom" ,
53+ "item_schema" : {
54+ "type" : "object" ,
55+ "properties" : {
56+ "query" : {
57+ "type" : "string"
58+ },
59+ "response" : {
60+ "type" : "string"
61+ }
62+ },
63+ "required" : []
64+ },
65+ "include_sample_schema" : True
66+ }
67+
68+ testing_criteria = [
69+ {
70+ "type" : "azure_ai_evaluator" ,
71+ "name" : "coherence" ,
72+ "evaluator_name" : "builtin.coherence" ,
73+ "initialization_parameters" : {
74+ "deployment_name" : f"{ model_deployment_name } "
75+ },
76+ "data_mapping" : {
77+ "query" : "{{item.query}}" ,
78+ "response" : "{{item.response}}"
79+ }
80+ }
81+ ]
82+
83+ print ("Creating Eval Group" )
84+ eval_object = client .evals .create (
85+ name = "label model test with inline data" ,
86+ data_source_config = data_source_config ,
87+ testing_criteria = testing_criteria ,
88+ )
89+ print (f"Eval Group created" )
90+
91+ print ("Get Eval Group by Id" )
92+ eval_object_response = client .evals .retrieve (eval_object .id )
93+ print ("Eval Run Response:" )
94+ pprint (eval_object_response )
95+
96+ # Sample inline data
97+ success_query = "What is the capital of France?"
98+ success_response = "The capital of France is Paris."
99+
100+ # Failure example - incoherent response
101+ failure_query = "What is the capital of France?"
102+ failure_response = "France capital is... well, the city where government sits is Paris but no wait, Lyon is bigger actually maybe Rome? The French people live in many cities but the main one, I think it's definitely Paris or maybe not, depends on what you mean by capital."
103+
104+ print ("Creating Eval Run with Inline Data" )
105+ eval_run_object = client .evals .runs .create (
106+ eval_id = eval_object .id ,
107+ name = "inline_data_run" ,
108+ metadata = {
109+ "team" : "eval-exp" ,
110+ "scenario" : "inline-data-v1"
111+ },
112+ data_source = CreateEvalJSONLRunDataSourceParam (
113+ type = "jsonl" ,
114+ source = SourceFileContent (
115+ type = "file_content" ,
116+ content = [
117+ # Success example - coherent response
118+ SourceFileContentContent (
119+ item = {
120+ "query" : success_query ,
121+ "response" : success_response
122+ }
123+ ),
124+ # Failure example - incoherent response
125+ SourceFileContentContent (
126+ item = {
127+ "query" : failure_query ,
128+ "response" : failure_response
129+ }
130+ )
131+ ]
132+ )
133+ )
134+ )
135+
136+ print (f"Eval Run created" )
137+ pprint (eval_run_object )
138+
139+ print ("Get Eval Run by Id" )
140+ eval_run_response = client .evals .runs .retrieve (run_id = eval_run_object .id , eval_id = eval_object .id )
141+ print ("Eval Run Response:" )
142+ pprint (eval_run_response )
143+
144+ print ("\n \n ----Eval Run Output Items----\n \n " )
145+
146+ while True :
147+ run = client .evals .runs .retrieve (run_id = eval_run_response .id , eval_id = eval_object .id )
148+ if run .status == "completed" or run .status == "failed" :
149+ output_items = list (client .evals .runs .output_items .list (
150+ run_id = run .id , eval_id = eval_object .id
151+ ))
152+ pprint (output_items )
153+ print (f"Eval Run Status: { run .status } " )
154+ print (f"Eval Run Report URL: { run .report_url } " )
155+ break
156+ time .sleep (5 )
157+ print ("Waiting for eval run to complete..." )
158+
159+ # [END evaluations_sample]
160+
161+
162+ def _to_json_primitive (obj ):
163+ if obj is None or isinstance (obj , (str , int , float , bool )):
164+ return obj
165+ if isinstance (obj , (list , tuple )):
166+ return [_to_json_primitive (i ) for i in obj ]
167+ if isinstance (obj , dict ):
168+ return {k : _to_json_primitive (v ) for k , v in obj .items ()}
169+ for method in ("to_dict" , "as_dict" , "dict" , "serialize" ):
170+ if hasattr (obj , method ):
171+ try :
172+ return _to_json_primitive (getattr (obj , method )())
173+ except Exception :
174+ pass
175+ if hasattr (obj , "__dict__" ):
176+ return _to_json_primitive ({k : v for k , v in vars (obj ).items () if not k .startswith ("_" )})
177+ return str (obj )
178+
179+ def pprint (str ) -> None :
180+ print (json .dumps (_to_json_primitive (str ), indent = 2 ))
181+
182+ if __name__ == "__main__" :
183+ main ()
0 commit comments