chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# Semantic Kernel Samples
|
||||
|
||||
| Type | Description |
|
||||
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`getting_started`](./getting_started/CONFIGURING_THE_KERNEL.md) | Take this step by step tutorial to get started with Semantic Kernel and get introduced to the key concepts. |
|
||||
| [`getting_started_with_agents`](./getting_started_with_agents/README.md) | Take this step by step tutorial to get started with Semantic Kernel Agents and get introduced to the key concepts. |
|
||||
| [`getting_started_with_processes`](./getting_started_with_processes/README.md) | Take this step by step tutorial to get started with Semantic Kernel Processes and get introduced to the key concepts. |
|
||||
| [`concepts`](./concepts/README.md) | This section contains focused samples which illustrate all of the concepts included in Semantic Kernel. |
|
||||
| [`demos`](./demos/README.md) | Look here to find a sample which demonstrate how to use many of Semantic Kernel features. |
|
||||
| [`learn_resources`](./learn_resources/README.md) | Code snippets that are related to online documentation sources like Microsoft Learn, DevBlogs and others |
|
||||
@@ -0,0 +1,81 @@
|
||||
# Sample Guidelines
|
||||
|
||||
Samples are extremely important for developers to get started with Semantic Kernel. We strive to provide a wide range of samples that demonstrate the capabilities of Semantic Kernel with consistency and quality. This document outlines the guidelines for creating samples.
|
||||
|
||||
## General Guidelines
|
||||
|
||||
- **Clear and Concise**: Samples should be clear and concise. They should demonstrate a specific set of features or capabilities of Semantic Kernel. The less concepts a sample demonstrates, the better.
|
||||
- **Consistent Structure**: All samples should have a consistent structure. This includes the folder structure, file naming, and the content of the sample.
|
||||
- **Incremental Complexity**: Samples should start simple and gradually increase in complexity. This helps developers understand the concepts and features of Semantic Kernel.
|
||||
- **Documentation**: Samples should be over-documented.
|
||||
|
||||
### **Clear and Concise**
|
||||
|
||||
Try not to include too many concepts in a single sample. The goal is to demonstrate a specific feature or capability of Semantic Kernel. If you find yourself including too many concepts, consider breaking the sample into multiple samples. A good example of this is to break non-streaming and streaming modes into separate samples.
|
||||
|
||||
### **Consistent Structure**
|
||||
|
||||
#### Getting Started Samples
|
||||
|
||||
The getting started samples are the simplest samples that require minimal setup. These samples should be named in the following format: `step<number>_<name>.py`. One exception to this rule is when the sample is a notebook, in which case the sample should be named in the following format: `<number>_<name>.ipynb`.
|
||||
|
||||
#### Concept Samples
|
||||
|
||||
Concept samples under [./concepts](./concepts) should be grouped by feature or capability. These samples should be relatively short and demonstrate a specific concept. These samples are more advanced than the getting started samples.
|
||||
|
||||
#### Demos
|
||||
|
||||
Demos under [./demos](./demos) are full console applications that demonstrate a specific set of features or capabilities of Semantic Kernel, potentially with external dependencies. Each of the demos should have a README.md file that explains the purpose of the demo and how to run it.
|
||||
|
||||
### **Incremental Complexity**
|
||||
|
||||
Try to do a best effort to make sure that the samples are incremental in complexity. For example, in the getting started samples, each step should build on the previous step, and the concept samples should build on the getting started samples, same with the demos.
|
||||
|
||||
### **Documentation**
|
||||
|
||||
Try to over-document the samples. This includes comments in the code, README.md files, and any other documentation that is necessary to understand the sample. We use the guidance from [PEP8](https://peps.python.org/pep-0008/#comments) for comments in the code, with a deviation for the initial summary comment in samples and the output of the samples.
|
||||
|
||||
For the getting started samples and the concept samples, we should have the following:
|
||||
|
||||
1. A README.md file is included in each set of samples that explains the purpose of the samples and the setup required to run them.
|
||||
2. A summary should be included at the top of the file that explains the purpose of the sample and required components/concepts to understand the sample. For example:
|
||||
|
||||
```python
|
||||
'''
|
||||
This sample shows how to create a chatbot. This sample uses the following two main components:
|
||||
- a ChatCompletionService: This component is responsible for generating responses to user messages.
|
||||
- a ChatHistory: This component is responsible for keeping track of the chat history.
|
||||
The chatbot in this sample is called Mosscap, who responds to user messages with long flowery prose.
|
||||
'''
|
||||
```
|
||||
|
||||
3. Mark the code with comments to explain the purpose of each section of the code. For example:
|
||||
|
||||
```python
|
||||
# 1. Create the instance of the Kernel to register the plugin and service.
|
||||
...
|
||||
|
||||
# 2. Create the agent with the kernel instance.
|
||||
...
|
||||
```
|
||||
|
||||
> This will also allow the sample creator to track if the sample is getting too complex.
|
||||
|
||||
4. At the end of the sample, include a section that explains the expected output of the sample. For example:
|
||||
|
||||
```python
|
||||
'''
|
||||
Sample output:
|
||||
User:> Why is the sky blue in one sentence?
|
||||
Mosscap:> The sky is blue due to the scattering of sunlight by the molecules in the Earth's atmosphere,
|
||||
a phenomenon known as Rayleigh scattering, which causes shorter blue wavelengths to become more
|
||||
prominent in our visual perception.
|
||||
'''
|
||||
```
|
||||
|
||||
For the demos, a README.md file must be included that explains the purpose of the demo and how to run it. The README.md file should include the following:
|
||||
|
||||
- A description of the demo.
|
||||
- A list of dependencies required to run the demo.
|
||||
- Instructions on how to run the demo.
|
||||
- Expected output of the demo.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from .service_settings import ServiceSettings
|
||||
from .sk_service_configurator import add_service
|
||||
|
||||
__all__ = ["add_service", "ServiceSettings"]
|
||||
@@ -0,0 +1,284 @@
|
||||
# Semantic Kernel Concepts by Feature
|
||||
|
||||
## Table of Contents
|
||||
|
||||
### Agents - Creating and using [agents](../../semantic_kernel/agents/) in Semantic Kernel
|
||||
|
||||
#### [Azure AI Agent](../../semantic_kernel/agents/azure_ai/azure_ai_agent.py)
|
||||
|
||||
- [Azure AI Agent as Kernel Function](./agents/azure_ai_agent/azure_ai_agent_as_kernel_function.py)
|
||||
- [Azure AI Agent with Auto Function Invocation Filter Streaming](./agents/azure_ai_agent/azure_ai_agent_auto_func_invocation_filter_streaming.py)
|
||||
- [Azure AI Agent with Auto Function Invocation Filter](./agents/azure_ai_agent/azure_ai_agent_auto_func_invocation_filter.py)
|
||||
- [Azure AI Agent with Azure AI Search](./agents/azure_ai_agent/azure_ai_agent_azure_ai_search.py)
|
||||
- [Azure AI Agent with Bing Grounding Streaming with Message Callback](./agents/azure_ai_agent/azure_ai_agent_bing_grounding_streaming_with_message_callback.py)
|
||||
- [Azure AI Agent with Bing Grounding](./agents/azure_ai_agent/azure_ai_agent_bing_grounding.py)
|
||||
- [Azure AI Agent with Code Interpreter Streaming with Message Callback](./agents/azure_ai_agent/azure_ai_agent_code_interpreter_streaming_with_message_callback.py)
|
||||
- [Azure AI Agent Declarative with Azure AI Search](./agents/azure_ai_agent/azure_ai_agent_declarative_azure_ai_search.py)
|
||||
- [Azure AI Agent Declarative with Bing Grounding](./agents/azure_ai_agent/azure_ai_agent_declarative_bing_grounding.py)
|
||||
- [Azure AI Agent Declarative with Code Interpreter](./agents/azure_ai_agent/azure_ai_agent_declarative_code_interpreter.py)
|
||||
- [Azure AI Agent Declarative with File Search](./agents/azure_ai_agent/azure_ai_agent_declarative_file_search.py)
|
||||
- [Azure AI Agent Declarative with Function Calling From File](./agents/azure_ai_agent/azure_ai_agent_declarative_function_calling_from_file.py)
|
||||
- [Azure AI Agent Declarative with OpenAPI Interpreter](./agents/azure_ai_agent/azure_ai_agent_declarative_openapi.py)
|
||||
- [Azure AI Agent Declarative with Existing Agent ID](./agents/azure_ai_agent/azure_ai_agent_declarative_with_existing_agent_id.py)
|
||||
- [Azure AI Agent File Manipulation](./agents/azure_ai_agent/azure_ai_agent_file_manipulation.py)
|
||||
- [Azure AI Agent MCP Streaming](./agents/azure_ai_agent/azure_ai_agent_mcp_streaming.py)
|
||||
- [Azure AI Agent Prompt Templating](./agents/azure_ai_agent/azure_ai_agent_prompt_templating.py)
|
||||
- [Azure AI Agent Message Callback Streaming](./agents/azure_ai_agent/azure_ai_agent_message_callback_streaming.py)
|
||||
- [Azure AI Agent Message Callback](./agents/azure_ai_agent/azure_ai_agent_message_callback.py)
|
||||
- [Azure AI Agent Retrieve Messages from Thread](./agents/azure_ai_agent/azure_ai_agent_retrieve_messages_from_thread.py)
|
||||
- [Azure AI Agent Streaming](./agents/azure_ai_agent/azure_ai_agent_streaming.py)
|
||||
- [Azure AI Agent Structured Outputs](./agents/azure_ai_agent/azure_ai_agent_structured_outputs.py)
|
||||
- [Azure AI Agent Truncation Strategy](./agents/azure_ai_agent/azure_ai_agent_truncation_strategy.py)
|
||||
|
||||
#### [Bedrock Agent](../../semantic_kernel/agents/bedrock/bedrock_agent.py)
|
||||
|
||||
- [Bedrock Agent Simple Chat Streaming](./agents/bedrock_agent/bedrock_agent_simple_chat_streaming.py)
|
||||
- [Bedrock Agent Simple Chat](./agents/bedrock_agent/bedrock_agent_simple_chat.py)
|
||||
- [Bedrock Agent With Code Interpreter Streaming](./agents/bedrock_agent/bedrock_agent_with_code_interpreter_streaming.py)
|
||||
- [Bedrock Agent With Code Interpreter](./agents/bedrock_agent/bedrock_agent_with_code_interpreter.py)
|
||||
- [Bedrock Agent With Kernel Function Simple](./agents/bedrock_agent/bedrock_agent_with_kernel_function_simple.py)
|
||||
- [Bedrock Agent With Kernel Function Streaming](./agents/bedrock_agent/bedrock_agent_with_kernel_function_streaming.py)
|
||||
- [Bedrock Agent With Kernel Function](./agents/bedrock_agent/bedrock_agent_with_kernel_function.py)
|
||||
- [Bedrock Agent Mixed Chat Agents Streaming](./agents/bedrock_agent/bedrock_mixed_chat_agents_streaming.py)
|
||||
- [Bedrock Agent Mixed Chat Agents](./agents/bedrock_agent/bedrock_mixed_chat_agents.py)
|
||||
|
||||
#### [Chat Completion Agent](../../semantic_kernel/agents/chat_completion/chat_completion_agent.py)
|
||||
|
||||
- [Chat Completion Agent as Kernel Function](./agents/chat_completion_agent/chat_completion_agent_as_kernel_function.py)
|
||||
- [Chat Completion Agent Function Termination](./agents/chat_completion_agent/chat_completion_agent_function_termination.py)
|
||||
- [Chat Completion Agent Message Callback Streaming](./agents/chat_completion_agent/chat_completion_agent_message_callback_streaming.py)
|
||||
- [Chat Completion Agent Message Callback](./agents/chat_completion_agent/chat_completion_agent_message_callback.py)
|
||||
- [Chat Completion Agent Templating](./agents/chat_completion_agent/chat_completion_agent_prompt_templating.py)
|
||||
- [Chat Completion Agent Streaming Token Usage](./agents/chat_completion_agent/chat_completion_agent_streaming_token_usage.py)
|
||||
- [Chat Completion Agent Summary History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_agent_summary_history_reducer_agent_chat.py)
|
||||
- [Chat Completion Agent Summary History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_agent_summary_history_reducer_single_agent.py)
|
||||
- [Chat Completion Agent Token Usage](./agents/chat_completion_agent/chat_completion_agent_token_usage.py)
|
||||
- [Chat Completion Agent Truncate History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_agent_truncate_history_reducer_agent_chat.py)
|
||||
- [Chat Completion Agent Truncate History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_agent_truncate_history_reducer_single_agent.py)
|
||||
|
||||
#### [Mixed Agent Group Chat](../../semantic_kernel/agents/group_chat/agent_group_chat.py)
|
||||
|
||||
- [Mixed Chat Agents Plugins](./agents/mixed_chat/mixed_chat_agents_plugins.py)
|
||||
- [Mixed Chat Agents](./agents/mixed_chat/mixed_chat_agents.py)
|
||||
- [Mixed Chat Files](./agents/mixed_chat/mixed_chat_files.py)
|
||||
- [Mixed Chat Images](./agents/mixed_chat/mixed_chat_images.py)
|
||||
- [Mixed Chat Reset](./agents/mixed_chat/mixed_chat_reset.py)
|
||||
- [Mixed Chat Streaming](./agents/mixed_chat/mixed_chat_streaming.py)
|
||||
|
||||
#### [OpenAI Assistant Agent](../../semantic_kernel/agents/open_ai/openai_assistant_agent.py)
|
||||
|
||||
- [Azure OpenAI Assistant Declarative Code Interpreter](./agents/openai_assistant/azure_openai_assistant_declarative_code_interpreter.py)
|
||||
- [Azure OpenAI Assistant Declarative File Search](./agents/openai_assistant/azure_openai_assistant_declarative_file_search.py)
|
||||
- [Azure OpenAI Assistant Declarative Function Calling From File](./agents/openai_assistant/azure_openai_assistant_declarative_function_calling_from_file.py)
|
||||
- [Azure OpenAI Assistant Declarative Templating](./agents/openai_assistant/azure_openai_assistant_declarative_templating.py)
|
||||
- [Azure OpenAI Assistant Declarative With Existing Agent ID](./agents/openai_assistant/azure_openai_assistant_declarative_with_existing_agent_id.py)
|
||||
- [OpenAI Assistant Auto Function Invocation Filter Streaming](./agents/openai_assistant/openai_assistant_auto_func_invocation_filter_streaming.py)
|
||||
- [OpenAI Assistant Auto Function Invocation Filter](./agents/openai_assistant/openai_assistant_auto_func_invocation_filter.py)
|
||||
- [OpenAI Assistant Chart Maker Streaming](./agents/openai_assistant/openai_assistant_chart_maker_streaming.py)
|
||||
- [OpenAI Assistant Chart Maker](./agents/openai_assistant/openai_assistant_chart_maker.py)
|
||||
- [OpenAI Assistant Declarative Code Interpreter](./agents/openai_assistant/openai_assistant_declarative_code_interpreter.py)
|
||||
- [OpenAI Assistant Declarative File Search](./agents/openai_assistant/openai_assistant_declarative_file_search.py)
|
||||
- [OpenAI Assistant Declarative Function Calling From File](./agents/openai_assistant/openai_assistant_declarative_function_calling_from_file.py)
|
||||
- [OpenAI Assistant Declarative Templating](./agents/openai_assistant/openai_assistant_declarative_templating.py)
|
||||
- [OpenAI Assistant Declarative With Existing Agent ID](./agents/openai_assistant/openai_assistant_declarative_with_existing_agent_id.py)
|
||||
- [OpenAI Assistant File Manipulation Streaming](./agents/openai_assistant/openai_assistant_file_manipulation_streaming.py)
|
||||
- [OpenAI Assistant File Manipulation](./agents/openai_assistant/openai_assistant_file_manipulation.py)
|
||||
- [OpenAI Assistant Retrieval](./agents/openai_assistant/openai_assistant_retrieval.py)
|
||||
- [OpenAI Assistant Message Callback Streaming](./agents/openai_assistant/openai_assistant_message_callback_streaming.py)
|
||||
- [OpenAI Assistant Message Callback](./agents/openai_assistant/openai_assistant_message_callback.py)
|
||||
- [OpenAI Assistant Streaming](./agents/openai_assistant/openai_assistant_streaming.py)
|
||||
- [OpenAI Assistant Structured Outputs](./agents/openai_assistant/openai_assistant_structured_outputs.py)
|
||||
- [OpenAI Assistant Templating Streaming](./agents/openai_assistant/openai_assistant_templating_streaming.py)
|
||||
- [OpenAI Assistant Vision Streaming](./agents/openai_assistant/openai_assistant_vision_streaming.py)
|
||||
|
||||
#### [OpenAI Responses Agent](../../semantic_kernel/agents/open_ai/openai_responses_agent.py)
|
||||
|
||||
- [Azure OpenAI Responses Agent Declarative File Search](./agents/openai_responses/azure_openai_responses_agent_declarative_file_search.py)
|
||||
- [Azure OpenAI Responses Agent Declarative Function Calling From File](./agents/openai_responses/azure_openai_responses_agent_declarative_function_calling_from_file.py)
|
||||
- [Azure OpenAI Responses Agent Declarative Templating](./agents/openai_responses/azure_openai_responses_agent_declarative_templating.py)
|
||||
- [OpenAI Responses Agent Declarative File Search](./agents/openai_responses/openai_responses_agent_declarative_file_search.py)
|
||||
- [OpenAI Responses Agent Declarative Function Calling From File](./agents/openai_responses/openai_responses_agent_declarative_function_calling_from_file.py)
|
||||
- [OpenAI Responses Agent Declarative Web Search](./agents/openai_responses/openai_responses_agent_declarative_web_search.py)
|
||||
- [OpenAI Responses Binary Content Upload](./agents/openai_responses/responses_agent_binary_content_upload.py)
|
||||
- [OpenAI Responses Message Callback Streaming](./agents/openai_responses/responses_agent_message_callback_streaming.py)
|
||||
- [OpenAI Responses Message Callback](./agents/openai_responses/responses_agent_message_callback.py)
|
||||
- [OpenAI Responses File Search Streaming](./agents/openai_responses/responses_agent_file_search_streaming.py)
|
||||
- [OpenAI Responses Plugins Streaming](./agents/openai_responses/responses_agent_plugins_streaming.py)
|
||||
- [OpenAI Responses Reuse Existing Thread ID](./agents/openai_responses/responses_agent_reuse_existing_thread_id.py)
|
||||
- [OpenAI Responses Web Search Streaming](./agents/openai_responses/responses_agent_web_search_streaming.py)
|
||||
|
||||
### Audio - Using services that support audio-to-text and text-to-audio conversion
|
||||
|
||||
- [Chat with Audio Input](./audio/01-chat_with_audio_input.py)
|
||||
- [Chat with Audio Output](./audio/02-chat_with_audio_output.py)
|
||||
- [Chat with Audio Input and Output](./audio/03-chat_with_audio_input_output.py)
|
||||
- [Audio Player](./audio/audio_player.py)
|
||||
- [Audio Recorder](./audio/audio_recorder.py)
|
||||
|
||||
### AutoFunctionCalling - Using `Auto Function Calling` to allow function call capable models to invoke Kernel Functions automatically
|
||||
|
||||
- [Azure Python Code Interpreter Function Calling](./auto_function_calling/azure_python_code_interpreter_function_calling.py)
|
||||
- [Function Calling with Required Type](./auto_function_calling/function_calling_with_required_type.py)
|
||||
- [Parallel Function Calling](./auto_function_calling/parallel_function_calling.py)
|
||||
- [Chat Completion with Auto Function Calling Streaming](./auto_function_calling/chat_completion_with_auto_function_calling_streaming.py)
|
||||
- [Functions Defined in JSON Prompt](./auto_function_calling/functions_defined_in_json_prompt.py)
|
||||
- [Chat Completion with Manual Function Calling Streaming](./auto_function_calling/chat_completion_with_manual_function_calling_streaming.py)
|
||||
- [Functions Defined in YAML Prompt](./auto_function_calling/functions_defined_in_yaml_prompt.py)
|
||||
- [Chat Completion with Auto Function Calling](./auto_function_calling/chat_completion_with_auto_function_calling.py)
|
||||
- [Chat Completion with Manual Function Calling](./auto_function_calling/chat_completion_with_manual_function_calling.py)
|
||||
- [Nexus Raven](./auto_function_calling/nexus_raven.py)
|
||||
|
||||
### ChatCompletion - Using [`ChatCompletion`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/chat_completion_client_base.py) messaging capable service with models
|
||||
|
||||
- [Simple Chatbot](./chat_completion/simple_chatbot.py)
|
||||
- [Simple Chatbot Kernel Function](./chat_completion/simple_chatbot_kernel_function.py)
|
||||
- [Simple Chatbot Logit Bias](./chat_completion/simple_chatbot_logit_bias.py)
|
||||
- [Simple Chatbot Store Metadata](./chat_completion/simple_chatbot_store_metadata.py)
|
||||
- [Simple Chatbot Streaming](./chat_completion/simple_chatbot_streaming.py)
|
||||
- [Simple Chatbot with Image](./chat_completion/simple_chatbot_with_image.py)
|
||||
- [Simple Chatbot with Summary History Reducer Keeping Function Content](./chat_completion/simple_chatbot_with_summary_history_reducer_keep_func_content.py)
|
||||
- [Simple Chatbot with Summary History Reducer](./chat_completion/simple_chatbot_with_summary_history_reducer.py)
|
||||
- [Simple Chatbot with Truncation History Reducer](./chat_completion/simple_chatbot_with_truncation_history_reducer.py)
|
||||
- [Simple Chatbot with Summary History Reducer using Auto Reduce](./chat_completion/simple_chatbot_with_summary_history_reducer_autoreduce.py)
|
||||
- [Simple Chatbot with Truncation History Reducer using Auto Reduce](./chat_completion/simple_chatbot_with_truncation_history_reducer_autoreduce.py)
|
||||
|
||||
### ChatHistory - Using and serializing the [`ChatHistory`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/contents/chat_history.py)
|
||||
|
||||
- [Serialize Chat History](./chat_history/serialize_chat_history.py)
|
||||
- [Store Chat History in CosmosDB](./chat_history/store_chat_history_in_cosmosdb.py)
|
||||
|
||||
### Filtering - Creating and using Filters
|
||||
|
||||
- [Auto Function Invoke Filters](./filtering/auto_function_invoke_filters.py)
|
||||
- [Function Invocation Filters](./filtering/function_invocation_filters.py)
|
||||
- [Function Invocation Filters Stream](./filtering/function_invocation_filters_stream.py)
|
||||
- [Prompt Filters](./filtering/prompt_filters.py)
|
||||
- [Retry with Filters](./filtering/retry_with_filters.py)
|
||||
|
||||
### Functions - Invoking [`Method`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_method.py) or [`Prompt`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_prompt.py) functions with [`Kernel`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/kernel.py)
|
||||
|
||||
- [Kernel Arguments](./functions/kernel_arguments.py)
|
||||
|
||||
### Grounding - An example of how to perform LLM grounding
|
||||
|
||||
- [Grounded](./grounding/grounded.py)
|
||||
|
||||
### Local Models - Using the [`OpenAI connector`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/open_ai/services/open_ai_chat_completion.py) and [`OnnxGenAI connector`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/onnx/services/onnx_gen_ai_chat_completion.py) to talk to models hosted locally in Ollama, OnnxGenAI, and LM Studio
|
||||
|
||||
- [ONNX Chat Completion](./local_models/onnx_chat_completion.py)
|
||||
- [LM Studio Text Embedding](./local_models/lm_studio_text_embedding.py)
|
||||
- [LM Studio Chat Completion](./local_models/lm_studio_chat_completion.py)
|
||||
- [ONNX Phi3 Vision Completion](./local_models/onnx_phi3_vision_completion.py)
|
||||
- [Ollama Chat Completion](./local_models/ollama_chat_completion.py)
|
||||
- [ONNX Text Completion](./local_models/onnx_text_completion.py)
|
||||
|
||||
### Logging - Showing how to set up logging
|
||||
|
||||
- [Setup Logging](./logging/setup_logging.py)
|
||||
|
||||
### Memory - Using [`Memory`](https://learn.microsoft.com/en-us/semantic-kernel/concepts/vector-store-connectors/?pivots=programming-language-python) AI concepts
|
||||
|
||||
- [Simple Memory](./memory/simple_memory.py)
|
||||
- [Memory Data Models](./memory/data_models.py)
|
||||
- [Memory with Pandas Dataframes](./memory/memory_with_pandas.py)
|
||||
- [Complex memory](./memory/complex_memory.py)
|
||||
- [Full sample with Azure AI Search including function calling](./memory/azure_ai_search_hotel_samples/README.md)
|
||||
|
||||
### Model-as-a-Service - Using models deployed as [`serverless APIs on Azure AI Studio`](https://learn.microsoft.com/en-us/azure/ai-studio/how-to/deploy-models-serverless?tabs=azure-ai-studio) to benchmark model performance against open-source datasets
|
||||
|
||||
- [MMLU Model Evaluation](./model_as_a_service/mmlu_model_eval.py)
|
||||
|
||||
### On Your Data - Examples of using AzureOpenAI [`On Your Data`](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data?tabs=mongo-db)
|
||||
|
||||
- [Azure Chat GPT with Data API](./on_your_data/azure_chat_gpt_with_data_api.py)
|
||||
- [Azure Chat GPT with Data API Function Calling](./on_your_data/azure_chat_gpt_with_data_api_function_calling.py)
|
||||
- [Azure Chat GPT with Data API Vector Search](./on_your_data/azure_chat_gpt_with_data_api_vector_search.py)
|
||||
|
||||
### Plugins - Different ways of creating and using [`Plugins`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_plugin.py)
|
||||
|
||||
- [Azure Key Vault Settings](./plugins/azure_key_vault_settings.py)
|
||||
- [Azure Python Code Interpreter](./plugins/azure_python_code_interpreter.py)
|
||||
- [OpenAI Function Calling with Custom Plugin](./plugins/openai_function_calling_with_custom_plugin.py)
|
||||
- [Plugins from Directory](./plugins/plugins_from_dir.py)
|
||||
|
||||
### Processes - Examples of using the [`Process Framework`](../../semantic_kernel/processes/)
|
||||
|
||||
- [Cycles with Fan-In](./processes/cycles_with_fan_in.py)
|
||||
- [Nested Process](./processes/nested_process.py)
|
||||
- [Plan and Execute](./processes/plan_and_execute.py)
|
||||
|
||||
### PromptTemplates - Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/prompt_template/prompt_template_base.py) with parametrization for `Prompt` rendering
|
||||
|
||||
- [Template Language](./prompt_templates/template_language.py)
|
||||
- [Azure Chat GPT API Jinja2](./prompt_templates/azure_chat_gpt_api_jinja2.py)
|
||||
- [Load YAML Prompt](./prompt_templates/load_yaml_prompt.py)
|
||||
- [Azure Chat GPT API Handlebars](./prompt_templates/azure_chat_gpt_api_handlebars.py)
|
||||
- [Configuring Prompts](./prompt_templates/configuring_prompts.py)
|
||||
|
||||
### RAG - Different ways of `RAG` (Retrieval-Augmented Generation)
|
||||
|
||||
- [RAG with Vector Collection](./rag/rag_with_vector_collection.py)
|
||||
- [Self-Critique RAG](./rag/self_critique_rag.py)
|
||||
|
||||
### Reasoning - Using [`ChatCompletion`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/chat_completion_client_base.py) to reason with OpenAI Reasoning
|
||||
|
||||
- [Simple Chatbot](./reasoning/simple_reasoning.py)
|
||||
- [Simple Function Calling](./reasoning/simple_reasoning_function_calling.py)
|
||||
|
||||
### Search - Using [`Search`](https://github.com/microsoft/semantic-kernel/tree/main/python/semantic_kernel/connectors/search) services information
|
||||
|
||||
- [Bing Text Search as Plugin](./search/bing_text_search_as_plugin.py)
|
||||
- [Brave Text Search as Plugin](./search/brave_text_search_as_plugin.py)
|
||||
- [Google Text Search as Plugin](./search/google_text_search_as_plugin.py)
|
||||
|
||||
### Service Selector - Shows how to create and use a custom service selector class
|
||||
|
||||
- [Custom Service Selector](./service_selector/custom_service_selector.py)
|
||||
|
||||
### Setup - How to set up environment variables for Semantic Kernel
|
||||
|
||||
- [OpenAI Environment Setup](./setup/openai_env_setup.py)
|
||||
- [Chat Completion Services](./setup/chat_completion_services.py)
|
||||
|
||||
### Structured Outputs - How to leverage OpenAI's json_schema [`Structured Outputs`](https://platform.openai.com/docs/guides/structured-outputs) functionality
|
||||
|
||||
- [JSON Structured Outputs](./structured_outputs/json_structured_outputs.py)
|
||||
- [JSON Structured Outputs Function Calling](./structured_outputs/json_structured_outputs_function_calling.py)
|
||||
|
||||
### TextGeneration - Using [`TextGeneration`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/text_completion_client_base.py) capable service with models
|
||||
|
||||
- [Text Completion Client](./local_models/onnx_text_completion.py)
|
||||
|
||||
# Configuring the Kernel
|
||||
|
||||
In Semantic Kernel for Python, we leverage Pydantic Settings to manage configurations for AI and Memory Connectors, among other components. Here’s a clear guide on how to configure your settings effectively:
|
||||
|
||||
## Steps for Configuration
|
||||
|
||||
1. **Reading Environment Variables:**
|
||||
- **Primary Source:** Pydantic first attempts to read the required settings from environment variables.
|
||||
|
||||
2. **Using a .env File:**
|
||||
- **Fallback Source:** If the required environment variables are not set, Pydantic will look for a `.env` file in the current working directory.
|
||||
- **Custom Path (Optional):** You can specify an alternative path for the `.env` file via `env_file_path`. This can be either a relative or an absolute path.
|
||||
|
||||
3. **Direct Constructor Input:**
|
||||
- As an alternative to environment variables and `.env` files, you can pass the required settings directly through the constructor of the AI Connector or Memory Connector.
|
||||
|
||||
## Azure Authentication
|
||||
|
||||
To authenticate to your Azure resources, you must provide one of the following authentication methods to successfully authenticate:
|
||||
|
||||
1. **AsyncTokenCredential** - provide one of the `AsyncTokenCredential` types (e.g. `AzureCliCredential`, `ManagedIdentityCredential`). More information here: [Credentials for asynchronous Azure SDK clients]("https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.aio?view=azure-python").
|
||||
2. **Custom AsyncAzureOpenAI client** - Pass a pre-configured client instance.
|
||||
3. **Access Token (`ad_token`)** - Provide a valid Microsoft Entra access token directly.
|
||||
4. **Token Provider (`ad_token_provider`)** - Provide a callable that returns a valid access token.
|
||||
5. **API Key** - Provide through an environment variable, a `.env` file, or the constructor.
|
||||
|
||||
To successfully retrieve and use the Entra Auth Token, you need the `Cognitive Services OpenAI Contributor` role assigned to your Azure OpenAI resource. By default, the `https://cognitiveservices.azure.com` token endpoint is used. You can override this endpoint by setting an environment variable `.env` variable as `AZURE_OPENAI_TOKEN_ENDPOINT` or by passing a new value to the `AzureChatCompletion` constructor as part of the `AzureOpenAISettings`.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **.env File Placement:** We highly recommend placing the `.env` file in the `semantic-kernel/python` root directory. This is a common practice when developing in the Semantic Kernel repository.
|
||||
|
||||
By following these guidelines, you can ensure that your settings for various components are configured correctly, enabling seamless functionality and integration of Semantic Kernel in your Python projects.
|
||||
@@ -0,0 +1,123 @@
|
||||
# Semantic Kernel: Agent concept examples
|
||||
|
||||
This project contains a step by step guide to get started with _Semantic Kernel Agents_ in Python.
|
||||
|
||||
## PyPI
|
||||
|
||||
- For the use of Chat Completion agents, the minimum allowed Semantic Kernel pypi version is 1.3.0.
|
||||
- For the use of OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.4.0.
|
||||
- For the use of Agent Group Chat, the minimum allowed Semantic kernel pypi version is 1.6.0.
|
||||
- For the use of Streaming OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.11.0.
|
||||
- For the use of AzureAI and Bedrock agents, the minimum allowed Semantic Kernel pypi version is 1.21.0.
|
||||
- For the use of Crew.AI as a plugin, the minimum allowed Semantic Kernel pypi version is 1.21.1.
|
||||
- For the use of OpenAI Responses agents, the minimum allowed Semantic Kernel pypi version is 1.27.0.
|
||||
|
||||
## Source
|
||||
|
||||
- [Semantic Kernel Agent Framework](../../../semantic_kernel/agents/)
|
||||
|
||||
## Examples
|
||||
|
||||
The concept agents examples are grouped by prefix:
|
||||
|
||||
Prefix|Description
|
||||
---|---
|
||||
autogen_conversable_agent| How to use [AutoGen 0.2 Conversable Agents](https://microsoft.github.io/autogen/0.2/docs/Getting-Started) within Semantic Kernel.
|
||||
azure_ai_agent|How to use an [Azure AI Agent](https://learn.microsoft.com/en-us/azure/ai-services/agents/quickstart?pivots=programming-language-python-azure) within Semantic Kernel.
|
||||
chat_completion_agent|How to use Semantic Kernel Chat Completion agents that leverage AI Connector Chat Completion APIs.
|
||||
bedrock|How to use [AWS Bedrock agents](https://aws.amazon.com/bedrock/agents/) in Semantic Kernel.
|
||||
mixed_chat|How to combine different agent types.
|
||||
openai_assistant|How to use [OpenAI Assistants](https://platform.openai.com/docs/assistants/overview) in Semantic Kernel.
|
||||
openai_responses|How to use [OpenAI Responses](https://platform.openai.com/docs/api-reference/responses) in Semantic Kernel.
|
||||
|
||||
## Configuring the Kernel
|
||||
|
||||
Similar to the Semantic Kernel Python concept samples, it is necessary to configure the secrets
|
||||
and keys used by the kernel. See the follow "Configuring the Kernel" [guide](../README.md#configuring-the-kernel) for
|
||||
more information.
|
||||
|
||||
## Running Concept Samples
|
||||
|
||||
Concept samples can be run in an IDE or via the command line. After setting up the required api key or token authentication
|
||||
for your AI connector, the samples run without any extra command line arguments.
|
||||
|
||||
## Managing Conversation Threads with AgentThread
|
||||
|
||||
This section explains how to manage conversation context using the `AgentThread` base class. Each agent has its own thread implementation that preserves the context of a conversation. If you invoke an agent without specifying a thread, a new one is created automatically and returned as part of the `AgentItemResponse` object—which includes both the message (of type `ChatMessageContent`) and the thread (`AgentThread`). You also have the option to create a custom thread for a specific agent by providing a unique `thread_id`.
|
||||
|
||||
## Overview
|
||||
|
||||
**Automatic Thread Creation:**
|
||||
When an agent is invoked without a provided thread, it creates a new thread to manage the conversation context automatically.
|
||||
|
||||
**Manual Thread Management:**
|
||||
You can explicitly create a specific implementation for the desired `Agent` that derives from the base class `AgentThread`. You have the option to assign a `thread_id` to manage the conversation session. This is particularly useful in complex scenarios or multi-user environments.
|
||||
|
||||
## Code Example
|
||||
|
||||
Below is a sample code snippet demonstrating thread management:
|
||||
|
||||
```python
|
||||
from semantic_kernel.agents import ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
|
||||
USER_INPUTS = [
|
||||
"Why is the sky blue?",
|
||||
]
|
||||
|
||||
# 1. Create the agent by specifying the service
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(),
|
||||
name="Assistant",
|
||||
instructions="Answer the user's questions.",
|
||||
)
|
||||
|
||||
# 2. Create a thread to hold the conversation
|
||||
# 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}")
|
||||
# 3. Invoke the agent for a response
|
||||
response = await agent.get_response(
|
||||
message=user_input,
|
||||
thread=thread,
|
||||
)
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
# 4. Cleanup: Clear the thread
|
||||
await thread.end() if thread else None
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
# User: Hello, I am John Doe.
|
||||
# Assistant: Hello, John Doe! How can I assist you today?
|
||||
# User: What is your name?
|
||||
# Assistant: I don't have a personal name like a human does, but you can call me Assistant.?
|
||||
# User: What is my name?
|
||||
# Assistant: You mentioned that your name is John Doe. How can I assist you further, John?
|
||||
"""
|
||||
```
|
||||
|
||||
## Detailed Explanation
|
||||
|
||||
**Thread Initialization:**
|
||||
The thread is initially set to `None`. If no thread is provided, the agent creates a new one and includes it in the response.
|
||||
|
||||
**Processing User Inputs:**
|
||||
A list of `user_inputs` simulates a conversation. For each input:
|
||||
- The code prints the user's message.
|
||||
- The agent is invoked using the `get_response` method, which returns the response asynchronously.
|
||||
|
||||
**Handling Responses:**
|
||||
- The thread is updated with each response to maintain the conversation context.
|
||||
|
||||
**Cleanup:**
|
||||
The code safely ends the thread if it exists.
|
||||
|
||||
By leveraging the `AgentThread`, you ensure that each conversation maintains its context seamlessly -- whether the thread is automatically created or manually managed with a custom `thread_id`. This approach is crucial for developing agents that deliver coherent and context-aware interactions.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
## AutoGen Conversable Agent (v0.2.X)
|
||||
|
||||
Semantic Kernel Python supports running AutoGen Conversable Agents provided in the 0.2.X package.
|
||||
|
||||
### Limitations
|
||||
|
||||
Currently, there are some limitations to note:
|
||||
|
||||
- AutoGen Conversable Agents in Semantic Kernel run asynchronously and do not support streaming of agent inputs or responses.
|
||||
|
||||
### Installation
|
||||
|
||||
Install the `semantic-kernel` package with the `autogen` extra:
|
||||
|
||||
```bash
|
||||
pip install semantic-kernel[autogen]
|
||||
```
|
||||
|
||||
For an example of how to integrate an AutoGen Conversable Agent using the Semantic Kernel Agent abstraction, please refer to [`autogen_conversable_agent_simple_convo.py`](autogen_conversable_agent_simple_convo.py).
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from autogen import ConversableAgent
|
||||
from autogen.coding import LocalCommandLineCodeExecutor
|
||||
|
||||
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to use the AutoGenConversableAgent to create a reply from an agent
|
||||
to a message with a code block. The agent executes the code block and replies with the output.
|
||||
|
||||
The sample follows the AutoGen flow outlined here:
|
||||
https://microsoft.github.io/autogen/0.2/docs/tutorial/code-executors#local-execution
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
thread: AutoGenConversableAgentThread = None
|
||||
|
||||
# Create a temporary directory to store the code files.
|
||||
import os
|
||||
|
||||
# Configure the temporary directory to be where the script is located.
|
||||
temp_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Create a local command line code executor.
|
||||
executor = LocalCommandLineCodeExecutor(
|
||||
timeout=10, # Timeout for each code execution in seconds.
|
||||
work_dir=temp_dir, # Use the temporary directory to store the code files.
|
||||
)
|
||||
|
||||
# Create an agent with code executor configuration.
|
||||
code_executor_agent = ConversableAgent(
|
||||
"code_executor_agent",
|
||||
llm_config=False, # Turn off LLM for this agent.
|
||||
code_execution_config={"executor": executor}, # Use the local command line code executor.
|
||||
human_input_mode="ALWAYS", # Always take human input for this agent for safety.
|
||||
)
|
||||
|
||||
autogen_agent = AutoGenConversableAgent(conversable_agent=code_executor_agent)
|
||||
|
||||
message_with_code_block = """This is a message with code block.
|
||||
The code block is below:
|
||||
```python
|
||||
def generate_fibonacci(max_val):
|
||||
a, b = 0, 1
|
||||
fibonacci_numbers = []
|
||||
while a <= max_val:
|
||||
fibonacci_numbers.append(a)
|
||||
a, b = b, a + b
|
||||
return fibonacci_numbers
|
||||
|
||||
if __name__ == "__main__":
|
||||
fib_numbers = generate_fibonacci(101)
|
||||
print(fib_numbers)
|
||||
```
|
||||
This is the end of the message.
|
||||
"""
|
||||
|
||||
async for response in autogen_agent.invoke(messages=message_with_code_block, thread=thread):
|
||||
print(f"# {response.role} - {response.name or '*'}: '{response}'")
|
||||
thread = response.thread
|
||||
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from autogen import ConversableAgent, register_function
|
||||
|
||||
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
|
||||
from semantic_kernel.contents.function_call_content import FunctionCallContent
|
||||
from semantic_kernel.contents.function_result_content import FunctionResultContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to use the AutoGenConversableAgent to create a conversation between two agents
|
||||
where one agent suggests a tool function call and the other agent executes the tool function call.
|
||||
|
||||
In this example, the assistant agent suggests a calculator tool function call to the user proxy agent. The user proxy
|
||||
agent executes the calculator tool function call. The assistant agent and the user proxy agent are created using the
|
||||
ConversableAgent class. The calculator tool function is registered with the assistant agent and the user proxy agent.
|
||||
|
||||
This sample follows the AutoGen flow outlined here:
|
||||
https://microsoft.github.io/autogen/0.2/docs/tutorial/tool-use
|
||||
"""
|
||||
|
||||
|
||||
Operator = Literal["+", "-", "*", "/"]
|
||||
|
||||
|
||||
async def main():
|
||||
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int:
|
||||
if operator == "+":
|
||||
return a + b
|
||||
if operator == "-":
|
||||
return a - b
|
||||
if operator == "*":
|
||||
return a * b
|
||||
if operator == "/":
|
||||
return int(a / b)
|
||||
raise ValueError("Invalid operator")
|
||||
|
||||
assistant = ConversableAgent(
|
||||
name="Assistant",
|
||||
system_message="You are a helpful AI assistant. "
|
||||
"You can help with simple calculations. "
|
||||
"Return 'TERMINATE' when the task is done.",
|
||||
# Note: the model "gpt-4o" leads to a "division by zero" error that doesn't occur with "gpt-4o-mini"
|
||||
# or even "gpt-4".
|
||||
llm_config={
|
||||
"config_list": [{"model": os.environ["OPENAI_CHAT_MODEL_ID"], "api_key": os.environ["OPENAI_API_KEY"]}]
|
||||
},
|
||||
)
|
||||
|
||||
# Create a thread for use with the agent.
|
||||
thread: AutoGenConversableAgentThread = None
|
||||
|
||||
# Create a Semantic Kernel AutoGenConversableAgent based on the AutoGen ConversableAgent.
|
||||
assistant_agent = AutoGenConversableAgent(conversable_agent=assistant)
|
||||
|
||||
user_proxy = ConversableAgent(
|
||||
name="User",
|
||||
llm_config=False,
|
||||
is_termination_msg=lambda msg: msg.get("content") is not None and "TERMINATE" in msg["content"],
|
||||
human_input_mode="NEVER",
|
||||
)
|
||||
|
||||
assistant.register_for_llm(name="calculator", description="A simple calculator")(calculator)
|
||||
|
||||
# Register the tool function with the user proxy agent.
|
||||
user_proxy.register_for_execution(name="calculator")(calculator)
|
||||
|
||||
register_function(
|
||||
calculator,
|
||||
caller=assistant, # The assistant agent can suggest calls to the calculator.
|
||||
executor=user_proxy, # The user proxy agent can execute the calculator calls.
|
||||
name="calculator", # By default, the function name is used as the tool name.
|
||||
description="A simple calculator", # A description of the tool.
|
||||
)
|
||||
|
||||
# Create a Semantic Kernel AutoGenConversableAgent based on the AutoGen ConversableAgent.
|
||||
user_proxy_agent = AutoGenConversableAgent(conversable_agent=user_proxy)
|
||||
|
||||
async for response in user_proxy_agent.invoke(
|
||||
thread=thread,
|
||||
recipient=assistant_agent,
|
||||
messages="What is (44232 + 13312 / (232 - 32)) * 5?",
|
||||
max_turns=10,
|
||||
):
|
||||
for item in response.items:
|
||||
match item:
|
||||
case FunctionResultContent(result=r):
|
||||
print(f"# {response.role} - {response.name or '*'}: '{r}'")
|
||||
case FunctionCallContent(function_name=fn, arguments=arguments):
|
||||
print(
|
||||
f"# {response.role} - {response.name or '*'}: Function Name: '{fn}', Arguments: '{arguments}'" # noqa: E501
|
||||
)
|
||||
case _:
|
||||
print(f"# {response.role} - {response.name or '*'}: '{response}'")
|
||||
thread = response.thread
|
||||
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from autogen import ConversableAgent
|
||||
|
||||
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to use the AutoGenConversableAgent to create a conversation between two agents
|
||||
where one agent suggests a joke and the other agent generates a joke.
|
||||
|
||||
The sample follows the AutoGen flow outlined here:
|
||||
https://microsoft.github.io/autogen/0.2/docs/tutorial/introduction#roles-and-conversations
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
thread: AutoGenConversableAgentThread = None
|
||||
|
||||
cathy = ConversableAgent(
|
||||
"cathy",
|
||||
system_message="Your name is Cathy and you are a part of a duo of comedians.",
|
||||
llm_config={
|
||||
"config_list": [
|
||||
{
|
||||
"model": os.environ["OPENAI_CHAT_MODEL_ID"],
|
||||
"temperature": 0.9,
|
||||
"api_key": os.environ.get("OPENAI_API_KEY"),
|
||||
}
|
||||
]
|
||||
},
|
||||
human_input_mode="NEVER", # Never ask for human input.
|
||||
)
|
||||
|
||||
cathy_autogen_agent = AutoGenConversableAgent(conversable_agent=cathy)
|
||||
|
||||
joe = ConversableAgent(
|
||||
"joe",
|
||||
system_message="Your name is Joe and you are a part of a duo of comedians.",
|
||||
llm_config={
|
||||
"config_list": [
|
||||
{
|
||||
"model": os.environ["OPENAI_CHAT_MODEL_ID"],
|
||||
"temperature": 0.7,
|
||||
"api_key": os.environ.get("OPENAI_API_KEY"),
|
||||
}
|
||||
]
|
||||
},
|
||||
human_input_mode="NEVER", # Never ask for human input.
|
||||
)
|
||||
|
||||
joe_autogen_agent = AutoGenConversableAgent(conversable_agent=joe)
|
||||
|
||||
async for response in cathy_autogen_agent.invoke(
|
||||
recipient=joe_autogen_agent, message="Tell me a joke about the stock market.", thread=thread, max_turns=3
|
||||
):
|
||||
print(f"# {response.role} - {response.name or '*'}: '{response}'")
|
||||
thread = response.thread
|
||||
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,6 @@
|
||||
AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = "<example-connection-string>"
|
||||
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "<example-model-deployment-name>"
|
||||
AZURE_AI_AGENT_ENDPOINT = "<example-endpoint>"
|
||||
AZURE_AI_AGENT_SUBSCRIPTION_ID = "<example-subscription-id>"
|
||||
AZURE_AI_AGENT_RESOURCE_GROUP_NAME = "<example-resource-group-name>"
|
||||
AZURE_AI_AGENT_PROJECT_NAME = "<example-project-name>"
|
||||
@@ -0,0 +1,13 @@
|
||||
## Azure AI Agents
|
||||
|
||||
For details on using Azure AI Agents within Semantic Kernel, see the [README](../../../getting_started_with_agents/azure_ai_agent/README.md) in the `getting_started_with_agents/azure_ai_agent` directory.
|
||||
|
||||
### Running the `azure_ai_agent_ai_search.py` Sample
|
||||
|
||||
Before running this sample, ensure you have a valid index configured in your Azure AI Search resource. This sample queries hotel data using the sample Azure AI Search hotels index.
|
||||
|
||||
For configuration details, refer to the comments in the sample script. For additional guidance, consult the [README](../../memory/azure_ai_search_hotel_samples/README.md), which provides step-by-step instructions for creating the sample index and generating vectors. This is one approach to setting up the index; you can also follow other tutorials, such as those on "Import and Vectorize Data" in your Azure AI Search resource.
|
||||
|
||||
### Requests and Rate Limits
|
||||
|
||||
For information on configuring rate limits or adjusting polling, refer [here](../../../getting_started_with_agents/azure_ai_agent/README.md#requests-and-rate-limits)
|
||||
@@ -0,0 +1,160 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.agents import (
|
||||
AzureAIAgent,
|
||||
AzureAIAgentSettings,
|
||||
ChatCompletionAgent,
|
||||
ChatHistoryAgentThread,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.filters import FunctionInvocationContext
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI Agent Agent
|
||||
and a ChatCompletionAgent use them as tools available for a Triage Agent
|
||||
to delegate requests to the appropriate agent. A Function Invocation Filter
|
||||
is used to show the function call content and the function result content so the caller
|
||||
can see which agent was called and what the response was.
|
||||
"""
|
||||
|
||||
|
||||
# Define the auto function invocation filter that will be used by the kernel
|
||||
async def function_invocation_filter(context: FunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
if "messages" not in context.arguments:
|
||||
await next(context)
|
||||
return
|
||||
print(f" Agent [{context.function.name}] called with messages: {context.arguments['messages']}")
|
||||
await next(context)
|
||||
print(f" Response from agent [{context.function.name}]: {context.result.value}")
|
||||
|
||||
|
||||
async def chat(triage_agent: ChatCompletionAgent, thread: ChatHistoryAgentThread = None) -> bool:
|
||||
"""
|
||||
Continuously prompt the user for input and show the assistant's response.
|
||||
Type 'exit' to exit.
|
||||
"""
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
if user_input.lower().strip() == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
response = await triage_agent.get_response(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
)
|
||||
|
||||
if response:
|
||||
print(f"Agent :> {response}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# Create and configure the kernel.
|
||||
kernel = Kernel()
|
||||
|
||||
# The filter is used for demonstration purposes to show the function invocation.
|
||||
kernel.add_filter("function_invocation", function_invocation_filter)
|
||||
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
async with (
|
||||
AzureAIAgent.create_client(credential=credential, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
# Create the agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="BillingAgent",
|
||||
instructions=(
|
||||
"You specialize in handling customer questions related to billing issues. "
|
||||
"This includes clarifying invoice charges, payment methods, billing cycles, "
|
||||
"explaining fees, addressing discrepancies in billed amounts, updating payment details, "
|
||||
"assisting with subscription changes, and resolving payment failures. "
|
||||
"Your goal is to clearly communicate and resolve issues specifically about payments and charges."
|
||||
),
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
billing_agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
refund_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
name="RefundAgent",
|
||||
instructions=(
|
||||
"You specialize in addressing customer inquiries regarding refunds. "
|
||||
"This includes evaluating eligibility for refunds, explaining refund policies, "
|
||||
"processing refund requests, providing status updates on refunds, handling complaints related to "
|
||||
"refunds, and guiding customers through the refund claim process. "
|
||||
"Your goal is to assist users clearly and empathetically to successfully resolve their refund-related "
|
||||
"concerns."
|
||||
),
|
||||
)
|
||||
|
||||
triage_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
kernel=kernel,
|
||||
name="TriageAgent",
|
||||
instructions=(
|
||||
"Your role is to evaluate the user's request and forward it to the appropriate agent based on the "
|
||||
"nature of the query. Forward requests about charges, billing cycles, payment methods, fees, or "
|
||||
"payment issues to the BillingAgent. Forward requests concerning refunds, refund eligibility, "
|
||||
"refund policies, or the status of refunds to the RefundAgent. Your goal is accurate identification "
|
||||
"of the appropriate specialist to ensure the user receives targeted assistance."
|
||||
),
|
||||
plugins=[billing_agent, refund_agent],
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
print("Welcome to the chat bot!\n Type 'exit' to exit.\n Try to get some billing or refund help.")
|
||||
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat(triage_agent, thread)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
I canceled my subscription but I was still charged.
|
||||
Agent [BillingAgent] called with messages: I canceled my subscription but I was still charged.
|
||||
Response from agent [BillingAgent]: I understand how concerning that can be. It's possible that the charge you
|
||||
received is for a billing cycle that was initiated before your cancellation was processed. Here are a few
|
||||
steps you can take:
|
||||
|
||||
1. **Check Cancellation Confirmation**: Make sure you received a confirmation of your cancellation.
|
||||
This usually comes via email.
|
||||
|
||||
2. **Billing Cycle**: Review your billing cycle to confirm whether the charge aligns with your subscription terms.
|
||||
If your billing is monthly, charges can occur even if you cancel before the period ends.
|
||||
|
||||
3. **Contact Support**: If you believe the charge was made in error, please reach out to customer support for
|
||||
further clarification and to rectify the situation.
|
||||
|
||||
If you can provide more details about the subscription and when you canceled it, I can help you further understand
|
||||
the charges.
|
||||
|
||||
Agent :> It's possible that the charge you received is for a billing cycle initiated before your cancellation was
|
||||
processed. Please check if you received a cancellation confirmation, review your billing cycle, and contact
|
||||
support for further clarification if you believe the charge was made in error. If you have more details,
|
||||
I can help you understand the charges better.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
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 Azure AI 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:
|
||||
ai_agent_settings = AzureAIAgentSettings.create()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Create an agent on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer the user's questions about the menu.",
|
||||
)
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
kernel=kernel,
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin()], # Add the plugin to the agent
|
||||
)
|
||||
|
||||
# 3. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 4. 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
|
||||
):
|
||||
# 5. Print the response
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# 6. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(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())
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
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 Azure AI agent that answers
|
||||
user questions. This sample demonstrates the basic steps to create an agent
|
||||
and simulate a streaming 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:
|
||||
ai_agent_settings = AzureAIAgentSettings.create()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Create an agent on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer the user's questions about the menu.",
|
||||
)
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
kernel=kernel,
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin()], # Add the plugin to the agent
|
||||
)
|
||||
|
||||
# 3. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 4. 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
|
||||
):
|
||||
# 5. 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:
|
||||
# 6. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(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,139 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.ai.agents.models import AzureAISearchTool
|
||||
from azure.ai.projects.models import ConnectionType
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a simple,
|
||||
Azure AI agent that uses the Azure AI Search tool and the demo
|
||||
hotels-sample-index to answer questions about hotels.
|
||||
|
||||
This sample requires:
|
||||
- A "Standard" Agent Setup (choose the Python (Azure SDK) tab):
|
||||
https://learn.microsoft.com/en-us/azure/ai-services/agents/quickstart
|
||||
- An Azure AI Search index named 'hotels-sample-index' created in your
|
||||
Azure AI Search service. You may follow this guide to create the index:
|
||||
https://learn.microsoft.com/azure/search/search-get-started-portal
|
||||
- You will need to make sure your Azure AI Agent project is set up with
|
||||
the required Knowledge Source to be able to use the Azure AI Search tool.
|
||||
Refer to the following link for information on how to do this:
|
||||
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/azure-ai-search
|
||||
|
||||
Refer to the README for information about configuring the index to work
|
||||
with the sample data model in Azure AI Search.
|
||||
"""
|
||||
|
||||
# The name of the Azure AI Search index, rename as needed
|
||||
AZURE_AI_SEARCH_INDEX_NAME = "hotels-sample-index"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
ai_search_conn_id = ""
|
||||
async for connection in client.connections.list():
|
||||
if connection.type == ConnectionType.AZURE_AI_SEARCH:
|
||||
ai_search_conn_id = connection.id
|
||||
break
|
||||
|
||||
ai_search = AzureAISearchTool(index_connection_id=ai_search_conn_id, index_name=AZURE_AI_SEARCH_INDEX_NAME)
|
||||
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
instructions="Answer questions about hotels using your index.",
|
||||
tools=ai_search.definitions,
|
||||
tool_resources=ai_search.resources,
|
||||
headers={"x-ms-enable-preview": "true"},
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Which hotels are available with full-sized kitchens in Nashville, TN?",
|
||||
"Fun hotels with free WiFi.",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'\n")
|
||||
# Invoke the agent for the specified thread
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
print(f"# Agent: {response}\n")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Which hotels are available with full-sized kitchens in Nashville, TN?'
|
||||
|
||||
# Agent: In Nashville, TN, there are several hotels available that feature full-sized kitchens:
|
||||
|
||||
1. **Extended-Stay Hotel Options**:
|
||||
- Many extended-stay hotels offer suites equipped with full-sized kitchens, which include cookware and
|
||||
appliances. These hotels are designed for longer stays, making them a great option for those needing more space
|
||||
and kitchen facilities【3:0†source】【3:1†source】.
|
||||
|
||||
2. **Amenities Included**:
|
||||
- Most of these hotels provide additional amenities like free Wi-Fi, laundry services, fitness centers, and some
|
||||
have on-site dining options【3:1†source】【3:2†source】.
|
||||
|
||||
3. **Location**:
|
||||
- The extended-stay hotels are often located near downtown Nashville, making it convenient for guests to
|
||||
explore the vibrant local music scene while enjoying the comfort of a home-like
|
||||
environment【3:0†source】【3:4†source】.
|
||||
|
||||
If you are looking for specific names or more detailed options, I can further assist you with that!
|
||||
|
||||
# User: 'Fun hotels with free WiFi.'
|
||||
|
||||
# Agent: Here are some fun hotels that offer free WiFi:
|
||||
|
||||
1. **Vibrant Downtown Hotel**:
|
||||
- Located near the heart of downtown, this hotel offers a warm atmosphere with free WiFi and even provides a
|
||||
delightful milk and cookies treat【7:2†source】.
|
||||
|
||||
2. **Extended-Stay Options**:
|
||||
- These hotels often feature fun amenities such as a bowling alley, fitness center, and themed rooms. They also
|
||||
provide free WiFi and are well-situated near local attractions【7:0†source】【7:1†source】.
|
||||
|
||||
3. **Luxury Hotel**:
|
||||
- Ranked highly by Traveler magazine, this 5-star luxury hotel boasts the biggest rooms in the city, free WiFi,
|
||||
espresso in the room, and flexible check-in/check-out options【7:1†source】.
|
||||
|
||||
4. **Budget-Friendly Hotels**:
|
||||
- Several budget hotels offer free WiFi, breakfast, and shuttle services to nearby attractions and airports
|
||||
while still providing a fun stay【7:3†source】.
|
||||
|
||||
These options ensure you stay connected while enjoying your visit! If you need more specific recommendations or
|
||||
details, feel free to ask!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,110 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.ai.agents.models import BingGroundingTool
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import (
|
||||
AnnotationContent,
|
||||
ChatMessageContent,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that
|
||||
uses the Bing grounding tool to answer a user's question.
|
||||
|
||||
Note: Please visit the following link to learn more about the Bing grounding tool:
|
||||
|
||||
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/bing-grounding?tabs=python&pivots=overview
|
||||
"""
|
||||
|
||||
TASK = "Which team won the 2025 NCAA basketball championship?"
|
||||
|
||||
|
||||
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() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Enter your Bing Grounding Connection Name
|
||||
bing_connection = await client.connections.get(name="<your-bing-grounding-connection-name>")
|
||||
conn_id = bing_connection.id
|
||||
|
||||
# 2. Initialize agent bing tool and add the connection id
|
||||
bing_grounding = BingGroundingTool(connection_id=conn_id)
|
||||
|
||||
# 3. Create an agent with Bing grounding on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
name="BingGroundingAgent",
|
||||
instructions="Use the Bing grounding tool to answer the user's question.",
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
tools=bing_grounding.definitions,
|
||||
)
|
||||
|
||||
# 4. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# 5. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
print(f"# User: '{TASK}'")
|
||||
# 6. Invoke the agent for the specified thread for response
|
||||
async for response in agent.invoke(
|
||||
messages=TASK, thread=thread, on_intermediate_message=handle_intermediate_steps
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
# 7. Show annotations
|
||||
if any(isinstance(item, AnnotationContent) for item in response.items):
|
||||
for annotation in response.items:
|
||||
if isinstance(annotation, AnnotationContent):
|
||||
print(
|
||||
f"Annotation :> {annotation.url}, source={annotation.quote}, with "
|
||||
f"start_index={annotation.start_index} and end_index={annotation.end_index}"
|
||||
)
|
||||
finally:
|
||||
# 8. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Which team won the 2025 NCAA basketball championship?'
|
||||
Function Call:> bing_grounding with arguments:
|
||||
{
|
||||
'requesturl': 'https://api.bing.microsoft.com/v7.0/search?q=search(query:2025 NCAA basketball championship winner)',
|
||||
'response_metadata': "{'market': 'en-US', 'num_docs_retrieved': 5, 'num_docs_actually_used': 5}"
|
||||
}
|
||||
# BingGroundingAgent: The team that won the 2025 NCAA men's basketball championship was the Florida Gators. They defeated the Houston Cougars with a final score of 65-63.
|
||||
The championship game took place in San Antonio, Texas, and the Florida team was coached by Todd Golden. This victory made Florida the national champion for the 2024-25
|
||||
NCAA Division I men's basketball season【3:0†source】【3:1†source】【3:2†source】.
|
||||
Annotation :> https://en.wikipedia.org/wiki/2025_NCAA_Division_I_men%27s_basketball_championship_game, source=【3:0†source】, with start_index=357 and end_index=369
|
||||
Annotation :> https://www.ncaa.com/history/basketball-men/d1, source=【3:1†source】, with start_index=369 and end_index=381
|
||||
Annotation :> https://sports.yahoo.com/article/won-march-madness-2025-ncaa-100551421.html, source=【3:2†source】, with start_index=381 and end_index=393
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.ai.agents.models import BingGroundingTool
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import (
|
||||
ChatMessageContent,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
StreamingAnnotationContent,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that
|
||||
uses the Bing grounding tool to answer a user's question.
|
||||
|
||||
Additionally, the `on_intermediate_message` callback is used to handle intermediate messages
|
||||
from the agent.
|
||||
|
||||
Note: Please visit the following link to learn more about the Bing grounding tool:
|
||||
|
||||
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/bing-grounding?tabs=python&pivots=overview
|
||||
"""
|
||||
|
||||
TASK = "Which team won the 2025 NCAA basketball championship?"
|
||||
|
||||
intermediate_steps: list[ChatMessageContent] = []
|
||||
|
||||
|
||||
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() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Enter your Bing Grounding Connection Name
|
||||
bing_connection = await client.connections.get(name="<your-bing-grounding-connection-name>")
|
||||
conn_id = bing_connection.id
|
||||
|
||||
# 2. Initialize agent bing tool and add the connection id
|
||||
bing_grounding = BingGroundingTool(connection_id=conn_id)
|
||||
|
||||
# 3. Create an agent with Bing grounding on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
name="BingGroundingAgent",
|
||||
instructions="Use the Bing grounding tool to answer the user's question.",
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
tools=bing_grounding.definitions,
|
||||
)
|
||||
|
||||
# 4. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# 5. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
print(f"# User: '{TASK}'")
|
||||
# 6. Invoke the agent for the specified thread for response
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK, thread=thread, on_intermediate_message=handle_streaming_intermediate_steps
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(f"{response}", end="", flush=True)
|
||||
thread = response.thread
|
||||
|
||||
# 7. Show annotations
|
||||
if any(isinstance(item, StreamingAnnotationContent) for item in response.items):
|
||||
print()
|
||||
for annotation in response.items:
|
||||
if isinstance(annotation, StreamingAnnotationContent):
|
||||
print(
|
||||
f"Annotation :> {annotation.url}, source={annotation.quote}, with "
|
||||
f"start_index={annotation.start_index} and end_index={annotation.end_index}"
|
||||
)
|
||||
finally:
|
||||
# 8. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Which team won the 2025 NCAA basketball championship?'
|
||||
Function Call:> bing_grounding with arguments: {'requesturl': 'https://api.bing.microsoft.com/v7.0/search?q=search(query: 2025 NCAA basketball championship winner)'}
|
||||
Function Call:> bing_grounding with arguments: {'response_metadata': "{'market': 'en-US', 'num_docs_retrieved': 5, 'num_docs_actually_used': 5}"}
|
||||
# BingGroundingAgent: The Florida Gators won the 2025 NCAA men's basketball championship. They defeated the Houston Cougars with a close score of 65-63 in the championship game held in San Antonio, Texas. This victory marked their third national title. Florida overcame a 12-point deficit during the game to claim the championship【3:0†source】
|
||||
Annotation :> https://en.wikipedia.org/wiki/2025_NCAA_Division_I_men%27s_basketball_championship_game, source=None, with start_index=308 and end_index=320
|
||||
【3:1†source】
|
||||
Annotation :> https://www.ncaa.com/history/basketball-men/d1, source=None, with start_index=320 and end_index=332
|
||||
【3:2†source】
|
||||
Annotation :> https://sports.yahoo.com/article/florida-gators-win-2025-ncaa-034021303.html, source=None, with start_index=332 and end_index=344.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from functools import reduce
|
||||
|
||||
from azure.ai.agents.models import CodeInterpreterTool
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import ChatMessageContent, StreamingChatMessageContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that
|
||||
uses the code interpreter tool and returns streaming responses to answer a coding question.
|
||||
Additionally, the `on_intermediate_message` callback is used to handle intermediate messages
|
||||
from the agent.
|
||||
"""
|
||||
|
||||
TASK = "Use code to determine the values in the Fibonacci sequence that that are less then the value of 101."
|
||||
|
||||
intermediate_steps: list[ChatMessageContent] = []
|
||||
|
||||
|
||||
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
intermediate_steps.append(message)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Create an agent with a code interpreter on the Azure AI agent service
|
||||
code_interpreter = CodeInterpreterTool()
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
tools=code_interpreter.definitions,
|
||||
tool_resources=code_interpreter.resources,
|
||||
)
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# 3. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
print(f"# User: '{TASK}'")
|
||||
# 4. Invoke the agent for the specified thread for response
|
||||
is_code = False
|
||||
last_role = None
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK, thread=thread, on_intermediate_message=handle_streaming_intermediate_steps
|
||||
):
|
||||
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)
|
||||
thread = response.thread
|
||||
if is_code:
|
||||
print("```\n")
|
||||
print()
|
||||
finally:
|
||||
# 6. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
print("====================================================")
|
||||
print("\nResponse complete:\n")
|
||||
# Combine the intermediate `StreamingChatMessageContent` chunks into a single message
|
||||
filtered_steps = [step for step in intermediate_steps if isinstance(step, StreamingChatMessageContent)]
|
||||
streaming_full_completion: StreamingChatMessageContent = reduce(lambda x, y: x + y, filtered_steps)
|
||||
# Grab the other messages that are not `StreamingChatMessageContent`
|
||||
other_steps = [s for s in intermediate_steps if not isinstance(s, StreamingChatMessageContent)]
|
||||
final_msgs = [streaming_full_completion] + other_steps
|
||||
for msg in final_msgs:
|
||||
print(f"{msg.content}")
|
||||
|
||||
r"""
|
||||
Sample Output:
|
||||
# User: 'Use code to determine the values in the Fibonacci sequence that that are less then the value of 101.'
|
||||
|
||||
```python
|
||||
def fibonacci_sequence(limit):
|
||||
fib_sequence = []
|
||||
a, b = 0, 1
|
||||
while a < limit:
|
||||
fib_sequence.append(a)
|
||||
a, b = b, a + b
|
||||
return fib_sequence
|
||||
|
||||
# Get Fibonacci sequence values less than 101
|
||||
fibonacci_values = fibonacci_sequence(101)
|
||||
fibonacci_values
|
||||
```
|
||||
|
||||
# AuthorRole.ASSISTANT: The values in the Fibonacci sequence that are less than 101 are:
|
||||
|
||||
\[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89\]
|
||||
====================================================
|
||||
|
||||
Response complete:
|
||||
|
||||
def fibonacci_sequence(limit):
|
||||
fib_sequence = []
|
||||
a, b = 0, 1
|
||||
while a < limit:
|
||||
fib_sequence.append(a)
|
||||
a, b = b, a + b
|
||||
return fib_sequence
|
||||
|
||||
# Get Fibonacci sequence values less than 101
|
||||
fibonacci_values = fibonacci_sequence(101)
|
||||
fibonacci_values
|
||||
The values in the Fibonacci sequence that are less than 101 are:
|
||||
|
||||
\[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89\]
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.function_call_content import FunctionCallContent
|
||||
from semantic_kernel.contents.function_result_content import FunctionResultContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that answers
|
||||
user questions using the Azure AI Search tool.
|
||||
|
||||
The agent is created using a YAML declarative spec that configures the
|
||||
Azure AI Search tool. The agent is then used to answer user questions
|
||||
that required grounding context from the Azure AI Search index.
|
||||
|
||||
Note: the `AzureAISearchConnectionId` is in the format of:
|
||||
/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.MachineLearningServices/workspaces/<workspace>/connections/AzureAISearch
|
||||
|
||||
It can either be configured as an env var `AZURE_AI_AGENT_BING_CONNECTION_ID` or passed in as an extra to
|
||||
`create_from_yaml`: extras={
|
||||
"AzureAISearchConnectionId": "<azure_ai_search_connection_id>",
|
||||
"AzureAISearchIndexName": "<azure_ai_search_index_name>"
|
||||
}
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: foundry_agent
|
||||
name: AzureAISearchAgent
|
||||
instructions: Answer questions using your index to provide grounding context.
|
||||
description: This agent answers questions using AI Search to provide grounding context.
|
||||
model:
|
||||
id: ${AzureAI:ChatModelId}
|
||||
options:
|
||||
temperature: 0.4
|
||||
tools:
|
||||
- type: azure_ai_search
|
||||
options:
|
||||
tool_connections:
|
||||
- ${AzureAI:AzureAISearchConnectionId}
|
||||
index_name: ${AzureAI:AzureAISearchIndexName}
|
||||
"""
|
||||
|
||||
settings = AzureAIAgentSettings() # ChatModelId comes from .env/env vars
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# Create the AzureAI 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 `AzureAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
settings=settings,
|
||||
extras={
|
||||
"AzureAISearchConnectionId": "<azure-ai-search-connection-id>",
|
||||
"AzureAISearchIndexName": "<azure-ai-search-index-name>",
|
||||
},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "What is Semantic Kernel?"
|
||||
|
||||
print(f"# User: '{TASK}'")
|
||||
|
||||
# Define a callback function to handle intermediate messages
|
||||
async def on_intermediate_message(message: ChatMessageContent):
|
||||
if message.items:
|
||||
for item in message.items:
|
||||
if isinstance(item, FunctionCallContent):
|
||||
print(f"# FunctionCallContent: arguments={item.arguments}")
|
||||
elif isinstance(item, FunctionResultContent):
|
||||
print(f"# FunctionResultContent: result={item.result}")
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(messages=TASK, on_intermediate_message=on_intermediate_message):
|
||||
print(f"# {response.name}: {response}")
|
||||
finally:
|
||||
# Cleanup: Delete the agent
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that answers
|
||||
user questions using the Bing Grounding tool.
|
||||
|
||||
The agent is created using a YAML declarative spec that configures the
|
||||
Bing Grounding tool. The agent is then used to answer user questions
|
||||
that require web search to answer correctly.
|
||||
|
||||
Note: the `BingConnectionId` is in the format of:
|
||||
/subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.MachineLearningServices/workspaces/<workspace>/connections/<bing_connection_id>
|
||||
|
||||
It can either be configured as an env var `AZURE_AI_AGENT_BING_CONNECTION_ID` or passed in as an extra to
|
||||
`create_from_yaml`: extras={"BingConnectionId": "<bing_connection_id>"}
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: foundry_agent
|
||||
name: BingAgent
|
||||
instructions: Answer questions using Bing to provide grounding context.
|
||||
description: This agent answers questions using Bing to provide grounding context.
|
||||
model:
|
||||
id: ${AzureAI:ChatModelId}
|
||||
options:
|
||||
temperature: 0.4
|
||||
tools:
|
||||
- type: bing_grounding
|
||||
options:
|
||||
tool_connections:
|
||||
- ${AzureAI:BingConnectionId}
|
||||
"""
|
||||
|
||||
settings = AzureAIAgentSettings() # ChatModelId & BingConnectionId come from .env/env vars
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# Create the AzureAI Agent from the YAML spec
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
settings=settings,
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "Who won the 2025 NCAA basketball championship?"
|
||||
|
||||
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: 'Who won the 2025 NCAA basketball championship?'
|
||||
# BingAgent: The Florida Gators won the 2025 NCAA men's basketball championship, narrowly defeating the Houston
|
||||
Cougars 65-63 in the final game. This marked Florida's first national title since
|
||||
2007【3:5†source】【3:9†source】.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.ai.agents.models import FilePurpose
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI 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: foundry_agent
|
||||
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: ${AzureAI:ChatModelId}
|
||||
connection:
|
||||
endpoint: ${AzureAI:Endpoint}
|
||||
tools:
|
||||
- type: code_interpreter
|
||||
options:
|
||||
file_ids:
|
||||
- ${AzureAI:FileId1}
|
||||
"""
|
||||
|
||||
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from env vars
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# Create the CSV file path for the sample
|
||||
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",
|
||||
)
|
||||
|
||||
try:
|
||||
# Upload the CSV file to the agent service
|
||||
file = await client.agents.files.upload_and_poll(file_path=csv_file_path, purpose=FilePurpose.AGENTS)
|
||||
|
||||
# Create the AzureAI 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 `AzureAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
settings=settings,
|
||||
extras={"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.agents.delete_agent(agent.id)
|
||||
await client.agents.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())
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.ai.agents.models import VectorStore
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that answers
|
||||
user questions using the file search tool from a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: foundry_agent
|
||||
name: FileSearchAgent
|
||||
description: Agent with file search tool.
|
||||
instructions: >
|
||||
Use the file search tool to answer questions from the user.
|
||||
model:
|
||||
id: ${AzureAI:ChatModelId}
|
||||
connection:
|
||||
endpoint: ${AzureAI:Endpoint}
|
||||
tools:
|
||||
- type: file_search
|
||||
options:
|
||||
vector_store_ids:
|
||||
- ${AzureAI:VectorStoreId}
|
||||
"""
|
||||
|
||||
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from .env/env vars
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# Read and upload the file to the Azure AI agent 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 agent service
|
||||
file = await client.agents.files.upload_and_poll(file_path=pdf_file_path, purpose="assistants")
|
||||
vector_store: VectorStore = await client.agents.vector_stores.create(file_ids=[file.id], name="my_vectorstore")
|
||||
|
||||
try:
|
||||
# Create the AzureAI 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 `AzureAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
settings=settings,
|
||||
extras={"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.agents.delete_agent(agent.id)
|
||||
await client.agents.vector_stores.delete(vector_store.id)
|
||||
await client.agents.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())
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI 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():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# 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",
|
||||
"spec.yaml",
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent from the YAML spec
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_file(
|
||||
file_path,
|
||||
plugins=[MenuPlugin()],
|
||||
client=client,
|
||||
settings=AzureAIAgentSettings(), # The Spec's ChatModelId & Endpoint come from .env/env vars
|
||||
)
|
||||
|
||||
# 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: AzureAIAgentThread | None = 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.agents.delete_agent(agent.id) if agent else None
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,196 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that answers
|
||||
user questions using the OpenAPI tool. The agent is then used to answer user
|
||||
questions that leverage a free weather API.
|
||||
"""
|
||||
|
||||
# Toggle between a JSON or a YAML OpenAPI spec
|
||||
USE_JSON_OPENAPI_SPEC = True
|
||||
|
||||
json_openapi_spec = """
|
||||
type: foundry_agent
|
||||
name: WeatherAgent
|
||||
instructions: Answer questions about the weather. For all other questions politely decline to answer.
|
||||
description: This agent answers question about the weather.
|
||||
model:
|
||||
id: ${AzureAI:ChatModelId}
|
||||
connection:
|
||||
endpoint: ${AzureAI:Endpoint}
|
||||
options:
|
||||
temperature: 0.4
|
||||
tools:
|
||||
- type: openapi
|
||||
id: GetCurrentWeather
|
||||
description: Retrieves current weather data for a location based on wttr.in.
|
||||
options:
|
||||
specification: |
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Get Weather Data",
|
||||
"description": "Retrieves current weather data for a location based on wttr.in.",
|
||||
"version": "v1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://wttr.in"
|
||||
}
|
||||
],
|
||||
"auth": [],
|
||||
"paths": {
|
||||
"/{location}": {
|
||||
"get": {
|
||||
"description": "Get weather information for a specific location",
|
||||
"operationId": "GetCurrentWeather",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "path",
|
||||
"description": "City or location to retrieve the weather for",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"in": "query",
|
||||
"description": "Always use j1 value for this parameter",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "j1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Location not found"
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemes": {}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
yaml_openapi_spec = """
|
||||
type: foundry_agent
|
||||
name: WeatherAgent
|
||||
instructions: Answer questions about the weather. For all other questions politely decline to answer.
|
||||
description: This agent answers question about the weather.
|
||||
model:
|
||||
id: ${AzureAI:ChatModelId}
|
||||
options:
|
||||
temperature: 0.4
|
||||
tools:
|
||||
- type: openapi
|
||||
id: GetCurrentWeather
|
||||
description: Retrieves current weather data for a location based on wttr.in.
|
||||
options:
|
||||
specification:
|
||||
openapi: "3.1.0"
|
||||
info:
|
||||
title: "Get Weather Data"
|
||||
description: "Retrieves current weather data for a location based on wttr.in."
|
||||
version: "v1.0.0"
|
||||
servers:
|
||||
- url: "https://wttr.in"
|
||||
auth: []
|
||||
paths:
|
||||
"/{location}":
|
||||
get:
|
||||
description: "Get weather information for a specific location"
|
||||
operationId: "GetCurrentWeather"
|
||||
parameters:
|
||||
- name: "location"
|
||||
in: "path"
|
||||
description: "City or location to retrieve the weather for"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
- name: "format"
|
||||
in: "query"
|
||||
description: "Always use j1 value for this parameter"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
default: "j1"
|
||||
responses:
|
||||
"200":
|
||||
description: "Successful response"
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: "string"
|
||||
"404":
|
||||
description: "Location not found"
|
||||
deprecated: false
|
||||
components:
|
||||
schemes: {}
|
||||
"""
|
||||
|
||||
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from .env/env vars
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# Create the AzureAI Agent from the YAML spec
|
||||
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=json_openapi_spec if USE_JSON_OPENAPI_SPEC else yaml_openapi_spec,
|
||||
client=client,
|
||||
settings=settings,
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
TASK = "What is the current weather in Seoul?"
|
||||
|
||||
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.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'What is the current weather in Seoul?'
|
||||
# WeatherAgent: The current weather in Seoul is 14°C (57°F) with "light drizzle." It feels like 13°C (55°F).
|
||||
The humidity is at 81%, and there is heavy cloud cover (99%). The visibility is reduced to 2 km (1 mile),
|
||||
and the wind is coming from the east at 11 km/h (7 mph)
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI Agent that invokes
|
||||
a story generation task using a prompt template and a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: foundry_agent
|
||||
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: ${AzureAI:ChatModelId}
|
||||
connection:
|
||||
connection_string: ${AzureAI: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():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# Create the AzureAI Agent from the YAML spec
|
||||
agent: AzureAIAgent = 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.agents.delete_agent(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())
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureAIAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent based
|
||||
on an existing agent ID.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
id: ${AzureAI:AgentId}
|
||||
type: foundry_agent
|
||||
instructions: You are helpful agent who always responds in French.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
try:
|
||||
# Create the AzureAI 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 `AzureAI:` prefix).
|
||||
# The short-format is used here for brevity
|
||||
agent: AzureAIAgent = 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())
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.ai.agents.models import DeepResearchTool
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import (
|
||||
ChatMessageContent,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
StreamingAnnotationContent,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an AzureAIAgent along
|
||||
with the Deep Research Tool. Please visit the following documentation for more info
|
||||
on what is required to run the sample: https://aka.ms/agents-deep-research. Please pay
|
||||
attention to the purple `Note` boxes in the Azure docs.
|
||||
|
||||
Note that when you use your Bing Connection ID, it needs to be the connection ID from the project, not the resource.
|
||||
It has the following format:
|
||||
|
||||
'/subscriptions/<sub_id>/resourceGroups/<rg_name>/providers/<provider_name>/accounts/<account_name>/projects/<project_name>/connections/<connection_name>'
|
||||
"""
|
||||
|
||||
TASK = (
|
||||
"Research the current state of studies on orca intelligence and orca language, "
|
||||
"including what is currently known about orcas' cognitive capabilities and communication systems."
|
||||
)
|
||||
|
||||
|
||||
async def handle_intermediate_messages(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}")
|
||||
elif isinstance(item, StreamingAnnotationContent):
|
||||
label = item.title or item.url or "Annotation"
|
||||
print(f"Annotation:> {label} ({item.citation_type}) -> {item.url}")
|
||||
else:
|
||||
print(f"{item}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
azure_ai_agent_settings = AzureAIAgentSettings()
|
||||
# 1. Define the Deep Research tool
|
||||
deep_research_tool = DeepResearchTool(
|
||||
bing_grounding_connection_id=azure_ai_agent_settings.bing_connection_id,
|
||||
deep_research_model=azure_ai_agent_settings.deep_research_model,
|
||||
)
|
||||
|
||||
# 2. Create an agent with the tool on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model="gpt-4o", # Deep Research requires the use of gpt-4o for scope clarification.
|
||||
tools=deep_research_tool.definitions,
|
||||
instructions="You are a helpful Agent that assists in researching scientific topics.",
|
||||
)
|
||||
|
||||
# 3. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(client=client, definition=agent_definition, name="DeepResearchAgent")
|
||||
|
||||
# 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: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
print(f"# User: '{TASK}'")
|
||||
# 5. Invoke the agent for the specified thread for response
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_intermediate_messages,
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
# Print the text chunk
|
||||
print(f"{response}", end="", flush=True)
|
||||
# Print any streaming annotations that may arrive in this chunk
|
||||
for item in response.items or []:
|
||||
if isinstance(item, StreamingAnnotationContent):
|
||||
label = item.title or item.url or (item.quote or "Annotation")
|
||||
print(f"\n[Annotation] {label} -> {item.url}")
|
||||
thread = response.thread
|
||||
print()
|
||||
finally:
|
||||
# 6. Cleanup: Delete the thread, agent, and file
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Research the current state of studies on orca intelligence and orca language, including what is
|
||||
currently known about orcas' cognitive capabilities and communication systems.'
|
||||
Function Call:> deep_research with arguments: {'input': '{"prompt": "Research the current state of studies on
|
||||
orca intelligence and orca communication, focusing on their cognitive capabilities and language systems.
|
||||
Provide an overview of key discoveries, critical experiments, and major conclusions about their
|
||||
intelligence and communication systems. Prioritize primary research papers, reputable academic sources,
|
||||
and recent updates in the field (from the past 5 years if available). Format as a structured report with
|
||||
appropriate headings for clarity, and respond in English."}'}
|
||||
# azure_agent_QhTQHlUs: Title: Current Studies on Orca Intelligence and Communication
|
||||
|
||||
Starting deep research...
|
||||
|
||||
The user's task is to research orca intelligence, focusing on cognitive capabilities and communication.
|
||||
【1†Bing Search】
|
||||
|
||||
[Annotation] Bing Search: 'orca communication research 2020 killer whale cognitive study' -> https://www.bing.com/search?q=orca%20communication%20research%202020%20killer%20whale%20cognitive%20study
|
||||
|
||||
**Weighing options**
|
||||
|
||||
I'm examining the research on orca social dynamics, comparing a potential review to a recent journal article
|
||||
on large-scale unsupervised clustering of orca calls.
|
||||
|
||||
**Investigating orca datasets**
|
||||
|
||||
OK, let me see. PDF, Interspeech 2020, "ORCA-CLEAN: A Deep Denoising Toolkit for Killer Whale Communication"
|
||||
seems relevant. They focus on cognitive capabilities, language systems, and communication.
|
||||
|
||||
I'm considering if the PDF is relevant and may not need it. ResearchGate's content might need a login
|
||||
to access. 【1†Bing Search】
|
||||
|
||||
[Annotation] Bing Search: '"Social Dynamics and Intelligence of Killer Whales (Orcinus orca)"' -> https://www.bing.com/search?q=%22Social%20Dynamics%20and%20Intelligence%20of%20Killer%20Whales%20%28Orcinus%20orca%29%22
|
||||
|
||||
**Evaluating sources**
|
||||
|
||||
I'm gathering info on "Social Dynamics and Intelligence of Killer Whales," weighing access to PDFs through
|
||||
ResearchGate, and considering associated online references for credibility.
|
||||
|
||||
**Considering capabilities**
|
||||
|
||||
I'm piecing together the intricacies of killer whale creativity under chemical stimuli, as explored
|
||||
in "Manitzas, Hill, et al 2022." Would love to learn more about their findings.
|
||||
|
||||
**Exploring external options**
|
||||
I'm weighing opening the PDF directly or using an external search. 【1†Bing Search】
|
||||
|
||||
[Annotation] Bing Search: 'Manitzas Hill 2022 killer whale creativity cognitive abilities' -> https://www.bing.com/search?q=Manitzas%20Hill%202022%20killer%20whale%20creativity%20cognitive%20abilities
|
||||
|
||||
...
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,88 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.ai.agents.models import CodeInterpreterTool, FilePurpose
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents.annotation_content import AnnotationContent
|
||||
from semantic_kernel.contents.utils.author_role import AuthorRole
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a simple,
|
||||
Azure AI agent that uses the code interpreter tool to answer
|
||||
a coding question.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as 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",
|
||||
)
|
||||
|
||||
file = await client.agents.files.upload_and_poll(file_path=csv_file_path, purpose=FilePurpose.AGENTS)
|
||||
|
||||
code_interpreter = CodeInterpreterTool(file_ids=[file.id])
|
||||
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
tools=code_interpreter.definitions,
|
||||
tool_resources=code_interpreter.resources,
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
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.",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
# Invoke the agent for the specified user input
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
if response.role != AuthorRole.TOOL:
|
||||
print(f"# Agent: {response}")
|
||||
if len(response.items) > 0:
|
||||
for item in response.items:
|
||||
# Show Annotation Content if it exist
|
||||
if isinstance(item, AnnotationContent):
|
||||
print(f"\n`{item.quote}` => {item.file_id}")
|
||||
response_content = await client.agents.get_file_content(file_id=item.file_id)
|
||||
content_bytes = bytearray()
|
||||
async for chunk in response_content:
|
||||
content_bytes.extend(chunk)
|
||||
tab_delimited_text = content_bytes.decode("utf-8")
|
||||
print(tab_delimited_text)
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,121 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.ai.agents.models import McpTool
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a simple, Azure AI agent that
|
||||
uses the mcp tool to connect to an mcp server with streaming responses.
|
||||
"""
|
||||
|
||||
TASK = "Please summarize the Azure REST API specifications Readme"
|
||||
|
||||
|
||||
async def handle_intermediate_messages(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() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Define the MCP tool with the server URL
|
||||
mcp_tool = McpTool(
|
||||
server_label="github",
|
||||
server_url="https://gitmcp.io/Azure/azure-rest-api-specs",
|
||||
allowed_tools=[], # Specify allowed tools if needed
|
||||
)
|
||||
|
||||
# Optionally you may configure to require approval
|
||||
# Allowed values are "never" or "always"
|
||||
mcp_tool.set_approval_mode("never")
|
||||
|
||||
# 2. Create an agent with the MCP tool on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
tools=mcp_tool.definitions,
|
||||
instructions="You are a helpful agent that can use MCP tools to assist users.",
|
||||
)
|
||||
|
||||
# 3. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
# 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: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
print(f"# User: '{TASK}'")
|
||||
# 5. Invoke the agent for the specified thread for response
|
||||
async for response in agent.invoke_stream(
|
||||
messages=TASK,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_intermediate_messages,
|
||||
):
|
||||
print(f"{response}", end="", flush=True)
|
||||
thread = response.thread
|
||||
finally:
|
||||
# 6. Cleanup: Delete the thread, agent, and file
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Please summarize the Azure REST API specifications Readme'
|
||||
Function Call:> fetch_azure_rest_api_docs with arguments: {}
|
||||
The Azure REST API specifications Readme provides comprehensive documentation and guidelines for designing,
|
||||
authoring, validating, and evolving Azure REST APIs. It covers key areas including:
|
||||
|
||||
1. Breaking changes and versioning: Guidelines to manage API changes that break backward compatibility, when to
|
||||
increment API versions, and how to maintain smooth API evolution.
|
||||
|
||||
2. OpenAPI/Swagger specifications: How to author REST APIs using OpenAPI specification 2.0 (Swagger), including
|
||||
structure, conventions, validation tools, and extensions used by AutoRest for generating client SDKs.
|
||||
|
||||
3. TypeSpec language: Introduction to TypeSpec, a powerful language for describing and generating REST API
|
||||
specifications and client SDKs with extensibility to other API styles.
|
||||
|
||||
4. Directory structure and uniform versioning: Organizing service specifications by teams, resource provider
|
||||
namespaces, and following uniform versioning to keep API versions consistent across documentation and SDKs.
|
||||
|
||||
5. Validation and tooling: Tools and processes like OAV, AutoRest, RESTler, and CI checks used to validate API
|
||||
specs, generate SDKs, detect breaking changes, lint specifications, and test service contract accuracy.
|
||||
|
||||
6. Authoring best practices: Manual and automated guidelines for quality API spec authoring, including writing
|
||||
effective descriptions, resource modeling, naming conventions, and examples.
|
||||
|
||||
7. Code generation configurations: How to configure readme files to generate SDKs for various languages
|
||||
including .NET, Java, Python, Go, Typescript, and Azure CLI using AutoRest.
|
||||
|
||||
8. API Scenarios and testing: Defining API scenario test files for end-to-end REST API workflows, including
|
||||
variables, ARM template integration, and usage of test-proxy for recording traffic.
|
||||
|
||||
9. SDK automation and release requests: Workflows for SDK generation validation, suppressing breaking change
|
||||
warnings, and requesting official Azure SDK releases.
|
||||
|
||||
Overall, the Readme acts as a central hub providing references, guidelines, examples, and tools for maintaining
|
||||
high-quality Azure REST API specifications and seamless SDK generation across multiple languages and
|
||||
platforms. It ensures consistent API design, versioning, validation, and developer experience in the Azure
|
||||
ecosystem.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,132 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import 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 Azure AI Agent 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() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
AGENT_NAME = "Host"
|
||||
AGENT_INSTRUCTIONS = "Answer questions about the menu."
|
||||
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name=AGENT_NAME,
|
||||
instructions=AGENT_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin()], # add the sample plugin to the agent
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_intermediate_steps,
|
||||
):
|
||||
print(f"# Agent: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# Agent: Hi there! How can I assist you today?
|
||||
# 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
|
||||
# Agent: The special soup is Clam Chowder. Would you like to know anything else about the menu?
|
||||
# User: 'How much does that cost?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
# Agent: The Clam Chowder costs $9.99. Let me know if you'd like assistance with anything else!
|
||||
# User: 'Thank you'
|
||||
# Agent: You're welcome! Enjoy your meal! 😊
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.core_plugins import MathPlugin
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
This sample demonstrates how to create an Azure AI Agent 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.
|
||||
"""
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
# 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() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions from the user using your provided functions. You must invoke multiple functions to answer the user's questions. ", # noqa: E501
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin(), MathPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"What is the price of the special drink and the special food item added together?",
|
||||
]
|
||||
|
||||
try:
|
||||
for user_input in user_inputs:
|
||||
print(f"# 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,
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.role}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'What is the price of the special drink and then special food item added together?'
|
||||
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
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item": "Chai Tea"}
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item": "Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
Function Call:> MathPlugin-Add with arguments: {"input":9.99,"amount":9.99}
|
||||
Function Result:> 19.98 for function: MathPlugin-Add
|
||||
# AuthorRole.ASSISTANT: The price of the special drink, Chai Tea, is $9.99 and the price of the special food
|
||||
item, Clam Chowder, is $9.99. Added together, the total price is $19.98.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,111 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
from semantic_kernel.prompt_template import PromptTemplateConfig
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI
|
||||
agent using Azure OpenAI within Semantic Kernel.
|
||||
It uses parameterized prompts and shows how to swap between
|
||||
"semantic-kernel," "jinja2," and "handlebars" template formats,
|
||||
This sample highlights the agent's prompt templates are managed
|
||||
and how kernel arguments are passed in and used.
|
||||
"""
|
||||
|
||||
# Define the inputs and styles to be used in the agent
|
||||
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_chat_completion_agent(agent: AzureAIAgent, inputs):
|
||||
"""Invokes the given agent with each (input, style) in inputs."""
|
||||
|
||||
thread = None
|
||||
|
||||
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:
|
||||
argument_overrides = KernelArguments(style=style)
|
||||
|
||||
# Stream agent responses
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
|
||||
print(f"{response.content}", end="", flush=True)
|
||||
thread = response.thread
|
||||
print("\n")
|
||||
|
||||
|
||||
async def invoke_agent_with_template(template_str: str, template_format: str, default_style: str = "haiku"):
|
||||
"""Creates an agent with the specified template and format, then invokes it using invoke_chat_completion_agent."""
|
||||
|
||||
# Configure the prompt template
|
||||
prompt_config = PromptTemplateConfig(template=template_str, template_format=template_format)
|
||||
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="MyPoetAgent",
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
prompt_template_config=prompt_config,
|
||||
arguments=KernelArguments(style=default_style),
|
||||
)
|
||||
|
||||
await invoke_chat_completion_agent(agent, inputs)
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI agent that answers
|
||||
questions about a sample menu using a Semantic Kernel Plugin. After all questions
|
||||
are answered, it retrieves and prints the messages from the thread.
|
||||
"""
|
||||
|
||||
|
||||
# Define a sample plugin for the sample
|
||||
class MenuPlugin:
|
||||
"""A sample Menu Plugin used for the concept sample."""
|
||||
|
||||
@kernel_function(description="Provides a list of specials from the menu.")
|
||||
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
|
||||
return """
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
"""
|
||||
|
||||
@kernel_function(description="Provides the price of the requested menu item.")
|
||||
def get_item_price(
|
||||
self, menu_item: Annotated[str, "The name of the menu item."]
|
||||
) -> Annotated[str, "Returns the price of the menu item."]:
|
||||
return "$9.99"
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
):
|
||||
# 1. Create an agent on the Azure AI agent service
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the Azure AI agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin()], # Add the plugin to the agent
|
||||
)
|
||||
|
||||
# 3. Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread | None = None
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 4. Invoke the agent for the specified thread for response
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# 5. Cleanup: Delete the thread and agent
|
||||
# await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
print("*" * 50)
|
||||
print("# Messages in the thread (asc order):\n")
|
||||
async for msg in thread.get_messages(sort_order="asc"):
|
||||
print(f"# {msg.role} for name={msg.name}: {msg.content}")
|
||||
print("*" * 50)
|
||||
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
# User: Hello
|
||||
# Host: Hello! How can I assist you with the menu today?
|
||||
# User: What is the special soup?
|
||||
# Host: The special soup today is Clam Chowder. Would you like to know more about it or anything else
|
||||
on the menu?
|
||||
# User: How much does that cost?
|
||||
# Host: The Clam Chowder costs $9.99. Would you like to order it or need information on other items?
|
||||
# User: Thank you
|
||||
# Host: You're welcome! If you have any more questions or need assistance with the menu, feel free to ask.
|
||||
Enjoy your meal!
|
||||
**************************************************
|
||||
# Messages in the thread (asc order):
|
||||
|
||||
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Hello
|
||||
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Hello! How can I assist you with the menu today?
|
||||
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: What is the special soup?
|
||||
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: The special soup today is Clam Chowder. Would
|
||||
you like to know more about it or anything else on the menu?
|
||||
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: How much does that cost?
|
||||
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: The Clam Chowder costs $9.99. Would you like to
|
||||
order it or need information on other items?
|
||||
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Thank you
|
||||
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: You're welcome! If you have any more questions
|
||||
or need assistance with the menu, feel free to ask. Enjoy your meal!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,120 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI Agent
|
||||
and use it with streaming responses. The agent is configured to use
|
||||
a plugin that provides a list of specials from the menu and the price
|
||||
of the requested menu item. The thread message ID is also printed as each
|
||||
message is processed.
|
||||
"""
|
||||
|
||||
|
||||
# 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() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
AGENT_NAME = "Host"
|
||||
AGENT_INSTRUCTIONS = "Answer questions about the menu."
|
||||
|
||||
# Create agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name=AGENT_NAME,
|
||||
instructions=AGENT_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
plugins=[MenuPlugin()], # add the sample plugin to the agent
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
try:
|
||||
last_thread_msg_id = None
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.role}: ", end="", flush=True)
|
||||
# Show the thread message id before the first text chunk
|
||||
if "thread_message_id" in response.content.metadata:
|
||||
current_id = response.content.metadata["thread_message_id"]
|
||||
if current_id != last_thread_msg_id:
|
||||
print(f"(thread message id: {current_id}) ", end="", flush=True)
|
||||
last_thread_msg_id = current_id
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
finally:
|
||||
# Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# AuthorRole.ASSISTANT: (thread message id: msg_HZ2h4Wzbj7GEcnVCjnyEuYWT) Hello! How can I assist you with
|
||||
the menu today?
|
||||
# User: 'What is the special soup?'
|
||||
# AuthorRole.ASSISTANT: (thread message id: msg_TSjkJK6hHJojIkPvF6uUofHD) The special soup today is
|
||||
Clam Chowder. Would you like to know more about it or anything else from the menu?
|
||||
# User: 'How much does that cost?'
|
||||
# AuthorRole.ASSISTANT: (thread message id: msg_liwTpBFrB9JpCM1oM9EXKiwq) The Clam Chowder costs $9.99.
|
||||
Is there anything else you'd like to know?
|
||||
# User: 'Thank you'
|
||||
# AuthorRole.ASSISTANT: (thread message id: msg_K6lpR3gYIHethXq17T6gJcxi) You're welcome!
|
||||
If you have any more questions or need assistance, feel free to ask. Enjoy your meal!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,93 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from enum import Enum
|
||||
|
||||
from azure.ai.agents.models import (
|
||||
ResponseFormatJsonSchema,
|
||||
ResponseFormatJsonSchemaType,
|
||||
)
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import BaseModel
|
||||
|
||||
from semantic_kernel.agents import (
|
||||
AzureAIAgent,
|
||||
AzureAIAgentSettings,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI Agent
|
||||
and leverage the agent's ability to return structured outputs,
|
||||
based on a user-defined Pydantic model.
|
||||
"""
|
||||
|
||||
|
||||
# Define a Pydantic model that represents the structured output from the agent
|
||||
class Planets(str, Enum):
|
||||
Earth = "Earth"
|
||||
Mars = "Mars"
|
||||
Jupyter = "Jupyter"
|
||||
|
||||
|
||||
class Planet(BaseModel):
|
||||
planet: Planets
|
||||
mass: float
|
||||
|
||||
|
||||
async def main():
|
||||
ai_agent_settings = AzureAIAgentSettings()
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
# Create the agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="Assistant",
|
||||
instructions="Extract the information about planets.",
|
||||
response_format=ResponseFormatJsonSchemaType(
|
||||
json_schema=ResponseFormatJsonSchema(
|
||||
name="planet_mass",
|
||||
description="Extract planet mass.",
|
||||
schema=Planet.model_json_schema(),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_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 = None
|
||||
|
||||
user_inputs = ["The mass of the Mars is 6.4171E23 kg; the mass of the Earth is 5.972168E24 kg;"]
|
||||
|
||||
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 = Planet.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.agents.delete_agent(agent_definition.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'The mass of the Mars is 6.4171E23 kg; the mass of the Earth is 5.972168E24 kg;'
|
||||
# AuthorRole.ASSISTANT: planet=<Planets.Earth: 'Earth'> mass=5.972168e+24
|
||||
# AuthorRole.ASSISTANT: planet=<Planets.Mars: 'Mars'> mass=6.4171e+23
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.ai.agents.models import TruncationObject
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import (
|
||||
AzureAIAgent,
|
||||
AzureAIAgentSettings,
|
||||
AzureAIAgentThread,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure AI Agent Agent
|
||||
and configure a truncation strategy for the agent.
|
||||
"""
|
||||
|
||||
USER_INPUTS = [
|
||||
"Why is the sky blue?",
|
||||
"What is the speed of light?",
|
||||
"What have we been talking about?",
|
||||
]
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
ai_agent_settings = AzureAIAgentSettings.create()
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
|
||||
):
|
||||
# Create the agent definition
|
||||
agent_definition = await client.agents.create_agent(
|
||||
model=ai_agent_settings.model_deployment_name,
|
||||
name="TruncateAgent",
|
||||
instructions="You are a helpful assistant that answers user questions in one sentence.",
|
||||
)
|
||||
|
||||
# Create the AzureAI Agent
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=agent_definition,
|
||||
)
|
||||
|
||||
thread: AzureAIAgentThread | None = None
|
||||
|
||||
# Options are "auto" or "last_messages"
|
||||
# If using "last_messages", specify the number of messages to keep with `last_messages` kwarg
|
||||
truncation_strategy = TruncationObject(type="last_messages", last_messages=2)
|
||||
|
||||
try:
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
# 4. Invoke the agent with the specified message for response
|
||||
response = await agent.get_response(
|
||||
messages=user_input, thread=thread, truncation_strategy=truncation_strategy
|
||||
)
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# 6. Cleanup: Delete the thread and agent
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.id)
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: Why is the sky blue?
|
||||
# TruncateAgent: The sky appears blue because molecules in the Earth's atmosphere scatter sunlight in all
|
||||
directions, and blue light is scattered more than other colors due to its shorter wavelength.
|
||||
# User: What is the speed of light?
|
||||
# TruncateAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second
|
||||
(or about 186,282 miles per second).
|
||||
# User: What have we been talking about?
|
||||
# TruncateAgent: I'm sorry, but I don't have access to previous interactions. Could you remind me what
|
||||
we've been discussing?
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,2 @@
|
||||
BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN=[YOUR_AGENT_ROLE_AMAZON_RESOURCE_NAME]
|
||||
BEDROCK_AGENT_FOUNDATION_MODEL=[YOUR_FOUNDATION_MODEL]
|
||||
@@ -0,0 +1,74 @@
|
||||
# Concept samples on how to use AWS Bedrock agents
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
1. You need to have an AWS account and [access to the foundation models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access-permissions.html)
|
||||
2. [AWS CLI installed](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [configured](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)
|
||||
|
||||
### Configuration
|
||||
|
||||
Follow this [guide](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration) to configure your environment to use the Bedrock API.
|
||||
|
||||
Please configure the `aws_access_key_id`, `aws_secret_access_key`, and `region` otherwise you will need to create custom clients for the services. For example:
|
||||
|
||||
```python
|
||||
runtime_client=boto.client(
|
||||
"bedrock-runtime",
|
||||
aws_access_key_id="your_access_key",
|
||||
aws_secret_access_key="your_secret_key",
|
||||
region_name="your_region",
|
||||
[...other parameters you may need...]
|
||||
)
|
||||
client=boto.client(
|
||||
"bedrock",
|
||||
aws_access_key_id="your_access_key",
|
||||
aws_secret_access_key="your_secret_key",
|
||||
region_name="your_region",
|
||||
[...other parameters you may need...]
|
||||
)
|
||||
|
||||
bedrock_agent = BedrockAgent.create_and_prepare_agent(
|
||||
name="your_agent_name",
|
||||
instructions="your_instructions",
|
||||
runtime_client=runtime_client,
|
||||
client=client,
|
||||
[...other parameters you may need...]
|
||||
)
|
||||
```
|
||||
|
||||
## Samples
|
||||
|
||||
| Sample | Description |
|
||||
|--------|-------------|
|
||||
| [bedrock_agent_simple_chat.py](bedrock_agent_simple_chat.py) | Demonstrates basic usage of the Bedrock agent. |
|
||||
| [bedrock_agent_simple_chat_streaming.py](bedrock_agent_simple_chat_streaming.py) | Demonstrates basic usage of the Bedrock agent with streaming. |
|
||||
| [bedrock_agent_with_kernel_function.py](bedrock_agent_with_kernel_function.py) | Shows how to use the Bedrock agent with a kernel function. |
|
||||
| [bedrock_agent_with_kernel_function_streaming.py](bedrock_agent_with_kernel_function_streaming.py) | Shows how to use the Bedrock agent with a kernel function with streaming. |
|
||||
| [bedrock_agent_with_code_interpreter.py](bedrock_agent_with_code_interpreter.py) | Example of using the Bedrock agent with a code interpreter. |
|
||||
| [bedrock_agent_with_code_interpreter_streaming.py](bedrock_agent_with_code_interpreter_streaming.py) | Example of using the Bedrock agent with a code interpreter and streaming. |
|
||||
| [bedrock_mixed_chat_agents.py](bedrock_mixed_chat_agents.py) | Example of using multiple chat agents in a single script. |
|
||||
| [bedrock_mixed_chat_agents_streaming.py](bedrock_mixed_chat_agents_streaming.py) | Example of using multiple chat agents in a single script with streaming. |
|
||||
|
||||
## Before running the samples
|
||||
|
||||
You need to set up some environment variables to run the samples. Please refer to the [.env.example](.env.example) file for the required environment variables.
|
||||
|
||||
### `BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN`
|
||||
|
||||
On your AWS console, go to the IAM service and go to **Roles**. Find the role you want to use and click on it. You will find the ARN in the summary section.
|
||||
|
||||
### `BEDROCK_AGENT_FOUNDATION_MODEL`
|
||||
|
||||
You need to make sure you have permission to access the foundation model. You can find the model ID in the [AWS documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html). To see the models you have access to, find the policy attached to your role you should see a list of models you have access to under the `Resource` section.
|
||||
|
||||
### How to add the `bedrock:InvokeModelWithResponseStream` action to an IAM policy
|
||||
|
||||
1. Open the [IAM console](https://console.aws.amazon.com/iam/).
|
||||
2. On the left navigation pane, choose `Roles` under `Access management`.
|
||||
3. Find the role you want to edit and click on it.
|
||||
4. Under the `Permissions policies` tab, click on the policy you want to edit.
|
||||
5. Under the `Permissions defined in this policy` section, click on the service. You should see **Bedrock** if you already have access to the Bedrock agent service.
|
||||
6. Click on the service, and then click `Edit`.
|
||||
7. On the right, you will be able to add an action. Find the service and search for `InvokeModelWithResponseStream`.
|
||||
8. Check the box next to the action and then scroll all the way down and click `Next`.
|
||||
9. Follow the prompts to save the changes.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
import boto3
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to use an already existing
|
||||
Bedrock Agent within Semantic Kernel. This sample requires that you
|
||||
have an existing agent created either previously in code or via the
|
||||
AWS Console.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
You will learn how to retrieve a Bedrock agent and talk to it.
|
||||
"""
|
||||
|
||||
# Replace "your-agent-id" with the ID of the agent you want to use
|
||||
AGENT_ID = "your-agent-id"
|
||||
|
||||
|
||||
async def main():
|
||||
client = boto3.client("bedrock-agent")
|
||||
agent_model = client.get_agent(agentId=AGENT_ID)["agent"]
|
||||
bedrock_agent = BedrockAgent(agent_model)
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
while True:
|
||||
user_input = input("User:> ")
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
break
|
||||
|
||||
# Invoke the agent
|
||||
# The chat history is maintained in the session
|
||||
async for response in bedrock_agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
print(f"Bedrock agent: {response}")
|
||||
thread = response.thread
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
finally:
|
||||
# Cleanup: Delete the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# User:> Hi, my name is John.
|
||||
# Bedrock agent: Hello John. How can I help you?
|
||||
# User:> What is my name?
|
||||
# Bedrock agent: Your name is John.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent in the simplest way.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
You will learn how to create a new Bedrock agent and talk to it.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
async def main():
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
while True:
|
||||
user_input = input("User:> ")
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
break
|
||||
|
||||
# Invoke the agent
|
||||
# The chat history is maintained in the session
|
||||
response = await bedrock_agent.get_response(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
)
|
||||
print(f"Bedrock agent: {response}")
|
||||
thread = response.thread
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# User:> Hi, my name is John.
|
||||
# Bedrock agent: Hello John. How can I help you?
|
||||
# User:> What is my name?
|
||||
# Bedrock agent: Your name is John.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,55 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent via streaming in the simplest way.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
You will learn how to create a new Bedrock agent and talk to it.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
async def main():
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
while True:
|
||||
user_input = input("User:> ")
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
break
|
||||
|
||||
# Invoke the agent
|
||||
# The chat history is maintained in the thread
|
||||
print("Bedrock agent: ", end="")
|
||||
async for response in bedrock_agent.invoke_stream(messages=user_input, thread=thread):
|
||||
print(response, end="")
|
||||
thread = response.thread
|
||||
print()
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# User:> Hi, my name is John.
|
||||
# Bedrock agent: Hello John. How can I help you?
|
||||
# User:> What is my name?
|
||||
# Bedrock agent: Your name is John.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,85 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
from semantic_kernel.contents.binary_content import BinaryContent
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent that is capable of writing and executing code.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
You will learn how to create a new Bedrock agent and ask it a question that requires coding to answer.
|
||||
After running this sample, a bar chart will be generated and saved to a file in the same directory
|
||||
as this script.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
ASK = """
|
||||
Create a bar chart for the following data:
|
||||
Panda 5
|
||||
Tiger 8
|
||||
Lion 3
|
||||
Monkey 6
|
||||
Dolphin 2
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
|
||||
await bedrock_agent.create_code_interpreter_action_group()
|
||||
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
# Placeholder for the file generated by the code interpreter
|
||||
binary_item: BinaryContent | None = None
|
||||
|
||||
try:
|
||||
# Invoke the agent
|
||||
async for response in bedrock_agent.invoke(
|
||||
messages=ASK,
|
||||
thread=thread,
|
||||
):
|
||||
print(f"Response:\n{response}")
|
||||
thread = response.thread
|
||||
if not binary_item:
|
||||
binary_item = next((item for item in response.items if isinstance(item, BinaryContent)), None)
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Save the chart to a file
|
||||
if not binary_item:
|
||||
raise RuntimeError("No chart generated")
|
||||
|
||||
# Securely assemble the file path and validate it's within the expected directory
|
||||
# This is a defense-in-depth measure against directory traversal attacks
|
||||
output_dir = Path(__file__).parent.resolve()
|
||||
file_path = (output_dir / binary_item.metadata["name"]).resolve()
|
||||
|
||||
# Verify the resolved path is within the expected directory
|
||||
if not file_path.is_relative_to(output_dir):
|
||||
raise RuntimeError("Invalid filename: would write outside the expected directory")
|
||||
|
||||
binary_item.write_to_file(file_path)
|
||||
print(f"Chart saved to {file_path}")
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# Response:
|
||||
# Here is the bar chart for the given data:
|
||||
# [A bar chart showing the following data:
|
||||
# Panda 5
|
||||
# Tiger 8
|
||||
# Lion 3
|
||||
# Monkey 6
|
||||
# Dolpin 2]
|
||||
# Chart saved to ...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
from semantic_kernel.contents.binary_content import BinaryContent
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent that is capable of writing and executing code.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
You will learn how to create a new Bedrock agent and ask it a question that requires coding to answer.
|
||||
After running this sample, a bar chart will be generated and saved to a file in the same directory
|
||||
as this script.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
ASK = """
|
||||
Create a bar chart for the following data:
|
||||
Panda 5
|
||||
Tiger 8
|
||||
Lion 3
|
||||
Monkey 6
|
||||
Dolphin 2
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
|
||||
await bedrock_agent.create_code_interpreter_action_group()
|
||||
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
# Placeholder for the file generated by the code interpreter
|
||||
binary_item: BinaryContent | None = None
|
||||
|
||||
try:
|
||||
# Invoke the agent
|
||||
print("Response: ")
|
||||
async for response in bedrock_agent.invoke_stream(
|
||||
messages=ASK,
|
||||
thread=thread,
|
||||
):
|
||||
print(response, end="")
|
||||
thread = response.thread
|
||||
if not binary_item:
|
||||
binary_item = next((item for item in response.items if isinstance(item, BinaryContent)), None)
|
||||
print()
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Save the chart to a file
|
||||
if not binary_item:
|
||||
raise RuntimeError("No chart generated")
|
||||
|
||||
# Securely assemble the file path and validate it's within the expected directory
|
||||
# This is a defense-in-depth measure against directory traversal attacks
|
||||
output_dir = Path(__file__).parent.resolve()
|
||||
file_path = (output_dir / binary_item.metadata["name"]).resolve()
|
||||
|
||||
# Verify the resolved path is within the expected directory
|
||||
if not file_path.is_relative_to(output_dir):
|
||||
raise RuntimeError("Invalid filename: would write outside the expected directory")
|
||||
|
||||
binary_item.write_to_file(file_path)
|
||||
print(f"Chart saved to {file_path}")
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# Response:
|
||||
# Here is the bar chart for the given data:
|
||||
# [A bar chart showing the following data:
|
||||
# Panda 5
|
||||
# Tiger 8
|
||||
# Lion 3
|
||||
# Monkey 6
|
||||
# Dolpin 2]
|
||||
# Chart saved to ...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
- a kernel function
|
||||
- a kernel
|
||||
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
class WeatherPlugin:
|
||||
"""Mock weather plugin."""
|
||||
|
||||
@kernel_function(description="Get real-time weather information.")
|
||||
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
|
||||
"""Returns the current weather."""
|
||||
return f"The weather in {location} is sunny."
|
||||
|
||||
|
||||
def get_kernel() -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
|
||||
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
# Create a kernel
|
||||
kernel = get_kernel()
|
||||
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
|
||||
AGENT_NAME,
|
||||
INSTRUCTION,
|
||||
kernel=kernel,
|
||||
)
|
||||
# Note: We still need to create the kernel function action group on the service side.
|
||||
await bedrock_agent.create_kernel_function_action_group()
|
||||
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
# Invoke the agent
|
||||
async for response in bedrock_agent.invoke(
|
||||
messages="What is the weather in Seattle?",
|
||||
thread=thread,
|
||||
):
|
||||
print(f"Response:\n{response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# Response:
|
||||
# The current weather in Seattle is sunny.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
|
||||
Instead of creating a kernel and adding plugins to it, you can directly pass the plugins to the
|
||||
agent when creating it.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
- a kernel function
|
||||
- a kernel
|
||||
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
class WeatherPlugin:
|
||||
"""Mock weather plugin."""
|
||||
|
||||
@kernel_function(description="Get real-time weather information.")
|
||||
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
|
||||
"""Returns the current weather."""
|
||||
return f"The weather in {location} is sunny."
|
||||
|
||||
|
||||
async def main():
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
|
||||
AGENT_NAME,
|
||||
INSTRUCTION,
|
||||
plugins=[WeatherPlugin()],
|
||||
)
|
||||
# Note: We still need to create the kernel function action group on the service side.
|
||||
await bedrock_agent.create_kernel_function_action_group()
|
||||
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
# Invoke the agent
|
||||
async for response in bedrock_agent.invoke(
|
||||
messages="What is the weather in Seattle?",
|
||||
thread=thread,
|
||||
):
|
||||
print(f"Response:\n{response}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# Response:
|
||||
# The current weather in Seattle is sunny.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
- a kernel function
|
||||
- a kernel
|
||||
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
|
||||
"""
|
||||
|
||||
AGENT_NAME = "semantic-kernel-bedrock-agent"
|
||||
INSTRUCTION = "You are a friendly assistant. You help people find information."
|
||||
|
||||
|
||||
class WeatherPlugin:
|
||||
"""Mock weather plugin."""
|
||||
|
||||
@kernel_function(description="Get real-time weather information.")
|
||||
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
|
||||
"""Returns the current weather."""
|
||||
return f"The weather in {location} is sunny."
|
||||
|
||||
|
||||
def get_kernel() -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
|
||||
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
# Create a kernel
|
||||
kernel = get_kernel()
|
||||
|
||||
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
|
||||
AGENT_NAME,
|
||||
INSTRUCTION,
|
||||
kernel=kernel,
|
||||
)
|
||||
# Note: We still need to create the kernel function action group on the service side.
|
||||
await bedrock_agent.create_kernel_function_action_group()
|
||||
|
||||
thread: BedrockAgentThread = None
|
||||
|
||||
try:
|
||||
# Invoke the agent
|
||||
print("Response: ")
|
||||
async for response in bedrock_agent.invoke_stream(
|
||||
messages="What is the weather in Seattle?",
|
||||
thread=thread,
|
||||
):
|
||||
print(response, end="")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Delete the agent
|
||||
await bedrock_agent.delete_agent()
|
||||
await thread.delete() if thread else None
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# Response:
|
||||
# The current weather in Seattle is sunny.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, BedrockAgent, ChatCompletionAgent
|
||||
from semantic_kernel.agents.strategies.termination.termination_strategy import TerminationStrategy
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents.utils.author_role import AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
This sample shows how to use a bedrock agent in a group chat that includes multiple agents of different roles.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
- a ChatCompletionAgent
|
||||
- an AgentGroupChat
|
||||
You will learn how to create a new or connect to an existing Bedrock agent and put it in a group chat with
|
||||
another agent.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
# This will be a chat completion agent
|
||||
REVIEWER_NAME = "ArtDirector"
|
||||
REVIEWER_INSTRUCTIONS = """
|
||||
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
|
||||
The goal is to determine if the given copy is acceptable to print.
|
||||
If so, state that it is approved. Only include the word "approved" if it is so.
|
||||
If not, provide insight on how to refine suggested copy without example.
|
||||
"""
|
||||
|
||||
# This will be a bedrock agent
|
||||
COPYWRITER_NAME = "CopyWriter"
|
||||
COPYWRITER_INSTRUCTIONS = """
|
||||
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
|
||||
The goal is to refine and decide on the single best copy as an expert in the field.
|
||||
Only provide a single proposal per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
"""
|
||||
|
||||
|
||||
class ApprovalTerminationStrategy(TerminationStrategy):
|
||||
"""A strategy for determining when an agent should terminate."""
|
||||
|
||||
async def should_agent_terminate(self, agent, history):
|
||||
"""Check if the agent should terminate."""
|
||||
return "approved" in history[-1].content.lower()
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion() -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
agent_reviewer = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion(),
|
||||
name=REVIEWER_NAME,
|
||||
instructions=REVIEWER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
agent_writer = await BedrockAgent.create_and_prepare_agent(
|
||||
COPYWRITER_NAME,
|
||||
instructions=COPYWRITER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
chat = AgentGroupChat(
|
||||
agents=[agent_writer, agent_reviewer],
|
||||
termination_strategy=ApprovalTerminationStrategy(
|
||||
agents=[agent_reviewer],
|
||||
maximum_iterations=10,
|
||||
),
|
||||
)
|
||||
|
||||
input = "A slogan for a new line of electric cars."
|
||||
|
||||
await chat.add_chat_message(message=input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
try:
|
||||
async for message in chat.invoke():
|
||||
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
print(f"# IS COMPLETE: {chat.is_complete}")
|
||||
finally:
|
||||
# Delete the agent
|
||||
await agent_writer.delete_agent()
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# AuthorRole.USER: 'A slogan for a new line of electric cars.'
|
||||
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Ahead: The Future of Driving'
|
||||
# AuthorRole.ASSISTANT - ArtDirector: 'The slogan "Charge Ahead: The Future of Driving" is compelling but could be
|
||||
# made even more impactful. Consider clarifying the unique selling proposition of the electric cars. Focus on what
|
||||
# sets them apart in terms of performance, eco-friendliness, or innovation. This will help create an emotional
|
||||
# connection and a clearer message for the audience.'
|
||||
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Forward: The Electrifying Future of Driving'
|
||||
# AuthorRole.ASSISTANT - ArtDirector: 'Approved'
|
||||
# IS COMPLETE: True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,118 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, BedrockAgent, ChatCompletionAgent
|
||||
from semantic_kernel.agents.strategies.termination.termination_strategy import TerminationStrategy
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents.utils.author_role import AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
This sample shows how to use a bedrock agent in a group chat that includes multiple agents of different roles.
|
||||
This sample uses the following main component(s):
|
||||
- a Bedrock agent
|
||||
- a ChatCompletionAgent
|
||||
- an AgentGroupChat
|
||||
You will learn how to create a new or connect to an existing Bedrock agent and put it in a group chat with
|
||||
another agent.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
# This will be a chat completion agent
|
||||
REVIEWER_NAME = "ArtDirector"
|
||||
REVIEWER_INSTRUCTIONS = """
|
||||
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
|
||||
The goal is to determine if the given copy is acceptable to print.
|
||||
If so, state that it is approved. Only include the word "approved" if it is so.
|
||||
If not, provide insight on how to refine suggested copy without example.
|
||||
"""
|
||||
|
||||
# This will be a bedrock agent
|
||||
COPYWRITER_NAME = "CopyWriter"
|
||||
COPYWRITER_INSTRUCTIONS = """
|
||||
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
|
||||
The goal is to refine and decide on the single best copy as an expert in the field.
|
||||
Only provide a single proposal per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
"""
|
||||
|
||||
|
||||
class ApprovalTerminationStrategy(TerminationStrategy):
|
||||
"""A strategy for determining when an agent should terminate."""
|
||||
|
||||
async def should_agent_terminate(self, agent, history):
|
||||
"""Check if the agent should terminate."""
|
||||
return "approved" in history[-1].content.lower()
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion() -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
agent_reviewer = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion(),
|
||||
name=REVIEWER_NAME,
|
||||
instructions=REVIEWER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
agent_writer = await BedrockAgent.create_and_prepare_agent(
|
||||
COPYWRITER_NAME,
|
||||
instructions=COPYWRITER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
chat = AgentGroupChat(
|
||||
agents=[agent_writer, agent_reviewer],
|
||||
termination_strategy=ApprovalTerminationStrategy(
|
||||
agents=[agent_reviewer],
|
||||
maximum_iterations=10,
|
||||
),
|
||||
)
|
||||
|
||||
input = "A slogan for a new line of electric cars."
|
||||
|
||||
await chat.add_chat_message(message=input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
try:
|
||||
current_agent = "*"
|
||||
async for message_chunk in chat.invoke_stream():
|
||||
if current_agent != message_chunk.name:
|
||||
current_agent = message_chunk.name or "*"
|
||||
print(f"\n# {message_chunk.role} - {current_agent}: ", end="")
|
||||
print(message_chunk.content, end="")
|
||||
print()
|
||||
print(f"# IS COMPLETE: {chat.is_complete}")
|
||||
finally:
|
||||
# Delete the agent
|
||||
await agent_writer.delete_agent()
|
||||
|
||||
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
|
||||
# AuthorRole.USER: 'A slogan for a new line of electric cars.'
|
||||
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Ahead: The Future of Driving'
|
||||
# AuthorRole.ASSISTANT - ArtDirector: 'The slogan "Charge Ahead: The Future of Driving" is compelling but could be
|
||||
# made even more impactful. Consider clarifying the unique selling proposition of the electric cars. Focus on what
|
||||
# sets them apart in terms of performance, eco-friendliness, or innovation. This will help create an emotional
|
||||
# connection and a clearer message for the audience.'
|
||||
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Forward: The Electrifying Future of Driving'
|
||||
# AuthorRole.ASSISTANT - ArtDirector: 'Approved'
|
||||
# IS COMPLETE: True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,45 @@
|
||||
# Chat Completion Agent Samples
|
||||
|
||||
The following samples demonstrate advanced usage of the `ChatCompletionAgent`.
|
||||
|
||||
---
|
||||
|
||||
## Chat History Reduction Strategies
|
||||
|
||||
When configuring chat history management, there are two important settings to consider:
|
||||
|
||||
### `reducer_msg_count`
|
||||
|
||||
- **Purpose:** Defines the target number of messages to retain after applying truncation or summarization.
|
||||
- **Controls:** Determines how much recent conversation history is preserved, while older messages are either discarded or summarized.
|
||||
- **Recommendations for adjustment:**
|
||||
- **Smaller values:** Ideal for memory-constrained environments or scenarios where brief context is sufficient.
|
||||
- **Larger values:** Useful when retaining extensive conversational context is critical for accurate responses or complex dialogue.
|
||||
|
||||
### `reducer_threshold`
|
||||
|
||||
- **Purpose:** Provides a buffer to prevent premature reduction when the message count slightly exceeds `reducer_msg_count`.
|
||||
- **Controls:** Ensures essential message pairs (e.g., a user query and the assistant’s response) aren't unintentionally truncated.
|
||||
- **Recommendations for adjustment:**
|
||||
- **Smaller values:** Use to enforce stricter message reduction criteria, potentially truncating older message pairs sooner.
|
||||
- **Larger values:** Recommended for preserving critical conversation segments, particularly in sensitive interactions involving API function calls or detailed responses.
|
||||
|
||||
### Interaction Between Parameters
|
||||
|
||||
The combination of these parameters determines **when** history reduction occurs and **how much** of the conversation is retained.
|
||||
|
||||
**Example:**
|
||||
- If `reducer_msg_count = 10` and `reducer_threshold = 5`, message history won't be truncated until the total message count exceeds 15. This strategy maintains conversational context flexibility while respecting memory limitations.
|
||||
|
||||
---
|
||||
|
||||
## Recommendations for Effective Configuration
|
||||
|
||||
- **Performance-focused environments:**
|
||||
- Lower `reducer_msg_count` to conserve memory and accelerate processing.
|
||||
|
||||
- **Context-sensitive scenarios:**
|
||||
- Higher `reducer_msg_count` and `reducer_threshold` help maintain continuity across multiple interactions, crucial for multi-turn conversations or complex workflows.
|
||||
|
||||
- **Iterative Experimentation:**
|
||||
- Start with default values (`reducer_msg_count = 10`, `reducer_threshold = 10`), and adjust according to the specific behavior and response quality required by your application.
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.filters import FunctionInvocationContext
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create Chat Completion Agents
|
||||
and use them as tools available for a Triage Agent to delegate requests
|
||||
to the appropriate agent. A Function Invocation Filter is used to show
|
||||
the function call content and the function result content so the caller
|
||||
can see which agent was called and what the response was.
|
||||
"""
|
||||
|
||||
|
||||
# Define the auto function invocation filter that will be used by the kernel
|
||||
async def function_invocation_filter(context: FunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
if "messages" not in context.arguments:
|
||||
await next(context)
|
||||
return
|
||||
print(f" Agent [{context.function.name}] called with messages: {context.arguments['messages']}")
|
||||
await next(context)
|
||||
print(f" Response from agent [{context.function.name}]: {context.result.value}")
|
||||
|
||||
|
||||
# Create and configure the kernel.
|
||||
kernel = Kernel()
|
||||
|
||||
# The filter is used for demonstration purposes to show the function invocation.
|
||||
kernel.add_filter("function_invocation", function_invocation_filter)
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
billing_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
name="BillingAgent",
|
||||
instructions=(
|
||||
"You specialize in handling customer questions related to billing issues. "
|
||||
"This includes clarifying invoice charges, payment methods, billing cycles, "
|
||||
"explaining fees, addressing discrepancies in billed amounts, updating payment details, "
|
||||
"assisting with subscription changes, and resolving payment failures. "
|
||||
"Your goal is to clearly communicate and resolve issues specifically about payments and charges."
|
||||
),
|
||||
)
|
||||
|
||||
refund_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
name="RefundAgent",
|
||||
instructions=(
|
||||
"You specialize in addressing customer inquiries regarding refunds. "
|
||||
"This includes evaluating eligibility for refunds, explaining refund policies, "
|
||||
"processing refund requests, providing status updates on refunds, handling complaints related to refunds, "
|
||||
"and guiding customers through the refund claim process. "
|
||||
"Your goal is to assist users clearly and empathetically to successfully resolve their refund-related concerns."
|
||||
),
|
||||
)
|
||||
|
||||
triage_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
kernel=kernel,
|
||||
name="TriageAgent",
|
||||
instructions=(
|
||||
"Your role is to evaluate the user's request and forward it to the appropriate agent based on the nature of "
|
||||
"the query. Forward requests about charges, billing cycles, payment methods, fees, or payment issues to the "
|
||||
"BillingAgent. Forward requests concerning refunds, refund eligibility, refund policies, or the status of "
|
||||
"refunds to the RefundAgent. Your goal is accurate identification of the appropriate specialist to ensure the "
|
||||
"user receives targeted assistance."
|
||||
),
|
||||
plugins=[billing_agent, refund_agent],
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
"""
|
||||
Continuously prompt the user for input and show the assistant's response.
|
||||
Type 'exit' to exit.
|
||||
"""
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
if user_input.lower().strip() == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
response = await triage_agent.get_response(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
)
|
||||
|
||||
if response:
|
||||
print(f"Agent :> {response}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
User:> I was charged twice for my subscription last month, can I get one of those payments refunded?
|
||||
Agent [BillingAgent] called with messages: I was charged twice for my subscription last month.
|
||||
Agent [RefundAgent] called with messages: Can I get one of those payments refunded?
|
||||
Response from agent RefundAgent: Of course, I'll be happy to help you with your refund inquiry. Could you please
|
||||
provide a bit more detail about the specific payment you are referring to? For instance, the item or service
|
||||
purchased, the transaction date, and the reason why you're seeking a refund? This will help me understand your
|
||||
situation better and provide you with accurate guidance regarding our refund policy and process.
|
||||
Response from agent BillingAgent: I'm sorry to hear about the duplicate charge. To resolve this issue, could
|
||||
you please provide the following details:
|
||||
|
||||
1. The date(s) of the transaction(s).
|
||||
2. The last four digits of the card used for the transaction or any other payment method details.
|
||||
3. The subscription plan you are on.
|
||||
|
||||
Once I have this information, I can look into the charges and help facilitate a refund for the duplicate transaction.
|
||||
Let me know if you have any questions in the meantime!
|
||||
|
||||
Agent :> To address your concern about being charged twice and seeking a refund for one of those payments, please
|
||||
provide the following information:
|
||||
|
||||
1. **Duplicate Charge Details**: Please share the date(s) of the transaction(s), the last four digits of the card used
|
||||
or details of any other payment method, and the subscription plan you are on. This information will help us verify
|
||||
the duplicate charge and assist you with a refund.
|
||||
|
||||
2. **Refund Inquiry Details**: Please specify the transaction date, the item or service related to the payment you want
|
||||
refunded, and the reason why you're seeking a refund. This will allow us to provide accurate guidance concerning
|
||||
our refund policy and process.
|
||||
|
||||
Once we have these details, we can proceed with resolving the duplicate charge and consider your refund request. If you
|
||||
have any more questions, feel free to ask!
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("Welcome to the chat bot!\n Type 'exit' to exit.\n Try to get some billing or refund help.")
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.filters import AutoFunctionInvocationContext
|
||||
from semantic_kernel.functions import kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to configure the auto
|
||||
function invocation filter while using a ChatCompletionAgent.
|
||||
This allows the developer or user to view the function call content
|
||||
and the function result content.
|
||||
"""
|
||||
|
||||
|
||||
# Define the auto function invocation filter that will be used by the kernel
|
||||
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
# if we don't call next, it will skip this function, and go to the next one
|
||||
await next(context)
|
||||
if context.function.plugin_name == "menu":
|
||||
context.terminate = True
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completionand_filter() -> Kernel:
|
||||
"""A helper function to create a kernel with a chat completion service and a filter."""
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
|
||||
kernel.add_filter("auto_function_invocation", auto_function_invocation_filter)
|
||||
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
|
||||
return kernel
|
||||
|
||||
|
||||
def _write_content(content: ChatMessageContent) -> None:
|
||||
"""Write the content to the console based on the content type."""
|
||||
last_item_type = type(content.items[-1]).__name__ if content.items else "(empty)"
|
||||
message_content = ""
|
||||
if isinstance(last_item_type, FunctionCallContent):
|
||||
message_content = f"tool request = {content.items[-1].function_name}"
|
||||
elif isinstance(last_item_type, FunctionResultContent):
|
||||
message_content = f"function result = {content.items[-1].result}"
|
||||
else:
|
||||
message_content = str(content.items[-1])
|
||||
print(f"[{last_item_type}] {content.role} : '{message_content}'")
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent with a kernel instance that contains
|
||||
# the auto function invocation filter and the AI service
|
||||
agent = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completionand_filter(),
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# 2. Define the thread
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"What is the special drink?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
# 3. Get the response from the agent
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
thread = response.thread
|
||||
_write_content(response)
|
||||
|
||||
print("================================")
|
||||
print("CHAT HISTORY")
|
||||
print("================================")
|
||||
|
||||
# 4. Print out the chat history to view the different types of messages
|
||||
async for message in thread.get_messages():
|
||||
_write_content(message)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
|
||||
# AuthorRole.USER: 'What is the special soup?'
|
||||
[FunctionResultContent] AuthorRole.TOOL : '
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
'
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
|
||||
anything else, feel free to ask!'
|
||||
================================
|
||||
CHAT HISTORY
|
||||
================================
|
||||
[TextContent] AuthorRole.USER : 'Hello'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
|
||||
[TextContent] AuthorRole.USER : 'What is the special soup?'
|
||||
[FunctionCallContent] AuthorRole.ASSISTANT : 'menu-get_specials({})'
|
||||
[FunctionResultContent] AuthorRole.TOOL : '
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
'
|
||||
[TextContent] AuthorRole.USER : 'What is the special drink?'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
|
||||
[TextContent] AuthorRole.USER : 'Thank you'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
|
||||
anything else, feel free to ask!'
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
|
||||
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with functions. In order to answer user questions, the
|
||||
agent internally uses the functions. These internal steps are returned
|
||||
to the user as part of the agent's response. Thus, the invoke method
|
||||
configures a message callback to receive the agent's internal messages.
|
||||
|
||||
The agent is configured to use a plugin that provides a list of
|
||||
specials from the menu and the price of the requested menu item.
|
||||
"""
|
||||
|
||||
|
||||
# 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, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
elif isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
else:
|
||||
print(f"{message.role}: {message.content}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# 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
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# AuthorRole.ASSISTANT: Hi there! How can I assist you today?
|
||||
# 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 anything else from the menu?
|
||||
# User: 'How much does that cost?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
# AuthorRole.ASSISTANT: The Clam Chowder costs $9.99. Would you like to know more about the menu or anything else?
|
||||
# User: 'Thank you'
|
||||
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with streaming responses. Additionally, the invoke_stream
|
||||
configures a message callback to receive fully formed messages once
|
||||
the streaming invocation is complete. The agent is configured to use
|
||||
a plugin that provides a list of specials from the menu and the price
|
||||
of the requested menu item.
|
||||
"""
|
||||
|
||||
|
||||
# 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, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
elif isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
else:
|
||||
print(f"{message.role}: {message.content}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_streaming_intermediate_steps,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I assist you today?
|
||||
|
||||
# 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
|
||||
The special soup today is Clam Chowder. Is there anything else you'd like to know?
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
The Clam Chowder costs $9.99. Would you like to know anything else about the menu?
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions, feel free to ask. Have a great day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
from semantic_kernel.prompt_template import PromptTemplateConfig
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion
|
||||
agent using Azure OpenAI within Semantic Kernel.
|
||||
It uses parameterized prompts and shows how to swap between
|
||||
"semantic-kernel," "jinja2," and "handlebars" template formats,
|
||||
This sample highlights the agent's chat history conversation
|
||||
is managed and how kernel arguments are passed in and used.
|
||||
"""
|
||||
|
||||
# Define the inputs and styles to be used in the agent
|
||||
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_chat_completion_agent(agent: ChatCompletionAgent, inputs):
|
||||
"""Invokes the given agent with each (input, style) in inputs."""
|
||||
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
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:
|
||||
argument_overrides = KernelArguments(style=style)
|
||||
|
||||
# Stream agent responses
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
|
||||
print(f"{response.content}", end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
|
||||
async def invoke_agent_with_template(template_str: str, template_format: str, default_style: str = "haiku"):
|
||||
"""Creates an agent with the specified template and format, then invokes it using invoke_chat_completion_agent."""
|
||||
|
||||
# Configure the prompt template
|
||||
prompt_config = PromptTemplateConfig(template=template_str, template_format=template_format)
|
||||
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="MyPoetAgent",
|
||||
prompt_template_config=prompt_config,
|
||||
arguments=KernelArguments(style=default_style),
|
||||
)
|
||||
|
||||
await invoke_chat_completion_agent(agent, inputs)
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with streaming responses. It also shows how to track token
|
||||
usage during the streaming process.
|
||||
"""
|
||||
|
||||
|
||||
# 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() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
completion_usage = CompletionUsage()
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content, end="", flush=True)
|
||||
if response.metadata.get("usage"):
|
||||
completion_usage += response.metadata["usage"]
|
||||
print(f"\nStreaming Usage: {response.metadata['usage']}")
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Print the completion usage
|
||||
print(f"\nStreaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I help you with the menu today?
|
||||
|
||||
# User: 'What is the special soup?'
|
||||
The special soup today is Clam Chowder. Would you like more details or are you interested in something else from
|
||||
the menu?
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
The Clam Chowder special soup costs $9.99. Would you like to add it to your order or ask about something else?
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your meal!
|
||||
|
||||
Streaming Total Completion Usage: {
|
||||
"prompt_tokens": 1150,
|
||||
"prompt_tokens_details": {
|
||||
"audio_tokens": 0,
|
||||
"cached_tokens": 0
|
||||
},
|
||||
"completion_tokens": 134,
|
||||
"completion_tokens_details": {
|
||||
"accepted_prediction_tokens": 0,
|
||||
"audio_tokens": 0,
|
||||
"reasoning_tokens": 0,
|
||||
"rejected_prediction_tokens": 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistorySummarizationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a chat history
|
||||
reducer as part of the Semantic Kernel Agent Framework. For this sample,
|
||||
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
|
||||
Reducer is a Summary Reducer. View the README for more information on
|
||||
how to use the reducer and what each parameter does.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
"""
|
||||
Single-function approach that shows the same chat reducer behavior
|
||||
while preserving all original logic and code lines (now commented).
|
||||
"""
|
||||
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# Create a summarization reducer and clear its history
|
||||
history_summarization_reducer = ChatHistorySummarizationReducer(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
history_summarization_reducer.clear()
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
)
|
||||
|
||||
# Create a group chat using the reducer
|
||||
chat = AgentGroupChat(chat_history=history_summarization_reducer)
|
||||
|
||||
# Simulate user messages
|
||||
message_count = 50 # Number of messages to simulate
|
||||
for index in range(1, message_count, 2):
|
||||
# Add user message to the chat
|
||||
await chat.add_chat_message(message=str(index))
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Attempt to reduce history
|
||||
is_reduced = await chat.reduce_history()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(history_summarization_reducer.messages)} messages.")
|
||||
|
||||
# Invoke the agent and display responses
|
||||
async for message in chat.invoke(agent):
|
||||
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
|
||||
# Retrieve messages
|
||||
msgs = []
|
||||
async for m in chat.get_chat_messages(agent):
|
||||
msgs.append(m)
|
||||
print(f"@ Message Count: {len(msgs)}\n")
|
||||
|
||||
# If a reduction happened and we use summarization, print the summary
|
||||
if is_reduced:
|
||||
for msg in msgs:
|
||||
if msg.metadata and msg.metadata.get("__summary__"):
|
||||
print(f"\tSummary: {msg.content}")
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistorySummarizationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a truncation chat
|
||||
history reducer as part of the Semantic Kernel Agent Framework. For
|
||||
this sample, a single ChatCompletionAgent is used.
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# Create a summarization reducer
|
||||
history_summarization_reducer = ChatHistorySummarizationReducer(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_summarization_reducer)
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
)
|
||||
|
||||
# Number of messages to simulate
|
||||
message_count = 50
|
||||
for index in range(1, message_count + 1, 2):
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Get agent response and store it
|
||||
response = await agent.get_response(messages=str(index), thread=thread)
|
||||
thread = response.thread
|
||||
print(f"# Agent - {response.name}: '{response.content}'")
|
||||
|
||||
# Attempt reduction
|
||||
is_reduced = await thread.reduce()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(thread)} messages.")
|
||||
|
||||
print(f"@ Message Count: {len(thread)}\n")
|
||||
|
||||
# If reduced, print summary if present
|
||||
if is_reduced:
|
||||
async for msg in thread.get_messages():
|
||||
if msg.metadata and msg.metadata.get("__summary__"):
|
||||
print(f"\tSummary: {msg.content}")
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with non-streaming responses. It also shows how to track token
|
||||
usage during agent invoke.
|
||||
"""
|
||||
|
||||
|
||||
# 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() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
completion_usage = CompletionUsage()
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content)
|
||||
if response.metadata.get("usage"):
|
||||
completion_usage += response.metadata["usage"]
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Print the completion usage
|
||||
print(f"\nNon-Streaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I help you with the menu today?
|
||||
|
||||
|
||||
# User: 'What is the special soup?'
|
||||
The special soup today is Clam Chowder. Would you like to know more about it or see the other specials?
|
||||
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
The Clam Chowder special costs $9.99. Would you like to add that to your order or need more information?
|
||||
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
|
||||
|
||||
Non-Streaming Total Completion Usage: {
|
||||
"prompt_tokens": 772,
|
||||
"prompt_tokens_details": {
|
||||
"audio_tokens": 0,
|
||||
"cached_tokens": 0
|
||||
},
|
||||
"completion_tokens": 92,
|
||||
"completion_tokens_details": {
|
||||
"accepted_prediction_tokens": 0,
|
||||
"audio_tokens": 0,
|
||||
"reasoning_tokens": 0,
|
||||
"rejected_prediction_tokens": 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistoryTruncationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a chat history
|
||||
reducer as part of the Semantic Kernel Agent Framework. For this sample,
|
||||
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
|
||||
Reducer is a Truncation Reducer. View the README for more information on
|
||||
how to use the reducer and what each parameter does.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
"""
|
||||
Single-function approach that shows the same chat reducer behavior
|
||||
while preserving all original logic and code lines (now commented).
|
||||
"""
|
||||
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
# Create a truncation reducer and clear its history
|
||||
history_truncation_reducer = ChatHistoryTruncationReducer(
|
||||
target_count=reducer_msg_count, threshold_count=reducer_threshold
|
||||
)
|
||||
history_truncation_reducer.clear()
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
)
|
||||
|
||||
# Create a group chat using the reducer
|
||||
chat = AgentGroupChat(chat_history=history_truncation_reducer)
|
||||
|
||||
# Simulate user messages
|
||||
message_count = 50 # Number of messages to simulate
|
||||
for index in range(1, message_count, 2):
|
||||
# Add user message to the chat
|
||||
await chat.add_chat_message(message=str(index))
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Attempt to reduce history
|
||||
is_reduced = await chat.reduce_history()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(history_truncation_reducer.messages)} messages.")
|
||||
|
||||
# Invoke the agent and display responses
|
||||
async for message in chat.invoke(agent):
|
||||
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
|
||||
# Retrieve messages
|
||||
msgs = []
|
||||
async for m in chat.get_chat_messages(agent):
|
||||
msgs.append(m)
|
||||
print(f"@ Message Count: {len(msgs)}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import (
|
||||
ChatCompletionAgent,
|
||||
)
|
||||
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import (
|
||||
ChatHistoryTruncationReducer,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a truncation chat
|
||||
history reducer as part of the Semantic Kernel Agent Framework. For
|
||||
this sample, a single ChatCompletionAgent is used.
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
# Create a truncation reducer
|
||||
history_truncation_reducer = ChatHistoryTruncationReducer(
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_truncation_reducer)
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
)
|
||||
|
||||
# Number of messages to simulate
|
||||
message_count = 50
|
||||
for index in range(1, message_count + 1, 2):
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Get agent response and store it
|
||||
response = await agent.get_response(messages=str(index), thread=thread)
|
||||
thread = response.thread
|
||||
print(f"# Agent - {response.name}: '{response.content}'")
|
||||
|
||||
# Attempt reduction
|
||||
is_reduced = await thread.reduce()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(thread)} messages.")
|
||||
|
||||
print(f"@ Message Count: {len(history_truncation_reducer.messages)}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,96 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAIAgent, AzureAIAgentSettings, ChatCompletionAgent
|
||||
from semantic_kernel.agents.strategies import TerminationStrategy
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import AuthorRole
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a Azure AI Foundry Agent,
|
||||
a chat completion agent and have them participate in a group chat to work towards
|
||||
the user's requirement.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
class ApprovalTerminationStrategy(TerminationStrategy):
|
||||
"""A strategy for determining when an agent should terminate."""
|
||||
|
||||
async def should_agent_terminate(self, agent, history):
|
||||
"""Check if the agent should terminate."""
|
||||
return "approved" in history[-1].content.lower()
|
||||
|
||||
|
||||
REVIEWER_NAME = "ArtDirector"
|
||||
REVIEWER_INSTRUCTIONS = """
|
||||
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
|
||||
The goal is to determine if the given copy is acceptable to print.
|
||||
If so, state that it is approved. Only include the word "approved" if it is so.
|
||||
If not, provide insight on how to refine suggested copy without example.
|
||||
"""
|
||||
|
||||
COPYWRITER_NAME = "CopyWriter"
|
||||
COPYWRITER_INSTRUCTIONS = """
|
||||
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
|
||||
The goal is to refine and decide on the single best copy as an expert in the field.
|
||||
Only provide a single proposal per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
async with (
|
||||
# 1. Login to Azure and create a Azure AI Project Client
|
||||
AzureAIAgent.create_client(credential=credential) as client,
|
||||
):
|
||||
# 2. Create agents
|
||||
agent_writer = AzureAIAgent(
|
||||
client=client,
|
||||
definition=await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
name=COPYWRITER_NAME,
|
||||
instructions=COPYWRITER_INSTRUCTIONS,
|
||||
),
|
||||
)
|
||||
agent_reviewer = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(service_id="artdirector", credential=credential),
|
||||
name=REVIEWER_NAME,
|
||||
instructions=REVIEWER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
# 3. Create the AgentGroupChat object and specify the list of agents along with the termination strategy
|
||||
chat = AgentGroupChat(
|
||||
agents=[agent_writer, agent_reviewer],
|
||||
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
|
||||
)
|
||||
|
||||
# 4. Provide the task an start running
|
||||
input = "a slogan for a new line of electric cars."
|
||||
await chat.add_chat_message(input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
async for content in chat.invoke():
|
||||
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
|
||||
|
||||
# 5. Done and remove the Auzre AI Foundry Agent.
|
||||
print(f"# IS COMPLETE: {chat.is_complete}")
|
||||
|
||||
await client.agents.delete_agent(agent_writer.definition.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,133 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
|
||||
from semantic_kernel.agents.strategies import TerminationStrategy
|
||||
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole
|
||||
from semantic_kernel.functions import KernelArguments, kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI, a chat completion
|
||||
agent and have them participate in a group chat to work towards
|
||||
the user's requirement. The ChatCompletionAgent uses a plugin
|
||||
that is part of the agent group chat.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
class ApprovalTerminationStrategy(TerminationStrategy):
|
||||
"""A strategy for determining when an agent should terminate."""
|
||||
|
||||
async def should_agent_terminate(self, agent, history):
|
||||
"""Check if the agent should terminate."""
|
||||
return "approved" in history[-1].content.lower()
|
||||
|
||||
|
||||
REVIEWER_NAME = "ArtDirector"
|
||||
REVIEWER_INSTRUCTIONS = """
|
||||
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
|
||||
The goal is to determine if the given copy is acceptable to print.
|
||||
If so, state that it is approved. Only include the word "approved" if it is so.
|
||||
If not, provide insight on how to refine suggested copy without example.
|
||||
You should always tie the conversation back to the food specials offered by the plugin.
|
||||
"""
|
||||
|
||||
COPYWRITER_NAME = "CopyWriter"
|
||||
COPYWRITER_INSTRUCTIONS = """
|
||||
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
|
||||
The goal is to refine and decide on the single best copy as an expert in the field.
|
||||
Only provide a single proposal per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
"""
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
|
||||
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
kernel = _create_kernel_with_chat_completion("artdirector", credential)
|
||||
settings = kernel.get_prompt_execution_settings_from_service_id(service_id="artdirector")
|
||||
# Configure the function choice behavior to auto invoke kernel functions
|
||||
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
|
||||
agent_reviewer = ChatCompletionAgent(
|
||||
kernel=kernel,
|
||||
name=REVIEWER_NAME,
|
||||
instructions=REVIEWER_INSTRUCTIONS,
|
||||
arguments=KernelArguments(settings=settings),
|
||||
)
|
||||
|
||||
# Create the Assistant Agent using Azure OpenAI resources
|
||||
client = AzureAssistantAgent.create_client(credential=credential)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name=COPYWRITER_NAME,
|
||||
instructions=COPYWRITER_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent_writer = AzureAssistantAgent(client=client, definition=definition)
|
||||
|
||||
chat = AgentGroupChat(
|
||||
agents=[agent_writer, agent_reviewer],
|
||||
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
|
||||
)
|
||||
|
||||
input = "Write copy based on the food specials."
|
||||
try:
|
||||
await chat.add_chat_message(input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
async for content in chat.invoke():
|
||||
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
|
||||
|
||||
print(f"# IS COMPLETE: {chat.is_complete}")
|
||||
finally:
|
||||
await agent_writer.client.beta.assistants.delete(agent_writer.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,117 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
|
||||
from semantic_kernel.contents import AnnotationContent, AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI, a chat completion
|
||||
agent and have them participate in a group chat working on
|
||||
an uploaded file.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"mixed_chat_files",
|
||||
"user-context.txt",
|
||||
)
|
||||
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=credential)
|
||||
|
||||
# If desired, create using OpenAI resources
|
||||
# client = OpenAIAssistantAgent.create_client()
|
||||
|
||||
# Load the text file as a FileObject
|
||||
with open(file_path, "rb") as file:
|
||||
file = await client.files.create(file=file, purpose="assistants")
|
||||
|
||||
code_interpreter_tool, code_interpreter_tool_resource = AzureAssistantAgent.configure_code_interpreter_tool(
|
||||
file_ids=file.id
|
||||
)
|
||||
|
||||
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_tool_resource,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
analyst_agent = AzureAssistantAgent(client=client, definition=definition)
|
||||
|
||||
service_id = "summary"
|
||||
summary_agent = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion(service_id=service_id, credential=credential),
|
||||
instructions="Summarize the entire conversation for the user in natural language.",
|
||||
name="SummaryAgent",
|
||||
)
|
||||
|
||||
# Create the AgentGroupChat object, which will manage the chat between the agents
|
||||
# We don't always need to specify the agents in the chat up front
|
||||
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
|
||||
# agent to the chat
|
||||
chat = AgentGroupChat()
|
||||
|
||||
try:
|
||||
user_and_agent_inputs = (
|
||||
(
|
||||
"Create a tab delimited file report of the ordered (descending) frequency distribution of "
|
||||
"words in the file 'user-context.txt' for any words used more than once.",
|
||||
analyst_agent,
|
||||
),
|
||||
(None, summary_agent),
|
||||
)
|
||||
|
||||
for input, agent in user_and_agent_inputs:
|
||||
if input:
|
||||
await chat.add_chat_message(input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
async for content in chat.invoke(agent=agent):
|
||||
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
|
||||
if len(content.items) > 0:
|
||||
for item in content.items:
|
||||
if (
|
||||
isinstance(agent, AzureAssistantAgent)
|
||||
and isinstance(item, AnnotationContent)
|
||||
and item.file_id
|
||||
):
|
||||
print(f"\n`{item.quote}` => {item.file_id}")
|
||||
response_content = await agent.client.files.content(item.file_id)
|
||||
print(response_content.text)
|
||||
finally:
|
||||
await client.files.delete(file_id=file.id)
|
||||
await client.beta.assistants.delete(analyst_agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
|
||||
from semantic_kernel.contents import AnnotationContent
|
||||
from semantic_kernel.contents.utils.author_role import AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI, a chat completion
|
||||
agent and have them participate in a group chat working with
|
||||
image content.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=credential)
|
||||
|
||||
# Get the code interpreter tool and resources
|
||||
code_interpreter_tool, code_interpreter_resources = AzureAssistantAgent.configure_code_interpreter_tool()
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="Analyst",
|
||||
instructions="Create charts as requested without explanation",
|
||||
tools=code_interpreter_tool,
|
||||
tool_resources=code_interpreter_resources,
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
analyst_agent = AzureAssistantAgent(client=client, definition=definition)
|
||||
|
||||
service_id = "summary"
|
||||
summary_agent = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion(service_id=service_id),
|
||||
instructions="Summarize the entire conversation for the user in natural language.",
|
||||
name="Summarizer",
|
||||
)
|
||||
|
||||
# Create the AgentGroupChat object, which will manage the chat between the agents
|
||||
# We don't always need to specify the agents in the chat up front
|
||||
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
|
||||
# agent to the chat
|
||||
chat = AgentGroupChat()
|
||||
|
||||
try:
|
||||
user_and_agent_inputs = (
|
||||
(
|
||||
"""
|
||||
Graph the percentage of storm events by state using a pie chart:
|
||||
|
||||
State, StormCount
|
||||
TEXAS, 4701
|
||||
KANSAS, 3166
|
||||
IOWA, 2337
|
||||
ILLINOIS, 2022
|
||||
MISSOURI, 2016
|
||||
GEORGIA, 1983
|
||||
MINNESOTA, 1881
|
||||
WISCONSIN, 1850
|
||||
NEBRASKA, 1766
|
||||
NEW YORK, 1750
|
||||
""".strip(),
|
||||
analyst_agent,
|
||||
),
|
||||
(None, summary_agent),
|
||||
)
|
||||
|
||||
for input, agent in user_and_agent_inputs:
|
||||
if input:
|
||||
await chat.add_chat_message(input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
async for content in chat.invoke(agent=agent):
|
||||
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
|
||||
if len(content.items) > 0:
|
||||
for item in content.items:
|
||||
if (
|
||||
isinstance(agent, AzureAssistantAgent)
|
||||
and isinstance(item, AnnotationContent)
|
||||
and item.file_id
|
||||
):
|
||||
print(f"\n`{item.quote}` => {item.file_id}")
|
||||
response_content = await agent.client.files.content(item.file_id)
|
||||
print(response_content.text)
|
||||
finally:
|
||||
await client.beta.assistants.delete(analyst_agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI, a chat completion
|
||||
agent and have them participate in a group chat to work towards
|
||||
the user's requirement. It also demonstrates how the underlying
|
||||
agent reset method is used to clear the current state of the chat
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# First create the ChatCompletionAgent
|
||||
chat_agent = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion("chat", credential),
|
||||
name="chat_agent",
|
||||
instructions="""
|
||||
The user may either provide information or query on information previously provided.
|
||||
If the query does not correspond with information provided, inform the user that their query
|
||||
cannot be answered.
|
||||
""",
|
||||
)
|
||||
|
||||
# Next, we will create the AzureAssistantAgent
|
||||
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=credential)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="copywriter",
|
||||
instructions="""
|
||||
The user may either provide information or query on information previously provided.
|
||||
If the query does not correspond with information provided, inform the user that their query
|
||||
cannot be answered.
|
||||
""",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
assistant_agent = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create the AgentGroupChat object, which will manage the chat between the agents
|
||||
# We don't always need to specify the agents in the chat up front
|
||||
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
|
||||
# agent to the chat
|
||||
chat = AgentGroupChat()
|
||||
|
||||
try:
|
||||
user_inputs = [
|
||||
"What is my favorite color?",
|
||||
"I like green.",
|
||||
"What is my favorite color?",
|
||||
"[RESET]",
|
||||
"What is my favorite color?",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
# Check for reset indicator
|
||||
if user_input == "[RESET]":
|
||||
print("\nResetting chat...")
|
||||
await chat.reset()
|
||||
continue
|
||||
|
||||
# First agent (assistant_agent) receives the user input
|
||||
await chat.add_chat_message(user_input)
|
||||
print(f"\n{AuthorRole.USER}: '{user_input}'")
|
||||
async for message in chat.invoke(agent=assistant_agent):
|
||||
if message.content is not None:
|
||||
print(f"\n# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
|
||||
# Second agent (chat_agent) just responds without new user input
|
||||
async for message in chat.invoke(agent=chat_agent):
|
||||
if message.content is not None:
|
||||
print(f"\n# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
finally:
|
||||
await chat.reset()
|
||||
await assistant_agent.client.beta.assistants.delete(assistant_agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
|
||||
from semantic_kernel.agents.strategies import TerminationStrategy
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
assistant using either Azure OpenAI or OpenAI, a chat completion
|
||||
agent and have them participate in a group chat to work towards
|
||||
the user's requirement.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
class ApprovalTerminationStrategy(TerminationStrategy):
|
||||
"""A strategy for determining when an agent should terminate."""
|
||||
|
||||
async def should_agent_terminate(self, agent, history):
|
||||
"""Check if the agent should terminate."""
|
||||
return "approved" in history[-1].content.lower()
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
|
||||
return kernel
|
||||
|
||||
|
||||
async def main():
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# First create a ChatCompletionAgent
|
||||
agent_reviewer = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completion("artdirector", credential),
|
||||
name="ArtDirector",
|
||||
instructions="""
|
||||
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
|
||||
The goal is to determine if the given copy is acceptable to print.
|
||||
If so, state that it is approved. Only include the word "approved" if it is so.
|
||||
If not, provide insight on how to refine suggested copy without example.
|
||||
""",
|
||||
)
|
||||
|
||||
# Next, we will create the AzureAssistantAgent
|
||||
|
||||
# Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureAssistantAgent.create_client(credential=credential)
|
||||
|
||||
# Create the assistant definition
|
||||
definition = await client.beta.assistants.create(
|
||||
model=AzureOpenAISettings().chat_deployment_name,
|
||||
name="CopyWriter",
|
||||
instructions="""
|
||||
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
|
||||
The goal is to refine and decide on the single best copy as an expert in the field.
|
||||
Only provide a single proposal per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
""",
|
||||
)
|
||||
|
||||
# Create the AzureAssistantAgent instance using the client and the assistant definition
|
||||
agent_writer = AzureAssistantAgent(
|
||||
client=client,
|
||||
definition=definition,
|
||||
)
|
||||
|
||||
# Create the AgentGroupChat object, which will manage the chat between the agents
|
||||
chat = AgentGroupChat(
|
||||
agents=[agent_writer, agent_reviewer],
|
||||
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
|
||||
)
|
||||
|
||||
input = "a slogan for a new line of electric cars."
|
||||
|
||||
try:
|
||||
await chat.add_chat_message(input)
|
||||
print(f"# {AuthorRole.USER}: '{input}'")
|
||||
|
||||
last_agent = None
|
||||
async for message in chat.invoke_stream():
|
||||
if message.content is not None:
|
||||
if last_agent != message.name:
|
||||
print(f"\n# {message.name}: ", end="", flush=True)
|
||||
last_agent = message.name
|
||||
print(f"{message.content}", end="", flush=True)
|
||||
|
||||
print()
|
||||
print(f"# IS COMPLETE: {chat.is_complete}")
|
||||
finally:
|
||||
await agent_writer.client.beta.assistants.delete(agent_writer.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -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())
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureResponsesAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Responses Agent that answers
|
||||
user questions using the file search tool.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: azure_responses
|
||||
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:
|
||||
endpoint: ${AzureOpenAI:Endpoint}
|
||||
tools:
|
||||
- type: file_search
|
||||
options:
|
||||
vector_store_ids:
|
||||
- ${AzureOpenAI:VectorStoreId}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the Azure OpenAI client
|
||||
client = AzureResponsesAgent.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 server
|
||||
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="responses_file_search",
|
||||
file_ids=[file.id],
|
||||
)
|
||||
|
||||
try:
|
||||
# Create the Responses 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: AzureResponsesAgent = 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.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())
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
# 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, AzureResponsesAgent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Responses 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 = AzureResponsesAgent.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_responses_spec.yaml",
|
||||
)
|
||||
|
||||
# Create the Responses Agent from the YAML spec
|
||||
agent: AzureResponsesAgent = 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
|
||||
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())
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, AzureResponsesAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an Azure Responses 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_responses
|
||||
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 Azure OpenAI client
|
||||
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# Create the Responses 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: AzureResponsesAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
)
|
||||
|
||||
USER_INPUTS = ["Tell me a fun story."]
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
for user_input in USER_INPUTS:
|
||||
# Print the user input
|
||||
print(f"# User: '{user_input}'")
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Tell me a fun story.'
|
||||
# StoryAgent: Late at night, a mischievous cat named Whiskers tiptoed across the piano keys,
|
||||
accidentally composing a tune so catchy that all the neighborhood felines gathered outside
|
||||
to dance. By morning, the humans awoke to find a crowd of cats meowing for an encore performance.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Responses Agent that answers
|
||||
user questions using the file search tool based on a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: openai_responses
|
||||
name: FileSearchAgent
|
||||
description: Agent with file search tool.
|
||||
instructions: >
|
||||
Find answers to the user's questions in the provided file.
|
||||
model:
|
||||
id: ${OpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${OpenAI:ApiKey}
|
||||
tools:
|
||||
- type: file_search
|
||||
description: File search for document retrieval.
|
||||
options:
|
||||
vector_store_ids:
|
||||
- ${OpenAI:VectorStoreId}
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI Responses client
|
||||
client = OpenAIResponsesAgent.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 Responses 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: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
extras={"OpenAI:VectorStoreId": vector_store.id},
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
USER_INPUTS = ["Who can help me if I have a sales question?", "Who works in sales?"]
|
||||
|
||||
thread = None
|
||||
|
||||
for user_input in USER_INPUTS:
|
||||
# Print the user input
|
||||
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}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
# Cleanup: Delete the vector store, and file
|
||||
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())
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Responses 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 = OpenAIResponsesAgent.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_responses_spec.yaml",
|
||||
)
|
||||
|
||||
# Create the Responses Agent from the YAML spec
|
||||
agent: OpenAIResponsesAgent = 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
|
||||
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())
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Responses 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_responses
|
||||
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 client
|
||||
client = OpenAIResponsesAgent.create_client()
|
||||
|
||||
# Create the Responses 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: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
)
|
||||
|
||||
USER_INPUTS = ["Tell me a fun story."]
|
||||
|
||||
# Invoke the agent for the specified task
|
||||
for user_input in USER_INPUTS:
|
||||
# Print the user input
|
||||
print(f"# User: '{user_input}'")
|
||||
# Invoke the agent for the specified task
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
):
|
||||
print(f"# {response.name}: {response}")
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Tell me a fun story.'
|
||||
# StoryAgent: Late at night, a mischievous cat named Whiskers tiptoed across the piano keys,
|
||||
accidentally composing a tune so catchy that all the neighborhood felines gathered outside
|
||||
to dance. By morning, the humans awoke to find a crowd of cats meowing for an encore performance.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Responses Agent that answers
|
||||
user questions using the web search tool based on a declarative spec.
|
||||
"""
|
||||
|
||||
# Define the YAML string for the sample
|
||||
spec = """
|
||||
type: openai_responses
|
||||
name: WebSearchAgent
|
||||
description: Agent with web search tool.
|
||||
instructions: >
|
||||
Find answers to the user's questions using the provided tool.
|
||||
model:
|
||||
id: ${OpenAI:ChatModelId}
|
||||
connection:
|
||||
api_key: ${OpenAI:ApiKey}
|
||||
tools:
|
||||
- type: web_search
|
||||
description: Search the internet for recent information.
|
||||
options:
|
||||
search_context_size: high
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup the OpenAI client
|
||||
client = OpenAIResponsesAgent.create_client()
|
||||
|
||||
try:
|
||||
# Create the Responses 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: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
|
||||
yaml_str=spec,
|
||||
client=client,
|
||||
)
|
||||
|
||||
# Define the task for the agent
|
||||
USER_INPUTS = ["Who won the 2025 NCAA basketball championship?"]
|
||||
|
||||
thread = None
|
||||
|
||||
for user_input in USER_INPUTS:
|
||||
# Print the user input
|
||||
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}")
|
||||
thread = response.thread
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: 'Who won the 2025 NCAA basketball championship?'
|
||||
# WebSearchAgent: The Florida Gators won the 2025 NCAA men's basketball championship, defeating the Houston
|
||||
Cougars 65-63 on April 7, 2025, at the Alamodome in San Antonio, Texas. This victory marked Florida's
|
||||
third national title and their first since 2007. ([reuters.com](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai))
|
||||
|
||||
In the championship game, Florida overcame a 12-point deficit in the second half. Senior guard Walter Clayton
|
||||
Jr. was instrumental in the comeback, scoring all 11 of his points in the second half and delivering a
|
||||
crucial defensive stop in the final seconds to secure the win. Will Richard led the Gators with 18 points. ([apnews.com](https://apnews.com/article/74a9c790277595ce53ca130c5ec64429?utm_source=openai))
|
||||
|
||||
Head coach Todd Golden, in his third season, became the youngest coach to win the NCAA title since 1983. ([reuters.com](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai))
|
||||
|
||||
## Florida Gators' 2025 NCAA Championship Victory:
|
||||
- [Florida overcome Houston in massive comeback to claim third NCAA title](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai)
|
||||
- [Walter Clayton Jr.'s defensive stop gives Florida its 3rd national title with 65-63 win over Houston](https://apnews.com/article/74a9c790277595ce53ca130c5ec64429?utm_source=openai)
|
||||
- [Reports: National champion Florida sets White House visit](https://www.reuters.com/sports/reports-national-champion-florida-sets-white-house-visit-2025-05-18/?utm_source=openai)
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from semantic_kernel.agents import OpenAIResponsesAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
|
||||
from semantic_kernel.contents.binary_content import BinaryContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.utils.author_role import AuthorRole
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to upload PDF and text files using BinaryContent
|
||||
with an OpenAI Responses Agent. This shows how to create BinaryContent objects from files
|
||||
and compose multi-modal messages that combine text and binary content.
|
||||
|
||||
The sample demonstrates:
|
||||
1. Creating BinaryContent from a PDF file
|
||||
2. Creating BinaryContent from a text file
|
||||
3. Composing multi-modal messages with mixed content types (text + binary)
|
||||
4. Sending complex messages directly to the agent via the messages parameter
|
||||
5. Having the agent process and respond to questions about the uploaded files
|
||||
|
||||
This approach differs from simple string-based interactions by showing how to combine
|
||||
multiple content types within a single message, which is useful for rich media interactions.
|
||||
|
||||
Note: This sample uses the existing employees.pdf file from the resources directory.
|
||||
"""
|
||||
|
||||
# Sample follow-up questions to demonstrate continued conversation
|
||||
USER_INPUTS = [
|
||||
"What specific types of files did I just upload?",
|
||||
"Can you tell me about the content in the PDF file?",
|
||||
"What does the text file contain?",
|
||||
"Can you provide a summary of both documents?",
|
||||
]
|
||||
|
||||
|
||||
def create_sample_text_content() -> str:
|
||||
"""Create sample text content for demonstration purposes.
|
||||
|
||||
Returns:
|
||||
str: A sample company policy document in text format.
|
||||
"""
|
||||
return """Company Policy Document - Remote Work Guidelines
|
||||
|
||||
This document outlines our company's remote work policies and procedures.
|
||||
|
||||
Remote Work Eligibility:
|
||||
- Full-time employees with at least 6 months tenure
|
||||
- Managers approval required
|
||||
- Home office setup must meet security requirements
|
||||
|
||||
Work Schedule:
|
||||
- Core hours: 10 AM - 3 PM local time
|
||||
- Flexible start/end times outside core hours
|
||||
- Maximum 3 remote days per week for hybrid roles
|
||||
|
||||
Communication Requirements:
|
||||
- Daily check-ins with team lead
|
||||
- Weekly video conference participation
|
||||
- Response time: within 4 hours during business hours
|
||||
|
||||
Equipment and Security:
|
||||
- Company-provided laptop and VPN access
|
||||
- Secure Wi-Fi connection required
|
||||
- No public Wi-Fi for work activities
|
||||
|
||||
For questions about remote work policies, contact HR at hr@company.com
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Initialize the OpenAI client
|
||||
client = OpenAIResponsesAgent.create_client()
|
||||
|
||||
# 2. Prepare file paths and create sample content
|
||||
pdf_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
|
||||
"resources",
|
||||
"file_search",
|
||||
"employees.pdf",
|
||||
)
|
||||
|
||||
# Create a temporary text file for demonstration purposes
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as text_file:
|
||||
text_content = create_sample_text_content()
|
||||
text_file.write(text_content)
|
||||
text_file_path = text_file.name
|
||||
|
||||
try:
|
||||
# 3. Create BinaryContent objects from files using different methods
|
||||
print("Creating BinaryContent from files...")
|
||||
|
||||
# Method 1: Create BinaryContent from an existing PDF file
|
||||
pdf_binary_content = BinaryContent.from_file(file_path=pdf_file_path, mime_type="application/pdf")
|
||||
print(f"Created PDF BinaryContent: {pdf_binary_content.mime_type}, can_read: {pdf_binary_content.can_read}")
|
||||
|
||||
# Method 2: Create BinaryContent from the temporary text file
|
||||
text_binary_content = BinaryContent.from_file(file_path=text_file_path, mime_type="text/plain")
|
||||
print(f"Created text BinaryContent: {text_binary_content.mime_type}, can_read: {text_binary_content.can_read}")
|
||||
|
||||
# Method 3: Create BinaryContent directly from in-memory data
|
||||
# This approach allows creating BinaryContent without file I/O operations
|
||||
alternative_text_content = BinaryContent(
|
||||
data=text_content.encode("utf-8"), mime_type="text/plain", data_format="base64"
|
||||
)
|
||||
print(f"Alternative text BinaryContent: {alternative_text_content.mime_type}")
|
||||
|
||||
# 4. Initialize the OpenAI Responses Agent with file analysis capabilities
|
||||
# Configure the AI model for responses
|
||||
settings = OpenAISettings()
|
||||
responses_model = settings.responses_model_id or "gpt-4o"
|
||||
|
||||
agent = OpenAIResponsesAgent(
|
||||
ai_model_id=responses_model,
|
||||
client=client,
|
||||
instructions=(
|
||||
"You are a helpful assistant that can analyze uploaded files. "
|
||||
"When users upload files, examine their content and provide helpful insights. "
|
||||
"You can identify file types, summarize content, and answer questions about the files."
|
||||
),
|
||||
name="FileAnalyzer",
|
||||
)
|
||||
|
||||
# 5. Demonstrate multi-modal message composition
|
||||
# This showcases combining text and binary content in a single message
|
||||
|
||||
# Compose a message containing both text instructions and file attachments
|
||||
# This pattern is ideal for scenarios requiring rich, mixed-content interactions
|
||||
initial_message = ChatMessageContent(
|
||||
role=AuthorRole.USER,
|
||||
items=[
|
||||
TextContent(text="I'm uploading a PDF document and a text file for you to analyze."),
|
||||
pdf_binary_content,
|
||||
text_binary_content,
|
||||
],
|
||||
)
|
||||
|
||||
# 6. Conduct a conversation with the agent about the uploaded files
|
||||
thread = None
|
||||
|
||||
# Send the initial multi-modal message containing file uploads
|
||||
print("\n# User: 'I'm uploading a PDF document and a text file for you to analyze.'")
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(messages=initial_message, thread=thread):
|
||||
thread = response.thread
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print() # New line after response
|
||||
|
||||
# Continue the conversation with text-based follow-up questions
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
|
||||
# Process follow-up questions using standard text 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.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print() # New line after response
|
||||
|
||||
finally:
|
||||
# 7. Clean up temporary resources
|
||||
if os.path.exists(text_file_path):
|
||||
os.unlink(text_file_path)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Sample completed!")
|
||||
print("\nKey points about BinaryContent:")
|
||||
print("1. Use BinaryContent.from_file() to create from existing files")
|
||||
print("2. Use BinaryContent(data=...) to create from bytes/string data")
|
||||
print("3. Specify appropriate mime_type for proper handling")
|
||||
print("4. BinaryContent can be included in chat messages alongside text")
|
||||
print("5. The OpenAI Responses API will process supported file types")
|
||||
print("\nSupported file types include:")
|
||||
print("- PDF documents (application/pdf)")
|
||||
print("- Text files (text/plain)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user