{"id":4751,"date":"2025-05-02T14:10:12","date_gmt":"2025-05-02T21:10:12","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=4751"},"modified":"2025-05-02T14:10:12","modified_gmt":"2025-05-02T21:10:12","slug":"guest-blog-orchestrating-ai-agents-with-semantic-kernel-plugins-a-technical-deep-dive","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/guest-blog-orchestrating-ai-agents-with-semantic-kernel-plugins-a-technical-deep-dive\/","title":{"rendered":"Guest Blog: Orchestrating AI Agents with Semantic Kernel Plugins: A Technical Deep Dive"},"content":{"rendered":"<p dir=\"auto\" data-line=\"4\">Today we&#8217;re excited to welcome Jarre Nejatyab as a guest blog to highlight a technical deep dive on orchestrating AI Agents with Semantic Kernel Plugins.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"4\">In the rapidly evolving world of Large Language Models (LLMs), orchestrating specialized AI agents has become crucial for building sophisticated cognitive architectures capable of complex reasoning and task execution. While powerful, coordinating multiple agents\u2014each with unique capabilities and data access\u2014presents significant engineering challenges. Microsoft&#8217;s Semantic Kernel (SK) offers a robust framework for managing this complexity through its intuitive plugin system. This blog post provides a technical deep dive into leveraging SK plugins for effective agent orchestration, illustrated with practical implementation patterns.<\/p>\n<h2 id=\"the-challenge-of-agent-orchestration\" class=\"code-line\" dir=\"auto\" data-line=\"6\">The Challenge of Agent Orchestration<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"8\">Modern AI applications often transcend the capabilities of a single LLM. They increasingly rely on ensembles of specialized agents working in concert. For instance, a query might require input from an agent accessing internal policy documents, another searching the public web, and a third querying a private database. The core challenge lies in:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"9\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"9\"><strong>Dynamically selecting<\/strong>\u00a0the right agent(s) for a given task.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"10\"><strong>Managing context and data flow<\/strong>\u00a0between agents.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"11\"><strong>Synthesizing potentially conflicting outputs<\/strong>\u00a0into a coherent final response.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"12\"><strong>Maintaining modularity and observability<\/strong>\u00a0as the system scales.<\/li>\n<\/ul>\n<h2 id=\"semantic-kernel-plugins\" class=\"code-line\" dir=\"auto\" data-line=\"14\">Semantic Kernel Plugins<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"16\">Semantic Kernel&#8217;s plugin architecture provides a structured solution. Plugins act as standardized wrappers around agent capabilities, enabling the kernel (the central orchestrator) to discover, invoke, and manage them effectively. Key benefits include:<\/p>\n<ol class=\"code-line\" dir=\"auto\" data-line=\"18\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"18\"><strong>Modular Agent Integration<\/strong>: Encapsulate each agent&#8217;s logic within a dedicated plugin.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"19\"><strong>Declarative Invocation<\/strong>: Define agent capabilities with clear descriptions, allowing the kernel&#8217;s LLM to dynamically choose the appropriate tool(s) based on the user query and context.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"20\"><strong>Unified Interface<\/strong>: Standardize communication, simplifying interactions between the orchestrator and diverse agents.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"21\"><strong>Centralized Monitoring<\/strong>: Track resource usage (like tokens) and execution flow across all agents.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"22\"><strong>Simplified Result Aggregation<\/strong>: Provide hooks to combine outputs from multiple agents into a cohesive final response.<\/li>\n<\/ol>\n<h2 id=\"architecture-overview\" class=\"code-line\" dir=\"auto\" data-line=\"24\">Architecture Overview<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"26\">Let&#8217;s examine a conceptual architecture for an orchestration system using SK plugins:<\/p>\n<p dir=\"auto\" data-line=\"26\"><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect.jpg\"><img decoding=\"async\" class=\"alignnone wp-image-4756 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect.jpg\" alt=\"sk multi architect image\" width=\"500\" height=\"432\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect.jpg 500w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect-300x259.jpg 300w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"29\">This architecture features:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"30\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"30\">A central\u00a0<strong>Orchestrator Agent<\/strong>, powered by Semantic Kernel, receiving user queries.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"31\">Multiple\u00a0<strong>Specialized Agent Plugins<\/strong>, each exposing the capabilities of a specific agent (e.g., Web Search, Org Policy Lookup, Private Data Query).<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"32\">A\u00a0<strong>Plugin Registration<\/strong>\u00a0mechanism making agent capabilities discoverable by the kernel.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"33\"><strong>Result Aggregation<\/strong>\u00a0logic within the orchestrator to synthesize a final answer. The kernel uses the descriptions provided within each plugin (via decorators like\u00a0<code>@kernel_function<\/code>) to determine which plugin(s) are relevant to the user&#8217;s query, enabling dynamic and context-aware agent invocation.<\/li>\n<\/ul>\n<h2 id=\"implementation-example\" class=\"code-line\" dir=\"auto\" data-line=\"36\">Implementation Example<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"38\">Consider this simplified Python implementation of an orchestrator agent using the Semantic Kernel SDK:<\/p>\n<pre><code class=\"code-line language-python\" dir=\"auto\" data-line=\"40\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">OrchestratorAgent<\/span>:\r\n    <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">invoke<\/span>(<span class=\"hljs-params\">self, message: ChatMessage, context: Context<\/span>) -&gt; ChatResponseMessage:\r\n        <span class=\"hljs-comment\"># 1. Set up the system prompt guiding the LLM orchestrator<\/span>\r\n        self._history.add_system_message(self.system_prompt)\r\n        self._history.add_user_message(message.user_query)\r\n\r\n        <span class=\"hljs-comment\"># 2. Initialize specialized agent plugins<\/span>\r\n        org_policy_agent_plugin = OrgPolicyAgentInvokingPlugin(kernel=self._kernel, message=message)\r\n        web_search_agent_plugin = WebSearchAgentInvokingPlugin(kernel=self._kernel, message=message)\r\n        private_data_agent_plugin = PrivateDataAgentInvokingPlugin(kernel=self._kernel, message=message)\r\n        generic_agent_plugin = GenericAgentInvokingPlugin(kernel=self._kernel, message=message) <span class=\"hljs-comment\"># Fallback agent<\/span>\r\n\r\n        <span class=\"hljs-comment\"># 3. Register plugins with the kernel, providing descriptive names<\/span>\r\n        self._kernel.add_plugin(org_policy_agent_plugin, plugin_name=<span class=\"hljs-string\">\"ORG_POLICY_AGENT\"<\/span>)\r\n        self._kernel.add_plugin(web_search_agent_plugin, plugin_name=<span class=\"hljs-string\">\"WEB_SEARCH_AGENT\"<\/span>)\r\n        self._kernel.add_plugin(private_data_agent_plugin, plugin_name=<span class=\"hljs-string\">\"PRIVATE_DATA_AGENT\"<\/span>)\r\n        self._kernel.add_plugin(generic_agent_plugin, plugin_name=<span class=\"hljs-string\">\"GENERIC_LLM_AGENT\"<\/span>)\r\n\r\n        <span class=\"hljs-comment\"># Configure the kernel to automatically invoke functions based on the prompt and plugin descriptions<\/span>\r\n        <span class=\"hljs-comment\"># execution_settings = ... # Configure execution settings, e.g., FunctionChoiceBehavior.Auto()<\/span>\r\n\r\n        <span class=\"hljs-comment\"># 4. Invoke the kernel. The underlying LLM uses the prompt and function descriptions<\/span>\r\n        <span class=\"hljs-comment\">#    to decide which plugin functions to call (sequentially or in parallel).<\/span>\r\n        results = []\r\n        <span class=\"hljs-comment\"># Assuming self._sk_agent uses the configured kernel and execution settings<\/span>\r\n        <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-keyword\">for<\/span> content <span class=\"hljs-keyword\">in<\/span> self._sk_agent.invoke(self._history): <span class=\"hljs-comment\"># Potentially involves multiple plugin calls<\/span>\r\n            results.append(content)\r\n\r\n        <span class=\"hljs-comment\"># 5. Aggregate results from all potentially invoked plugins<\/span>\r\n        <span class=\"hljs-comment\">#    (Plugins should track their own invocation status and results)<\/span>\r\n        agent_invoking_plugins = [\r\n            org_policy_agent_plugin,\r\n            web_search_agent_plugin,\r\n            private_data_agent_plugin,\r\n            generic_agent_plugin\r\n        ] <span class=\"hljs-comment\"># List of all potential plugins<\/span>\r\n\r\n        <span class=\"hljs-comment\"># 6. Calculate total token usage across invoked plugins<\/span>\r\n        <span class=\"hljs-comment\">#    (Requires plugins to expose usage data)<\/span>\r\n        total_prompt_tokens = <span class=\"hljs-built_in\">sum<\/span>(plugin.token_usage.prompt_token <span class=\"hljs-keyword\">for<\/span> plugin <span class=\"hljs-keyword\">in<\/span> agent_invoking_plugins <span class=\"hljs-keyword\">if<\/span> plugin.was_invoked) <span class=\"hljs-comment\"># Example: Check if invoked<\/span>\r\n        total_completion_tokens = <span class=\"hljs-built_in\">sum<\/span>(plugin.token_usage.completion_token <span class=\"hljs-keyword\">for<\/span> plugin <span class=\"hljs-keyword\">in<\/span> agent_invoking_plugins <span class=\"hljs-keyword\">if<\/span> plugin.was_invoked)\r\n\r\n        <span class=\"hljs-comment\"># 7. Compile search results\/citations from invoked plugins<\/span>\r\n        <span class=\"hljs-comment\">#    (Requires plugins to expose relevant results)<\/span>\r\n        search_result = SearchResult(docs=[], citations=[])\r\n        <span class=\"hljs-keyword\">for<\/span> plugin <span class=\"hljs-keyword\">in<\/span> agent_invoking_plugins:\r\n            <span class=\"hljs-keyword\">if<\/span> plugin.was_invoked: <span class=\"hljs-comment\"># Example: Check if invoked<\/span>\r\n                search_result.docs.extend(plugin.search_result.docs)\r\n                search_result.citations.extend(plugin.search_result.citations)\r\n\r\n        <span class=\"hljs-comment\"># 8. Return the consolidated response (likely the final LLM synthesis from step 4)<\/span>\r\n        final_content = results[-<span class=\"hljs-number\">1<\/span>].content <span class=\"hljs-keyword\">if<\/span> results <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-string\">\"Could not generate a response.\"<\/span>\r\n        <span class=\"hljs-keyword\">return<\/span> ChatResponseMessage(\r\n            content=final_content,\r\n            search_result=search_result,\r\n            token_usage=TokenUsage(\r\n                prompt_token=total_prompt_tokens,\r\n                completion_token=total_completion_tokens,\r\n            ),\r\n        )\r\n\r\n<span class=\"hljs-comment\"># Note: Requires AgentInvokingPlugin base class to define\/manage<\/span>\r\n<span class=\"hljs-comment\"># token_usage, search_result, was_invoked attributes, etc.<\/span>\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"105\">This example highlights how plugins are registered and how the kernel orchestrates their execution, followed by result aggregation. (Note: Error handling and detailed state management are omitted for brevity).<\/p>\n<h2 id=\"anatomy-of-an-agent-plugin-websearchagentinvokingplugin\" class=\"code-line\" dir=\"auto\" data-line=\"107\">Anatomy of an Agent Plugin: WebSearchAgentInvokingPlugin<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"109\">Let&#8217;s examine the\u00a0<code>WebSearchAgentInvokingPlugin<\/code>\u00a0more closely.<\/p>\n<pre><code class=\"code-line language-python\" dir=\"auto\" data-line=\"111\"><span class=\"hljs-comment\"># Assumes AgentInvokingPlugin base class handles kernel, message, runtime, etc.<\/span>\r\n<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">WebSearchAgentInvokingPlugin<\/span>(<span class=\"hljs-title class_ inherited__\">AgentInvokingPlugin<\/span>):\r\n<span class=\"hljs-meta\">    @kernel_function(<span class=\"hljs-params\">\r\n        name=<span class=\"hljs-string\">\"invoke_web_search_agent\"<\/span>,\r\n        description=<span class=\"hljs-string\">\"\"\"WebSearch plugin. Use this to answer questions requiring current, public information, such as:\r\n        - General knowledge questions or facts (e.g., 'What is the capital of France?')\r\n        - Current events, market data, or industry trends (e.g., 'Latest stock price for MSFT?')\r\n        - Technical information likely found online (e.g., 'How to configure a Flask server?')\r\n        - Information published in academic papers or public industry reports.\"\"\"<\/span>,\r\n    <\/span>)<\/span>\r\n    <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">invoke_web_search_agent<\/span>(<span class=\"hljs-params\">\r\n        self,\r\n        query: Annotated[<span class=\"hljs-built_in\">str<\/span>, <span class=\"hljs-string\">\"The specific question or topic to search the web for. Should be self-contained.\"<\/span>],\r\n    <\/span>):\r\n        <span class=\"hljs-string\">\"\"\"Invokes the external Web Search Agent.\"\"\"<\/span>\r\n        <span class=\"hljs-comment\"># self.was_invoked = True # Mark as invoked<\/span>\r\n        message_body = self.create_message_body(query) <span class=\"hljs-comment\"># Prepare agent-specific message<\/span>\r\n        recipient = AgentId(WEBSEARCH_AGENT, <span class=\"hljs-built_in\">str<\/span>(self.message.metadata.session_id)) <span class=\"hljs-comment\"># Target agent<\/span>\r\n\r\n        <span class=\"hljs-comment\"># Send message via runtime and await response<\/span>\r\n        result = <span class=\"hljs-keyword\">await<\/span> self.runtime.send_message(message=message_body, recipient=recipient)\r\n\r\n        <span class=\"hljs-comment\"># Process result, update internal state (token usage, search results), and return<\/span>\r\n        processed_response = self.proccess_and_create_response(result)\r\n        <span class=\"hljs-comment\"># self.token_usage = ... # Update token usage based on result<\/span>\r\n        <span class=\"hljs-comment\"># self.search_result = ... # Update search results based on result<\/span>\r\n        <span class=\"hljs-keyword\">return<\/span> processed_response <span class=\"hljs-comment\"># Return processed data, often just a summary string for the orchestrator LLM<\/span>\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"141\">Key aspects enabling orchestration:<\/p>\n<h3 id=\"1-clear-domain-boundaries-via-kernel_function\" class=\"code-line\" dir=\"auto\" data-line=\"143\">1. Clear Domain Boundaries via\u00a0<code>@kernel_function<\/code><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"145\">The\u00a0<code>description<\/code>\u00a0parameter in\u00a0<code>@kernel_function<\/code>\u00a0is crucial. The orchestrator LLM uses this natural language description to understand\u00a0<em>when<\/em>\u00a0to use this specific plugin. A well-crafted description significantly improves the accuracy of dynamic function calling.<\/p>\n<h3 id=\"2-informative-parameter-signatures-with-annotated\" class=\"code-line\" dir=\"auto\" data-line=\"147\">2. Informative Parameter Signatures with\u00a0<code>Annotated<\/code><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"149\">Type hints (<code>str<\/code>) and\u00a0<code>Annotated<\/code>\u00a0descriptions (<code>\"The specific question...\"<\/code>) provide further context to the LLM, helping it formulate the correct input (<code>query<\/code>) for the function based on the overall user request.<\/p>\n<h3 id=\"3-encapsulated-agent-communication-logic\" class=\"code-line\" dir=\"auto\" data-line=\"151\">3. Encapsulated Agent Communication Logic<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"153\">The plugin abstracts the details of interacting with the specific agent (creating messages, identifying recipients, handling runtime communication). The orchestrator only needs to know about the high-level\u00a0<code>invoke_web_search_agent<\/code>\u00a0function.<\/p>\n<h3 id=\"4-standardized-result-processing\" class=\"code-line\" dir=\"auto\" data-line=\"155\">4. Standardized Result Processing<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"157\">The\u00a0<code>proccess_and_create_response<\/code>\u00a0method (part of the base class or implemented here) normalizes the agent&#8217;s raw output into a format the orchestrator expects. It also updates shared state like token counts and extracted citations, essential for the final aggregation step.<\/p>\n<h2 id=\"hierarchical-plugin-structure\" class=\"code-line\" dir=\"auto\" data-line=\"159\">Hierarchical Plugin Structure<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"161\">Semantic Kernel supports organizing plugins hierarchically, which can mirror complex agent interactions:<\/p>\n<p dir=\"auto\" data-line=\"161\"><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect-hierarchy.jpg\"><img decoding=\"async\" class=\"alignnone wp-image-4760 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect-hierarchy.jpg\" alt=\"sk multi architect hierarchy image\" width=\"500\" height=\"192\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect-hierarchy.jpg 500w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/05\/sk-multi-architect-hierarchy-300x115.jpg 300w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"165\">An\u00a0<code>AgentInvokingPlugin<\/code>\u00a0might internally use other, more granular plugins (e.g., a\u00a0<code>BingSearchPlugin<\/code>\u00a0or an\u00a0<code>HttpRequestPlugin<\/code>). This allows for composition and reuse of lower-level functionalities within the agent abstraction.<\/p>\n<h2 id=\"the-power-of-plugin-based-orchestration\" class=\"code-line\" dir=\"auto\" data-line=\"167\">The Power of Plugin-Based Orchestration<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"169\">This SK plugin approach yields significant advantages:<\/p>\n<h3 id=\"1-dynamic--context-aware-agent-selection\" class=\"code-line\" dir=\"auto\" data-line=\"171\">1. Dynamic &amp; Context-Aware Agent Selection<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"173\">The kernel&#8217;s LLM acts as the intelligent router, using function descriptions and conversation history to select the most relevant agent(s) for each turn or sub-task. The\u00a0<code>system_prompt<\/code>\u00a0guides this selection process:<\/p>\n<pre><code class=\"code-line language-python\" dir=\"auto\" data-line=\"175\"><span class=\"hljs-comment\"># Example system prompt snippet for the orchestrator LLM<\/span>\r\nsystem_prompt = <span class=\"hljs-string\">\"\"\"You are an AI assistant orchestrating specialized agents. Analyze the user query.\r\nBased on the query and the descriptions of available tools (plugins), select the most appropriate tool(s).\r\nAvailable tools:\r\n- ORG_POLICY_AGENT: Use for questions about internal company policies and procedures.\r\n- WEB_SEARCH_AGENT: Use for current events, public facts, and general web knowledge.\r\n- PRIVATE_DATA_AGENT: Use for queries requiring access to internal databases (e.g., sales figures, user data).\r\n- GENERIC_LLM_AGENT: Use as a fallback for general conversation or if no other tool is suitable.\r\nInvoke the chosen tool(s). If multiple tools are needed, plan their execution. Synthesize their outputs into a final, comprehensive response.\r\n\"\"\"<\/span>\r\n<\/code><\/pre>\n<h3 id=\"2-flexible-execution-flows-parallelsequential\" class=\"code-line\" dir=\"auto\" data-line=\"188\">2. Flexible Execution Flows (Parallel\/Sequential)<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"190\">SK supports different function calling modes. You can configure the kernel to:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"191\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"191\">Invoke multiple plugins in parallel if their tasks are independent.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"192\">Chain plugin calls sequentially if one agent&#8217;s output is needed as input for another.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"193\">Allow the LLM to automatically decide the best execution strategy.<\/li>\n<\/ul>\n<h3 id=\"3-unified-resource-monitoring\" class=\"code-line\" dir=\"auto\" data-line=\"195\">3. Unified Resource Monitoring<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"197\">By having plugins report their token usage and execution time back to the orchestrator, you gain centralized visibility into costs and performance bottlenecks across the entire multi-agent system.<\/p>\n<h2 id=\"implementation-patterns\" class=\"code-line\" dir=\"auto\" data-line=\"199\">Implementation Patterns<\/h2>\n<h3 id=\"1-base-class-for-agent-invocation-plugins\" class=\"code-line\" dir=\"auto\" data-line=\"201\">1. Base Class for Agent Invocation Plugins<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"203\">Create a base class to handle common logic like kernel\/message storage, runtime access, state tracking (invocation status, token usage, results), and result processing.<\/p>\n<pre><code class=\"code-line language-python\" dir=\"auto\" data-line=\"205\"><span class=\"hljs-keyword\">from<\/span> semantic_kernel.kernel_pugin <span class=\"hljs-keyword\">import<\/span> KernelPlugin\r\n<span class=\"hljs-comment\"># ... other imports ...<\/span>\r\n\r\n<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title class_\">AgentInvokingPlugin<\/span>(<span class=\"hljs-title class_ inherited__\">KernelPlugin<\/span>):\r\n    <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">__init__<\/span>(<span class=\"hljs-params\">self, kernel, message, runtime<\/span>):\r\n        self.kernel = kernel\r\n        self.message = message\r\n        self.runtime = runtime <span class=\"hljs-comment\"># Agent communication runtime<\/span>\r\n        self.token_usage = TokenUsage(prompt_token=<span class=\"hljs-number\">0<\/span>, completion_token=<span class=\"hljs-number\">0<\/span>)\r\n        self.search_result = SearchResult(docs=[], citations=[])\r\n        self.was_invoked = <span class=\"hljs-literal\">False<\/span>\r\n        <span class=\"hljs-comment\"># Potentially add abstract methods for processing results, etc.<\/span>\r\n\r\n    <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">create_message_body<\/span>(<span class=\"hljs-params\">self, query: <span class=\"hljs-built_in\">str<\/span><\/span>) -&gt; <span class=\"hljs-built_in\">dict<\/span>:\r\n        <span class=\"hljs-comment\"># Standardize message creation<\/span>\r\n        <span class=\"hljs-keyword\">pass<\/span>\r\n\r\n    <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">proccess_and_create_response<\/span>(<span class=\"hljs-params\">self, agent_result: <span class=\"hljs-built_in\">dict<\/span><\/span>) -&gt; <span class=\"hljs-built_in\">str<\/span>:\r\n        <span class=\"hljs-comment\"># Standardize response processing, update state (tokens, results)<\/span>\r\n        <span class=\"hljs-comment\"># Returns a string summary suitable for the orchestrator LLM<\/span>\r\n        <span class=\"hljs-keyword\">pass<\/span>\r\n\r\n    <span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title function_\">get_summary<\/span>(<span class=\"hljs-params\">self<\/span>) -&gt; <span class=\"hljs-built_in\">str<\/span>:\r\n        <span class=\"hljs-comment\"># Return a summary of results if invoked<\/span>\r\n        <span class=\"hljs-keyword\">pass<\/span>\r\n\r\n    <span class=\"hljs-comment\"># ... other common methods ...<\/span>\r\n<\/code><\/pre>\n<h3 id=\"2-descriptive-plugin-and-function-naming\" class=\"code-line\" dir=\"auto\" data-line=\"235\">2. Descriptive Plugin and Function Naming<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"237\">Use clear, descriptive names for plugin registration (<code>plugin_name=\"WEB_SEARCH_AGENT\"<\/code>) and kernel functions (<code>@kernel_function(name=\"invoke_web_search_agent\", ...)<\/code>). This aids both the LLM&#8217;s understanding and human debugging.<\/p>\n<h3 id=\"3-explicit-function-choice-configuration\" class=\"code-line\" dir=\"auto\" data-line=\"239\">3. Explicit Function Choice Configuration<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"241\">Leverage\u00a0<code>FunctionChoiceBehavior<\/code>\u00a0(or similar mechanisms in the specific SK SDK version) to control how the LLM selects and executes functions (e.g.,\u00a0<code>Auto<\/code>\u00a0for dynamic selection,\u00a0<code>Required<\/code>\u00a0to force a specific function call).<\/p>\n<h2 id=\"best-practices-for-agent-orchestration-with-sk-plugins\" class=\"code-line\" dir=\"auto\" data-line=\"243\">Best Practices for Agent Orchestration with SK Plugins<\/h2>\n<ol class=\"code-line\" dir=\"auto\" data-line=\"245\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"245\"><strong>Rich Function Descriptions<\/strong>: Write detailed, unambiguous descriptions for\u00a0<code>@kernel_function<\/code>. This is paramount for accurate dynamic routing.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"246\"><strong>Clear System Prompts<\/strong>: Guide the orchestrator LLM on the overall goal, available tools, and how to choose between them.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"247\"><strong>Standardized Inputs\/Outputs<\/strong>: Design plugin functions to accept simple inputs (like strings) where possible and return standardized, predictable outputs (or update state predictably).<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"248\"><strong>Robust Error Handling<\/strong>: Implement try\/except blocks within plugin functions and report errors clearly back to the orchestrator.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"249\"><strong>Comprehensive Telemetry<\/strong>: Log key events (plugin invocation, agent requests\/responses, errors, timings) for monitoring and debugging. Use correlation IDs.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"250\"><strong>State Management<\/strong>: Carefully manage shared state (like conversation history) passed to plugins and how plugins update aggregated results (tokens, citations).<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"251\"><strong>Observability First<\/strong>: Design plugins with logging and metrics in mind from the outset. Track token usage per plugin\/agent.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"252\"><strong>Agent Contract Testing<\/strong>: Implement tests for each plugin, mocking the underlying agent, to ensure it adheres to its expected interface and behavior.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"253\"><strong>Idempotency Considerations<\/strong>: If agents might be retried, consider designing their actions to be idempotent where possible.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"254\"><strong>Circuit Breakers<\/strong>: Implement resilience patterns like circuit breakers for calls to external agents that might be unreliable or slow.<\/li>\n<\/ol>\n<h2 id=\"conclusion\" class=\"code-line\" dir=\"auto\" data-line=\"256\">Conclusion<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"258\">Semantic Kernel plugins offer a powerful and structured approach to the complex challenge of AI agent orchestration. By encapsulating agent capabilities within a standardized plugin framework, developers can build sophisticated multi-agent systems that benefit from:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"260\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"260\"><strong>Modularity<\/strong>: Easier development, testing, and maintenance.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"261\"><strong>Dynamic Routing<\/strong>: Intelligent, context-aware selection of specialized agents.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"262\"><strong>Scalability<\/strong>: A clear pattern for adding new agent capabilities.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"263\"><strong>Observability<\/strong>: Centralized monitoring of performance and resource consumption.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"265\">As AI applications increasingly rely on collaborative ensembles of specialized agents, mastering plugin-based orchestration frameworks like Semantic Kernel will be essential for building the next generation of intelligent, capable, and maintainable systems.<\/p>\n<h2 id=\"references\" class=\"code-line\" dir=\"auto\" data-line=\"267\">References:<\/h2>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"269\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"269\"><a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/kernel\" data-href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/kernel\">Semantic Kernel<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"270\"><a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/plugins\" data-href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/plugins\">Semantic Kernel Plugin<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"271\"><a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/ai-services\/chat-completion\/function-calling\" data-href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/ai-services\/chat-completion\/function-calling\">Function calling<\/a><\/li>\n<\/ul>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"273\" \/>\n<p class=\"code-line code-active-line\" dir=\"auto\" data-line=\"275\"><em>This blog post targets software engineers familiar with LLM concepts and agent-based architectures. Code examples are illustrative and simplified; production systems require more extensive error handling, configuration, and state management.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re excited to welcome Jarre Nejatyab as a guest blog to highlight a technical deep dive on orchestrating AI Agents with Semantic Kernel Plugins. In the rapidly evolving world of Large Language Models (LLMs), orchestrating specialized AI agents has become crucial for building sophisticated cognitive architectures capable of complex reasoning and task execution. While [&hellip;]<\/p>\n","protected":false},"author":149071,"featured_media":4764,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[117,1],"tags":[48,63,9],"class_list":["post-4751","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-guest-blog","category-semantic-kernel","tag-ai","tag-microsoft-semantic-kernel","tag-semantic-kernel"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re excited to welcome Jarre Nejatyab as a guest blog to highlight a technical deep dive on orchestrating AI Agents with Semantic Kernel Plugins. In the rapidly evolving world of Large Language Models (LLMs), orchestrating specialized AI agents has become crucial for building sophisticated cognitive architectures capable of complex reasoning and task execution. While [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/149071"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=4751"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4751\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/4764"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=4751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=4751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=4751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}