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
2 changes: 1 addition & 1 deletion sdk/ai/azure-ai-agents/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/ai/azure-ai-agents",
"Tag": "java/ai/azure-ai-agents_5238437e7d"
"Tag": "java/ai/azure-ai-agents_767bd42da6"
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@
* <li>FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint.</li>
* <li>FOUNDRY_MODEL_NAME - The model deployment name.</li>
* <li>FABRIC_IQ_PROJECT_CONNECTION_ID - The FabricIQ connection ID.</li>
* <li>FABRIC_IQ_USER_INPUT - Optional. The natural-language question to send to the agent.</li>
* </ul>
*/
public class FabricIQAsync {
public static void main(String[] args) {
String endpoint = Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT");
String model = Configuration.getGlobalConfiguration().get("FOUNDRY_MODEL_NAME");
String fabricIqConnectionId = Configuration.getGlobalConfiguration().get("FABRIC_IQ_PROJECT_CONNECTION_ID");
String userInput = Configuration.getGlobalConfiguration().get("FABRIC_IQ_USER_INPUT",
"Use FabricIQ to summarize the available enterprise context.");

AgentsClientBuilder builder = new AgentsClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
Expand All @@ -51,10 +54,10 @@ public static void main(String[] args) {
.setDescription("Use FabricIQ to answer questions grounded in enterprise data.");

PromptAgentDefinition agentDefinition = new PromptAgentDefinition(model)
.setInstructions("You are a data assistant that can use FabricIQ for grounded enterprise answers.")
.setInstructions("Use the available Fabric IQ tools to answer questions and perform tasks.")
.setTools(Collections.singletonList(fabricIqTool));

agentsAsyncClient.createAgentVersion("fabric-iq-async-agent", agentDefinition)
agentsAsyncClient.createAgentVersion("fabric-iq-agent", agentDefinition)
.flatMap(agent -> {
agentRef.set(agent);
System.out.printf("Agent created: %s (version %s)%n", agent.getName(), agent.getVersion());
Expand All @@ -65,7 +68,7 @@ public static void main(String[] args) {
return responsesAsyncClient.createAzureResponse(
new AzureCreateResponseOptions().setAgentReference(agentReference),
ResponseCreateParams.builder()
.input("Use FabricIQ to summarize the available enterprise context."));
.input(userInput));
})
.doOnNext(response -> System.out.println("Response: " + response.output()))
.then(Mono.defer(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
* <li>FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint.</li>
* <li>FOUNDRY_MODEL_NAME - The model deployment name.</li>
* <li>FABRIC_IQ_PROJECT_CONNECTION_ID - The FabricIQ connection ID.</li>
* <li>FABRIC_IQ_USER_INPUT - Optional. The natural-language question to send to the agent.</li>
* </ul>
*/
public class FabricIQSync {
public static void main(String[] args) {
String endpoint = Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT");
String model = Configuration.getGlobalConfiguration().get("FOUNDRY_MODEL_NAME");
String fabricIqConnectionId = Configuration.getGlobalConfiguration().get("FABRIC_IQ_PROJECT_CONNECTION_ID");
String userInput = Configuration.getGlobalConfiguration().get("FABRIC_IQ_USER_INPUT",
"Use FabricIQ to summarize the available enterprise context.");

AgentsClientBuilder builder = new AgentsClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
Expand All @@ -52,7 +55,7 @@ public static void main(String[] args) {
// END: com.azure.ai.agents.define_fabric_iq

PromptAgentDefinition agentDefinition = new PromptAgentDefinition(model)
.setInstructions("You are a data assistant that can use FabricIQ for grounded enterprise answers.")
.setInstructions("Use the available Fabric IQ tools to answer questions and perform tasks.")
.setTools(Collections.singletonList(fabricIqTool));

AgentVersionDetails agent = agentsClient.createAgentVersion("fabric-iq-agent", agentDefinition);
Expand All @@ -65,7 +68,7 @@ public static void main(String[] args) {
Response response = responsesClient.createAzureResponse(
new AzureCreateResponseOptions().setAgentReference(agentReference),
ResponseCreateParams.builder()
.input("Use FabricIQ to summarize the available enterprise context."));
.input(userInput));

System.out.println("Response: " + response.output());
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ protected AgentsClientBuilder getClientBuilder(HttpClient httpClient, AgentsServ
builder.endpoint("https://localhost:8080").credential(new MockTokenCredential());
} else if (testMode == TestMode.RECORD) {
builder.addPolicy(interceptorManager.getRecordPolicy())
.endpoint(Configuration.getGlobalConfiguration().get("AZURE_AGENTS_ENDPOINT"))
.endpoint(Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT"))
.credential(new DefaultAzureCredentialBuilder().build());
} else {
builder.endpoint(Configuration.getGlobalConfiguration().get("AZURE_AGENTS_ENDPOINT"))
builder.endpoint(Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT"))
.credential(new DefaultAzureCredentialBuilder().build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,127 @@

package com.azure.ai.agents.tools;

import com.azure.ai.agents.AgentsAsyncClient;
import com.azure.ai.agents.AgentsClient;
import com.azure.ai.agents.AgentsClientBuilder;
import com.azure.ai.agents.AgentsServiceVersion;
import com.azure.ai.agents.ClientTestBase;
import com.azure.ai.agents.ResponsesAsyncClient;
import com.azure.ai.agents.ResponsesClient;
import com.azure.core.http.HttpClient;
import org.junit.jupiter.api.Disabled;
import com.azure.core.test.TestMode;
import com.azure.core.util.Configuration;
import com.azure.ai.agents.models.AgentReference;
import com.azure.ai.agents.models.AgentVersionDetails;
import com.azure.ai.agents.models.AzureCreateResponseOptions;
import com.azure.ai.agents.models.FabricIQPreviewTool;
import com.azure.ai.agents.models.PromptAgentDefinition;
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStatus;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static com.azure.core.test.TestProxyTestBase.getHttpClients;

public class FabricIQSamplesTests extends ClientTestBase {
private static final String DISPLAY_NAME_WITH_ARGUMENTS = "{displayName} with [{arguments}]";
private static final String DEFAULT_USER_INPUT = "Show weather events in Texas.";

static Stream<Arguments> getTestParameters() {
List<Arguments> argumentsList = new ArrayList<>();
getHttpClients().forEach(httpClient -> argumentsList.add(Arguments.of(httpClient, AgentsServiceVersion.V1)));
return argumentsList.stream();
}

@Disabled("Requires FABRIC_IQ_PROJECT_CONNECTION_ID and FOUNDRY_MODEL_NAME.")
@Timeout(value = 5, unit = TimeUnit.MINUTES)
@ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS)
@MethodSource("getTestParameters")
public void fabricIqSyncSample(HttpClient httpClient, AgentsServiceVersion serviceVersion) {
Assertions.fail("Enable after providing FABRIC_IQ_PROJECT_CONNECTION_ID and FOUNDRY_MODEL_NAME.");
AgentsClientBuilder builder = getClientBuilder(httpClient, serviceVersion);
AgentsClient agentsClient = builder.buildAgentsClient();
ResponsesClient responsesClient = builder.buildResponsesClient();

String agentName = testResourceNamer.randomName("fabric-iq-sync-", 40);
AgentVersionDetails agent = agentsClient.createAgentVersion(agentName, createAgentDefinition());
Assertions.assertNotNull(agent);

AgentReference agentReference = new AgentReference(agent.getName()).setVersion(agent.getVersion());
Response response
= responsesClient.createAzureResponse(new AzureCreateResponseOptions().setAgentReference(agentReference),
ResponseCreateParams.builder().input(getUserInput()));

assertCompletedResponse(response);
agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
}

@Disabled("Requires FABRIC_IQ_PROJECT_CONNECTION_ID and FOUNDRY_MODEL_NAME.")
@Timeout(value = 5, unit = TimeUnit.MINUTES)
@ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS)
@MethodSource("getTestParameters")
public void fabricIqAsyncSample(HttpClient httpClient, AgentsServiceVersion serviceVersion) {
Assertions.fail("Enable after providing FABRIC_IQ_PROJECT_CONNECTION_ID and FOUNDRY_MODEL_NAME.");
AgentsClientBuilder builder = getClientBuilder(httpClient, serviceVersion);
AgentsAsyncClient agentsAsyncClient = builder.buildAgentsAsyncClient();
ResponsesAsyncClient responsesAsyncClient = builder.buildResponsesAsyncClient();

String agentName = testResourceNamer.randomName("fabric-iq-async-", 40);
AgentVersionDetails agent
= agentsAsyncClient.createAgentVersion(agentName, createAgentDefinition()).block(Duration.ofMinutes(2));
Assertions.assertNotNull(agent);

AgentReference agentReference = new AgentReference(agent.getName()).setVersion(agent.getVersion());
Response response
= responsesAsyncClient
.createAzureResponse(new AzureCreateResponseOptions().setAgentReference(agentReference),
ResponseCreateParams.builder().input(getUserInput()))
.block(Duration.ofMinutes(3));

assertCompletedResponse(response);
agentsAsyncClient.deleteAgentVersion(agent.getName(), agent.getVersion()).block(Duration.ofMinutes(1));
}

private PromptAgentDefinition createAgentDefinition() {
FabricIQPreviewTool fabricIqTool
= new FabricIQPreviewTool(getRecordedConfig("FABRIC_IQ_PROJECT_CONNECTION_ID")).setServerLabel("fabric_iq")
.setRequireApproval("never")
.setName("fabric_iq_lookup")
.setDescription("Use FabricIQ to answer questions grounded in enterprise data.");

return new PromptAgentDefinition(getRecordedConfig("FOUNDRY_MODEL_NAME"))
.setInstructions("Use the available Fabric IQ tools to answer questions and perform tasks.")
.setTools(Collections.singletonList(fabricIqTool));
}

private String getRecordedConfig(String name) {
if (getTestMode() == TestMode.PLAYBACK) {
return testResourceNamer.recordValueFromConfig(name);
}

String value = Configuration.getGlobalConfiguration().get(name);
if (getTestMode() == TestMode.RECORD) {
testResourceNamer.recordValueFromConfig(name);
}
return value;
}

private static String getUserInput() {
return Configuration.getGlobalConfiguration().get("FABRIC_IQ_USER_INPUT", DEFAULT_USER_INPUT);
}

private static void assertCompletedResponse(Response response) {
Assertions.assertNotNull(response);
Assertions.assertTrue(response.status().isPresent());
Assertions.assertEquals(ResponseStatus.COMPLETED, response.status().get());
Assertions.assertFalse(response.output().isEmpty());
Assertions.assertTrue(response.output().stream().anyMatch(item -> item.isMessage()));
}
}
18 changes: 18 additions & 0 deletions sdk/ai/azure-ai-projects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ EvalService evalService = builder.buildOpenAIClient().evals();
EvalServiceAsync evalAsyncService = builder.buildOpenAIAsyncClient().evals();
```

When using Azure-specific evaluator models with OpenAI evaluations, use `EvaluationsHelper` to adapt the Azure model to
the OpenAI request type. This keeps application code from depending on the serialization details used by the OpenAI SDK.

```java com.azure.ai.projects.evaluationsHelper
Map<String, String> dataMapping = new LinkedHashMap<>();
dataMapping.put("query", "{{item.query}}");
dataMapping.put("response", "{{sample.output_text}}");

TestingCriterionAzureAIEvaluator coherenceEvaluator = new TestingCriterionAzureAIEvaluator("coherence",
"builtin.coherence")
.setInitializationParameters(Collections.singletonMap("deployment_name",
BinaryData.fromObject("gpt-4o-mini")))
.setDataMapping(dataMapping);

EvalCreateParams.TestingCriterion testingCriterion
= EvaluationsHelper.toTestingCriterion(coherenceEvaluator);
```

For the Agents operation, you can use the `azure-ai-agents` package which is available as transitive dependency:

```java com.azure.ai.projects.agentsSubClients
Expand Down
2 changes: 1 addition & 1 deletion sdk/ai/azure-ai-projects/assets.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"AssetsRepo":"Azure/azure-sdk-assets","AssetsRepoPrefixPath":"java","TagPrefix":"java/ai/azure-ai-projects","Tag": "java/ai/azure-ai-projects_cd9e4bffa9"}
{"AssetsRepo":"Azure/azure-sdk-assets","AssetsRepoPrefixPath":"java","TagPrefix":"java/ai/azure-ai-projects","Tag": "java/ai/azure-ai-projects_8ce9469bb9"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.ai.projects;

import com.azure.ai.projects.implementation.OpenAIJsonHelper;
import com.azure.ai.projects.models.TestingCriterionAzureAIEvaluator;
import com.openai.models.evals.EvalCreateParams;

/**
* Helper methods for Azure AI evaluations.
*/
public final class EvaluationsHelper {
private EvaluationsHelper() {
}

/**
* Converts an Azure AI evaluator model to an OpenAI evaluation testing criterion.
*
* <p>Use this helper when creating OpenAI evaluations with Azure-specific evaluator types such as
* {@link TestingCriterionAzureAIEvaluator}. The helper preserves the Azure evaluator wire shape while hiding the
* serialization details needed to pass it to the OpenAI SDK.</p>
*
* @param evaluator The Azure AI evaluator to use as an evaluation testing criterion.
* @return The OpenAI evaluation testing criterion.
* @throws NullPointerException if {@code evaluator} is null.
*/
public static EvalCreateParams.TestingCriterion toTestingCriterion(TestingCriterionAzureAIEvaluator evaluator) {
return OpenAIJsonHelper.toOpenAIType(evaluator, EvalCreateParams.TestingCriterion.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.ai.projects.implementation;

import com.azure.core.util.BinaryData;
import com.azure.json.JsonSerializable;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openai.core.ObjectMappers;

import java.io.IOException;

/**
* Helper methods for adapting Azure SDK models to openai-java models.
*/
public final class OpenAIJsonHelper {
private static final ObjectMapper MAPPER = ObjectMappers.jsonMapper();

private OpenAIJsonHelper() {
}

/**
* Converts an Azure SDK type that implements {@link JsonSerializable} to an openai-java type.
*
* @param azureObject The Azure SDK model to convert.
* @param openAIType The target openai-java type.
* @param <S> The Azure SDK source type.
* @param <T> The openai-java target type.
* @return The openai-java model.
* @throws NullPointerException if {@code azureObject} or {@code openAIType} is null.
* @throws RuntimeException if conversion fails.
*/
public static <S extends JsonSerializable<S>, T> T toOpenAIType(S azureObject, Class<T> openAIType) {
if (azureObject == null) {
throw new NullPointerException("'azureObject' cannot be null.");
}
if (openAIType == null) {
throw new NullPointerException("'openAIType' cannot be null.");
}

try {
return MAPPER.readValue(BinaryData.fromObject(azureObject).toString(), openAIType);
} catch (IOException e) {
throw new RuntimeException("Failed to convert Azure SDK type to OpenAI type.", e);
}
}
}
Loading