
精通多智能体系统:使用 Microsoft Semantic Kernel 构建投资组合管理器的逐步指南
- Rifx.Online
- Machine Learning , AI Applications , Programming
- 05 Mar, 2025
利用 SelectionFunction 实现高效协作
在我之前的博客中,我们介绍了如何使用 Semantic Kernel 创建一个多智能体系统。链接。
然而,智能体之间的协作确实具有挑战性,因为我们无法控制智能体如何协作。我们可以设置终止策略来决定何时停止智能体之间的协作,但不能决定智能体将如何参与。
新版本的 Semantic Kernel 引入了 selectionFunction,解决了这个问题。如何解决?让我们通过一个例子和一步一步的指南来深入了解。
多智能体系统中的 Selection Function 选择
Semantic Kernel 中的选择函数有助于定义智能体协作的基本规则。在多智能体系统中,智能体经常进入错误的循环,导致输出不一致。Semantic Kernel 中的选择函数解决了这个问题。
我们将通过一个“投资组合管理多智能体系统”的例子来理解选择函数的工作原理。 让我们首先定义 3 个智能体:
- 投资组合优化器智能体:该智能体将有权访问我的个人财务状况和目标,并可以帮助优化我的投资组合。
- 网络冲浪者智能体:该智能体可以浏览网络以获取最新新闻和信息。
- 股票分析器智能体:该智能体分析历史股票数据、当前新闻和趋势以评估股票。
我创建了一个应用程序,它将向我展示托管的智能体,并且我应该能够按需以及按计划运行智能体。
Semantic Kernel 智能体平台截图
构建投资组合管理器的分步指南
关于如何创建 Semantic Kernel,请参考我之前的 博客 或 python 代码示例,请参考官方 文档。
步骤 1:定义 Agent
/// Step 1: Define Agents
/// Creating individual agents for portfolio management, web surfing, and stock analysis.
PortfolioManagerAgent = new()
{
Name = nameof(PortfolioManagerAgents),
Instructions = @"Your are experieced Portfolio Manager.
You have access to user's porfolio.
You make recommendations based on latest news and stock analysis report.
You provide the portfolio to other participant if needed.
If you don't have latest news or stock analysis report, you ask for it to other participants. Never give general guidelines",
Kernel = Kernel,
Arguments = new KernelArguments(openAIPromptExecutionSettings)
};
WebAgent = new()
{
Name = nameof(WebSurferAgent),
Instructions = "Your task is to retrieve and summarize the latest stock market news from reliable sources. " +
"You will monitor stock trends, economic events, and financial updates, providing real-time insights. " +
"to enhance investment recommendations. Ensure the news is current, relevant, and sourced from credible financial sources. Never provide general insights. You only provide news",
Kernel = Kernel,
Arguments = new KernelArguments(openAIPromptExecutionSettings)
};
/// Defining the Stock Analyzer Agent using OpenAI
Agent = OpenAIAssistantAgent.CreateAsync(
OpenAIClientProvider.ForAzureOpenAI(apiKeyCredential, new Uri("https://testmediumazureopenai.openai.azure.com")),
new OpenAIAssistantDefinition("GPT4ov1")
{
Name = nameof(StockAnalyzerAgent),
Instructions = "You are responsible for analyzing stock market data and sentiment analysis on news updates. " +
"Leverage historical stock data, technical indicators, and fundamental analysis to assess market trends. " +
"Perform sentiment analysis on news provided by the WebSurferAgent to gauge market sentiment.. Create charts in HTML",
},
Kernel);
步骤 2:定义选择策略
/// Step 2: Define Selection Strategy
/// This function determines which agent should take the next turn in the collaboration.
private KernelFunction GetSelectionFunction()
{
return AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Determine which participant takes the next turn in a conversation based on the most recent participant.
State only the name of the participant to take the next turn.
No participant should take more than one turn in a row.
Choose only from these participants:
- {{{nameof(PortfolioManagerAgents)}}}
- {{{nameof(WebSurferAgent)}}}
- {{{nameof(StockAnalyzerAgent)}}}
Always follow these rules when selecting the next participant:
- After {{{nameof(PortfolioManagerAgents)}}}, it is {{{nameof(WebSurferAgent)}}}'s turn.
- After {{{nameof(WebSurferAgent)}}}, it is {{{nameof(StockAnalyzerAgent)}}}'s turn.
- After {{{nameof(StockAnalyzerAgent)}}}, it is {{{nameof(PortfolioManagerAgents)}}}'s turn.
History:
{{$history}}
""",
safeParameterNames: "history");
}
步骤 3:定义终止策略
/// Step 3: Define Termination Strategy
/// This function ensures that the process stops once the Portfolio Manager makes a recommendation.
private KernelFunction GetTerminationStrategy()
{
KernelFunction terminationFunction =
AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Determine if the PortfolioManager is done with recommendations.
If so, respond with a single word: done
History:
{{$history}}
""",
safeParameterNames: "history");
return terminationFunction;
}
步骤 4:创建有用的工具。
我正在添加 2 个工具
- NewsAPI 用于获取最新新闻(已注册 WebSurfer agent)
- GetPortfolio 用于获取我的最新投资组合(已注册 PortfolioManagement Agent)
我不会深入研究如何为 Semantic Kernel 编写工具,因为我之前的博客中已经涵盖了这一点。相反,我将分享一个关于如何为代理启用函数调用的简短代码片段。有关官方文档,请查看 此处
// Define function/tools
[KernelFunction, Description("Get my latest portfolio information.")]
public string GetMyPortfolio(string user)
{
// implmentation here
}
Kernel.Plugins.AddFromObject(portfolioTools);
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
PortfolioManagerAgent = new()
{
....
Arguments = new KernelArguments(openAIPromptExecutionSettings)
.....
};
步骤 5:创建多代理聊天
/// Step 5: Putting It All Together
/// This function initializes the agent system and manages the execution workflow.
public async Task StartAsync(CancellationToken cancellationToken)
{
StringBuilder interactions = new StringBuilder();
try
{
var PAgent = new PortfolioManagerAgents().GetAgent();
var WebAgent = new WebSurferAgent().GetAgent();
var stockAgent = new StockAnalyzerAgent().GetAgent();
// Define selection strategy
KernelFunctionSelectionStrategy selectionStrategy =
new(GetSelectionFunction(), Kernel)
{
InitialAgent = PAgent,
HistoryVariableName = "history",
HistoryReducer = new ChatHistoryTruncationReducer(10),
};
// Define termination strategy
KernelFunctionTerminationStrategy terminationStrategy =
new(GetTerminationStrategy(), Kernel)
{
Agents = [PAgent],
ResultParser = (result) =>
result.GetValue<string>()?.Contains("done", StringComparison.OrdinalIgnoreCase) ?? false,
HistoryVariableName = "history",
HistoryReducer = new ChatHistoryTruncationReducer(1),
MaximumIterations = 10,
};
// Initialize the multi-agent system
Agen
投资组合管理的多智能体系统
public async Task RunPortfolioManagementAgentSystem(CancellationToken cancellationToken = default)
{
try
{
var kernel = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(
"gpt-35-turbo",
Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!,
Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY")!)
.AddSemanticFunction(
"PortfolioManagerAgent",
"PortfolioManagerAgent",
"PortfolioManagerAgent")
.AddSemanticFunction(
"WebAgent",
"WebAgent",
"WebAgent")
.AddSemanticFunction(
"StockAgent",
"StockAgent",
"StockAgent")
.Build();
// Define the agents
var PAgent = new Agent(kernel, "PortfolioManagerAgent");
var WebAgent = new Agent(kernel, "WebAgent");
var stockAgent = new Agent(kernel, "StockAgent");
// Define the termination strategy
var terminationStrategy = new MaxTurnsStrategy(3);
// Define the selection strategy
var selectionStrategy = new RoundRobinStrategy();
// Create the chat
tGroupChat chat = new(PAgent, WebAgent, stockAgent)
{
ExecutionSettings = new()
{
TerminationStrategy = terminationStrategy,
SelectionStrategy = selectionStrategy,
}
};
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, "start. Note today is Jan 15th 2025"));
// Execute the multi-agent collaboration
await foreach (var content in chat.InvokeAsync(cancellationToken))
{
string interaction = $"<b>#{content.Role}</b> - <i>{content.AuthorName ?? "*"}</i>: \"{content.Content}\"";
Console.WriteLine(interaction);
interactions.Append(interaction + "\n");
}
Console.WriteLine("PortfolioManagementAgentSystem has completed execution.");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
var prompt = @"Write an email body outlining the necessary actions for my portfolio.
Provide the output in HTML format and keep it concise.
Include graphs and charts in HTML format.
Start directly with the email content without any additional text before or after.";
var emailContent = await Kernel.InvokePromptAsync($"{prompt} {interactions}");
EmailSender.SendEmail("Portfolio Agent Update", emailContent.ToString());
}
这是我的投资组合,PortfolioManagerAgent 可以访问
示例投资组合。数值是虚构的,不是股票或债券的真实价格
这是我运行这个多智能体系统后收到的电子邮件。你可以在控制台日志中输出它。
我收到的示例电子邮件