Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create classes ad sample code for Azure Functions #47319

Merged
merged 23 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 22 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
6 changes: 6 additions & 0 deletions sdk/ai/Azure.AI.Projects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@

### Features Added

* Added `AzureFunctionToolDefinition` support to inform Agents about Azure Functions.
* Added `OpenApiTool` for Agents, which creates and executes a REST function defined by an OpenAPI spec.
* Add `parallel_tool_calls` parameter to allow parallel tool execution for Agents.
nick863 marked this conversation as resolved.
Show resolved Hide resolved

### Breaking Changes

### Bugs Fixed
nick863 marked this conversation as resolved.
Show resolved Hide resolved

* Fix a bug preventing additional messages to be created when using `CreateRunStreamingAsync` and `CreateRunAsync` see [issue](https://github.com/Azure/azure-sdk-for-net/issues/47244).

### Other Changes

## 1.0.0-beta.1 (2024-11-19)
Expand Down
123 changes: 123 additions & 0 deletions sdk/ai/Azure.AI.Projects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Use the AI Projects client library to:
- [Retrieve messages](#retrieve-messages)
- [File search](#file-search)
- [Function call](#function-call)
- [Azure function call](#azure-function-call)
nick863 marked this conversation as resolved.
Show resolved Hide resolved
- [Azure Function Call](#create-agent-with-azure-function-call)
- [OpenAPI](#create-agent-with-openapi)
- [Troubleshooting](#troubleshooting)
- [Next steps](#next-steps)
- [Contributing](#contributing)
Expand Down Expand Up @@ -347,6 +350,126 @@ while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress);
```

#### Azure function call

We also can use Azure Function from inside the agent. In the example below we are calling function "foo", which responds "Bar". In this example we create `AzureFunctionToolDefinition` object, with the function name, description, input and output queues, followed by function parameters.
```C# Snippet:AzureFunctionsDefineFunctionTools
AzureFunctionToolDefinition azureFnTool = new(
name: "foo",
description: "Get answers from the foo bot.",
inputBinding: new AzureFunctionBinding(
new AzureFunctionStorageQueue(
queueName: "azure-function-foo-input",
storageServiceEndpoint: storageQueueUri
)
),
outputBinding: new AzureFunctionBinding(
new AzureFunctionStorageQueue(
queueName: "azure-function-tool-output",
storageServiceEndpoint: storageQueueUri
)
),
parameters: BinaryData.FromObjectAsJson(
new
{
Type = "object",
Properties = new
{
query = new
{
Type = "string",
Description = "The question to ask.",
},
outputqueueuri = new
{
Type = "string",
Description = "The full output queue uri."
}
},
},
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }
)
);
```

Note that in this scenario we are asking agent to supply storage queue URI to the azure function whenever it is called.
```C# Snippet:AzureFunctionsCreateAgentWithFunctionTools
Response<Agent> agentResponse = await client.CreateAgentAsync(
model: "gpt-4",
name: "azure-function-agent-foo",
instructions: "You are a helpful support agent. Use the provided function any "
+ "time the prompt contains the string 'What would foo say?'. When you invoke "
+ "the function, ALWAYS specify the output queue uri parameter as "
+ $"'{storageQueueUri}/azure-function-tool-output'. Always responds with "
+ "\"Foo says\" and then the response from the tool.",
tools: new List<ToolDefinition> { azureFnTool }
);
Agent agent = agentResponse.Value;
```

After we have created a message with request to ask "What would foo say?", we need to wait while the run is in queued, in progress or requires action states.
```C# Snippet:AzureFunctionsHandlePollingWithRequiredAction
Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
thread.Id,
MessageRole.User,
"What is the most prevalent element in the universe? What would foo say?");
ThreadMessage message = messageResponse.Value;

Response<ThreadRun> runResponse = await client.CreateRunAsync(thread, agent);

do
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
}
while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress
|| runResponse.Value.Status == RunStatus.RequiresAction);
```

#### Create Agent With OpenAPI

OpenAPI specifications describe REST operations against a specific endpoint. Agents SDK can read an OpenAPI spec, create a function from it, and call that function against the REST endpoint without additional client-side execution.

Here is an example creating an OpenAPI tool (using anonymous authentication):
```C# Snippet:OpenAPIDefineFunctionTools
OpenApiAnonymousAuthDetails oaiAuth = new();
OpenApiToolDefinition openapiTool = new(
name: "get_weather",
description: "Retrieve weather information for a location",
spec: BinaryData.FromBytes(File.ReadAllBytes(file_path)),
auth: oaiAuth
);

Response<Agent> agentResponse = await client.CreateAgentAsync(
model: "gpt-4",
name: "azure-function-agent-foo",
instructions: "You are a helpful assistant.",
tools: new List<ToolDefinition> { openapiTool }
);
Agent agent = agentResponse.Value;
```

In this example we are using the `weather_openapi.json` file and agent will request the wttr.in website for the weather in a location fron the prompt.
```C# Snippet:OpenAPIHandlePollingWithRequiredAction
Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
thread.Id,
MessageRole.User,
"What's the weather in Seattle?");
ThreadMessage message = messageResponse.Value;

Response<ThreadRun> runResponse = await client.CreateRunAsync(thread, agent);

do
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
}
while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress
|| runResponse.Value.Status == RunStatus.RequiresAction);
```

nick863 marked this conversation as resolved.
Show resolved Hide resolved
## Troubleshooting

Any operation that fails will throw a [RequestFailedException][RequestFailedException]. The exception's `code` will hold the HTTP response status code. The exception's `message` contains a detailed message that may be helpful in diagnosing the issue:
Expand Down
Loading
Loading