From 195c6bea1ea364ad7d42bc727a2f3cfdc86f4268 Mon Sep 17 00:00:00 2001 From: Wasim Date: Sun, 30 Aug 2026 16:58:07 +0530 Subject: [PATCH] docs: add PZERO OpenAI-compatible endpoint sample and documentation --- dotnet/docs/OPENAI-CONNECTOR-MIGRATION.md | 23 ++++- .../ChatCompletion/PZero_ChatCompletion.cs | 92 +++++++++++++++++++ dotnet/samples/Concepts/README.md | 1 + .../chat_completion/pzero_chat_completion.py | 59 ++++++++++++ 4 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 dotnet/samples/Concepts/ChatCompletion/PZero_ChatCompletion.cs create mode 100644 python/samples/concepts/chat_completion/pzero_chat_completion.py diff --git a/dotnet/docs/OPENAI-CONNECTOR-MIGRATION.md b/dotnet/docs/OPENAI-CONNECTOR-MIGRATION.md index 00cf243fc193..7393de26ca58 100644 --- a/dotnet/docs/OPENAI-CONNECTOR-MIGRATION.md +++ b/dotnet/docs/OPENAI-CONNECTOR-MIGRATION.md @@ -73,6 +73,22 @@ We have the two only specific cases where we attempted to auto-correct the endpo + http://any-host-and-port/v1 ``` +### 5.1 OpenAI-Compatible Endpoints Example (e.g., PZERO) + +When connecting to third-party OpenAI-compatible endpoints such as PZERO (`https://api.pzero.studio/v1`), provide the `/v1` root endpoint, API key, and model ID: + +```csharp +using Microsoft.SemanticKernel; + +var builder = Kernel.CreateBuilder(); +builder.AddOpenAIChatCompletion( + modelId: "deepseek-v4-flash", + endpoint: new Uri("https://api.pzero.studio/v1"), + apiKey: Environment.GetEnvironmentVariable("PZERO_API_KEY")! +); +var kernel = builder.Build(); +``` + ## 6. SemanticKernel MetaPackage To be retro compatible with the new OpenAI and AzureOpenAI Connectors, our `Microsoft.SemanticKernel` meta package changed its dependency to use the new `Microsoft.SemanticKernel.Connectors.AzureOpenAI` package that depends on the `Microsoft.SemanticKernel.Connectors.OpenAI` package. This way if you are using the metapackage, no change is needed to get access to `Azure` related types. @@ -181,15 +197,14 @@ The type also changed from `CompletionsUsage` to `ChatTokenUsage`. ```diff - Before - var usage = FunctionResult.Metadata?["Usage"] as CompletionsUsage; -- var completionTokesn = usage?.CompletionTokens ?? 0; +- var completionTokens = usage?.CompletionTokens ?? 0; - var promptTokens = usage?.PromptTokens ?? 0; + After + var usage = FunctionResult.Metadata?["Usage"] as ChatTokenUsage; + var promptTokens = usage?.InputTokens ?? 0; -+ var completionTokens = completionTokens: usage?.OutputTokens ?? 0; - -totalTokens: usage?.TotalTokens ?? 0; ++ var completionTokens = usage?.OutputTokens ?? 0; ++ var totalTokens = usage?.TotalTokens ?? 0; ``` #### 9.9 OpenAIClient diff --git a/dotnet/samples/Concepts/ChatCompletion/PZero_ChatCompletion.cs b/dotnet/samples/Concepts/ChatCompletion/PZero_ChatCompletion.cs new file mode 100644 index 000000000000..8661b0dd8126 --- /dev/null +++ b/dotnet/samples/Concepts/ChatCompletion/PZero_ChatCompletion.cs @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; +using Microsoft.SemanticKernel.Connectors.OpenAI; + +namespace ChatCompletion; + +/// +/// This example shows how to use the OpenAI connector with PZERO's OpenAI-compatible endpoint. +/// +/// Get a key from https://pzero.studio/agents +/// Set the environment variable PZERO_API_KEY with your key +/// Configure the endpoint to https://api.pzero.studio/v1 +/// Run the example +/// +/// +public class PZero_ChatCompletion(ITestOutputHelper output) : BaseTest(output) +{ + /// + /// This example shows how to configure PZERO OpenAI-compatible endpoint with Kernel InvokeAsync. + /// + [Fact] + public async Task UsingKernelWithPZero() + { + Console.WriteLine($"======== PZERO - Chat Completion - {nameof(UsingKernelWithPZero)} ========"); + + var apiKey = Environment.GetEnvironmentVariable("PZERO_API_KEY"); + if (string.IsNullOrEmpty(apiKey)) + { + Console.WriteLine("PZERO_API_KEY environment variable is not set. Skipping execution."); + return; + } + + var modelId = "deepseek-v4-flash"; + var endpoint = new Uri("https://api.pzero.studio/v1"); + + var kernel = Kernel.CreateBuilder() + .AddOpenAIChatCompletion( + modelId: modelId, + endpoint: endpoint, + apiKey: apiKey) + .Build(); + + var prompt = @"Rewrite the text between triple backticks into a business email. Use a professional tone, be clear and concise. + Sign the email as AI Assistant. + + Text: ```{{$input}}```"; + + var mailFunction = kernel.CreateFunctionFromPrompt(prompt, new OpenAIPromptExecutionSettings + { + TopP = 0.5, + MaxTokens = 1000, + }); + + var response = await kernel.InvokeAsync(mailFunction, new() { ["input"] = "Tell David that I will complete the report by Friday." }); + Console.WriteLine(response); + } + + /// + /// Sample showing how to use directly with a against PZERO. + /// + [Fact] + public async Task UsingServiceNonStreamingWithPZero() + { + Console.WriteLine($"======== PZERO - Chat Completion - {nameof(UsingServiceNonStreamingWithPZero)} ========"); + + var apiKey = Environment.GetEnvironmentVariable("PZERO_API_KEY"); + if (string.IsNullOrEmpty(apiKey)) + { + Console.WriteLine("PZERO_API_KEY environment variable is not set. Skipping execution."); + return; + } + + var modelId = "deepseek-v4-flash"; + var endpoint = new Uri("https://api.pzero.studio/v1"); + + OpenAIChatCompletionService chatService = new(modelId: modelId, endpoint: endpoint, apiKey: apiKey); + + Console.WriteLine("Chat content:"); + Console.WriteLine("------------------------"); + + var chatHistory = new ChatHistory("You are a helpful assistant."); + + chatHistory.AddUserMessage("Hello! Can you summarize the purpose of Semantic Kernel in one sentence?"); + this.OutputLastMessage(chatHistory); + + var reply = await chatService.GetChatMessageContentAsync(chatHistory); + chatHistory.Add(reply); + this.OutputLastMessage(chatHistory); + } +} diff --git a/dotnet/samples/Concepts/README.md b/dotnet/samples/Concepts/README.md index 77fe10e7a8ab..1241f0a5f235 100644 --- a/dotnet/samples/Concepts/README.md +++ b/dotnet/samples/Concepts/README.md @@ -97,6 +97,7 @@ dotnet test -l "console;verbosity=detailed" --filter "FullyQualifiedName=ChatCom - [OpenAI_RepeatedFunctionCalling](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/ChatCompletion/OpenAI_RepeatedFunctionCalling.cs) - [OpenAI_StructuredOutputs](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/ChatCompletion/OpenAI_StructuredOutputs.cs) - [OpenAI_UsingLogitBias](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/ChatCompletion/OpenAI_UsingLogitBias.cs) +- [PZero_ChatCompletion](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/ChatCompletion/PZero_ChatCompletion.cs) ### DependencyInjection - Examples on using `DI Container` diff --git a/python/samples/concepts/chat_completion/pzero_chat_completion.py b/python/samples/concepts/chat_completion/pzero_chat_completion.py new file mode 100644 index 000000000000..7962ba3bc970 --- /dev/null +++ b/python/samples/concepts/chat_completion/pzero_chat_completion.py @@ -0,0 +1,59 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import os + +from openai import AsyncOpenAI + +from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion +from semantic_kernel.contents.chat_history import ChatHistory +from semantic_kernel.functions.kernel_arguments import KernelArguments +from semantic_kernel.kernel import Kernel + +# This concept sample shows how to use the OpenAI connector with PZERO's +# OpenAI-compatible endpoint: https://api.pzero.studio/v1 +# Get an API key from https://pzero.studio/agents and set PZERO_API_KEY. + +system_message = """ +You are a helpful and concise AI assistant. +""" + +kernel = Kernel() + +service_id = "pzero-deepseek" + +api_key = os.environ.get("PZERO_API_KEY", "your-pzero-api-key") +endpoint = "https://api.pzero.studio/v1" +model_id = "deepseek-v4-flash" + +open_ai_client: AsyncOpenAI = AsyncOpenAI( + api_key=api_key, + base_url=endpoint, +) +kernel.add_service(OpenAIChatCompletion(service_id=service_id, ai_model_id=model_id, async_client=open_ai_client)) + +settings = kernel.get_prompt_execution_settings_from_service_id(service_id) +settings.max_tokens = 1000 +settings.temperature = 0.7 + +chat_function = kernel.add_function( + plugin_name="ChatBot", + function_name="Chat", + prompt="{{$chat_history}}{{$user_input}}", + template_format="semantic-kernel", + prompt_execution_settings=settings, +) + + +async def main() -> None: + chat_history = ChatHistory(system_message=system_message) + user_message = "What is Semantic Kernel in one sentence?" + chat_history.add_user_message(user_message) + + answer = await kernel.invoke(chat_function, KernelArguments(user_input=user_message, chat_history=chat_history)) + print(f"User:> {user_message}") + print(f"Assistant:> {answer}") + + +if __name__ == "__main__": + asyncio.run(main())