-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Python: Allow plugins via agent constructors. Update samples. (#10707)
### Motivation and Context In Semantic Kernel, our goal is to simplify working with agents. When an agent is created without a specified kernel, one is automatically created on the user’s behalf. This enables developers to pass in a list of plugins that are then added to the underlying kernel. If both the agent constructor and the provided kernel include plugins, those specified via the agent constructor take precedence—since plugins are stored in a dictionary, any duplicate names result in the agent’s plugin overwriting the existing one. For the `ChatCompletionAgent`, usage is further simplified by allowing a `ChatCompletionClientBase` service to be passed via the constructor. If a kernel is supplied and already contains a chat completion service, the new service is added to the kernel. Moreover, if no execution settings are provided via KernelArguments, the first service registered on the kernel is used. New usage to create a ChatCompletionAgent ```python agent = ChatCompletionAgent( service=AzureChatCompletion(), name="<name>", instructions="<instructions>", ) ``` New usage to create a ChatCompletionAgent with plugins: ```python agent = ChatCompletionAgent( service=AzureChatCompletion(), name="<name>", instructions="<instructions>", plugins=[SamplePlugin()], ) ``` Previously, the `service_id` constructor argument was retained after introducing KernelArguments. However, with our transition to using the kernel’s AI service selector, the `service_id` parameter has become redundant. As we move from the experimental phase toward a release candidate, removing `service_id` is a necessary, albeit breaking, change. The `getting_started_with_agents/chat_completion` samples now begin by demonstrating the simplest way to configure the agent. The subsequent step illustrates the original method for setting up the chat completion service on the kernel. Similarly, for plugins, the initial approach is the easiest to follow, while the following step shows the traditional method of managing the kernel. Updated documentation will follow, once these changes are released in a new package. !-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description Simplifying interactions with agents. - Updated the `ChatCompletionAgent`, `AzureAssistantAgent`, and `OpenAIAssistantAgent` classes with the `release_candidate` decorator in place of the `experimental` decorator. - Add a chat completion agent structured outputs sample - Closes #10604 <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [X] The code builds clean without any errors or warnings - [X] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [X] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
- Loading branch information
Showing
37 changed files
with
579 additions
and
216 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
python/samples/concepts/agents/openai_assistant/openai_assistant_chart_maker.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...samples/getting_started_with_agents/chat_completion/step1_chat_completion_agent_simple.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Copyright (c) Microsoft. All rights reserved. | ||
|
||
import asyncio | ||
|
||
from semantic_kernel.agents import ChatCompletionAgent | ||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion | ||
from semantic_kernel.contents import ChatHistory | ||
|
||
""" | ||
The following sample demonstrates how to create a chat completion agent that | ||
answers user questions using the Azure Chat Completion service. The Chat Completion | ||
Service is passed directly via the ChatCompletionAgent constructor. This sample | ||
demonstrates the basic steps to create an agent and simulate a conversation | ||
with the agent. | ||
The interaction with the agent is via the `get_response` method, which sends a | ||
user input to the agent and receives a response from the agent. The conversation | ||
history needs to be maintained by the caller in the chat history object. | ||
""" | ||
|
||
# Simulate a conversation with the agent | ||
USER_INPUTS = [ | ||
"Hello, I am John Doe.", | ||
"What is your name?", | ||
"What is my name?", | ||
] | ||
|
||
|
||
async def main(): | ||
# 1. Create the agent by specifying the service | ||
agent = ChatCompletionAgent( | ||
service=AzureChatCompletion(), | ||
name="Assistant", | ||
instructions="Answer the user's questions.", | ||
) | ||
|
||
# 2. Create a chat history to hold the conversation | ||
chat_history = ChatHistory() | ||
|
||
for user_input in USER_INPUTS: | ||
# 3. Add the user input to the chat history | ||
chat_history.add_user_message(user_input) | ||
print(f"# User: {user_input}") | ||
# 4. Invoke the agent for a response | ||
response = await agent.get_response(chat_history) | ||
print(f"# {response.name}: {response}") | ||
# 5. Add the agent response to the chat history | ||
chat_history.add_message(response) | ||
|
||
""" | ||
Sample output: | ||
# User: Hello, I am John Doe. | ||
# Assistant: Hello, John Doe! How can I assist you today? | ||
# User: What is your name? | ||
# Assistant: I don't have a personal name like a human does, but you can call me Assistant.? | ||
# User: What is my name? | ||
# Assistant: You mentioned that your name is John Doe. How can I assist you further, John? | ||
""" | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
.../getting_started_with_agents/chat_completion/step3_chat_completion_agent_plugin_simple.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# Copyright (c) Microsoft. All rights reserved. | ||
|
||
import asyncio | ||
from typing import Annotated | ||
|
||
from semantic_kernel.agents import ChatCompletionAgent | ||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion | ||
from semantic_kernel.contents import ChatHistory | ||
from semantic_kernel.functions import kernel_function | ||
|
||
""" | ||
The following sample demonstrates how to create a chat completion agent that | ||
answers questions about a sample menu using a Semantic Kernel Plugin. The Chat | ||
Completion Service is passed directly via the ChatCompletionAgent constructor. | ||
Additionally, the plugin is supplied via the constructor. | ||
""" | ||
|
||
|
||
# Define a sample plugin for the sample | ||
class MenuPlugin: | ||
"""A sample Menu Plugin used for the concept sample.""" | ||
|
||
@kernel_function(description="Provides a list of specials from the menu.") | ||
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]: | ||
return """ | ||
Special Soup: Clam Chowder | ||
Special Salad: Cobb Salad | ||
Special Drink: Chai Tea | ||
""" | ||
|
||
@kernel_function(description="Provides the price of the requested menu item.") | ||
def get_item_price( | ||
self, menu_item: Annotated[str, "The name of the menu item."] | ||
) -> Annotated[str, "Returns the price of the menu item."]: | ||
return "$9.99" | ||
|
||
|
||
# Simulate a conversation with the agent | ||
USER_INPUTS = [ | ||
"Hello", | ||
"What is the special soup?", | ||
"What does that cost?", | ||
"Thank you", | ||
] | ||
|
||
|
||
async def main(): | ||
# 1. Create the agent | ||
agent = ChatCompletionAgent( | ||
service=AzureChatCompletion(), | ||
name="Host", | ||
instructions="Answer questions about the menu.", | ||
plugins=[MenuPlugin()], | ||
) | ||
|
||
# 2. Create a chat history to hold the conversation | ||
chat_history = ChatHistory() | ||
|
||
for user_input in USER_INPUTS: | ||
# 3. Add the user input to the chat history | ||
chat_history.add_user_message(user_input) | ||
print(f"# User: {user_input}") | ||
# 4. Invoke the agent for a response | ||
response = await agent.get_response(chat_history) | ||
print(f"# {response.name}: {response.content} ") | ||
|
||
""" | ||
Sample output: | ||
# User: Hello | ||
# Host: Hello! How can I assist you today? | ||
# User: What is the special soup? | ||
# Host: The special soup is Clam Chowder. | ||
# User: What does that cost? | ||
# Host: The special soup, Clam Chowder, costs $9.99. | ||
# User: Thank you | ||
# Host: You're welcome! If you have any more questions, feel free to ask. Enjoy your day! | ||
""" | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.