{"id":4175,"date":"2025-02-10T15:08:14","date_gmt":"2025-02-10T23:08:14","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=4175"},"modified":"2025-02-10T15:08:14","modified_gmt":"2025-02-10T23:08:14","slug":"guest-blog-step-by-step-guide-to-building-a-portfolio-manager-a-multi-agent-system-with-microsoft-semantic-kernel-and-azure-openai","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/guest-blog-step-by-step-guide-to-building-a-portfolio-manager-a-multi-agent-system-with-microsoft-semantic-kernel-and-azure-openai\/","title":{"rendered":"Guest Blog: Step-by-Step Guide to Building a Portfolio Manager: A Multi-Agent System with Microsoft Semantic Kernel and Azure OpenAI"},"content":{"rendered":"<p>Today the Semantic Kernel team is excited to welcome back a guest author, <a href=\"https:\/\/medium.com\/@akshaykokane09\">Akshay Kokane<\/a> to share his recent Medium article using Semantic Kernel and Azure OpenAI, showcasing a step-by-step guide to building a Portfolio Manager. We\u2019ll turn it over to him to dive into his work below.<\/p>\n<p><img decoding=\"async\" class=\"alignnone\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:700\/1*HFkM-GmK0aLPWB24yLa8hg.png\" alt=\"\" width=\"700\" height=\"525\" \/><\/p>\n<p id=\"3a8e\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">In my previous blog, we went over how Semantic Kernel can be used to create a multi-agent system.\u00a0<a class=\"af ou\" href=\"https:\/\/medium.com\/@akshaykokane09\/step-by-step-guide-to-develop-ai-multi-agent-system-using-microsoft-semantic-kernel-and-gpt-4o-f5991af40ea6\" rel=\"noopener\">Link<\/a>.<\/p>\n<p id=\"be12\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">However, agent collaboration was really challenging, as we were not able to control how agents collaborated. We could set the termination strategy to decide when to stop collaboration between agents, but not how agents would participate.<\/p>\n<p id=\"19f9\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">The new version of Semantic Kernel introduced selectionFunction, which solves this problem. How? Let\u2019s dive deeper into it with an example and a step-by-step guide.<\/p>\n<h1 id=\"8019\" class=\"ov ow hn bf ox oy oz in pa pb pc iq pd pe pf pg ph pi pj pk pl pm pn po pp pq bk\" data-selectable-paragraph=\"\">Selection Function in a Multi-Agent System\nSelection<\/h1>\n<p id=\"7174\" class=\"pw-post-body-paragraph ny nz hn oa b il pr oc od io ps of og oh pt oj ok ol pu on oo op pv or os ot gn bk\" data-selectable-paragraph=\"\">The selection function in Semantic Kernel helps define the ground rules for agents to collaborate. In a multi-agent system, agents often enter incorrect loops, leading to inconsistent output. The selection function in Semantic Kernel solves this problem.<\/p>\n<p id=\"eb82\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">We will understand how the selection function works with the example of a \u2018Portfolio Management Multi-Agent System.\u2019 Let\u2019s start by define 3 agents:<\/p>\n<ol class=\"\">\n<li id=\"7010\" class=\"ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot pw px py bk\" data-selectable-paragraph=\"\"><strong class=\"oa ho\">Portfolio Optimizer Agent<\/strong>: This agent will have access to my personal financial position and goals and can help optimize my portfolio.<\/li>\n<li id=\"bae3\" class=\"ny nz hn oa b il pz oc od io qa of og oh qb oj ok ol qc on oo op qd or os ot pw px py bk\" data-selectable-paragraph=\"\"><strong class=\"oa ho\">Web Surfer Agent<\/strong>: This agent can browse the web for the latest news and information.<\/li>\n<li id=\"4a59\" class=\"ny nz hn oa b il pz oc od io qa of og oh qb oj ok ol qc on oo op qd or os ot pw px py bk\" data-selectable-paragraph=\"\"><strong class=\"oa ho\">Stock Analyzer Agent<\/strong>: This agent analyzes historical stock data, current news, and trends to evaluate stocks.<\/li>\n<\/ol>\n<p id=\"d41e\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">I created an app that will show me hosted agents, and I should be able to run agents on demand as well as on a schedule.<\/p>\n<p data-selectable-paragraph=\"\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1000\/1*nhJL4feY_Ah1E18ctmxa-g.png\" \/><\/p>\n<h1 id=\"f0ff\" class=\"ov ow hn bf ox oy oz in pa pb pc iq pd pe pf pg ph pi pj pk pl pm pn po pp pq bk\" data-selectable-paragraph=\"\">Step-by-Step Guide to Building a Portfolio Manager<\/h1>\n<p id=\"2d30\" class=\"pw-post-body-paragraph ny nz hn oa b il pr oc od io ps of og oh pt oj ok ol pu on oo op pv or os ot gn bk\" data-selectable-paragraph=\"\">On how to create Semantic Kernel, please refer to the official <a class=\"af ou\" href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/get-started\/quick-start-guide?pivots=programming-language-python\" target=\"_blank\" rel=\"noopener ugc nofollow\">docs<\/a>.<\/p>\n<p id=\"374e\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\"><strong class=\"oa ho\">Step 1: Define Agents<\/strong><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">   \/\/\/ Step 1: Define Agents\r\n            \/\/\/ Creating individual agents for portfolio management, web surfing, and stock analysis.\r\n            PortfolioManagerAgent = new()\r\n            {\r\n                Name = nameof(PortfolioManagerAgents),\r\n                Instructions = @\"Your are experieced Portfolio Manager.\r\n                                You have access to user's porfolio.\r\n                                You make recommendations based on latest news and stock analysis report.\r\n                                You provide the portfolio to other participant if needed.\r\n                                If you don't have latest news or stock analysis report, you ask for it to other participants. Never give general guidelines\",\r\n                Kernel = Kernel,\r\n                Arguments = new KernelArguments(openAIPromptExecutionSettings)\r\n            };\r\n\r\n            WebAgent = new()\r\n            {\r\n                Name = nameof(WebSurferAgent),\r\n                Instructions = \"Your task is to retrieve and summarize the latest stock market news from reliable sources. \" +\r\n                   \"You will monitor stock trends, economic events, and financial updates, providing real-time insights. \" +\r\n                   \"to enhance investment recommendations. Ensure the news is current, relevant, and sourced from credible financial sources. Never provide general insights. You only provide news\",\r\n                Kernel = Kernel,\r\n                Arguments = new KernelArguments(openAIPromptExecutionSettings)\r\n            };\r\n\r\n            \/\/\/ Defining the Stock Analyzer Agent using OpenAI\r\n            Agent = OpenAIAssistantAgent.CreateAsync(\r\n                OpenAIClientProvider.ForAzureOpenAI(apiKeyCredential, new Uri(\"https:\/\/testmediumazureopenai.openai.azure.com\")),\r\n                new OpenAIAssistantDefinition(\"GPT4ov1\")\r\n                {\r\n                    Name = nameof(StockAnalyzerAgent),\r\n                    Instructions = \"You are responsible for analyzing stock market data and sentiment analysis on news updates. \" +\r\n                   \"Leverage historical stock data, technical indicators, and fundamental analysis to assess market trends. \" +\r\n                   \"Perform sentiment analysis on news provided by the WebSurferAgent to gauge market sentiment.. Create charts in HTML\",\r\n                },\r\n                Kernel);<\/code><\/pre>\n<p data-selectable-paragraph=\"\"><strong class=\"oa ho\">Step 2: Define Selection Strategy<\/strong><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\"> \/\/\/ Step 2: Define Selection Strategy\r\n\/\/\/ This function determines which agent should take the next turn in the collaboration.\r\nprivate KernelFunction GetSelectionFunction()\r\n{\r\n    return AgentGroupChat.CreatePromptFunctionForStrategy(\r\n        $$$\"\"\"\r\n        Determine which participant takes the next turn in a conversation based on the most recent participant.\r\n        State only the name of the participant to take the next turn.\r\n        No participant should take more than one turn in a row.\r\n\r\n        Choose only from these participants:\r\n        - {{{nameof(PortfolioManagerAgents)}}}\r\n        - {{{nameof(WebSurferAgent)}}}\r\n        - {{{nameof(StockAnalyzerAgent)}}}\r\n\r\n        Always follow these rules when selecting the next participant:\r\n        - After {{{nameof(PortfolioManagerAgents)}}}, it is {{{nameof(WebSurferAgent)}}}'s turn.\r\n        - After {{{nameof(WebSurferAgent)}}}, it is {{{nameof(StockAnalyzerAgent)}}}'s turn.\r\n        - After {{{nameof(StockAnalyzerAgent)}}}, it is {{{nameof(PortfolioManagerAgents)}}}'s turn.\r\n        \r\n        History:\r\n        {{$history}}\r\n        \"\"\",\r\n        safeParameterNames: \"history\");\r\n}<\/code><\/pre>\n<p data-selectable-paragraph=\"\"><strong class=\"oa ho\">Step 3: Define Termination Strategy<\/strong><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">\/\/\/ Step 3: Define Termination Strategy\r\n\/\/\/ This function ensures that the process stops once the Portfolio Manager makes a recommendation.\r\nprivate KernelFunction GetTerminationStrategy()\r\n{\r\n    KernelFunction terminationFunction =\r\n        AgentGroupChat.CreatePromptFunctionForStrategy(\r\n            $$$\"\"\"\r\n            Determine if the PortfolioManager is done with recommendations.\r\n            If so, respond with a single word: done\r\n\r\n            History:\r\n            {{$history}}\r\n            \"\"\",\r\n            safeParameterNames: \"history\");\r\n\r\n    return terminationFunction;\r\n}<\/code><\/pre>\n<p data-selectable-paragraph=\"\"><strong class=\"oa ho\">Step 4: Create Useful Tools<\/strong><\/p>\n<p id=\"8111\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">I am adding 2 tools<\/p>\n<ol class=\"\">\n<li id=\"e4e4\" class=\"ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot pw px py bk\" data-selectable-paragraph=\"\"><a class=\"af ou\" href=\"https:\/\/newsapi.org\/docs\/get-started\" target=\"_blank\" rel=\"noopener ugc nofollow\">NewsAPI<\/a>\u00a0for getting latest news (registered with WebSurfer agent)<\/li>\n<li id=\"d04d\" class=\"ny nz hn oa b il pz oc od io qa of og oh qb oj ok ol qc on oo op qd or os ot pw px py bk\" data-selectable-paragraph=\"\">GetPortfolio for getting my upto date portfolio (registered with PortfolioManagement Agent)<\/li>\n<\/ol>\n<p id=\"f355\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">I will not go into how to write tools for Semantic Kernel, as I have covered that in my previous blogs. Instead, I am sharing a small snippet on how to enable function calling for agents. For official docs, check\u00a0<a class=\"af ou\" href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/concepts\/plugins\/\" target=\"_blank\" rel=\"noopener ugc nofollow\">here<\/a><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">\/\/ Define function\/tools\r\n[KernelFunction, Description(\"Get my latest portfolio information.\")]\r\npublic string GetMyPortfolio(string user)\r\n{\r\n  \/\/ implmentation here\r\n}\r\n\r\nKernel.Plugins.AddFromObject(portfolioTools);\r\n\r\nOpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()\r\n{\r\n   FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()\r\n};\r\n\r\nPortfolioManagerAgent = new()\r\n            {\r\n                ....\r\n                Arguments = new KernelArguments(openAIPromptExecutionSettings)\r\n                .....\r\n            };<\/code><\/pre>\n<p data-selectable-paragraph=\"\"><strong class=\"oa ho\">Step 5: Creating Multi-Agent Chat<\/strong><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">\/\/\/ Step 5: Putting It All Together\r\n\/\/\/ This function initializes the agent system and manages the execution workflow.\r\npublic async Task StartAsync(CancellationToken cancellationToken)\r\n{\r\n    StringBuilder interactions = new StringBuilder();\r\n\r\n    try\r\n    {\r\n        var PAgent = new PortfolioManagerAgents().GetAgent();\r\n        var WebAgent = new WebSurferAgent().GetAgent();\r\n        var stockAgent = new StockAnalyzerAgent().GetAgent();\r\n        \r\n        \/\/ Define selection strategy\r\n        KernelFunctionSelectionStrategy selectionStrategy =\r\n            new(GetSelectionFunction(), Kernel)\r\n            {\r\n                InitialAgent = PAgent,\r\n                HistoryVariableName = \"history\",\r\n                HistoryReducer = new ChatHistoryTruncationReducer(10),\r\n            };\r\n\r\n        \/\/ Define termination strategy\r\n        KernelFunctionTerminationStrategy terminationStrategy =\r\n          new(GetTerminationStrategy(), Kernel)\r\n          {\r\n              Agents = [PAgent],\r\n              ResultParser = (result) =&gt;\r\n                result.GetValue&lt;string&gt;()?.Contains(\"done\", StringComparison.OrdinalIgnoreCase) ?? false,\r\n              HistoryVariableName = \"history\",\r\n              HistoryReducer = new ChatHistoryTruncationReducer(1),\r\n              MaximumIterations = 10,\r\n          };\r\n\r\n        \/\/ Initialize the multi-agent system\r\n        AgentGroupChat chat = new(PAgent, WebAgent, stockAgent)\r\n        {\r\n            ExecutionSettings = new()\r\n            {\r\n                TerminationStrategy = terminationStrategy,\r\n                SelectionStrategy = selectionStrategy,\r\n            }\r\n        };\r\n\r\n        chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, \"start. Note today is Jan 15th 2025\"));\r\n\r\n        \/\/ Execute the multi-agent collaboration\r\n        await foreach (var content in chat.InvokeAsync(cancellationToken))\r\n        {\r\n            string interaction = $\"&lt;b&gt;#{content.Role}&lt;\/b&gt; - &lt;i&gt;{content.AuthorName ?? \"*\"}&lt;\/i&gt;: \\\"{content.Content}\\\"\";\r\n            Console.WriteLine(interaction);\r\n            interactions.Append(interaction + \"\\n\");\r\n        }\r\n\r\n        Console.WriteLine(\"PortfolioManagementAgentSystem has completed execution.\");\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        Console.WriteLine($\"Error: {ex.Message}\");\r\n    }\r\n    \r\n    var prompt = @\"Write an email body outlining the necessary actions for my portfolio. \r\n                  Provide the output in HTML format and keep it concise. \r\n                  Include graphs and charts in HTML format. \r\n                  Start directly with the email content without any additional text before or after.\";\r\n    \r\n    var emailContent = await Kernel.InvokePromptAsync($\"{prompt} {interactions}\");\r\n    \r\n    EmailSender.SendEmail(\"Portfolio Agent Update\", emailContent.ToString());\r\n}<\/code><\/pre>\n<p id=\"07fb\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">This is my portfolio that PortfolioManagerAgent has access too<\/p>\n<figure class=\"qk ql qm qn qo ha gs gt paragraph-image\">\n<div class=\"hb hc fj hd bh he\" tabindex=\"0\" role=\"button\">\n<div class=\"gs gt ra\"><picture><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/format:webp\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 1400w\" type=\"image\/webp\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" \/><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/1*e8p6_t1gGU6VTfCdM6UgRQ.png 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" data-testid=\"og\" \/><img decoding=\"async\" class=\"bh hf hg c\" role=\"presentation\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:700\/1*e8p6_t1gGU6VTfCdM6UgRQ.png\" alt=\"\" width=\"700\" height=\"290\" \/><\/picture><\/div>\n<\/div><figcaption class=\"hh ff hi gs gt hj hk bf b bg z du\" data-selectable-paragraph=\"\">Sample portfolio. Values are fake and not a real price of stocks or bonds<\/figcaption><\/figure>\n<p id=\"571d\" class=\"pw-post-body-paragraph ny nz hn oa b il ob oc od io oe of og oh oi oj ok ol om on oo op oq or os ot gn bk\" data-selectable-paragraph=\"\">Here is the email I got once I run this multi-agent system. You can just output this in console log.<\/p>\n<figure class=\"qk ql qm qn qo ha gs gt paragraph-image\">\n<div class=\"hb hc fj hd bh he\" tabindex=\"0\" role=\"button\">\n<div class=\"gs gt rb\"><picture><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/format:webp\/1*NmNADqWcUY6u9RmaMloIlQ.png 1400w\" type=\"image\/webp\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" \/><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/1*NmNADqWcUY6u9RmaMloIlQ.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/1*NmNADqWcUY6u9RmaMloIlQ.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/1*NmNADqWcUY6u9RmaMloIlQ.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/1*NmNADqWcUY6u9RmaMloIlQ.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/1*NmNADqWcUY6u9RmaMloIlQ.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/1*NmNADqWcUY6u9RmaMloIlQ.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/1*NmNADqWcUY6u9RmaMloIlQ.png 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" data-testid=\"og\" \/><img decoding=\"async\" class=\"bh hf hg c\" role=\"presentation\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:700\/1*NmNADqWcUY6u9RmaMloIlQ.png\" alt=\"\" width=\"700\" height=\"367\" \/><\/picture><\/div>\n<\/div><figcaption class=\"hh ff hi gs gt hj hk bf b bg z du\" data-selectable-paragraph=\"\">From the Semantic Kernel team, we\u2019d like to thank Akshay for his time and all of his great work. \u00a0Please reach out if you have any questions or feedback through our <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/discussions\/categories\/general\" target=\"_blank\" rel=\"noopener\">Semantic Kernel GitHub Discussion Channel<\/a>. We look forward to hearing from you!\u00a0<\/figcaption><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Today the Semantic Kernel team is excited to welcome back a guest author, Akshay Kokane to share his recent Medium article using Semantic Kernel and Azure OpenAI, showcasing a step-by-step guide to building a Portfolio Manager. We\u2019ll turn it over to him to dive into his work below. In my previous blog, we went over [&hellip;]<\/p>\n","protected":false},"author":149071,"featured_media":2302,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[117],"tags":[48,63,9],"class_list":["post-4175","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-guest-blog","tag-ai","tag-microsoft-semantic-kernel","tag-semantic-kernel"],"acf":[],"blog_post_summary":"<p>Today the Semantic Kernel team is excited to welcome back a guest author, Akshay Kokane to share his recent Medium article using Semantic Kernel and Azure OpenAI, showcasing a step-by-step guide to building a Portfolio Manager. We\u2019ll turn it over to him to dive into his work below. In my previous blog, we went over [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4175","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=4175"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4175\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/2302"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=4175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=4175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=4175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}