Building an AI Dev Space With a Little Assistance from Aspire by info.odysseyx@gmail.com October 14, 2024 written by info.odysseyx@gmail.com October 14, 2024 0 comment 12 views 12 Getting started Azure OpenAI is easy enough – Here’s our deployment and here’s our API key. Go! From a marketing perspective, it’s great. Less so if you want to save tokens. But when developing AI solutions, cost is just one parameter. Testability, mock data, redundancy, etc. are needed. That means you’ll need everything you need, even if you don’t have any AI anywhere near your app. Although it’s not front and center on the Azure landing page, Microsoft has tools and features to help with this, which we’ll take a look at today. AI simulator NOTE: The focus here is not on the AI bit itself, so The part is That’s not cool at all. The focus is on the support part. I understand that if you don’t want to be connected to the cloud during development, you can run the model locally on your machine and expose the API accordingly, but that’s not the use case we’re trying to solve here. You want something connected to Azure while still allowing flexibility. Cloud vs. local. (But if you want, you can run something in LM Studio and tweak this code to work with your local model.) Let’s demonstrate the developer experience from a few different angles using a simple web app and the Azure OpenAI SDK for .NET. Microsoft provides the Azure OpenAI simulator. From an API/SDK perspective act like Real life example: This is the basis of what we will be working with in the sample. For our purposes, it’s easiest to deploy it like this: docher images on location (Docker file offer To MS). Since I’ve been using .NET Aspire recently, I decided to use it as my central orchestration part. The structure of the view (we’ll cover what the view does along the way) is almost identical. Across a variety of use cases: @code { public class chatDialog { public string? systemMessage; public string? inputText; public string? outputText; public int maxTokens = 400; public float temperature = 0.7f; } //This view is hardwired to use the simulator so we can adjust accordingly private string oaiEndpoint = string.Empty; private string oaiDeploymentName = string.Empty; private string oaiKey = string.Empty; public static chatDialog dialog = new(); protected override void OnInitialized() { oaiEndpoint = "http://localhost:8000"; oaiDeploymentName = Configuration["oaiDeploymentName"] ?? "gpt-4o"; oaiKey = Configuration["oaiKey"] ?? string.Empty; dialog = new() { systemMessage = "I am a hiking enthusiast named Forest who helps people discover hikes in their area. If no area is specified, I will default to near Rainier National Park. I will then provide three suggestions for nearby hikes that vary in length. I will also share an interesting fact about the local nature on the hikes when making a recommendation.", inputText = "Can you recommend some good hikes in the Redmond area?", outputText = string.Empty, temperature = 0.7f, maxTokens = 400, }; } protected async Task chat() { AzureOpenAIClient client = new AzureOpenAIClient(new Uri(oaiEndpoint), new System.ClientModel.ApiKeyCredential(oaiKey)); OpenAI.Chat.ChatClient chatClient = client.GetChatClient(oaiDeploymentName); OpenAI.Chat.ChatCompletionOptions chatCompletionOptions = new() { MaxOutputTokenCount = dialog.maxTokens, Temperature = dialog.temperature, }; OpenAI.Chat.ChatCompletion completion = await chatClient.CompleteChatAsync( [ new OpenAI.Chat.SystemChatMessage(dialog.systemMessage), new OpenAI.Chat.UserChatMessage(dialog.inputText), ],chatCompletionOptions); var response = $"Response:\r\n{completion.Content[0].Text} \r\nOutput tokens: {completion.Usage.OutputTokenCount}\r\nTotal tokens: {completion.Usage.TotalTokenCount}"; dialog.outputText = response; } } All code for this post can be found here. It seems like you’re hardcoding localhost. It’s a bad idea and kind of non-distributable. I know and that’s on purpose. here. We tested pushing the simulator to Azure Container Registry and pulling it to Azure Container App. That’s not a problem at all, (localhost is also invalid) but that will be I need some additional logic Create deployment script So I chose making things are simpler instead. The following code adds: simulator instance Web app (to AppHost program.cs😞 builder.AddDockerfile("aoai-simulator-generate", "../AOAI_API_Simulator") .WithHttpEndpoint(port: 8000, targetPort:oaiSimulatorPort) .WithEnvironment("SIMULATOR_MODE", "generate") .WithEnvironment("SIMULATOR_API_KEY", localOaiKey) .ExcludeFromManifest(); The results are ridiculous Practice SDK, perform load testing and Experiment with UI that works. (As with actual AI deployments, creation may be delayed.) You probably want to look past the fluff and get real reactions. The simulator also has a mod for this. You can insert values for your Azure OpenAI deployment. Then enter ‘recording’ mode. Your question will then be proxied and the response will be saved to disk as a JSON file. If you add a few lines of code, Aspire can handle this part as well. Create both an Azure OpenAI resource and another instance of the simulator. var azaoai = builder.AddBicepTemplate( name: "AI", bicepFile: "../infra/ai.bicep") .WithParameter(AzureBicepResource.KnownParameters.KeyVaultName); var cloudEndpoint = azaoai.GetOutput("endpoint"); var accountName = azaoai.GetOutput("accountName"); var cloudKey = azaoai.GetSecretOutput("accountKey"); var cloudDeployment = "gpt-4o"; builder.AddDockerfile("aoai-simulator-record", "../AOAI_API_Simulator") .WithBindMount("recordings", "/app/.recording") .WithHttpEndpoint(port: 8001, targetPort: oaiSimulatorPort) .WithEnvironment("SIMULATOR_API_KEY", localOaiKey) .WithEnvironment("SIMULATOR_MODE", "record") .WithEnvironment("AZURE_OPENAI_ENDPOINT", cloudEndpoint) .WithEnvironment("AZURE_OPENAI_KEY", cloudKey) .WithEnvironment("AZURE_OPENAI_DEPLOYMENT", cloudDeployment) .WithEnvironment("AZURE_OPENAI_EMBEDDING_DEPLOYMENT", cloudDeployment) .ExcludeFromManifest(); That will happen if you ask the same question. hopefully Get more meaningful answers. This also acts as a cache, so repeating the question requires reading from the file. Instead of hitting the endpoint in Azure. We don’t just record because we can. It also provides a playback mode for recording. So we create another simulator instance pointing to the same directory as the recorder. builder.AddDockerfile("aoai-simulator-replay", "../AOAI_API_Simulator") .WithBindMount("recordings", "/app/.recording") .WithHttpEndpoint(port: 8002, targetPort: oaiSimulatorPort) .WithEnvironment("SIMULATOR_API_KEY", localOaiKey) .WithEnvironment("SIMULATOR_MODE", "replay") this is not the case It forwards the request to the cloud but only verifies the file locally. This means that asking the same question repeatedly will give you the exact same answer, but the results will be different. action Rather than asking an AI assistant There is an advantage to being More predictable in development and testing. For that matter, you can edit the JSON to change the answer, add a question, and more. If you are asking a new question (No recorded responses) Since we can’t return anything meaningful, we just catch the exception and take a shortcut to insert the placeholder text. I used the simulator’s defaults, but you can also change the latency and token limit like this: you may not want for unlimited use. try { OpenAI.Chat.ChatCompletion completion = await chatClient.CompleteChatAsync( [ new OpenAI.Chat.SystemChatMessage(dialog.systemMessage), new OpenAI.Chat.UserChatMessage(dialog.inputText), ], chatCompletionOptions); var response = $"Response:\r\n{completion.Content[0].Text} \r\nOutput tokens: {completion.Usage.OutputTokenCount}\r\nTotal tokens: {completion.Usage.TotalTokenCount}"; dialog.outputText = response; } catch (Exception) { dialog.outputText = "I don't know what you are talking about."; } And as expected, minor tweaks to the locations I queried mean the bot knows nothing about. It looks good, but there’s one more trick you can use here to blur the line between development and production. Many companies don’t want their API calls to go directly to exposing resources. that data. Instead, Put Azure API Management (APIM) in front to control inbound traffic and add features like load balancing, throttling, and more. APIM has OpenAI awareness, so AI deployments you create as a backend can easily be added to a separate API.. More information about this can be found here.: I chose the “Token Rate Limiting lab” policy, but you are free to experiment with more complex policies. You probably won’t be surprised By now This is also something I am adding with Aspire. var apimai = builder.AddBicepTemplate( name: "APIM", bicepFile: "../infra/apim.bicep") .WithParameter(AzureBicepResource.KnownParameters.KeyVaultName) .WithParameter("apimResourceName", "apim") .WithParameter("apimSku", "Basicv2") .WithParameter("openAIAccountName", accountName); var apimEndpoint = apimai.GetOutput("apimResourceGatewayURL"); var apimKey = apimai.GetSecretOutput("subscriptionKey"); builder.AddDockerfile("aoai-simulator-record", "../AOAI_API_Simulator") .WithBindMount("recordings", "/app/.recording") .WithHttpEndpoint(port: 8001, targetPort: oaiSimulatorPort) .WithEnvironment("SIMULATOR_API_KEY", localOaiKey) .WithEnvironment("SIMULATOR_MODE", "record") .WithEnvironment("AZURE_OPENAI_ENDPOINT", apimEndpoint) .WithEnvironment("AZURE_OPENAI_KEY", apimKey) .WithEnvironment("AZURE_OPENAI_DEPLOYMENT", cloudDeployment) .WithEnvironment("AZURE_OPENAI_EMBEDDING_DEPLOYMENT", cloudDeployment) .ExcludeFromManifest(); Instantiating the AI simulator is the same as before. Use URL and key instead of APIM. Azure OpenAI credentials. APIM provisioning uses those values in a secure way. Again, to reduce complexity, we’re using keys here instead of managed IDs.ch I recommend it using As much as possible when your code runs on Azure. Perhaps it creates a rather lengthy request pipeline, and it gets It gets complicated when you apply different restrictions at each step. You may not want to use all of these components, but you can mix and match them in the sense that your code doesn’t have to have any say in what’s behind the endpoint. Although we do not deploy apps to Azure Obviously both Azure OpenAI and Azure APIM are what you use. Must be provisioned as a subscription/resource group. I think this creates an interesting paradigm. you always had the ability to do itIt’s similar to creating a SQL database in Azure and connecting to it from a debugging session in Visual Studio, but it was more common to use LocalDB locally and replace the connection string during deployment. Here you can create configurations that use Azure. Seamlessly integrates into the developer inner loop. Resources are designed for a single developer, but can also be easily shared with a team if needed. (Key Vault is almost free. & Azure OpenAI costs nothing unless you actively use it. Send tokens back and forth. APIM costs money because policies cannot be used with consumption SKUs.) The code so far has not addressed how these resources are created. that builder.AddBicepTemplate Points to the Bicep file that manages it. We don’t use the Azure developer CLI because we’re not deploying an actual web app. Aspire can handle the rest on its own. You can see that there is some value to add. app settings.json With predefined patterns: { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Aspire.Hosting.Dcp": "Warning" } }, "Parameters": { "TenantId": "guid", "ClientId": "guid", "ClientSecret": "secret" }, "Azure": { "SubscriptionId": "", "AllowResourceGroupCreation": true, "ResourceGroup": "", "Location": "" } } The “Parameters” section is for logging into the app and requires registration with Entra ID for it to work. The “Azure” section is the section that Aspire uses for user-provided Bicep code. The code I’m sending you can be found here: You can later go into the Azure portal and play with the resources Aspire creates, but the code is completely local (until you check into the repository and follow that flow). Once complete, you can delete the resource from Porta.L. Please note that you must delete your AI deployment before your AI account. Key Vault and APIM must be deleted and then removed. Otherwise redeployment will fail. In the end, AI development is just ‘development’ 🙂 Source link Share 0 FacebookTwitterPinterestEmail info.odysseyx@gmail.com previous post Kubernetes – Consumo de memória elevado em aplicações que escrevem em disco next post Demystify potential data leaks with Insider Risk Management insights in Defender XDR You may also like A good Los Angeles rebuild with fire-resistant houses January 20, 2025 2024 PC shipments increase with strong refresh cycle, Win10 ends January 15, 2025 Biden Battered Over AI Diffusion Policy January 14, 2025 The best thing about CES 2025 January 13, 2025 Meta Scrap fact-checker, eases content restrictions January 8, 2025 2025 Cyber Security Predictions Influenced by AI January 7, 2025 Leave a Comment Cancel Reply Save my name, email, and website in this browser for the next time I comment.