.NET集成ChatGPT:rodion-m开源库生产级应用指南

news2026/5/8 11:18:39
1. 项目概述与核心价值如果你正在用 .NET 技术栈开发应用并且想集成类似 ChatGPT 的对话能力那么rodion-m/ChatGPT_API_dotnet这个开源库绝对值得你花时间研究。它不是一个简单的 API 封装器而是一个为 .NET 开发者量身定制的、生产就绪的解决方案核心价值在于将 OpenAI、Azure OpenAI 乃至 OpenRouter 的 Chat Completions API 无缝集成到你的 ASP.NET Core 应用架构中。简单来说这个库帮你解决了几个最头疼的问题如何优雅地管理 API 密钥和配置如何与依赖注入DI容器无缝结合如何持久化保存用户与 AI 的多轮对话历史以便下次能“接着聊”以及如何以最符合 .NET 开发者习惯的方式比如强类型对象、异步流来使用这些 AI 能力。它内置了对 Entity Framework Core 的支持意味着你可以用熟悉的数据库SQL Server、SQLite、PostgreSQL 等来存储聊天记录同时也提供了足够的扩展性让你可以接入自己的存储方案。从我自己的使用经验来看直接裸调 OpenAI 的 HTTP API 在原型阶段没问题但一旦要上线配置管理、错误重试、对话状态维护这些“脏活累活”会迅速消耗你的开发精力。这个库把这些基础设施都打包好了让你能更专注于业务逻辑本身——也就是如何设计 Prompt 和利用 AI 的回复。接下来我会带你深入拆解这个库的设计思路、核心用法并分享一些从项目 README 和实际踩坑中总结出的实操要点。2. 核心设计思路与架构解析2.1 分层设计与职责分离这个库的设计遵循了清晰的层次结构理解这一点对正确使用它至关重要。它不是一个大而全的“黑盒”而是由几个职责分明的 NuGet 包组成你可以按需引用。最底层是OpenAI.ChatGPT包。这是最核心、最纯粹的 API 客户端只负责与 OpenAI 兼容的端点进行 HTTP 通信。它提供了OpenAiClient这个类封装了发起补全请求、处理流式响应等基础操作。如果你只需要一个简单的、无状态的客户端或者想在控制台应用、后台服务里快速调用 API直接用这个包就够了。它的设计非常干净没有依赖 ASP.NET Core 的任何东西。往上走一层是OpenAI.ChatGPT.AspNetCore包。它在核心客户端的基础上增加了对 ASP.NET Core 依赖注入DI和配置系统的支持。它引入了ChatGPTFactory和ChatGPT这样的服务类核心目的是管理“对话会话”。一个ChatGPT实例通常会关联一个用户通过userId并且能够通过IChatHistoryStorage接口来保存和加载该用户的对话历史。这个包提供了抽象的存储接口但具体的实现需要你自己来写。最上层是OpenAI.ChatGPT.EntityFrameworkCore包。这是开箱即用体验最好的一个包。它基于AspNetCore包并提供了IChatHistoryStorage接口的 Entity Framework Core 实现。你只需要在Startup或Program.cs里配置一下数据库连接它就会自动创建所需的表结构来存储消息历史。对于大多数需要持久化对话的 Web 应用来说这是最推荐的选择。这种分层设计的好处是灵活。你可以从底层开始逐步引入你需要的功能而不是被迫接受一整坨复杂的依赖。2.2 多提供商支持与配置驱动库的另一个亮点是对多 AI 提供商的原生支持。早期版本可能只支持 OpenAI但现在它已经集成了Azure OpenAI和OpenRouter。这意味着你可以根据成本、网络延迟或模型可用性灵活切换后端服务。它的配置系统设计得很巧妙通过一个统一的配置节来驱动。你不需要在代码里写死 API 密钥和端点。看一下appsettings.json的配置示例就明白了{ AIProvider: openai, // 或 azure_openai 或 openrouter OpenAICredentials: { ApiKey: sk-..., ApiHost: https://api.openai.com/v1/ // 默认值可省略 }, AzureOpenAICredentials: { ApiKey: your-azure-key, ApiHost: https://your-resource.openai.azure.com/, DeploymentName: gpt-4-turbo // Azure 特有的部署名 }, OpenRouterCredentials: { ApiKey: your-openrouter-key, ApiHost: https://openrouter.ai/api/v1 } }关键在于AIProvider这个字段。库在启动时会读取这个值然后自动选择对应的凭证配置块来初始化客户端。这种设计使得在不同环境开发、测试、生产或不同客户配置之间切换 AI 提供商变得非常简单只需要改一下配置文件代码完全不用动。实操心得我强烈建议将ApiKey这类敏感信息放在环境变量或用户机密中而不是直接写在appsettings.json里。库支持通过环境变量ASPNETCORE_OpenAICredentials:ApiKey的方式注入这与 ASP.NET Core 的配置优先级机制完全一致是更安全的做法。3. 快速上手指南与核心 API 使用3.1 环境准备与项目初始化假设我们正在构建一个 ASP.NET Core Web API 项目并且希望集成对话 AI 功能。第一步是通过 NuGet 安装包。如果你需要对话历史持久化最方便的是安装 Entity Framework Core 集成包dotnet add package OpenAI.ChatGPT.EntityFrameworkCore这个包会同时拉取AspNetCore和核心ChatGPT包的依赖。接下来在Program.cs中进行服务注册。这是将库接入你应用的关键一步var builder WebApplication.CreateBuilder(args); // ... 其他服务配置 // 添加 ChatGPT 集成并配置使用 SQLite 数据库存储历史记录 builder.Services.AddChatGptEntityFrameworkIntegration( builder.Configuration, options options.UseSqlite(Data Sourcechats.db)); // 如果你用的是 SQL Server可能是这样 // builder.Services.AddChatGptEntityFrameworkIntegration( // builder.Configuration, // options options.UseSqlServer(builder.Configuration.GetConnectionString(DefaultConnection)));AddChatGptEntityFrameworkIntegration这个方法做了很多事情它注册了配置化的OpenAiClient、ChatGPTFactory以及基于 EF Core 的对话存储服务。builder.Configuration参数是必须的用于读取我们上面提到的那些配置项。3.2 核心服务注入与基础对话服务注册好后你就可以在任何通过 DI 创建的服务如 Controller、Minimal API、BackgroundService中注入ChatGPTFactory了。ChatGPTFactory是创建和管理用户会话的工厂。假设我们有一个 API 控制器需要处理用户的聊天请求[ApiController] [Route(api/chat)] public class ChatController : ControllerBase { private readonly ChatGPTFactory _chatGptFactory; public ChatController(ChatGPTFactory chatGptFactory) { _chatGptFactory chatGptFactory; } [HttpPost({userId})] public async TaskIActionResult SendMessage(string userId, [FromBody] UserMessageRequest request) { // 1. 为该用户创建或获取一个 ChatGPT 会话实例 ChatGPT chatGpt await _chatGptFactory.Create(userId); // 2. 继续之前的对话主题或开始一个新主题 // 这里返回的 ChatService 是真正执行对话的对象 var chatService await chatGpt.ContinueOrStartNewTopic(); // 3. 获取 AI 的回复 string response await chatService.GetNextMessageResponse(request.Text); return Ok(new { Response response }); } } public record UserMessageRequest(string Text);这段代码展示了最基础的流程Create(userId): 根据userId创建一个ChatGPT实例。这个userId是你的业务系统内的用户标识库会用这个 ID 来关联和查找该用户的所有历史对话。ContinueOrStartNewTopic(): 这个方法很关键。它会检查这个用户是否有未完成的对话即上一次的对话没有明确结束。如果有就返回一个能继续上次对话的ChatService如果没有就基于配置如InitialSystemMessage开启一个全新的对话主题。这模拟了 ChatGPT 网页版“连续对话”的体验。GetNextMessageResponse: 向 AI 发送用户的新消息并等待完整的回复。这个方法会自动将本次交互用户消息和 AI 回复保存到历史记录中所以你下次调用ContinueOrStartNewTopic时上下文是连续的。注意事项ChatGPT和ChatService实例不是线程安全的。它们的生命周期设计是短暂的通常在一个 HTTP 请求或一个用户操作周期内使用。ChatGPTFactory.Create是一个异步方法因为它内部可能需要去数据库查询用户的历史记录。确保你的使用模式符合这个假设不要尝试在多个线程间共享同一个实例。3.3 流式响应实现ChatGPT 网页版那种逐字打印的效果体验很好对于生成长文本尤其有用。这个库通过 C# 的异步流async stream完美支持了这个特性。改造上面的SendMessage方法使其支持流式响应[HttpPost(stream/{userId})] public async IAsyncEnumerablestring StreamMessage(string userId, [FromBody] UserMessageRequest request) { ChatGPT chatGpt await _chatGptFactory.Create(userId); var chatService await chatGpt.ContinueOrStartNewTopic(); await foreach (string chunk in chatService.StreamNextMessageResponse(request.Text)) { // chunk 是 AI 回复的一小段文本 yield return chunk; } // 循环结束后对话历史同样会被自动保存 }在客户端比如前端使用 SSE 或 WebSocket你可以接收到这些陆续到达的chunk并实时拼接显示从而实现“打字机”效果。这是提升用户体验的一个非常重要的功能点。4. 高级功能与模块化应用4.1 StructuredResponse 模块获取强类型响应很多时候我们调用 AI 不只是为了得到一段自由文本而是希望它返回结构化的数据比如 JSON 对象。手动解析 AI 返回的文本并反序列化既不可靠又麻烦。StructuredResponse模块就是为了解决这个问题而生。首先你需要安装独立的 NuGet 包dotnet add package OpenAI.ChatGPT.Modules.StructuredResponse假设你的应用需要从用户描述中提取事件信息你可以这样定义 C# 记录Recordpublic record CalendarEvent(string Title, DateTimeOffset StartTime, DateTimeOffset? EndTime, string Location);然后使用OpenAiClient可以从 DI 中获取IOpenAiClient接口的GetStructuredResponse方法public class EventService { private readonly IOpenAiClient _client; public EventService(IOpenAiClient client) _client client; public async TaskCalendarEvent ParseEventDescriptionAsync(string userInput) { // 构建一个简单的对话上下文指导 AI 输出格式 var dialog Dialog.StartAsSystem(你是一个日历助手请将用户的输入解析为包含标题、开始时间、结束时间和地点的结构化事件。请只返回JSON格式的数据。) .ThenUser($解析这个事件{userInput}); // 直接获取强类型对象 CalendarEvent event await _client.GetStructuredResponseCalendarEvent(dialog, model: ChatCompletionModels.Gpt4Turbo); return event; } }背后的原理这个模块利用了 OpenAI API 的JSON ModeGPT-4 Turbo 和 GPT-3.5 Turbo 1106 及以上版本原生支持。在请求中它会设置response_format: { type: json_object }并精心设计 System Prompt引导模型输出一个合法的 JSON 对象然后库会帮你完成反序列化。重要提示对于 GPT-3.5 等不支持原生 JSON Mode 的模型或者对于复杂的嵌套对象建议在GetStructuredResponse方法中提供examples参数。examples是一个ListChatCompletionMessage你可以提供一两个输入输出的示例这能极大地提高模型返回正确格式的稳定性。这是 Prompt Engineering 中“少样本学习”Few-shot Learning的实践。4.2 Translator 模块简化翻译任务另一个实用的独立模块是Translator。翻译是一个常见的 AI 应用场景这个模块将其封装成了简单的方法。同样需要先安装包dotnet add package OpenAI.ChatGPT.Modules.Translator使用起来非常直观public class TranslationService { private readonly IChatGptTranslatorService _translator; public TranslationService(IChatGptTranslatorService translator) _translator translator; public async Taskstring TranslateProductDescriptionAsync(string englishDescription) { // 将英文产品描述翻译成中文 string chineseDescription await _translator.TranslateText( englishDescription, sourceLanguage: English, targetLanguage: Simplified Chinese // 使用明确的语言名称 ); return chineseDescription; } }更强大的是它可以与StructuredResponse结合翻译整个对象public record Product(string Name, string Description, decimal Price); public async TaskProduct TranslateProductAsync(Product englishProduct) { Product chineseProduct await _translator.TranslateObject( englishProduct, sourceLanguage: English, targetLanguage: Simplified Chinese ); // 返回的 chineseProduct 对象中所有字符串字段都已被翻译 return chineseProduct; }这个功能在国际化i18n或跨语言内容管理的应用中非常有用。它省去了你手动遍历对象属性、拼接翻译请求的繁琐工作。5. 配置详解、异常处理与生产级考量5.1 关键 API 参数调优通过ChatGPTConfig配置类你可以精细控制 AI 的行为。这些配置可以在appsettings.json中设置也可以在创建ChatGPT实例时通过参数覆盖。{ ChatGPTConfig: { InitialSystemMessage: 你是一个专业的软件开发助手回答要简洁、准确。, MaxTokens: 1500, Model: gpt-4-turbo-preview, Temperature: 0.7, PassUserIdToOpenAiRequests: false } }InitialSystemMessage: 这是对话的系统提示词用于设定 AI 的角色和行为准则。对于需要特定风格或专业知识的对话这里至关重要。例如你可以设置为“你是一位经验丰富的金融顾问用中文回答避免使用专业术语”。MaxTokens: 限制单次回复的最大令牌数。需要平衡回复的完整性和成本/时间。库内部会校验该值是否超过所选模型的上下文上限通过ChatCompletionModels.GetMaxTokensLimitForModel方法。一个粗略的估计是英文中 1 token 约等于 4 个字符或 0.75 个单词。Model: 指定使用的模型。库提供了ChatCompletionModels静态类里面包含了所有支持的模型常量如Gpt4Turbo,Gpt35_Turbo避免你拼写错误。选择模型时需综合考虑成本、速度、上下文长度和能力。Temperature: 创造性参数。值越高接近 2.0输出越随机、多样值越低接近 0输出越确定、一致。对于代码生成、事实问答建议较低0.1-0.3对于创意写作可以调高0.7-0.9。库提供了ChatCompletionTemperatures静态类包含Deterministic(0.1),Balanced(0.5),Creative(0.9) 等预设。PassUserIdToOpenAiRequests: 一个隐私和安全相关的设置。如果设为true你在Create(userId)中传入的userId会作为user字段发送给 OpenAI API。这有助于 OpenAI 监控和防止滥用但意味着你的用户标识会离开你的服务器。请根据你的隐私政策决定是否开启。5.2 异常处理与重试策略网络请求总有可能失败。库在遇到非成功的 API 响应时会抛出NotExpectedResponseException其中包含了来自 OpenAI 服务器的错误信息方便你排查是认证问题、额度不足还是请求格式错误。对于网络波动、瞬时超时等问题你需要自己实现重试机制。幸运的是由于库的客户端基于IHttpClientFactory你可以轻松集成 Polly 这样的弹性库。首先安装 Polly 扩展包dotnet add package Microsoft.Extensions.Http.Polly然后在服务注册时配置 HTTP 客户端的重试策略builder.Services.AddHttpClientIOpenAiClient, OpenAiClient() // 假设你直接注册了客户端 .AddTransientHttpErrorPolicy(policyBuilder policyBuilder .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5) }));如果你使用的是AddChatGptEntityFrameworkIntegration它内部已经注册了命名的HttpClient。你需要找到其注册名称通常是OpenAiClient或类似然后为其单独配置策略。查看库源码或文档可以找到具体的名称。通过 Polly你可以配置复杂的策略包括重试、熔断、超时等这对于生产环境的稳定性至关重要。5.3 线程安全与异步上下文这一点需要特别强调ChatGPT和ChatService类不是线程安全的。它们的实现依赖于IChatHistoryStorage而 EF Core 的DbContext默认也不是线程安全的。这意味着不要在多个线程间共享同一个ChatGPT或ChatService实例。在 Web 应用中最安全的使用模式是“请求-作用域”Scoped。这正是依赖注入的典型用法。每个 HTTP 请求都会从容器中获取一个新的实例处理完请求后实例被销毁。AddChatGptEntityFrameworkIntegration默认就是以 Scoped 生命周期注册相关服务的。所有公共方法都是异步的async并且使用了ConfigureAwait(false)借助ConfigureAwait.Fody包。这表示这些方法在恢复执行时不会强制回到原始的同步上下文如 UI 线程。这在后台服务或非 UI 应用中能避免死锁并提升性能但在 UI 应用中需要注意如果要在异步调用后更新 UI可能需要手动派发回 UI 线程。6. 实战案例与常见问题排查6.1 构建一个带记忆的聊天机器人后端让我们整合以上所有知识构建一个稍复杂的示例一个支持多轮对话、可切换话题、并且能提取结构化信息的聊天机器人 API。首先定义我们的请求和响应 DTO以及话题管理模型// DTOs public record SendMessageRequest(string Text, string? TopicId); public record SendMessageResponse(string MessageId, string Text, string Role, DateTimeOffset CreatedAt); public record TopicInfo(string Id, string? Title, DateTimeOffset LastActivity); // 服务接口 public interface IChatBotService { TaskTopicInfo StartNewTopicAsync(string userId, string initialMessage); TaskSendMessageResponse SendMessageAsync(string userId, SendMessageRequest request); TaskIEnumerableTopicInfo GetUserTopicsAsync(string userId); Taskbool CloseTopicAsync(string userId, string topicId); } // 服务实现 public class ChatBotService : IChatBotService { private readonly ChatGPTFactory _chatGptFactory; private readonly ILoggerChatBotService _logger; public ChatBotService(ChatGPTFactory chatGptFactory, ILoggerChatBotService logger) { _chatGptFactory chatGptFactory; _logger logger; } public async TaskTopicInfo StartNewTopicAsync(string userId, string initialMessage) { // 创建一个新的 ChatGPT 实例并指定一个唯一的话题ID var topicId Guid.NewGuid().ToString(); var chatGpt await _chatGptFactory.Create(userId, topicId: topicId); // 开始新话题可以设置自定义的系统提示 var chatService await chatGpt.StartNewTopic( systemMessage: 你是一个友好的助手。如果用户提到了计划或事件请主动询问是否需要创建日历项。, initialUserMessage: initialMessage ); string assistantReply await chatService.GetNextMessageResponse(initialMessage); // 我们可以尝试从对话中提取一个标题作为话题名 string inferredTitle initialMessage.Length 30 ? initialMessage.Substring(0, 30) ... : initialMessage; return new TopicInfo(topicId, inferredTitle, DateTimeOffset.UtcNow); } public async TaskSendMessageResponse SendMessageAsync(string userId, SendMessageRequest request) { ChatGPT chatGpt; if (string.IsNullOrEmpty(request.TopicId)) { // 如果没有提供话题ID则继续最近的话题或创建一个新的库的默认行为 chatGpt await _chatGptFactory.Create(userId); } else { // 继续指定的话题 chatGpt await _chatGptFactory.Create(userId, topicId: request.TopicId); } var chatService await chatGpt.ContinueOrStartNewTopic(); string assistantReply await chatService.GetNextMessageResponse(request.Text); // 在实际项目中你可能需要从 chatService 或返回的消息对象中获取消息ID var response new SendMessageResponse( MessageId: Guid.NewGuid().ToString(), Text: assistantReply, Role: assistant, CreatedAt: DateTimeOffset.UtcNow ); // 检查回复中是否包含事件信息简化示例 if (assistantReply.Contains(会议) || assistantReply.Contains(约会)) { _logger.LogInformation(检测到用户可能提到了事件可触发后续处理流程。); // 这里可以触发一个后台任务使用 StructuredResponse 模块进行解析 } return response; } public async TaskIEnumerableTopicInfo GetUserTopicsAsync(string userId) { // 注意基础库可能不直接提供查询话题列表的API。 // 你需要根据你使用的存储实现如自定义的 IChatHistoryStorage来查询。 // 这里假设我们通过注入的存储服务来获取。 // 这是一个需要你根据实际存储层扩展的功能。 throw new NotImplementedException(需要实现自定义存储查询逻辑); } public async Taskbool CloseTopicAsync(string userId, string topicId) { // 标记某个话题为已关闭后续 ContinueOrStartNewTopic 将开启新话题。 // 这同样可能需要扩展存储层在对话记录中添加一个“已结束”标记。 var chatGpt await _chatGptFactory.Create(userId, topicId: topicId); await chatGpt.CloseCurrentTopic(); return true; } }这个服务类展示了如何管理多个对话话题如何根据业务逻辑定制系统提示以及如何将 AI 对话与你的业务逻辑如事件检测结合起来。控制器层只需调用这些服务方法即可。6.2 常见问题与排查技巧在实际集成中你可能会遇到以下问题。这里有一个快速排查指南问题现象可能原因排查步骤与解决方案抛出NotExpectedResponseException错误信息包含401或Invalid API KeyAPI 密钥错误、过期或配置未正确加载。1. 检查appsettings.json或环境变量中的ApiKey是否正确。2. 确认AIProvider设置与使用的凭证块匹配例如AIProvider: openai但配置了AzureOpenAICredentials。3. 对于 Azure OpenAI检查DeploymentName是否正确以及该部署是否支持聊天补全 API。请求超时无响应网络问题、API 服务不稳定或请求的MaxTokens过大导致生成时间过长。1. 使用 Polly 配置重试和超时策略。2. 适当降低MaxTokens值。3. 检查防火墙或代理设置确保能访问api.openai.com或你的 Azure 端点。GetStructuredResponse返回的 JSON 反序列化失败AI 未返回有效的 JSON或返回的 JSON 结构与 C# 类不匹配。1. 确保使用的模型支持 JSON Mode如 GPT-4 Turbo。2. 在 System Prompt 中明确要求返回 JSON并描述格式。3. 为 GPT-3.5 等模型提供examples参数给出输入输出示例。4. 在GetStructuredResponse调用中捕获JsonException并记录 AI 返回的原始文本进行调试。流式响应 (StreamNextMessageResponse) 中途停止或报错网络连接中断或客户端提前取消了请求如用户关闭了浏览器标签。1. 在StreamNextMessageResponse方法中设置throwOnCancellation: false来忽略由客户端取消引发的OperationCanceledException。2. 在前端实现重连逻辑并设计一个机制如发送一个“继续”的请求来恢复中断的流。对话历史没有正确延续userId或topicId不一致或存储层如数据库出现问题。1. 确保每次为同一用户对话使用相同的userId。2. 如果你想管理多个独立对话请使用不同的topicId。3. 检查数据库连接确认 EF Core 迁移已正确运行ChatMessages等表已创建。4. 调试时可以注入IChatHistoryStorage直接查看存储的内容。性能问题响应慢模型太大、MaxTokens设置过高、网络延迟或数据库查询慢。1. 考虑使用更快的模型如 GPT-3.5 Turbo 快于 GPT-4。2. 优化MaxTokens设置合理的上限。3. 对于 Azure选择离你区域近的终端。4. 确保数据库有适当的索引特别是在UserId和TopicId字段上。一个关于配置的深度提示在appsettings.Development.json和appsettings.Production.json中使用不同的配置是标准做法。在开发环境你可以使用一个低额度的测试密钥并将Temperature调高以观察多样性。在生产环境务必使用安全的密钥管理方式如 Azure Key Vault、AWS Secrets Manager并将Temperature调低以保证回答的一致性。同时生产环境一定要配置好 Polly 策略和全面的日志记录以便监控 API 调用成功率、延迟和费用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2594570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…