摘要:using CodeAgent.Function;using Microsoft.SemanticKernel;using Microsoft.SemanticKernel.Agents;using Microsoft.SemanticKernel.Agent
在AI很火爆的时候,到现在为止还有很多人很迷茫,如何入门AI?了解AI?下面我将带你进入AI Agent高级AI编程的领域。
下面我们将基于Microsoft.SemanticKernel去实现Agent的功能,创建一个CodeAgent,用户提出需求,然后由Agent进行实现。,然后安装以下依赖Include="Microsoft.Semantickernel"Version="1.33.0" />
Include="Microsoft.SemanticKernel.Agents.Core"Version="1.33.0-alpha" />
Include="Microsoft.SemanticKernel.Agents.OpenAI"Version="1.33.0-alpha" />
打开Program.cs
AI Agent是一种能够感知环境并作出相应决策和行动的智能系统。在本文中,我们将创建三个协同工作的AI Agent:
CodeReviewAgent: 负责代码审查和需求确认
ProgrammerAgent: 负责代码实现和文件操作
CodeErrorCheckAgent: 负责代码错误检查和反馈
using CodeAgent.Function;using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Chat;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
#pragma warning disable OPENAI001
#pragma warning disable SKEXP0001
#pragma warning disable SKEXP0110
#pragma warning disable SKEXP0010
internalclassProgram
{
public static async Task Main(string args)
{
var model = "gpt-4o";
var kernelBuilder = Kernel.CreateBuilder;
KernelBuilder.Plugins.AddFromType;
kernelBuilder.Plugins.AddFromType;
kernelBuilder.AddOpenAIChatCompletion(model, new Uri("https://api.token-ai.cn/v1"),
await File.ReadAllTextAsync("token"));
var kernel = kernelBuilder.Build;
var codeReviewAgent = CreateCodeReviewAgent(kernel);
var programmerAgent = CreateProgrammerAgent(kernel);
var codeErrorCheckAgent = CreateCodeErrorCheckAgent(kernel);
var chat = new AgentGroupChat(codeReviewAgent, programmerAgent, codeErrorCheckAgent)
{
ExecutionSettings = new AgentGroupChatSettings
{
TerminationStrategy = new CodeTerminationStrategy
{
Agents = [CodeReviewAgent],
MaximumIterations =10
}
}
};
var chatHistory = new ChatMessageContent(AuthorRole.User, "使用Avalonia实现一个简单的计算器,工作目录:D:\\agent");
chat.AddChatMessage(chatHistory);
WriteAgentChatMessage(chatHistory);
awaitforeach (var item in chat.InvokeAsync)
{
WriteAgentChatMessage(item);
}
}
publicsealedclassCodeTerminationStrategy : TerminationStrategy
{
protected override Task ShouldAgentTerminateAsync(Agent agent, IReadOnlyList history,
CancellationToken cancellationToken)
{
// 如果最后一条消息包含[done]则终止
return history[^1].Content?.Contains("[done]") ==true? Task.FromResult(true) : Task.FromResult(false);
}
}
public static void WriteAgentChatMessage(ChatMessageContent messages)
{
var authorExpression = messages.Role == AuthorRole.User ? string.Empty : $"- {messages.AuthorName ?? "*"}";
var contentExpression = string.IsOrWhiteSpace(messages.Content) ? string.Empty : messages.Content;
var isCode = messages.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ??false;
var codeMarker = isCode ? "\n [CODE]\n" : string.Empty;
Console.ForegroundColor = messages.Role == AuthorRole.User ? ConsoleColor.Green : ConsoleColor.Blue;
Console.Write($"\n [{messages.Role}]:");
Console.ResetColor;
Console.WriteLine($"{authorExpression} {codeMarker} {contentExpression}");
foreach (var item in messages.Items)
{
switch (item)
{
case annotationContent annotation:
Console.WriteLine($" [{item.GetType.Name}] {annotation.Quote}: File #{annotation.FileId}");
break;
case FileReferenceContent fileReference:
Console.WriteLine($" [{item.GetType.Name}] File #{fileReference.FileId}");
break;
case ImageContent image:
Console.WriteLine(
$" [{item.GetType.Name}] {image.Uri?.Tostring ?? image.DataUri ?? $"{image.Data?.Length} bytes"}");
break;
case FunctionCallContent functionCall:
Console.WriteLine($" [{item.GetType.Name}] {functionCall.Id}");
break;
case FunctionResultContent functionResult:
Console.WriteLine(
$" [{item.GetType.Name}] {functionResult.CallId} - {functionResult.Result ?? "*"}");
break;
}
}
}
public static ChatCompletionAgent CreateCodeReviewAgent(Kernel kernel)
{
conststring reviewAgentName = "CodeReviewAgent";
conststring reviewInstruction =
"""
你是CodeReviewAgent,
- 你的职责是检查代码问题,只需要检查代码的质量,不需要编写代码。
- 如果给出的代码完全符合预期,那么只回复:[done]。
- 如果不符合用户的需求,你需要提出建议,并且给出解决方案的思路,提供思维链的一系列解决思路,但是不要直接给出答案。
- 你还需要将用户的问题提供一些思维链的计划,然后告知ProgrammerAgent,但是你不能直接[done]。
""";
var codeReviewAgent = new ChatCompletionAgent
{
Name = reviewAgentName,
Instructions = reviewInstruction,
Kernel = kernel,
Description = "代码审查机器人",
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings
{ FunctionChoiceBehavior = FunctionChoiceBehavior.Auto }),
};
return codeReviewAgent;
}
///
/// 检查代码是否存在报错
///
///
public static ChatCompletionAgent CreateCodeErrorCheckAgent(Kernel kernel)
{
conststring errorCheckAgentName = "CodeErrorCheckAgent";
conststring errorCheckInstruction =
"""
你是CodeErrorCheckAgent,
- 你的职责是检查代码是否存在报错,只需要检查代码的质量,不需要编写代码。
- 如果代码构建没问题,那么只回复:[yes-code]。
- 如果代码构建出现异常,那么你需要告知ProgrammerAgent,然后提供解决方案的思路。
""";
var codeErrorCheckAgent = new ChatCompletionAgent
{
Name = errorCheckAgentName,
Instructions = errorCheckInstruction,
Kernel = kernel,
Description = "代码错误检查机器人",
};
return codeErrorCheckAgent;
}
///
/// 创建一个程序员Agent
///
public static ChatCompletionAgent CreateProgrammerAgent(Kernel kernel)
{
conststring programmerAgentName = "ProgrammerAgent";
conststring programmerInstruction =
"""
你是ProgrammerAgent,
- 你的职责是编写代码,
- 请根据用户的需求编写代码,
- 尽可能考虑到最佳实践,并且保持代码的可读性。
- 您还可以帮助用户直接创建项目,修改代码文件,如果需要构建项目,通知CodeErrorCheckAgent 检查代码是否存在报错。
""";
var programmerAgent = new ChatCompletionAgent
{
Name = programmerAgentName,
Instructions = programmerInstruction,
Kernel = kernel,
Description = "程序员机器人",
};
return programmerAgent;
}
}
然后我们提供一些Agent需要的能力,创建俩个文件CodeFunctionCodeFunction.cs这个Function由于提供操作文件的功能给AIusing System.ComponentModel;
using System.Diagnostics;
using System.Text;
using Microsoft.SemanticKernel;
namespaceCodeAgent.Function;
publicclassCodeFunction
{
///
/// 执行CMD命令
///
[KernelFunction, Description("执行CMD命令, 并且等待命令执行完成")]
public async Task ExecuteCommand(string command)
{
Console.WriteLine(command);
var process = new Process
{
StartInfo = new ProcessStartInfo
{
fileName = "cmd.exe",
Arguments = $"/c {command}",
// 显示窗口,并且将控制台内容输出
RedirectStandardOutput =true
RedirectStandardError =true
UseShellExecute =false
CreateNoWindow =false
// 设置编码
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
}
};
process.Start;
await process.WaitForExitAsync;
var result = await process.StandardOutput.ReadToEndAsync;
var error = await process.StandardError.ReadToEndAsync;
process.Close;
if (string.IsOrWhiteSpace(error))
{
Console.WriteLine(result);
return result;
}
await Console.Error.WriteLineAsync(error);
return error;
}
///
/// DotNet构建指定目录下的项目
///
///
public Task BuildDotNetProject(
[Description("项目路径")] string projectPath)
{
return ExecuteCommand($"dotnet build {projectPath}");
}
///
/// 获取当前系统基本信息
///
[KernelFunction, Description("获取当前系统基本信息")]
public string GetSystemInfo
{
var os = Environment.OSVersion;
var platform = Environment.OSVersion.Platform;
var version = Environment.OSVersion.VersionString;
var processorCount = Environment.ProcessorCount;
var systemDirectory = Environment.SystemDirectory;
var userName = Environment.UserName;
var machineName = Environment.MachineName;
var userDomainName = Environment.UserDomainName;
var currentDirectory = Environment.CurrentDirectory;
var is64BitOperatingSystem = Environment.Is64BitOperatingSystem;
var is64BitProcess = Environment.Is64BitProcess;
return @$"
操作系统:{os}
平台:{platform}
版本:{version}
处理器数量:{processorCount}
系统目录:{systemDirectory}
用户名:{userName}
机器名:{machineName}
用户域名:{userDomainName}
当前目录:{currentDirectory}
是否为64位操作系统:{is64BitOperatingSystem}
是否为64位进程:{is64BitProcess}
";
}
///
/// 修改指定的文件的内容
///
[KernelFunction, Description("修改指定的文件的内容")]
public async Task ModifyFileContent(string filePath, string content)
{
await File.WriteAllTextAsync(filePath, content);
}
///
/// 获取指定目录下所有文件
///
[KernelFunction, Description("获取指定目录下所有文件")]
public string GetFilesInDirectory(
[Description("目录路径")] string directoryPath)
{
return Directory.GetFiles(directoryPath);
}
///
/// 文件重命名
///
[KernelFunction, Description("文件重命名")]
public string RenameFile(
[Description("文件路径")] string filePath,
[Description("新文件名")] string newFileName)
{
File.Move(filePath, Path.Combine(Path.GetDirectoryName(filePath), newFileName));
return"文件重命名成功";
}
///
/// 修改指定的文件 指定行的内容,如果行不存在则添加
///
[KernelFunction, Description("修改指定的文件 指定行的内容,如果行不存在则添加")]
public async Task ModifyFileLineContent(string filePath, int lineNumber, string content)
{
Console.WriteLine("修改指定的文件 指定行的内容,如果行不存在则添加:{0} {1} {2}", filePath, lineNumber, content);
var lines = await File.ReadAllLinesAsync(filePath);
if (lineNumber > lines.Length)
{
await File.AppendAllTextAsync(filePath, content);
}
else
{
lines[lineNumber -1] = content;
await File.WriteAllLinesAsync(filePath, lines);
}
}
///
/// 读取指定文件的内容
///
[KernelFunction, Description("读取指定文件的内容")]
public async Task ReadFileContent(string filePath)
{
Console.WriteLine("读取指定文件的内容:{0}", filePath);
returnawait File.ReadAllTextAsync(filePath);
}
///
/// 读取指定文件的指定行的内容
///
[KernelFunction, Description("读取指定文件的指定行的内容")]
public async Task ReadFileLineContent(string filePath, int lineNumber)
{
Console.WriteLine("读取指定文件的指定行的内容:{0} {1}", filePath, lineNumber);
{
return"行数超出文件行数";
}
return lines[lineNumber -1];
}
}
UserFunction 如果需要在确认一些功能需求的时候需要让用户输入,所以需要提供读取用户输入的Function。using System.ComponentModel;
using Microsoft.SemanticKernel;
namespaceCodeAgent.Function;
publicclassUserFunction
{
///
/// 找用户确认需求
///
///
[KernelFunction, Description("找用户确认需求,并且等待用户提供确认")]
public string ConfirmRequirement(
[Description("需要确认的需求")] string requirement
)
{
Console.WriteLine(requirement);
Console.WriteLine("请确认需求,输入yes/no");
var result = Console.ReadLine;
return result;
}
///
/// 确认用户是否有额外的需要
///
[KernelFunction, Description("确认用户是否有额外的需要")]
public string ConfirmAdditionalRequirement(
[Description("提醒用户是否有额外的需求")] string reminder
)
{
Console.WriteLine(reminder);
Console.Write("用户输入:");
return result;
}
///
/// 当任务完成时,通知用户,让用户确认是否满足需求,如果满足则返回[done]
///
[KernelFunction, Description("当任务完成时,通知用户,让用户确认是否满足需求,如果满足则返回[done]")]
public string NotifyUserTaskDone(
[Description("任务完成的消息")] string message
)
{
Console.WriteLine(message);
return result;
}
}
token然后我们执行项目,下面是执行的流程,在执行过程中,AI会先找我们确认详细的需求,然后确认以后他会生成一个计划告知ProgrammerAgent然后ProgrammerAgent进行代码实现,ProgrammerAgent会创建项目和修改代码文件,在日志中存在读取文件内容,和修改文件内容,然后CodeErrorCheckAgent会进行代码检查,代码检查是通过dotnet build去查看代码异常信息,然后再给ProgrammerAgent修复异常内容。[user]: 使用Avalonia实现一个简单的计算器,工作目录:D:\agent
您提到使用Avalonia实现一个简单的计算器,是否有具体的功能需求或界面设计偏好?例如,加减乘除基础运算,或是需要历史记录等功能。
请确认需求,输入yes/no
基本操作、历史记录、主题切换
[Assistant]:- CodeReviewAgent 为了实现一个符合您要求的计算器应用程序,可以按照以下思路来构建项目:
1. **基础操作**:
- 实现基本的四则运算:加、减、乘、除。
- 在UI设计上,布局可以采用简单的网格布局来放置按钮,确保按键的响应速度和准确性。
2. **历史记录**:
- 在计算器界面的侧边或底部增加一个区域,显示历史计算的结果。
- 考虑使用一个列表控件(如`ListBox`或`DataGrid`)来存放历史记录。
- 可以将历史记录保存在内存中,并在用户需要时进行清空。
3. **主题切换**:
- 提供一个下拉菜单或者按钮,供用户切换主题配色。
- 定义几个主题风格,并实现动态资源的切换,以便用户在运行时可以改变主题。
4. **项目组织**:
- 创建一个新的Avalonia应用程序项目,用于开发此计算器。
- 确保代码结构清晰,使用MVVM架构,使得界面与逻辑分离。
请确认这些思路符合您的期望,然后我们可以继续进行如何具体实现代码的探讨。
dotnet new avalonia.app -o D:\agent\AvaloniaCalculator
已成功创建模板“Avalonia .NET App”。
正在处理创建后操作...
正在还原 D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj:
正在确定要还原的项目…
已还原 D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj (用时 201 毫秒)。
已成功还原。
读取指定文件的内容:D:\agent\AvaloniaCalculator\MainWindow.axaml
读取指定文件的内容:D:\agent\AvaloniaCalculator\MainWindow.axaml.cs
cdD:\agent\AvaloniaCalculator && dotnet build
正在确定要还原的项目…
所有项目均是最新的,无法还原。
C:\Program Files\dotnet\sdk\9.0.200-preview.0.24575.35\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: 你正在用 .NET 的预览版。请参阅 https://aka.ms/dotnet-support-policy [D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj]
D:\agent\AvaloniaCalculator\MainWindow.axaml.cs(15,9): error CS0200: 无法为属性或索引器“ItemsControl.Items”赋值 - 它是只读的 [D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj]
D:\agent\AvaloniaCalculator\MainWindow.axaml.cs(22,30): warning CS8602: 解引用可能出现空引用。 [D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj]
D:\agent\AvaloniaCalculator\MainWindow.axaml.cs(31,36): warning CS8602: 解引用可能出现空引用。 [D:\agent\AvaloniaCalculator\AvaloniaCalculator.csproj]
D:\agent\AvaloniaCalculator\MainWindow.axaml.cs(62,29): warning CS8604: “double double.Parse(string s)”中的形参“s”可能传入 引用实参。 [D:\agent\AvaloniaCalculator\AvaloniaCalculat
实际运行效果
让我们通过一个实际案例来看看这个系统是如何工作的。以下是创建一个Avalonia计算器应用的过程:
需求确认阶段
Agent询问具体需求
用户确认功能要求
开发实现阶段
自动创建项目结构
生成必要的代码文件
实现基本功能
检查优化阶段
代码质量审查
错误检测和修复
功能完善
最终成果通过AI Agent的协作,我们成功创建了一个具有以下功能的计算器应用:
基础计算功能
历史记录
主题切换
总结通过本文的实践,我们了解了:
如何使用Semantic Kernel框架构建AI Agent
如何实现Agent之间的协作
如何将AI能力应用到实际开发中
这个案例展示了AI Agent在软件开发中的潜力,为我们提供了一个全新的开发范式。
进阶建议尝试扩展Agent的功能
优化Agent之间的交互
探索更多实际应用场景
希望这个教程能帮助你更好地理解和使用AI Agent技术!
交流群开源地址:https://gitee.com/hejiale010426/code-agent
来源:opendotnet