AI驱动.NET 5计算器开发:从架构设计到CI/CD的工程实践
1. 项目概述一个由AI驱动的.NET 5计算器实践最近在探索AI辅助开发工具链我尝试了一个挺有意思的实验完全使用Cursor IDE的Composer功能配合Claude 3.5 Sonnet和GPT-4o的提示词从零构建了一个.NET 5平台的计算器应用。这不仅仅是一个简单的控制台程序而是一个包含了依赖注入、单元测试、RESTful API并集成了SonarCloud代码质量分析以及Telegram构建状态通知的完整项目。整个过程我几乎没有手写一行核心业务代码全部通过结构化的提示词来驱动AI生成。这个项目更像是一个“元开发”的实践我想验证在当下一个开发者如何高效地利用AI作为副驾驶来构建一个符合现代工程标准的、可维护的小型应用。如果你也对AI编程、.NET技术栈的工程化实践或者如何将CI/CD与即时通讯工具结合感兴趣那么这个从构思到部署的完整记录或许能给你一些启发。2. 技术栈选型与项目架构设计思路2.1 为什么选择.NET 5与AI驱动选择.NET 5作为技术栈是基于其作为长期支持版本与现代化特性的平衡。.NET 5是.NET Core 3.1之后、.NET 6之前的统一平台它移除了传统的.NET Framework包袱提供了出色的跨平台能力和高性能。对于计算器这样一个逻辑清晰但需要良好结构示范的项目来说.NET 5的轻量级和成熟的生态系统如强大的依赖注入容器、高效的测试框架非常合适。更重要的是我想测试AI对特定技术栈的上下文理解能力。.NET的语法和约定相对严谨这能很好地检验Claude和GPT-4o生成代码的准确性和规范性。而全程使用Cursor Composer配合AI模型则是一个核心实验。Composer允许你将复杂的开发任务分解成多个步骤并通过自然语言指令串联起来。我的角色从“编码者”转变为“架构描述者”和“代码审查者”。我通过提示词定义模块、接口、实现逻辑以及测试用例AI则负责生成具体的代码实现。这种模式极大地提升了原型构建和样板代码编写的速度让我能更专注于整体架构设计和工程实践的集成。2.2 核心架构分层与解耦尽管项目规模不大但我仍然采用了清晰的分层架构这是为了向AI传达明确的结构意图也为了项目本身的可测试性和可维护性。架构主要分为三层应用核心层包含计算器的核心业务逻辑例如ICalculatorService接口及其实现。这里定义了加、减、乘、除等运算方法。这一层纯粹是业务领域对象不依赖任何外部框架或基础设施。这是单元测试的重点区域。接口适配层主要包括Web API控制器。它负责接收HTTP请求调用核心层的服务并将结果封装成HTTP响应返回。这一层很薄主要职责是协议转换和输入验证。基础设施与集成层这是工程化实践的体现。包括测试项目使用xUnit和Moq框架编写的单元测试。CI/CD管道配置用于GitHub Actions的YAML文件定义了构建、测试、代码分析流程。外部集成配置SonarCloud的分析配置文件和Telegram Bot的集成代码。这种分层确保了核心业务逻辑的独立性。例如未来如果想将Web API替换为gRPC接口或者增加一个桌面GUI核心层的代码几乎不需要改动。注意在与AI协作时清晰地描述每一层的职责至关重要。例如我会提示“在核心类库中创建一个ICalculatorService接口包含四个异步方法分别对应四则运算并考虑除零异常。” 明确的指令能得到更准确的输出。3. 核心模块实现与AI协作细节3.1 业务逻辑层计算器服务的实现业务逻辑是整个应用的基石。我首先通过提示词让AI创建了服务接口和实现。接口定义提示示例 “在SimpleCalculator.Core项目中创建一个ICalculatorService接口。它应该包含四个方法AddAsync,SubtractAsync,MultiplyAsync,DivideAsync。每个方法接收两个double类型的参数返回Taskdouble。请为接口添加清晰的XML注释说明。”AI生成的接口代码通常很标准。关键在于实现类特别是异常处理。我给的提示是“实现CalculatorService类。在DivideAsync方法中如果第二个参数除数为零则抛出ArgumentException并给出友好提示。其他方法直接返回运算结果。使用Task.FromResult来包装同步结果。”// AI生成的核心服务实现示例 namespace SimpleCalculator.Core.Services { public class CalculatorService : ICalculatorService { public Taskdouble AddAsync(double a, double b) { return Task.FromResult(a b); } public Taskdouble DivideAsync(double a, double b) { if (Math.Abs(b) double.Epsilon) // 更精确的零值判断 { throw new ArgumentException(Divisor cannot be zero., nameof(b)); } return Task.FromResult(a / b); } // ... 其他方法 } }这里我手动优化了AI的初版代码将b 0改为了Math.Abs(b) double.Epsilon以处理浮点数的精度问题。这是AI生成代码后需要人工审查的一个典型场景——它实现了基本逻辑但可能缺乏对特定领域细节的深度考量。3.2 依赖注入配置为了让API层能方便地使用核心服务需要在启动时进行依赖注入配置。在.NET 5的Web API项目中这通常在Startup.cs或Program.cs中完成。我给AI的提示是“在SimpleCalculator.API项目的Startup.ConfigureServices方法中将ICalculatorService注册为Scoped生命周期并指定其实现类为CalculatorService。”AI正确地生成了services.AddScopedICalculatorService, CalculatorService();这行代码。依赖注入的引入使得单元测试中可以轻松使用Moq等框架模拟ICalculatorService从而隔离测试Web API控制器。3.3 Web API控制器暴露HTTP端点API控制器是外部世界与业务逻辑的桥梁。我设计了一个简单的RESTful风格端点/api/calculate。控制器创建提示“在SimpleCalculator.API项目的Controllers文件夹下创建一个CalculatorController。它继承自ControllerBase并使用[ApiController]和[Route(“api/[controller]”)]属性。注入ICalculatorService。创建一个HTTP POST方法Calculate它接收一个CalculationRequest对象包含Operation属性如’add’, ‘subtract’和两个Operand属性根据Operation调用相应的服务方法并返回结果。”AI不仅生成了控制器还生成了CalculationRequest这个请求模型类。这展示了AI在理解“创建配套类”方面的上下文能力。在生成的控制器方法中通常会有一个switch语句来路由不同的操作。我随后补充了提示要求它添加详细的HTTP状态码返回比如成功时返回200 OK除零错误时返回400 Bad Request。[HttpPost] public async TaskIActionResult Calculate([FromBody] CalculationRequest request) { try { double result request.Operation.ToLower() switch { add await _calculatorService.AddAsync(request.Operand1, request.Operand2), subtract await _calculatorService.SubtractAsync(request.Operand1, request.Operand2), // ... 其他操作 _ throw new ArgumentException($Unsupported operation: {request.Operation}) }; return Ok(new CalculationResult { Value result }); } catch (ArgumentException ex) { return BadRequest(new { error ex.Message }); } catch (Exception ex) { // 记录日志 return StatusCode(500, new { error An internal error occurred. }); } }4. 工程化实践测试、分析与通知4.1 单元测试使用xUnit和Moq编写可靠的单元测试是保证核心逻辑正确性的关键。我为CalculatorService和CalculatorController分别创建了测试类。服务测试提示“在SimpleCalculator.Tests项目中为CalculatorService创建单元测试。使用xUnit框架。测试用例应包括正常加法、正常减法、乘法、正常除法、除零异常。使用[Fact]和[Theory]特性来组织测试。”AI出色地生成了结构化的测试代码包括使用[InlineData]的特性化测试。对于除零测试它正确地使用了Assert.ThrowsAsyncArgumentException来验证异常。控制器测试提示“为CalculatorController创建单元测试。你需要使用Moq框架来模拟ICalculatorService。测试一个成功的POST请求和一个遇到除零错误返回400的请求。”这里AI协作的挑战更大因为它需要理解模拟、设置以及验证交互。我给出的提示需要更具体“使用MockICalculatorService。在测试成功场景时通过Setup方法让模拟服务返回一个特定值然后调用控制器的Calculate方法最后使用Assert.IsTypeOkObjectResult来验证结果并断言结果值是否正确。”通过几次迭代AI能生成正确的测试结构。但设置模拟对象的语法细节有时需要人工微调比如确保使用了.Object属性来获取模拟实例。4.2 代码质量守护集成SonarCloudSonarCloud是一个云端的静态代码分析平台能帮助发现代码中的 bug、漏洞和代码异味。将其集成到项目中可以为AI生成的代码提供一道自动化的质量检查关卡。集成步骤在SonarCloud上创建项目关联你的GitHub仓库。生成令牌在SonarCloud中生成一个用户令牌。配置GitHub Secrets在GitHub仓库设置中将SonarCloud令牌添加为SONAR_TOKEN密钥。创建sonar-project.properties文件我通过提示词让AI生成这个配置文件的基本内容指定项目Key、名称以及需要排除分析的目录如bin/,obj/。编写GitHub Actions工作流这是最关键的一步。工作流需要在构建和测试之后运行SonarScanner分析代码。工作流文件提示“创建一个GitHub Actions工作流文件.github/workflows/build-and-analyze.yml。它应该在每次推送到main分支或创建PR时触发。步骤包括检出代码、设置.NET 5 SDK、恢复依赖、构建项目、运行单元测试、最后使用sonarcloud动作进行代码分析。确保在分析步骤使用了SONAR_TOKEN密钥。”AI能够生成一个基本可用的工作流文件。但需要人工检查步骤的顺序和sonarcloud动作的正确配置方式。例如需要确保dotnet test命令带有收集代码覆盖率报告的参数如--collect:”XPlat Code Coverage”这样SonarCloud才能显示测试覆盖率。4.3 即时反馈Telegram Bot构建通知为了及时获知每次代码提交后的集成状态我集成了Telegram Bot。当GitHub Actions的构建成功或失败时我会在Telegram上收到一条通知。实现原理创建Telegram Bot通过BotFather创建一个新的Bot获取其API Token。获取Chat ID给你的Bot发送一条消息然后通过https://api.telegram.org/botYourBOTToken/getUpdates这个API调用来获取你的Chat ID。配置GitHub Secrets将TELEGRAM_BOT_TOKEN和TELEGRAM_CHAT_ID存入GitHub仓库的密钥中。在工作流中添加通知步骤在GitHub Actions工作流的最后根据作业成功或失败的状态调用Telegram Bot API发送消息。我通过提示词让AI在已有的工作流文件中添加这个步骤“在工作流的最后添加一个步骤无论成功失败都运行。使用curl命令调用Telegram Bot API发送通知。消息内容应包含仓库名、工作流名称、运行状态成功/失败和提交信息。成功和失败的消息语气可以略有不同。”AI生成的curl命令模板基本正确但需要根据Telegram Bot API的格式调整消息内容的JSON结构。这是一个典型的“AI搭骨架人工填血肉”的场景。最终一个成功的构建会触发一条如“✅ Build passed forEvgenyYushko/gpt-SimpleCalculatorSolution! Commit: ‘Add unit tests for divide by zero’”的消息。5. AI协作开发的经验、挑战与优化技巧5.1 有效提示词工程的心得这个项目成功的关键在于编写有效的提示词。我总结了几点心得角色扮演与上下文设定在复杂的指令前先设定AI的角色。例如“你是一个资深的.NET后端架构师请…”这能让AI以更专业的视角生成代码。分步拆解迭代细化不要试图用一个提示完成所有事。像Composer工具设计的那样先定义项目结构再创建接口然后实现类最后写测试。每一步的反馈都用于优化下一步的提示。提供示例与约束当需要特定格式时在提示词中给出简短示例。例如“请生成一个calculation-request.json文件的示例用于测试API。” 同时明确约束如“不要使用过时的[FromUri]属性请使用[FromBody]。”要求解释在生成代码后可以追加提示“请解释一下这段代码中依赖注入生命周期选择Scoped的原因。” 这不仅能加深自己的理解也能检验AI生成的逻辑是否合理。5.2 遇到的典型问题与排查AI的“幻觉”与过时知识有时AI会引用已过时的包版本或废弃的API。例如它可能建议一个不再维护的NuGet包。解决方案对于关键依赖手动在NuGet官网或通过dotnet add package命令确认最新稳定版本并在提示词中明确指定版本号。生成的代码逻辑正确但结构不佳AI可能把所有代码写在一个文件里或者将接口和实现放在同一层级。解决方案在初始提示中就明确项目结构和文件组织。“请将接口ICalculatorService放在Core/Interfaces文件夹将其实现CalculatorService放在Core/Services文件夹。”集成配置的细节错误在配置SonarCloud或Telegram Bot时AI生成的YAML或脚本可能存在缩进错误、参数顺序错误。解决方案对于这类精确的配置文件以AI生成的代码为草稿务必对照官方文档进行逐行检查和测试。GitHub Actions的日志输出是极佳的调试工具。测试模拟的复杂性当测试逻辑变得复杂时AI可能无法一次性生成正确的Moq设置。解决方案将测试用例拆解。先提示“为CalculatorController创建一个测试模拟ICalculatorService在调用AddAsync时返回5”确保基础模拟正确。再逐步增加异常流测试等复杂场景。5.3 项目总结与可扩展方向这个“AI全栈”项目最终成功运行代码通过了SonarCloud的质量门禁每一次提交都能触发构建并向我推送Telegram通知。它验证了在当前阶段AI可以作为强大的开发加速器尤其擅长生成结构化的样板代码、基础算法和配置模板。它将开发者从繁琐的重复劳动中解放出来让我们能更聚焦于架构设计、复杂逻辑和系统集成。当然它并非银弹。AI生成的代码需要经过严格的审查、测试和重构。它缺乏真正的“理解”和业务上下文无法做出关键的架构决策。这个项目的意义在于展示了一种人机协作的高效模式人类负责战略、设计和验收AI负责战术、实施和草稿。这个计算器项目本身还可以沿多个方向扩展作为后续的AI协作练习前端界面提示AI使用Blazor或React创建一个简单的前端调用这个后端API。数据库集成增加一个功能将计算历史记录到数据库如SQLite或PostgreSQL并生成相应的实体和仓储模式代码。容器化提示AI编写Dockerfile和多阶段构建脚本将应用容器化。高级特性实现更复杂的表达式解析、支持更多数学函数这可以考验AI对算法和数据结构知识的掌握。最终工具的价值取决于使用者。熟练掌握与AI对话的技巧明确你的需求并始终保持批判性思维去审视输出结果你就能将这个强大的“副驾驶”的作用发挥到极致在提升开发效率的同时依然牢牢掌控着代码的质量与项目的方向。