chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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())
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from semantic_kernel.agents import OpenAIResponsesAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
|
||||
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI Responses Agent.
|
||||
The sample shows how to have the agent answer questions about the provided
|
||||
document with streaming responses.
|
||||
|
||||
The interaction with the agent is via the `get_response` method, which sends a
|
||||
user input to the agent and receives a response from the agent. The conversation
|
||||
history is maintained by the agent service, i.e. the responses are automatically
|
||||
associated with the thread. Therefore, client code does not need to maintain the
|
||||
conversation history.
|
||||
"""
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = [
|
||||
"By birthday, who is the youngest employee?",
|
||||
"Who works in sales?",
|
||||
"I have a customer request, who can help me?",
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the client using OpenAI resources and configuration
|
||||
client = OpenAIResponsesAgent.create_client()
|
||||
|
||||
pdf_file_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "employees.pdf"
|
||||
)
|
||||
|
||||
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="step4_assistant_file_search",
|
||||
file_ids=[file.id],
|
||||
)
|
||||
|
||||
file_search_tool = OpenAIResponsesAgent.configure_file_search_tool(vector_store.id)
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
|
||||
agent = OpenAIResponsesAgent(
|
||||
ai_model_id=OpenAISettings().chat_model_id,
|
||||
client=client,
|
||||
instructions="Find answers to the user's questions in the provided file.",
|
||||
name="FileSearch",
|
||||
tools=[file_search_tool],
|
||||
)
|
||||
|
||||
# 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 = None
|
||||
|
||||
response_chunks: list[StreamingChatMessageContent] = []
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: '{user_input}'")
|
||||
# 4. Invoke the agent for the current message and print the response
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread):
|
||||
thread = response.thread
|
||||
response_chunks.append(response)
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print()
|
||||
|
||||
"""
|
||||
# User: 'By birthday, who is the youngest employee?'
|
||||
# Agent: The youngest employee by birthday is Teodor Britton, born on January 9, 1997.
|
||||
# User: 'Who works in sales?'
|
||||
# Agent: The employees who work in sales are:
|
||||
|
||||
- Mariam Jaslyn, Sales Representative
|
||||
- Hicran Bea, Sales Manager
|
||||
- Angelino Embla, Sales Representative.
|
||||
# User: 'I have a customer request, who can help me?'
|
||||
# Agent: For a customer request, you could reach out to the following people in the sales department:
|
||||
|
||||
- Mariam Jaslyn, Sales Representative
|
||||
- Hicran Bea, Sales Manager
|
||||
- Angelino Embla, Sales Representative.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,115 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureResponsesAgent
|
||||
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
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create an OpenAI
|
||||
Responses Agent using either Azure OpenAI or OpenAI. The
|
||||
Responses Agent allow for function calling, the use of file search and a
|
||||
web search tool. Responses Agent Threads are used to manage the
|
||||
conversation state, similar to a Semantic Kernel Chat History.
|
||||
Additionally, the invoke configures a message callback
|
||||
to receive the conversation messages during invocation.
|
||||
"""
|
||||
|
||||
|
||||
# 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():
|
||||
# 1. Create the client using Azure OpenAI resources and configuration
|
||||
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
|
||||
agent = AzureResponsesAgent(
|
||||
ai_model_id=AzureOpenAISettings().chat_deployment_name,
|
||||
client=client,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# 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 = 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,
|
||||
):
|
||||
thread = response.thread
|
||||
print(f"# {response.name}: {response.content}")
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
# Host: Hi there! How can I assist 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
|
||||
# Host: The special soup is Clam Chowder. Would you like to know more about any other specials?
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
# Host: The special drink is Chai Tea. Would you like any more information?
|
||||
# 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
|
||||
# Host: The Chai Tea is $9.99. Is there anything else you'd like to know?
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
# Host: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.agents import OpenAIResponsesAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
|
||||
from semantic_kernel.contents import AuthorRole, 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 an OpenAI
|
||||
Responses Agent using either Azure OpenAI or OpenAI. The
|
||||
Responses Agent allow for function calling, the use of file search and a
|
||||
web search tool. Responses Agent Threads are used to manage the
|
||||
conversation state, similar to a Semantic Kernel Chat History.
|
||||
Additionally, the invoke_stream configures a message callback
|
||||
to receive the conversation messages during streaming invocation.
|
||||
This sample also demonstrates the Responses Agent Streaming
|
||||
capability and how to manage a Responses Agent 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"
|
||||
|
||||
|
||||
# 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():
|
||||
# 1. Create the client using Azure OpenAI resources and configuration
|
||||
client = OpenAIResponsesAgent.create_client()
|
||||
|
||||
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
|
||||
agent = OpenAIResponsesAgent(
|
||||
ai_model_id=OpenAISettings().chat_model_id,
|
||||
client=client,
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# 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 = 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.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
print()
|
||||
finally:
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
# Host: Hello! How can I assist 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
|
||||
# Host: The special soup today is Clam Chowder. Would you like to know more about it or hear about other specials?
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
# Host: The special drink today is Chai Tea. Would you like more details or are you interested in ordering it?
|
||||
# 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
|
||||
# Host: The special drink, Chai Tea, is $9.99. Would you like to order one or need information on something else?
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
# Host: You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
|
||||
"""
|
||||
|
||||
|
||||
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