chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
## OpenAI Assistant Agents
|
||||
|
||||
The following getting started samples show how to use OpenAI Assistant agents with Semantic Kernel.
|
||||
|
||||
## Assistants API Overview
|
||||
|
||||
The Assistants API is a robust solution from OpenAI that empowers developers to integrate powerful, purpose-built AI assistants into their applications. It streamlines the development process by handling conversation histories, managing threads, and providing seamless access to advanced tools.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Purpose-Built AI Assistants:**
|
||||
Assistants are specialized AIs that leverage OpenAI’s models to interact with users, access files, maintain persistent threads, and call additional tools. This enables highly tailored and effective user interactions.
|
||||
|
||||
- **Simplified Conversation Management:**
|
||||
The concept of a **thread** -- a dedicated conversation session between an assistant and a user -- ensures that message history is managed automatically. Threads optimize the conversation context by storing and truncating messages as needed.
|
||||
|
||||
- **Integrated Tool Access:**
|
||||
The API provides built-in tools such as:
|
||||
- **Code Interpreter:** Allows the assistant to execute code, enhancing its ability to solve complex tasks.
|
||||
- **File Search:** Implements best practices for retrieving data from uploaded files, including advanced chunking and embedding techniques.
|
||||
|
||||
- **Enhanced Function Calling:**
|
||||
With improved support for third-party tool integration, the Assistants API enables assistants to extend their capabilities beyond native functions.
|
||||
|
||||
For more detailed technical information, refer to the [Assistants API](https://platform.openai.com/docs/assistants/overview).
|
||||
|
||||
### Semantic Kernel OpenAI Assistant Agents
|
||||
|
||||
OpenAI Assistant Agents are created in the following way:
|
||||
|
||||
```python
|
||||
from semantic_kernel.agents import OpenAIAssistantAgent
|
||||
|
||||
# Create the client using OpenAI resources and configuration
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name
|
||||
instructions="<instructions>",
|
||||
name="<name>",
|
||||
)
|
||||
|
||||
# Define the Semantic Kernel OpenAI Assistant Agent
|
||||
agent = OpenAIAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Define a thread
|
||||
thread = None
|
||||
|
||||
# Invoke the agent
|
||||
async for content in agent.invoke(messages="user input", thread=thread):
|
||||
print(f"# {content.role}: {content.content}")
|
||||
# Grab the thread from the response to continue with the current context
|
||||
thread = response.thread
|
||||
```
|
||||
|
||||
### Semantic Kernel Azure Assistant Agents
|
||||
|
||||
Azure Assistant Agents are currently in preview and require a `-preview` API version (minimum version: `2024-05-01-preview`). As new features are introduced, API versions will be updated accordingly. For the latest versioning details, please refer to the [Azure OpenAI API preview lifecycle](https://learn.microsoft.com/azure/ai-services/openai/api-version-deprecation).
|
||||
|
||||
To specify the correct API version, set the following environment variable (for example, in your `.env` file):
|
||||
|
||||
```bash
|
||||
AZURE_OPENAI_API_VERSION="2025-01-01-preview"
|
||||
```
|
||||
|
||||
Alternatively, you can pass the `api_version` parameter when creating an `AzureAssistantAgent`:
|
||||
|
||||
```python
|
||||
from semantic_kernel.agents import AzureAssistantAgent
|
||||
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client()
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name
|
||||
instructions="<instructions>",
|
||||
name="<name>",
|
||||
)
|
||||
|
||||
# Define the Semantic Kernel Azure OpenAI Assistant Agent
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Define a thread
|
||||
thread = None
|
||||
|
||||
# Invoke the agent
|
||||
async for content in agent.invoke(messages="user input", thread=thread):
|
||||
print(f"# {content.role}: {content.content}")
|
||||
# Grab the thread from the response to continue with the current context
|
||||
thread = response.thread
|
||||
```
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent that answers
|
||||
user questions using the code interpreter tool.
|
||||
|
||||
The agent is then used to answer user questions that require code to be generated and
|
||||
executed. The responses are handled in a streaming manner.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: azure_assistant
|
||||
name: CodeInterpreterAgent
|
||||
description: Agent with code interpreter tool.
|
||||
instructions: >
|
||||
Use the code interpreter tool to answer questions that require code to be generated
|
||||
and executed.
|
||||
model:
|
||||
id: ${AzureOpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${AzureOpenAI:ApiKey}
|
||||
tools:
|
||||
- type: code_interpreter
|
||||
options:
|
||||
file_ids:
|
||||
- ${AzureOpenAI:FileId1}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
csv_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"agent_assistant_file_manipulation",
|
||||
"sales.csv",
|
||||
)
|
||||
|
||||
# Load the employees PDF file as a FileObject
|
||||
with open(csv_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"AzureOpenAI:FileId1": file.id},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Give me the code to calculate the total sales for all segments."
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
is_code = False
|
||||
last_role = None
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK,
|
||||
):
|
||||
current_is_code = response.metadata.get("code", False)
|
||||
|
||||
if current_is_code:
|
||||
if not is_code:
|
||||
print("\n\n```python")
|
||||
is_code = True
|
||||
print(response.content, end="", flush=True)
|
||||
else:
|
||||
if is_code:
|
||||
print("\n```")
|
||||
is_code = False
|
||||
last_role = None
|
||||
if hasattr(response, "role") and response.role is not None and last_role != response.role:
|
||||
print(f"\n# {response.role}: ", end="", flush=True)
|
||||
last_role = response.role
|
||||
print(response.content, end="", flush=True)
|
||||
if is_code:
|
||||
print("```\n")
|
||||
print()
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
await client.files.delete(file.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Give me the code to calculate the total sales for all segments.'
|
||||
|
||||
# AuthorRole.ASSISTANT: Let me first examine the contents of the uploaded file to determine its structure. This
|
||||
will allow me to create the appropriate code for calculating the total sales for all segments. Hang tight!
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
|
||||
# Load the uploaded file to examine its contents
|
||||
file_path = '/mnt/data/assistant-3nXizu2EX2EwXikUz71uNc'
|
||||
data = pd.read_csv(file_path)
|
||||
|
||||
# Display the first few rows and column names to understand the structure of the dataset
|
||||
data.head(), data.columns
|
||||
```
|
||||
|
||||
# AuthorRole.ASSISTANT: The dataset contains several columns, including `Segment`, `Sales`, and others such as
|
||||
`Country`, `Product`, and date-related information. To calculate the total sales for all segments, we will:
|
||||
|
||||
1. Group the data by the `Segment` column.
|
||||
2. Sum the `Sales` column for each segment.
|
||||
3. Calculate the grand total of all sales across all segments.
|
||||
|
||||
Here is the code snippet for this task:
|
||||
|
||||
```python
|
||||
# Group by 'Segment' and sum up 'Sales'
|
||||
segment_sales = data.groupby('Segment')['Sales'].sum()
|
||||
|
||||
# Calculate the total sales across all segments
|
||||
total_sales = segment_sales.sum()
|
||||
|
||||
print("Total Sales per Segment:")
|
||||
print(segment_sales)
|
||||
print(f"\nGrand Total Sales: {total_sales}")
|
||||
```
|
||||
|
||||
Would you like me to execute this directly for the uploaded data?
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent that answers
|
||||
user questions using the file search tool.
|
||||
|
||||
The agent is used to answer user questions that require file search to help ground
|
||||
answers from the model.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: azure_assistant
|
||||
name: FileSearchAgent
|
||||
description: Agent with file search tool.
|
||||
instructions: >
|
||||
Use the file search tool to answer questions from the user.
|
||||
model:
|
||||
id: ${AzureOpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${AzureOpenAI:ApiKey}
|
||||
tools:
|
||||
- type: file_search
|
||||
options:
|
||||
vector_store_ids:
|
||||
- ${AzureOpenAI:VectorStoreId}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI Assistant client
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Read and upload the file to the OpenAI AI service
|
||||
pdf_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"file_search",
|
||||
"employees.pdf",
|
||||
)
|
||||
# Upload the pdf file to the assistant service
|
||||
with open(pdf_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
vector_store = await client.vector_stores.create(
|
||||
name="assistant_file_search",
|
||||
file_ids=[file.id],
|
||||
)
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"AzureOpenAI:VectorStoreId": vector_store.id},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Who can help me if I have a sales question?"
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=TASK,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the agent, vector store, and file
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
await client.vector_stores.delete(vector_store.id)
|
||||
await client.files.delete(file.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Who can help me if I have a sales question?'
|
||||
# FileSearchAgent: If you have a sales question, you may contact the following individuals:
|
||||
|
||||
1. **Hicran Bea** - Sales Manager
|
||||
2. **Mariam Jaslyn** - Sales Representative
|
||||
3. **Angelino Embla** - Sales Representative
|
||||
|
||||
This information comes from the employee records【4:0†source】.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent that answers
|
||||
user questions. The sample shows how to load a declarative spec from a file.
|
||||
The plugins/functions must already exist in the kernel.
|
||||
They are not created declaratively via the spec.
|
||||
"""
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Define the YAML file path for the sample
|
||||
file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"declarative_spec",
|
||||
"azure_assistant_spec.yaml",
|
||||
)
|
||||
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
agent: AzureAssistantAgent = await AgentRegistry.create_from_file(
|
||||
file_path,
|
||||
plugins=[MenuPlugin()],
|
||||
client=client,
|
||||
)
|
||||
|
||||
# Create the agent
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread = None
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
# Store the thread for the next iteration
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.beta.assistants.delete(agent.id) if agent else None
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# Host: Hi there! How can I assist you today?
|
||||
# User: 'What is the special soup?'
|
||||
# Host: The special soup is Clam Chowder.
|
||||
# User: 'What is the special drink?'
|
||||
# Host: The special drink is Chai Tea.
|
||||
# User: 'How much is it?'
|
||||
# Host: The Chai Tea costs $9.99.
|
||||
# User: 'Thank you'
|
||||
# Host: You're welcome! If you have any more questions, feel free to ask.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent that invokes
|
||||
a story generation task using a prompt template and a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: azure_assistant
|
||||
name: StoryAgent
|
||||
description: An agent that generates a story about a topic.
|
||||
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
|
||||
model:
|
||||
id: ${AzureOpenAI:ChatModelId}
|
||||
connection:
|
||||
endpoint: ${AzureOpenAI:Endpoint}
|
||||
inputs:
|
||||
topic:
|
||||
description: The topic of the story.
|
||||
required: true
|
||||
default: Cats
|
||||
length:
|
||||
description: The number of sentences in the story.
|
||||
required: true
|
||||
default: 2
|
||||
outputs:
|
||||
output1:
|
||||
description: The generated story.
|
||||
template:
|
||||
format: semantic-kernel
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI Assistant client
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
)
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=None,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the agent, vector store, and file
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# StoryAgent: Under the silvery moon, three mischievous cats tiptoed across the rooftop, chasing
|
||||
shadows and sharing secret whispers. By dawn, they curled up together, purring softly, dreaming
|
||||
of adventures yet to come.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent based
|
||||
on an existing agent ID.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
id: ${AzureOpenAI:AgentId}
|
||||
type: azure_assistant
|
||||
instructions: You are helpful agent who always responds in French.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"AgentId": "<my-agent-id>"}, # Specify the existing agent ID
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Why is the sky blue?"
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=TASK,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Why is the sky blue?'
|
||||
# WeatherAgent: Le ciel est bleu à cause d'un phénomène appelé **diffusion de Rayleigh**. La lumière du
|
||||
Soleil est composée de toutes les couleurs du spectre visible, mais lorsqu'elle traverse l'atmosphère
|
||||
terrestre, elle entre en contact avec les molécules d'air et les particules présentes.
|
||||
|
||||
Les couleurs à courtes longueurs d'onde, comme le bleu et le violet, sont diffusées dans toutes les directions
|
||||
beaucoup plus efficacement que les couleurs à longues longueurs d'onde, comme le rouge et l'orange. Bien que le
|
||||
violet ait une longueur d'onde encore plus courte que le bleu, nos yeux sont moins sensibles à cette couleur,
|
||||
et une partie du violet est également absorbée par la haute atmosphère. Ainsi, le bleu domine, donnant au ciel
|
||||
sa couleur caractéristique.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.filters import (
|
||||
AutoFunctionInvocationContext,
|
||||
FilterTypes,
|
||||
)
|
||||
from semantic_kernel.functions import FunctionResult, kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant agent that
|
||||
answers user questions. This sample demonstrates the basic steps to create an agent
|
||||
and simulate a conversation with the agent.
|
||||
|
||||
This sample demonstrates how to create a filter that will be called for each
|
||||
function call in the response. The filter can be used to modify the function
|
||||
result or to terminate the function call. The filter can also be used to
|
||||
log the function call or to perform any other action before or after the
|
||||
function call.
|
||||
"""
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
# Define a kernel instance so we can attach the filter to it
|
||||
kernel = Kernel()
|
||||
|
||||
|
||||
# Define a list to store intermediate steps
|
||||
intermediate_steps: list[ChatMessageContent] = []
|
||||
|
||||
|
||||
# Define a callback function to handle intermediate step content messages
|
||||
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
intermediate_steps.append(message)
|
||||
|
||||
|
||||
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
|
||||
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
print("\nAuto function invocation filter")
|
||||
print(f"Function: {context.function.name}")
|
||||
|
||||
# if we don't call next, it will skip this function, and go to the next one
|
||||
await next(context)
|
||||
"""
|
||||
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
|
||||
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
|
||||
context.terminate = True
|
||||
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
|
||||
|
||||
Auto function invocation filter
|
||||
Function: get_specials
|
||||
# Assistant: MenuPlugin-get_specials -
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
"""
|
||||
result = context.function_result
|
||||
if "menu" in context.function.plugin_name.lower():
|
||||
print("Altering the Menu plugin function result...\n")
|
||||
context.function_result = FunctionResult(
|
||||
function=result.function,
|
||||
value="We are sold out, sorry!",
|
||||
)
|
||||
context.terminate = True
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# 2. Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# 3. Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
plugins=[MenuPlugin()],
|
||||
kernel=kernel,
|
||||
)
|
||||
|
||||
# 4. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread = None
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 5. Invoke the agent with the specified message for response
|
||||
async for response in agent.invoke(
|
||||
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
|
||||
):
|
||||
# 6. Print the response from the agent
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# 7. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
# Print the intermediate steps
|
||||
print("\nIntermediate Steps:")
|
||||
for msg in intermediate_steps:
|
||||
if any(isinstance(item, FunctionResultContent) for item in msg.items):
|
||||
for fr in msg.items:
|
||||
if isinstance(fr, FunctionResultContent):
|
||||
print(f"Function Result:> {fr.result} for function: {fr.name}")
|
||||
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
|
||||
for fcc in msg.items:
|
||||
if isinstance(fcc, FunctionCallContent):
|
||||
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
|
||||
else:
|
||||
print(f"{msg.role}: {msg.content}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: What's the special food on the menu?
|
||||
|
||||
Auto function invocation filter
|
||||
Function: get_specials
|
||||
Altering the Menu plugin function result...
|
||||
|
||||
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
|
||||
looking for, please let me know!
|
||||
# User: What should I do then?
|
||||
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
|
||||
information about specific items, such as prices or ingredients, feel free to ask!
|
||||
|
||||
Intermediate Steps:
|
||||
Function Call:> MenuPlugin-get_specials with arguments: {}
|
||||
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
|
||||
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
|
||||
else you're looking for, please let me know!
|
||||
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
|
||||
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.filters import (
|
||||
AutoFunctionInvocationContext,
|
||||
FilterTypes,
|
||||
)
|
||||
from semantic_kernel.functions import FunctionResult, kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant agent that
|
||||
answers user questions. This sample demonstrates the basic steps to create an agent
|
||||
and simulate a conversation with the agent.
|
||||
|
||||
This sample demonstrates how to create a filter that will be called for each
|
||||
function call in the response. The filter can be used to modify the function
|
||||
result or to terminate the function call. The filter can also be used to
|
||||
log the function call or to perform any other action before or after the
|
||||
function call.
|
||||
"""
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
# Define a kernel instance so we can attach the filter to it
|
||||
kernel = Kernel()
|
||||
|
||||
|
||||
# Define a list to store intermediate steps
|
||||
intermediate_steps: list[ChatMessageContent] = []
|
||||
|
||||
|
||||
# Define a callback function to handle intermediate step content messages
|
||||
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
intermediate_steps.append(message)
|
||||
|
||||
|
||||
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
|
||||
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
print("\nAuto function invocation filter")
|
||||
print(f"Function: {context.function.name}")
|
||||
|
||||
# if we don't call next, it will skip this function, and go to the next one
|
||||
await next(context)
|
||||
"""
|
||||
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
|
||||
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
|
||||
context.terminate = True
|
||||
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
|
||||
|
||||
Auto function invocation filter
|
||||
Function: get_specials
|
||||
# Assistant: MenuPlugin-get_specials -
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
"""
|
||||
result = context.function_result
|
||||
if "menu" in context.function.plugin_name.lower():
|
||||
print("Altering the Menu plugin function result...\n")
|
||||
context.function_result = FunctionResult(
|
||||
function=result.function,
|
||||
value="We are sold out, sorry!",
|
||||
)
|
||||
context.terminate = True
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# 2. Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# 3. Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
plugins=[MenuPlugin()],
|
||||
kernel=kernel,
|
||||
)
|
||||
|
||||
# 4. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread = None
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 5. Invoke the agent with the specified message for response
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
|
||||
):
|
||||
# 6. Print the response
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(f"{response}", end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
finally:
|
||||
# 7. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
# Print the intermediate steps
|
||||
print("\nIntermediate Steps:")
|
||||
for msg in intermediate_steps:
|
||||
if any(isinstance(item, FunctionResultContent) for item in msg.items):
|
||||
for fr in msg.items:
|
||||
if isinstance(fr, FunctionResultContent):
|
||||
print(f"Function Result:> {fr.result} for function: {fr.name}")
|
||||
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
|
||||
for fcc in msg.items:
|
||||
if isinstance(fcc, FunctionCallContent):
|
||||
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
|
||||
else:
|
||||
print(f"{msg.role}: {msg.content}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: What's the special food on the menu?
|
||||
|
||||
Auto function invocation filter
|
||||
Function: get_specials
|
||||
Altering the Menu plugin function result...
|
||||
|
||||
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
|
||||
looking for, please let me know!
|
||||
# User: What should I do then?
|
||||
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
|
||||
information about specific items, such as prices or ingredients, feel free to ask!
|
||||
|
||||
Intermediate Steps:
|
||||
Function Call:> MenuPlugin-get_specials with arguments: {}
|
||||
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
|
||||
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
|
||||
else you're looking for, please let me know!
|
||||
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
|
||||
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,86 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_images
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import FileReferenceContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and leverage the
|
||||
assistant and leverage the assistant's code interpreter tool
|
||||
in a streaming fashion.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Get the code interpreter tool and resources
|
||||
code_interpreter_tool, code_interpreter_resource = AzureAssistantAgent.configure_code_interpreter_tool()
|
||||
|
||||
# Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
instructions="Create charts as requested without explanation.",
|
||||
name="ChartMaker",
|
||||
tools=code_interpreter_tool,
|
||||
tool_resources=code_interpreter_resource,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"""
|
||||
Display this data using a bar-chart:
|
||||
|
||||
Banding Brown Pink Yellow Sum
|
||||
X00000 339 433 126 898
|
||||
X00300 48 421 222 691
|
||||
X12345 16 395 352 763
|
||||
Others 23 373 156 552
|
||||
Sum 426 1622 856 2904
|
||||
""",
|
||||
"Can you regenerate this same chart using the category names as the bar colors?",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
file_ids = []
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
if response.content:
|
||||
print(f"# {response.role}: {response}")
|
||||
|
||||
if len(response.items) > 0:
|
||||
for item in response.items:
|
||||
if isinstance(item, FileReferenceContent):
|
||||
file_ids.extend([
|
||||
item.file_id
|
||||
for item in response.items
|
||||
if isinstance(item, FileReferenceContent) and item.file_id is not None
|
||||
])
|
||||
|
||||
# Use a sample utility method to download the files to the current working directory
|
||||
await download_response_images(agent, file_ids)
|
||||
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_images
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import StreamingFileReferenceContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and leverage the
|
||||
assistant and leverage the assistant's code interpreter tool
|
||||
in a streaming fashion.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Get the code interpreter tool and resources
|
||||
code_interpreter_tool, code_interpreter_resource = AzureAssistantAgent.configure_code_interpreter_tool()
|
||||
|
||||
# Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
instructions="Create charts as requested without explanation.",
|
||||
name="ChartMaker",
|
||||
tools=code_interpreter_tool,
|
||||
tool_resources=code_interpreter_resource,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"""
|
||||
Display this data using a bar-chart:
|
||||
|
||||
Banding Brown Pink Yellow Sum
|
||||
X00000 339 433 126 898
|
||||
X00300 48 421 222 691
|
||||
X12345 16 395 352 763
|
||||
Others 23 373 156 552
|
||||
Sum 426 1622 856 2904
|
||||
""",
|
||||
"Can you regenerate this same chart using the category names as the bar colors?",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
|
||||
file_ids: list[str] = []
|
||||
is_code = False
|
||||
last_role = None
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
current_is_code = response.metadata.get("code", False)
|
||||
|
||||
if current_is_code:
|
||||
if not is_code:
|
||||
print("\n\n```python")
|
||||
is_code = True
|
||||
print(response.content, end="", flush=True)
|
||||
else:
|
||||
if is_code:
|
||||
print("\n```")
|
||||
is_code = False
|
||||
last_role = None
|
||||
if hasattr(response, "role") and response.role is not None and last_role != response.role:
|
||||
print(f"\n# {response.role}: ", end="", flush=True)
|
||||
last_role = response.role
|
||||
print(response.content, end="", flush=True)
|
||||
file_ids.extend([
|
||||
item.file_id
|
||||
for item in response.items
|
||||
if isinstance(item, StreamingFileReferenceContent) and item.file_id is not None
|
||||
])
|
||||
if is_code:
|
||||
print("```\n")
|
||||
|
||||
# Use a sample utility method to download the files to the current working directory
|
||||
await download_response_images(agent, file_ids)
|
||||
file_ids.clear()
|
||||
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
|
||||
user questions using the code interpreter tool.
|
||||
|
||||
The agent is then used to answer user questions that require code to be generated and
|
||||
executed. The responses are handled in a streaming manner.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: openai_assistant
|
||||
name: CodeInterpreterAgent
|
||||
description: Agent with code interpreter tool.
|
||||
instructions: >
|
||||
Use the code interpreter tool to answer questions that require code to be generated
|
||||
and executed.
|
||||
model:
|
||||
id: ${OpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${OpenAI:ApiKey}
|
||||
tools:
|
||||
- type: code_interpreter
|
||||
options:
|
||||
file_ids:
|
||||
- ${OpenAI:FileId1}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
csv_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"agent_assistant_file_manipulation",
|
||||
"sales.csv",
|
||||
)
|
||||
|
||||
# Load the employees PDF file as a FileObject
|
||||
with open(csv_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"OpenAI:FileId1": file.id},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Give me the code to calculate the total sales for all segments."
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
is_code = False
|
||||
last_role = None
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK,
|
||||
):
|
||||
current_is_code = response.metadata.get("code", False)
|
||||
|
||||
if current_is_code:
|
||||
if not is_code:
|
||||
print("\n\n```python")
|
||||
is_code = True
|
||||
print(response.content, end="", flush=True)
|
||||
else:
|
||||
if is_code:
|
||||
print("\n```")
|
||||
is_code = False
|
||||
last_role = None
|
||||
if hasattr(response, "role") and response.role is not None and last_role != response.role:
|
||||
print(f"\n# {response.role}: ", end="", flush=True)
|
||||
last_role = response.role
|
||||
print(response.content, end="", flush=True)
|
||||
if is_code:
|
||||
print("```\n")
|
||||
print()
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
await client.files.delete(file.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Give me the code to calculate the total sales for all segments.'
|
||||
|
||||
# AuthorRole.ASSISTANT: Let me first examine the contents of the uploaded file to determine its structure. This
|
||||
will allow me to create the appropriate code for calculating the total sales for all segments. Hang tight!
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
|
||||
# Load the uploaded file to examine its contents
|
||||
file_path = '/mnt/data/assistant-3nXizu2EX2EwXikUz71uNc'
|
||||
data = pd.read_csv(file_path)
|
||||
|
||||
# Display the first few rows and column names to understand the structure of the dataset
|
||||
data.head(), data.columns
|
||||
```
|
||||
|
||||
# AuthorRole.ASSISTANT: The dataset contains several columns, including `Segment`, `Sales`, and others such as
|
||||
`Country`, `Product`, and date-related information. To calculate the total sales for all segments, we will:
|
||||
|
||||
1. Group the data by the `Segment` column.
|
||||
2. Sum the `Sales` column for each segment.
|
||||
3. Calculate the grand total of all sales across all segments.
|
||||
|
||||
Here is the code snippet for this task:
|
||||
|
||||
```python
|
||||
# Group by 'Segment' and sum up 'Sales'
|
||||
segment_sales = data.groupby('Segment')['Sales'].sum()
|
||||
|
||||
# Calculate the total sales across all segments
|
||||
total_sales = segment_sales.sum()
|
||||
|
||||
print("Total Sales per Segment:")
|
||||
print(segment_sales)
|
||||
print(f"\nGrand Total Sales: {total_sales}")
|
||||
```
|
||||
|
||||
Would you like me to execute this directly for the uploaded data?
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
|
||||
user questions using the file search tool.
|
||||
|
||||
The agent is used to answer user questions that require file search to help ground
|
||||
answers from the model.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: openai_assistant
|
||||
name: FileSearchAgent
|
||||
description: Agent with code interpreter tool.
|
||||
instructions: >
|
||||
Use the code interpreter tool to answer questions that require code to be generated
|
||||
and executed.
|
||||
model:
|
||||
id: ${OpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${OpenAI:ApiKey}
|
||||
tools:
|
||||
- type: file_search
|
||||
options:
|
||||
vector_store_ids:
|
||||
- ${OpenAI:VectorStoreId}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI Assistant client
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
# Read and upload the file to the OpenAI AI service
|
||||
pdf_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"file_search",
|
||||
"employees.pdf",
|
||||
)
|
||||
# Upload the pdf file to the assistant service
|
||||
with open(pdf_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
vector_store = await client.vector_stores.create(
|
||||
name="assistant_file_search",
|
||||
file_ids=[file.id],
|
||||
)
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"OpenAI:VectorStoreId": vector_store.id},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Who can help me if I have a sales question?"
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=TASK,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the agent, vector store, and file
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
await client.vector_stores.delete(vector_store.id)
|
||||
await client.files.delete(file.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Who can help me if I have a sales question?'
|
||||
# FileSearchAgent: If you have a sales question, you can contact either Mariam Jaslyn or Angelino Embla, who
|
||||
are both listed as Sales Representatives. Alternatively, you may also reach out to Hicran Bea,
|
||||
the Sales Manager【4:0†employees.pdf】.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
|
||||
user questions. The sample shows how to load a declarative spec from a file.
|
||||
The plugins/functions must already exist in the kernel.
|
||||
They are not created declaratively via the spec.
|
||||
"""
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
# Define the YAML file path for the sample
|
||||
file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"declarative_spec",
|
||||
"openai_assistant_spec.yaml",
|
||||
)
|
||||
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_file(
|
||||
file_path,
|
||||
plugins=[MenuPlugin()],
|
||||
client=client,
|
||||
)
|
||||
|
||||
# Create the agent
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread = None
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
# Store the thread for the next iteration
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.beta.assistants.delete(agent.id) if agent else None
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# Host: Hi there! How can I assist you today?
|
||||
# User: 'What is the special soup?'
|
||||
# Host: The special soup is Clam Chowder.
|
||||
# User: 'What is the special drink?'
|
||||
# Host: The special drink is Chai Tea.
|
||||
# User: 'How much is it?'
|
||||
# Host: The Chai Tea costs $9.99.
|
||||
# User: 'Thank you'
|
||||
# Host: You're welcome! If you have any more questions, feel free to ask.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant Agent that invokes
|
||||
a story generation task using a prompt template and a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: openai_assistant
|
||||
name: StoryAgent
|
||||
description: An agent that generates a story about a topic.
|
||||
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
|
||||
model:
|
||||
id: ${OpenAI:ChatModelId}
|
||||
inputs:
|
||||
topic:
|
||||
description: The topic of the story.
|
||||
required: true
|
||||
default: Cats
|
||||
length:
|
||||
description: The number of sentences in the story.
|
||||
required: true
|
||||
default: 2
|
||||
outputs:
|
||||
output1:
|
||||
description: The generated story.
|
||||
template:
|
||||
format: semantic-kernel
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI Assistant client
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
)
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=None,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the agent, vector store, and file
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# StoryAgent: Under the silvery moon, three mischievous cats tiptoed across the rooftop, chasing
|
||||
shadows and sharing secret whispers. By dawn, they curled up together, purring softly, dreaming
|
||||
of adventures yet to come.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Assistant Agent based
|
||||
on an existing agent ID.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
id: ${OpenAI:AgentId}
|
||||
type: openai_assistant
|
||||
instructions: You are helpful agent who always responds in French.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
try:
|
||||
# Create the Assistant Agent from the YAML spec
|
||||
# Note: the extras can be provided in the short-format (shown below) or
|
||||
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"AgentId": "<my-agent-id>"}, # Specify the existing agent ID
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Why is the sky blue?"
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=TASK,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Why is the sky blue?'
|
||||
# WeatherAgent: Le ciel est bleu à cause d'un phénomène appelé **diffusion de Rayleigh**. La lumière du
|
||||
Soleil est composée de toutes les couleurs du spectre visible, mais lorsqu'elle traverse l'atmosphère
|
||||
terrestre, elle entre en contact avec les molécules d'air et les particules présentes.
|
||||
|
||||
Les couleurs à courtes longueurs d'onde, comme le bleu et le violet, sont diffusées dans toutes les directions
|
||||
beaucoup plus efficacement que les couleurs à longues longueurs d'onde, comme le rouge et l'orange. Bien que le
|
||||
violet ait une longueur d'onde encore plus courte que le bleu, nos yeux sont moins sensibles à cette couleur,
|
||||
et une partie du violet est également absorbée par la haute atmosphère. Ainsi, le bleu domine, donnant au ciel
|
||||
sa couleur caractéristique.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,87 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_files
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import AnnotationContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and leverage the
|
||||
assistant's ability to have the code interpreter work with
|
||||
uploaded files. This sample uses non-streaming responses.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
csv_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"agent_assistant_file_manipulation",
|
||||
"sales.csv",
|
||||
)
|
||||
|
||||
# Load the employees PDF file as a FileObject
|
||||
with open(csv_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
# Get the code interpreter tool and resources
|
||||
code_interpreter_tool, code_interpreter_tool_resource = AzureAssistantAgent.configure_code_interpreter_tool(file.id)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="FileManipulation",
|
||||
instructions="Find answers to the user's questions in the provided file.",
|
||||
tools=code_interpreter_tool,
|
||||
tool_resources=code_interpreter_tool_resource,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
try:
|
||||
user_inputs = [
|
||||
"Which segment had the most sales?",
|
||||
"List the top 5 countries that generated the most profit.",
|
||||
"Create a tab delimited file report of profit by each country per month.",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
if response.metadata.get("code", False):
|
||||
print(f"# {response.role}:\n\n```python")
|
||||
print(response)
|
||||
print("```")
|
||||
else:
|
||||
print(f"# {response.role}: {response}")
|
||||
|
||||
if response.items:
|
||||
for item in response.items:
|
||||
if isinstance(item, AnnotationContent):
|
||||
await download_response_files(agent, [item])
|
||||
finally:
|
||||
await client.files.delete(file.id)
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_files
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import ChatMessageContent, StreamingAnnotationContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Assistant Agent
|
||||
to leverage the assistant's ability to have the code interpreter work with
|
||||
uploaded files. This sample uses streaming responses.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
csv_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"agent_assistant_file_manipulation",
|
||||
"sales.csv",
|
||||
)
|
||||
|
||||
# Load the employees PDF file as a FileObject
|
||||
with open(csv_file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
# Get the code interpreter tool and resources
|
||||
code_interpreter_tools, code_interpreter_tool_resources = AzureAssistantAgent.configure_code_interpreter_tool(
|
||||
file.id
|
||||
)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="FileManipulation",
|
||||
instructions="Find answers to the user's questions in the provided file.",
|
||||
tools=code_interpreter_tools,
|
||||
tool_resources=code_interpreter_tool_resources,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
try:
|
||||
user_inputs = [
|
||||
# "Which segment had the most sales?",
|
||||
# "List the top 5 countries that generated the most profit.",
|
||||
"Create a tab delimited file report of profit by each country per month.",
|
||||
]
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
annotations: list[StreamingAnnotationContent] = []
|
||||
messages: list[ChatMessageContent] = []
|
||||
is_code = False
|
||||
last_role = None
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
current_is_code = response.metadata.get("code", False)
|
||||
|
||||
if current_is_code:
|
||||
if not is_code:
|
||||
print("\n\n```python")
|
||||
is_code = True
|
||||
print(response.content, end="", flush=True)
|
||||
else:
|
||||
if is_code:
|
||||
print("\n```")
|
||||
is_code = False
|
||||
last_role = None
|
||||
if hasattr(response, "role") and response.role is not None and last_role != response.role:
|
||||
print(f"\n# {response.role}: ", end="", flush=True)
|
||||
last_role = response.role
|
||||
print(response.content, end="", flush=True)
|
||||
if is_code:
|
||||
print("```\n")
|
||||
else:
|
||||
print()
|
||||
|
||||
# Use a sample utility method to download the files to the current working directory
|
||||
annotations.extend(
|
||||
item for message in messages for item in message.items if isinstance(item, StreamingAnnotationContent)
|
||||
)
|
||||
await download_response_files(agent, annotations)
|
||||
annotations.clear()
|
||||
finally:
|
||||
await client.files.delete(file.id)
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,131 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
This sample demonstrates how to create an AzureAssistantAgent/OpenAIAssistantAgent and invoke it using the
|
||||
non-streaming `invoke()` method. While `invoke()` returns only the final assistant message, the agent can
|
||||
optionally emit intermediate messages (e.g., function calls and results) via a callback by supplying
|
||||
`on_intermediate_message`.
|
||||
|
||||
In this example, the agent is configured with a plugin that provides menu specials and item pricing. As the user
|
||||
asks about the menu, the agent performs tool calls mid-invocation, and those intermediate steps are surfaced
|
||||
via the callback function while the invocation is still in progress.
|
||||
"""
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
|
||||
# This callback function will be called for each intermediate message,
|
||||
# which will allow one to handle FunctionCallContent and FunctionResultContent.
|
||||
# If the callback is not provided, the agent will return the final response
|
||||
# with no intermediate tool call steps.
|
||||
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
for item in message.items or []:
|
||||
if isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
elif isinstance(item, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
else:
|
||||
print(f"{item}")
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"What is the special drink?",
|
||||
"How much is that?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# {AuthorRole.USER}: '{user_input}'")
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_intermediate_steps,
|
||||
):
|
||||
print(f"# {response.role}: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
# AuthorRole.ASSISTANT: Hello! How can I assist you today?
|
||||
# AuthorRole.USER: 'What is the special soup?'
|
||||
Function Call:> MenuPlugin-get_specials with arguments: {}
|
||||
Function Result:>
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
for function: MenuPlugin-get_specials
|
||||
# AuthorRole.ASSISTANT: The special soup is Clam Chowder. Would you like to know more about the specials or
|
||||
anything else?
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
# AuthorRole.ASSISTANT: The special drink is Chai Tea. If you have any more questions, feel free to ask!
|
||||
# AuthorRole.USER: 'How much is that?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
# AuthorRole.ASSISTANT: The Chai Tea is priced at $9.99. If there's anything else you'd like to know,
|
||||
just let me know!
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions or need further assistance, feel free to
|
||||
ask. Enjoy your day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
This sample demonstrates how to create an AzureAssistantAgent/OpenAIAssistantAgent and use it with the
|
||||
streaming `invoke_stream()` method. The agent returns assistant messages as a stream of incremental chunks.
|
||||
In addition, you can specify an `on_intermediate_message` callback to receive fully-formed tool-related
|
||||
messages — such as function calls and their results — while the assistant response is still being streamed.
|
||||
|
||||
In this example, the agent is configured with a plugin that provides menu specials and item pricing.
|
||||
As the user interacts with the agent, tool messages (like function calls) are emitted via the callback,
|
||||
while assistant replies stream back incrementally through the main response loop.
|
||||
"""
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
|
||||
# This callback function will be called for each intermediate message,
|
||||
# which will allow one to handle FunctionCallContent and FunctionResultContent.
|
||||
# If the callback is not provided, the agent will return the final response
|
||||
# with no intermediate tool call steps.
|
||||
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
for item in message.items or []:
|
||||
if isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
elif isinstance(item, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
else:
|
||||
print(f"{item}")
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"What is the special drink?",
|
||||
"How much is that?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# {AuthorRole.USER}: '{user_input}'")
|
||||
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_streaming_intermediate_steps,
|
||||
):
|
||||
thread = response.thread
|
||||
if first_chunk:
|
||||
print(f"# {response.role}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print()
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
# AuthorRole.ASSISTANT: Hello! How can I help you with the menu today?
|
||||
# AuthorRole.USER: 'What is the special soup?'
|
||||
Function Call:> MenuPlugin-get_specials with arguments: {}
|
||||
Function Result:>
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
for function: MenuPlugin-get_specials
|
||||
# AuthorRole.ASSISTANT: The special soup today is Clam Chowder. Would you like to know more about it or see other
|
||||
specials?
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
# AuthorRole.ASSISTANT: The special drink is Chai Tea. Would you like more information about it or the other
|
||||
specials?
|
||||
# AuthorRole.USER: 'How much is that?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
# AuthorRole.ASSISTANT: The special drink, Chai Tea, is $9.99. Would you like to order one or have questions about
|
||||
something else on the menu?
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions or need help with the menu, just let me
|
||||
know. Enjoy your meal!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and retrieve it from
|
||||
the server to create a new instance of the assistant. This is done by
|
||||
retrieving the assistant definition from the server using the Assistant's
|
||||
ID and creating a new instance of the assistant using the retrieved definition.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant answering questions about the world in one sentence.",
|
||||
)
|
||||
|
||||
# Store the assistant ID
|
||||
assistant_id = definition.id
|
||||
|
||||
# Retrieve the assistant definition from the server based on the assistant ID
|
||||
new_asst_definition = await client.beta.assistants.retrieve(assistant_id)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=new_asst_definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = ["Why is the sky blue?"]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
print(f"# {response.role}: {response.content}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,54 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import os
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.agents import OpenAIAssistantAgent
|
||||
from semantic_kernel.contents import AnnotationContent, StreamingAnnotationContent
|
||||
|
||||
|
||||
async def download_file_content(agent: "OpenAIAssistantAgent", file_id: str, file_extension: str):
|
||||
"""A sample utility method to download the content of a file."""
|
||||
try:
|
||||
# Fetch the content of the file using the provided method
|
||||
response_content = await agent.client.files.content(file_id)
|
||||
|
||||
# Get the current working directory of the file
|
||||
current_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Define the path to save the image in the current directory
|
||||
file_path = os.path.join(
|
||||
current_directory, # Use the current directory of the file
|
||||
f"{file_id}.{file_extension}", # You can modify this to use the actual filename with proper extension
|
||||
)
|
||||
|
||||
# Save content to a file asynchronously
|
||||
with open(file_path, "wb") as file:
|
||||
file.write(response_content.content)
|
||||
|
||||
print(f"\n\nFile saved to: {file_path}")
|
||||
except Exception as e:
|
||||
print(f"An error occurred while downloading file {file_id}: {str(e)}")
|
||||
|
||||
|
||||
async def download_response_images(agent: "OpenAIAssistantAgent", file_ids: list[str]):
|
||||
"""A sample utility method to download the content of a list of files."""
|
||||
if file_ids:
|
||||
# Iterate over file_ids and download each one
|
||||
for file_id in file_ids:
|
||||
await download_file_content(agent, file_id, "png")
|
||||
|
||||
|
||||
async def download_response_files(
|
||||
agent: "OpenAIAssistantAgent", annotations: Sequence["StreamingAnnotationContent | AnnotationContent"]
|
||||
):
|
||||
"""A sample utility method to download the content of a file."""
|
||||
if annotations:
|
||||
# Iterate over file_ids and download each one
|
||||
for ann in annotations:
|
||||
if ann.quote is None or ann.file_id is None:
|
||||
continue
|
||||
extension = os.path.splitext(ann.quote)[1].lstrip(".")
|
||||
await download_file_content(agent, ann.file_id, extension)
|
||||
@@ -0,0 +1,85 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI. OpenAI Assistants
|
||||
allow for function calling, the use of file search and a
|
||||
code interpreter. Assistant Threads are used to manage the
|
||||
conversation state, similar to a Semantic Kernel Chat History.
|
||||
This sample also demonstrates the Assistants Streaming
|
||||
capability and how to manage an Assistants chat history.
|
||||
"""
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Define the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = ["Hello", "What is the special soup?", "What is the special drink?", "How much is that?", "Thank you"]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# {AuthorRole.USER}: '{user_input}'")
|
||||
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
if first_chunk:
|
||||
print(f"# {response.role}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print()
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
from pydantic import BaseModel
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and leverage the
|
||||
assistant's ability to returned structured outputs, based on a user-defined
|
||||
Pydantic model. This could also be a non-Pydantic model. Use the convenience
|
||||
method on the OpenAIAssistantAgent class to configure the response format,
|
||||
as shown below.
|
||||
|
||||
Note, you may specify your own JSON Schema. You'll need to make sure it is correct
|
||||
if not using the convenience method, per the following format:
|
||||
|
||||
json_schema = {
|
||||
"type": "json_schema",
|
||||
"json_schema": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"response": {"title": "Response", "type": "string"},
|
||||
"items": {"items": {"type": "string"}, "title": "Items", "type": "array"},
|
||||
},
|
||||
"required": ["response", "items"],
|
||||
"title": "ResponseModel",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
},
|
||||
"name": "ResponseModel",
|
||||
"strict": True,
|
||||
},
|
||||
}
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant answering questions about the world in one sentence.",
|
||||
response_format=json_schema,
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
# Define a Pydantic model that represents the structured output from the OpenAI service
|
||||
class ResponseModel(BaseModel):
|
||||
response: str
|
||||
items: list[str]
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant answering questions about the world in one sentence.",
|
||||
response_format=AzureAssistantAgent.configure_response_format(ResponseModel),
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
user_inputs = ["Why is the sky blue?"]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
# The response returned is a Pydantic Model, so we can validate it using the model_validate_json method
|
||||
response_model = ResponseModel.model_validate_json(str(response.content))
|
||||
print(f"# {response.role}: {response_model}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
from semantic_kernel.prompt_template import PromptTemplateConfig
|
||||
from semantic_kernel.prompt_template.const import TEMPLATE_FORMAT_TYPES
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an assistant
|
||||
agent using either Azure OpenAI or OpenAI within Semantic Kernel.
|
||||
It uses parameterized prompts and shows how to swap between
|
||||
"semantic-kernel," "jinja2," and "handlebars" template formats,
|
||||
This sample highlights how the agent's threaded conversation
|
||||
state parallels the Chat History in Semantic Kernel, ensuring
|
||||
all responses and parameters remain consistent throughout the
|
||||
session.
|
||||
"""
|
||||
|
||||
inputs = [
|
||||
("Home cooking is great.", None),
|
||||
("Talk about world peace.", "iambic pentameter"),
|
||||
("Say something about doing your best.", "e. e. cummings"),
|
||||
("What do you think about having fun?", "old school rap"),
|
||||
]
|
||||
|
||||
|
||||
async def invoke_agent_with_template(
|
||||
template_str: str, template_format: TEMPLATE_FORMAT_TYPES, default_style: str = "haiku"
|
||||
):
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Configure the prompt template
|
||||
prompt_template_config = PromptTemplateConfig(template=template_str, template_format=template_format)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="MyPoetAgent",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client, the assistant definition,
|
||||
# the prompt template config, and the constructor-level Kernel Arguments
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
prompt_template_config=prompt_template_config, # type: ignore
|
||||
arguments=KernelArguments(style=default_style),
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
try:
|
||||
for user_input, style in inputs:
|
||||
print(f"# User: {user_input}\n")
|
||||
|
||||
# If style is specified, override the 'style' argument
|
||||
argument_overrides = None
|
||||
if style:
|
||||
# Arguments passed in at invocation time take precedence over
|
||||
# the default arguments that were added via the constructor.
|
||||
argument_overrides = KernelArguments(style=style)
|
||||
|
||||
# Stream agent responses
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
|
||||
if response.content:
|
||||
print(f"{response.content}", flush=True, end="")
|
||||
thread = response.thread
|
||||
print("\n")
|
||||
finally:
|
||||
# Clean up
|
||||
await thread.delete() if thread else None
|
||||
await client.beta.assistants.delete(agent.id)
|
||||
|
||||
|
||||
async def main():
|
||||
# 1) Using "semantic-kernel" format
|
||||
print("\n===== SEMANTIC-KERNEL FORMAT =====\n")
|
||||
semantic_kernel_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{$style}}.
|
||||
Always state the requested style of the poem. Write appropriate G-rated content.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=semantic_kernel_template,
|
||||
template_format="semantic-kernel",
|
||||
default_style="haiku",
|
||||
)
|
||||
|
||||
# 2) Using "jinja2" format
|
||||
print("\n===== JINJA2 FORMAT =====\n")
|
||||
jinja2_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{style}}.
|
||||
Always state the requested style of the poem. Write appropriate G-rated content.
|
||||
"""
|
||||
await invoke_agent_with_template(template_str=jinja2_template, template_format="jinja2", default_style="haiku")
|
||||
|
||||
# 3) Using "handlebars" format
|
||||
print("\n===== HANDLEBARS FORMAT =====\n")
|
||||
handlebars_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{style}}.
|
||||
Always state the requested style of the poem. Write appropriate G-rated content.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FileReferenceContent, ImageContent, TextContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI and leverage the
|
||||
multi-modal content types to have the assistant describe images
|
||||
and answer questions about them and provide streaming responses.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))), "resources", "cat.jpg"
|
||||
)
|
||||
|
||||
with open(file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
instructions="Answer questions about the menu.",
|
||||
name="Host",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create a new thread for use with the assistant
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AssistantAgentThread = None
|
||||
|
||||
# Define a series of message with either ImageContent or FileReferenceContent
|
||||
user_inputs = {
|
||||
ChatMessageContent(
|
||||
role=AuthorRole.USER,
|
||||
items=[
|
||||
TextContent(text="Describe this image."),
|
||||
ImageContent(
|
||||
uri="https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/New_york_times_square-terabass.jpg/1200px-New_york_times_square-terabass.jpg"
|
||||
),
|
||||
],
|
||||
),
|
||||
ChatMessageContent(
|
||||
role=AuthorRole.USER,
|
||||
items=[
|
||||
TextContent(text="What is the main color in this image?"),
|
||||
ImageContent(uri="https://upload.wikimedia.org/wikipedia/commons/5/56/White_shark.jpg"),
|
||||
],
|
||||
),
|
||||
ChatMessageContent(
|
||||
role=AuthorRole.USER,
|
||||
items=[
|
||||
TextContent(text="Is there an animal in this image?"),
|
||||
FileReferenceContent(file_id=file.id),
|
||||
],
|
||||
),
|
||||
}
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input.items[0].text}'") # type: ignore
|
||||
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread):
|
||||
if response.role != AuthorRole.TOOL:
|
||||
if first_chunk:
|
||||
print("# Agent: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print("\n")
|
||||
|
||||
finally:
|
||||
await client.files.delete(file.id)
|
||||
await thread.delete() if thread else None
|
||||
await agent.client.beta.assistants.delete(assistant_id=agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user