Kotlin多平台集成OpenAI API:类型安全与协程流式处理实践

news2026/5/13 5:47:05
1. 项目概述当Kotlin遇见OpenAI如果你是一名Android或Kotlin多平台KMP开发者最近想在自己的应用中集成AI对话、图像生成或者语音转文本这类酷炫功能那么你大概率绕不开OpenAI的API。但当你兴冲冲地打开官方文档准备用Kotlin开干时可能会遇到一些小麻烦官方提供的SDK主要是Python和Node.js的虽然REST API是通用的但自己从零开始封装网络请求、处理流式响应、管理复杂的请求体和错误类型着实需要花一番功夫。这时候一个专门为Kotlin生态打造的OpenAI客户端库就显得格外贴心。aallam/openai-kotlin正是这样一个项目它不是一个简单的API包装器而是一个充分利用Kotlin语言特性如协程、流、多平台支持构建的现代化、类型安全、且开发者体验极佳的SDK。简单来说openai-kotlin让你能用最“Kotlin”的方式调用OpenAI的各种服务。想象一下你不再需要手动拼接JSON、操心HTTP客户端配置而是像调用本地函数一样使用suspend函数发起一个聊天请求或者用Flow来优雅地处理一个字一个字蹦出来的流式回复。这个库帮你处理了所有底层细节包括认证、重试、多平台兼容性让你能专注于构建应用逻辑本身。无论是想在Android App里加个智能助手还是在Kotlin后端服务中集成内容生成它都能大幅提升你的开发效率。2. 核心设计理念与架构解析2.1 为什么选择Kotlin Multiplatformopenai-kotlin最引人注目的特性之一就是其Kotlin MultiplatformKMP支持。这意味着同一套代码经过编译可以运行在JVMAndroid、Spring Boot后端、iOS通过Kotlin/Native、JavaScript浏览器或Node.js甚至原生桌面环境上。这种设计并非炫技而是有深刻的实用考量。首先代码复用最大化。对于同时维护Android和iOS客户端的团队使用这个库意味着两端的AI集成逻辑可以完全一致无需分别用Java/Kotlin和Swift去实现两套网络层。后端JVM和前端JS也能共享同一套高质量的类型定义和业务逻辑。其次统一开发者体验。无论你在哪个平台上开发使用的API、错误处理方式、配置方法都是一样的。这降低了上下文切换的成本也让团队内的知识传递更加顺畅。最后拥抱未来生态。KMP是JetBrains和Kotlin社区重点推进的方向越来越多的库开始提供多平台支持。openai-kotlin选择KMP使其能够无缝融入这个不断壮大的生态系统比如与Ktor Client其底层网络库的多平台特性完美结合。2.2 类型安全与空安全从源头杜绝错误OpenAI的API参数繁多模型名、温度值、最大token数等等任何一个参数传错类型或值域都会导致请求失败。传统的做法可能是用一个MapString, Any或者可空性模糊的数据类来承载请求体这为运行时错误埋下了隐患。openai-kotlin充分利用了Kotlin强大的类型系统。它为每一个API如Chat Completion、Image Generation都定义了详尽的数据类data class。这些类的属性使用了恰当的类型如Double表示温度Int表示最大token数和可空性标记?。编译器会在你编写代码时就帮你检查类型是否匹配、非空参数是否已提供。例如创建一个聊天请求val request ChatCompletionRequest( model ModelId(gpt-3.5-turbo), messages listOf( ChatMessage( role ChatRole.User, content Content.Text(Hello, world!) ) ), temperature 0.7, // 明确的Double类型 maxTokens 100 // 明确的Int类型 )如果你不小心把model设成了null或者给temperature传了一个StringIDE会立刻报错而不是等到运行时才收到一个晦涩的API错误响应。这种编译期检查极大地提高了代码的健壮性和开发效率。2.3 协程与流异步处理的现代范式OpenAI的API调用本质上是网络I/O操作天生就是异步的。库全面拥抱Kotlin协程Coroutines和流Flow来处理异步编程。所有执行网络请求的函数都是suspend函数。这意味着你可以用同步的书写方式处理异步逻辑告别回调地狱callback hell。在协程作用域内你可以直接val response openAI.chatCompletion(request)代码清晰易读。对于聊天补全Chat Completion等支持流式响应streaming的API库返回一个FlowChatCompletionChunk。流Flow是Kotlin中处理异步数据序列的利器。你可以像操作集合一样对返回的token流进行变换、过滤和收集openAI.chatCompletions(request) // 返回 FlowChatCompletionChunk .onEach { chunk - // 每收到一个chunk包含部分token就实时更新UI val delta chunk.choices.firstOrNull()?.delta?.content delta?.let { appendToUI(it) } } .catch { e - showError(e) } .launchIn(scope)这种模式非常适合需要实时显示生成结果的场景比如仿ChatGPT的对话界面用户体验非常流畅。3. 快速上手指南与核心API详解3.1 环境配置与客户端初始化首先在你的Kotlin项目中添加依赖。以GradleKotlin DSL为例对于JVM项目dependencies { implementation(com.aallam.openai:openai-client:3.7.0) // 请检查最新版本 // 还需要一个Ktor引擎依赖例如对于Android或OkHttp环境 implementation(io.ktor:ktor-client-okhttp:2.3.7) }对于多平台项目你需要在commonMain源集中添加openai-client依赖并在各平台如androidMain、iosMain添加对应的Ktor引擎依赖。接下来是初始化OpenAI客户端。核心是构建一个OpenAI实例最关键的是需要你的API Key。import com.aallam.openai.api.http.Timeout import com.aallam.openai.client.OpenAI import io.ktor.client.engine.okhttp.OkHttp import kotlin.time.Duration.Companion.seconds val openAI OpenAI( token sk-your-api-key-here, // 你的OpenAI API Key timeout Timeout(socket 60.seconds), // 设置超时 engine OkHttp.create() // 指定Ktor引擎这里用OkHttp )注意API Key是最高机密绝对不要硬编码在代码中或提交到版本控制系统如Git。务必通过环境变量、构建配置文件或安全的密钥管理服务来注入。例如可以从环境变量读取token System.getenv(OPENAI_API_KEY)。Timeout配置非常重要特别是对于生成较长文本的请求默认超时时间可能不够。engine的选择取决于你的目标平台JVM/Android上常用OkHttpiOS上用DarwinJS上用Js或Curl。3.2 聊天补全对话的核心这是最常用的功能。核心是构建ChatCompletionRequest并调用chatCompletion非流式或chatCompletions流式方法。非流式调用一次性获取完整回复suspend fun getChatResponse(prompt: String): String { val request ChatCompletionRequest( model ModelId(gpt-4), // 指定模型 messages listOf( ChatMessage(role ChatRole.System, content Content.Text(你是一个有用的助手。)), ChatMessage(role ChatRole.User, content Content.Text(prompt)) ), temperature 0.8, // 控制随机性0-2越高越随机 maxTokens 500 // 控制回复最大长度 ) val response: ChatCompletion openAI.chatCompletion(request) return response.choices.first().message.content.orEmpty() }这里的ChatMessage支持多种角色System,User,Assistant,Tool,Function方便构建多轮对话上下文。temperature参数是关键如果你需要确定性的、事实性的回答如代码生成可以设低一点如0.1-0.3如果需要创造性、多样性的回答如写诗、讲故事可以设高一点如0.7-1.0。流式调用实时逐字输出suspend fun streamChatResponse(prompt: String): FlowString flow { val request ChatCompletionRequest(...) // 同上构建请求 openAI.chatCompletions(request).collect { chunk - val content chunk.choices.firstOrNull()?.delta?.content content?.let { emit(it) } // 将每个token增量发射到流中 } } // 在UI层如Compose或Android ViewModel中收集这个流 viewModelScope.launch { streamChatResponse(讲个故事).collect { token - _uiState.update { it.copy(accumulatedText token) } } }流式调用能极大提升用户感知速度实现“打字机”效果。注意处理每个chunk它包含的是本次增量delta而不是完整的消息。3.3 其他重要API速览除了聊天库还完整支持了OpenAI的其他核心功能1. 嵌入Embeddings用于将文本转换为高维向量是语义搜索、聚类、推荐的基础。suspend fun getEmbedding(text: String): ListDouble { val request EmbeddingRequest( model ModelId(text-embedding-3-small), input listOf(text) // 支持批量输入 ) val response: EmbeddingResponse openAI.embedding(request) return response.data.first().embedding }返回的向量浮点数列表可以存入向量数据库如Pinecone、Weaviate供后续检索。2. 图像生成DALL·E根据描述生成图像。suspend fun generateImage(prompt: String): String? { val request ImageCreation( prompt prompt, model ModelId(dall-e-3), // 或 dall-e-2 size ImageSize.is1024x1024, // 尺寸枚举 quality ImageQuality.Standard, // 质量标准 style ImageStyle.Natural // 风格生动或自然 ) val response: ImageURL openAI.imageURL(request) // 返回URL // 或者使用 openAI.imageJSON(request) 返回Base64编码 return response.url }注意DALL·E 3在质量和提示词理解上比DALL·E 2有显著提升但成本也更高。3. 音频转录与翻译Whisper将音频文件转换为文字。suspend fun transcribeAudio(audioFile: File): String { val request TranscriptionRequest( audio AudioSource(audioFile), model ModelId(whisper-1), responseFormat AudioResponseFormat.VerboseJson // 返回详细JSON ) val response: Transcription openAI.transcription(request) return response.text }库支持从File、ByteArray等多种来源读取音频。翻译功能类似只需调用openAI.translation并指定目标语言目前Whisper主要支持翻译成英文。4. 微调Fine-tuning用于定制专属模型流程较为复杂涉及上传训练数据、创建微调任务、轮询状态等。库提供了相应的API但通常用于后台作业管理。4. 高级特性与最佳实践4.1 文件上传与处理一些功能如微调、音频转录需要上传文件。库通过kotlinx.io库提供了便捷的文件处理抽象。你需要将文件转换为BinaryData或AudioSource等类型。例如为微调准备训练数据JSONL格式val trainingFile File(path/to/training_data.jsonl) val binaryData BinaryData(trainingFile.readBytes(), application/jsonl) val uploadRequest FileUpload( file binaryData, purpose Purpose.FineTune // 指定用途 ) val uploadedFile: OpenAIFile openAI.upload(uploadRequest) println(文件已上传ID: ${uploadedFile.id})上传后你会获得一个文件ID在后续的微调任务创建请求中需要引用它。记得管理文件的生命周期不需要时通过openAI.deleteFile(fileId)进行删除。4.2 函数调用Function Calling集成函数调用是让大模型与外部工具/API交互的强大能力。openai-kotlin对此有很好的支持。首先你需要定义函数工具的描述val getWeatherTool ChatTool( function ChatFunction( name get_current_weather, description 获取指定城市的当前天气, parameters JsonSchema( type JsonType.Object, properties mapOf( location to JsonSchema( type JsonType.String, description 城市名例如北京上海 ), unit to JsonSchema( type JsonType.String, enumValues listOf(celsius, fahrenheit), description 温度单位 ) ), required listOf(location) ) ) )然后在聊天请求中传入工具列表并设置toolChoice为autoval request ChatCompletionRequest( model ModelId(gpt-3.5-turbo), messages messages, tools listOf(getWeatherTool), toolChoice ChatToolChoice.Auto // 让模型决定是否调用 )当模型的回复中finishReason为tool_calls时表示它希望调用函数。你需要解析choice.message.toolCalls执行相应的本地函数如真正调用一个天气API然后将执行结果作为一条新的Tool角色消息追加到对话历史中再次请求模型让它生成面向用户的总结。这个过程虽然有些繁琐但库提供了完整的类型ChatToolCall,ChatTool来帮助你安全地解析和处理。4.3 配置与自定义打造健壮的客户端默认配置可能不适合所有生产环境你可以通过OpenAIConfig进行深度定制。1. 自定义HTTP客户端底层Ktor客户端可以完全自定义。val httpClient HttpClient(OkHttp) { install(ContentNegotiation) { json() } // 安装JSON序列化 engine { // 配置OkHttp引擎 config { connectTimeout(30, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS) } } defaultRequest { // 默认请求头等 header(HttpHeaders.UserAgent, MyApp/1.0) } } val openAI OpenAI(token sk-..., httpClient httpClient)这样你可以添加拦截器如日志拦截器、配置代理、管理连接池等。2. 重试与容错网络请求可能失败实现简单的重试逻辑能提升稳定性。suspend fun T withRetry( maxRetries: Int 3, initialDelay: Long 1000, block: suspend () - T ): T { var currentDelay initialDelay repeat(maxRetries) { attempt - try { return block() } catch (e: Exception) { if (attempt maxRetries - 1) throw e if (e is OpenAIException e.status in listOf(429, 500, 502, 503)) { // 针对速率限制或服务器错误进行延迟重试 delay(currentDelay) currentDelay * 2 // 指数退避 } else { // 其他错误如4xx客户端错误通常不重试 throw e } } } throw IllegalStateException(Unreachable) } // 使用 val response withRetry { openAI.chatCompletion(request) }对于更复杂的场景可以考虑使用retry库它提供了更灵活的重试策略。3. 请求日志与监控在生产环境中记录请求和响应注意脱敏API Key对于调试和成本监控至关重要。你可以通过自定义Ktor的HttpClient插件或拦截器来实现。class LoggingInterceptor : HttpRequestInterceptor { override suspend fun intercept(request: HttpRequestBuilder, context: HttpRequestContext) { println(Request: ${request.url} | Headers: ${request.headers}) // 注意不要在这里打印包含API Key的Authorization头 } } // 将拦截器安装到HttpClient配置中5. 实战场景与性能优化5.1 场景一构建一个Android智能助手App假设我们要开发一个Android App具备聊天、根据描述生成图片、总结长文章通过嵌入和摘要的功能。架构设计采用MVVM模式在ViewModel或UseCase层注入OpenAI客户端实例。使用依赖注入框架如Hilt或Koin管理其生命周期。// AppModule.kt Module InstallIn(SingletonComponent::class) object AppModule { Provides Singleton fun provideOpenAI(ApplicationContext context: Context): OpenAI { val token Secrets.getApiKey(context) // 从安全存储获取 return OpenAI( token token, timeout Timeout(socket 90.seconds), engine OkHttp.create { // 可配置Android特定的OkHttp参数 } ) } } // ChatViewModel.kt HiltViewModel class ChatViewModel Inject constructor( private val openAI: OpenAI, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val _chatState MutableStateFlow(ChatUiState()) val chatState: StateFlowChatUiState _chatState.asStateFlow() fun sendMessage(userInput: String) { viewModelScope.launch { _chatState.update { it.copy(isLoading true) } try { val messages buildMessages(userInput) // 构建包含历史的对话列表 val request ChatCompletionRequest(...) openAI.chatCompletions(request) // 使用流式 .onEach { chunk - ... } // 更新UI状态 .catch { e - handleError(e) } .collect() } catch (e: Exception) { handleError(e) } finally { _chatState.update { it.copy(isLoading false) } } } } }关键点生命周期管理确保网络请求在ViewModel作用域内发起页面销毁时自动取消。状态管理使用StateFlow或MutableState管理UI状态配合Compose实现响应式UI。错误处理统一捕获OpenAIException库自定义的异常根据其status和message向用户展示友好提示如“网络超时”、“额度不足”、“内容被过滤”。5.2 场景二后端服务批量处理与缓存在后端你可能需要处理大量文本例如为商品描述生成嵌入向量并存入向量数据库。批量处理优化OpenAI的嵌入API支持批量输入但单次请求有token总数限制。需要实现分批处理逻辑。suspend fun batchGenerateEmbeddings(texts: ListString): MapString, ListDouble { val batchSize 20 // 根据模型token限制调整text-embedding-3-small约8192 tokens val results mutableMapOfString, ListDouble() texts.chunked(batchSize).forEach { batch - val request EmbeddingRequest( model ModelId(text-embedding-3-small), input batch, encodingFormat EncodingFormat.Float // 或 .Base64 ) val response openAI.embedding(request) batch.zip(response.data).forEach { (originalText, embeddingData) - results[originalText] embeddingData.embedding } delay(100) // 简单的请求间隔避免触发速率限制 } return results }嵌入向量缓存对于不常变动的文本如商品描述、文章其嵌入向量是固定的。重复计算浪费API调用和金钱。引入缓存层如Redis至关重要。class EmbeddingService( private val openAI: OpenAI, private val cache: CacheString, ListDouble // 例如使用Caffeine或Redis客户端 ) { suspend fun getEmbedding(text: String): ListDouble { val cacheKey embed:${text.hashCode()} // 简单示例生产环境需更健壮的Key return cache.get(cacheKey) { val request EmbeddingRequest(...) openAI.embedding(request).data.first().embedding } } }缓存策略需要根据数据更新频率和存储成本来制定。5.3 成本控制与监控OpenAI API按token计费成本是需要密切关注的问题。1. 估算Token数量在发起请求前特别是对于长文本估算token数有助于预测成本和避免超出模型上下文限制。// 注意openai-kotlin库本身不提供token计数功能但可以集成tiktoken库需自行寻找Kotlin/Java版本或通过JVM调用Python // 以下是一个简化示例思路 fun estimateTokens(text: String, model: String): Int { // 简单规则对于英文近似按单词数*1.3估算中文按字符数*2估算。 // 生产环境应使用更准确的算法或调用外部服务。 return if (model.contains(gpt-4)) { text.length * 2 // 非常粗略的估算 } else { (text.split(\\s.toRegex()).size * 1.3).toInt() } } // 在构建请求前检查 val estimatedTokens estimateTokens(userInput, gpt-4) if (estimatedTokens 8000) { // 提示用户输入过长或自动截断 }2. 记录与审计记录每一次API调用的模型、输入输出token数、成本可事后根据OpenAI定价表计算。data class ApiCallLog( val timestamp: Instant, val endpoint: String, val model: String, val promptTokens: Int, val completionTokens: Int, val totalTokens: Int, val estimatedCost: Double ) suspend fun T callWithLogging( operation: String, model: String, block: suspend () - T ): T { val startTime System.currentTimeMillis() val result block() // 注意非流式响应可直接从response对象获取usage信息 // 流式响应需要累加每个chunk中的usage如果提供 val usage // ... 从result中提取或估算usage val log ApiCallLog(...) saveLogToDb(log) // 存入数据库或发送到监控系统 return result }定期分析这些日志找出消耗大的端点或用户优化使用策略。6. 常见问题排查与调试技巧6.1 网络与连接问题问题请求超时或连接被拒绝。排查检查API Key和端点确认token正确且没有多余的空格。默认端点是api.openai.com如果你使用Azure OpenAI或代理需要通过自定义OpenAIConfig或HttpClient的defaultRequest来修改base URL。调整超时设置对于生成长文本或嵌入大量内容增加socket和request超时时间。检查网络环境确保运行环境能访问OpenAI服务。在某些地区或网络下可能需要配置代理。这需要在自定义的HttpClient引擎中设置。// 示例在JVM上通过OkHttp配置代理注意此仅为技术示例请确保符合当地法律法规和网络使用政策 val proxy Proxy(Proxy.Type.HTTP, InetSocketAddress(proxy-host, 8080)) val okHttpClient OkHttpClient.Builder().proxy(proxy).build() val engine OkHttp.create(okHttpClient)查看详细日志启用Ktor客户端的日志拦截器查看原始的HTTP请求和响应头注意屏蔽敏感信息。6.2 API错误与异常处理库会抛出OpenAIException其中包含HTTP状态码和错误信息。状态码常见原因解决方案401API Key无效、过期或格式错误。检查Key是否正确是否包含sk-前缀在OpenAI平台确认是否有效。429达到速率限制RPM/TPM或请求过快。降低请求频率实现指数退避重试逻辑。检查控制台的用量限制。400请求参数错误如模型不存在、参数值超出范围、消息格式错误。仔细检查请求体特别是model名称、messages数组结构、temperature范围(0-2)等。使用库的类型安全构建器能避免很多此类错误。500 / 503OpenAI服务器内部错误。等待一段时间后重试。如果是持续性问题查看OpenAI状态页面。其他4xx如403可能表示模型权限不足如未开通GPT-4权限。在OpenAI平台检查账户权限和模型访问列表。处理示例try { val response openAI.chatCompletion(request) } catch (e: OpenAIException) { when (e.status) { 401 - showError(认证失败请检查API Key。) 429 - { showError(请求过于频繁请稍后再试。) // 可以在这里触发带退避的重试 } 400 - { // 解析e.message或e.body获取更详细错误 val errorDetail e.body?.toString() ?: e.message showError(请求参数有误: $errorDetail) } else - showError(服务异常 (${e.status}): ${e.message}) } } catch (e: IOException) { showError(网络连接异常: ${e.message}) } catch (e: Exception) { showError(未知错误: ${e.message}) }6.3 流式响应中断或不完整问题使用chatCompletions流式请求时流提前结束或内容不完整。排查检查上下文长度确保对话历史所有messages的token总和加上maxTokens没有超过模型的上限如gpt-3.5-turbo通常是4096或16384。超限会导致生成被截断。处理finish_reason每个流式chunk或最终的非流式响应中choice.finishReason字段解释了生成停止的原因。常见值有stop: 遇到停止序列如\n\n或正常结束。length: 达到max_tokens限制。content_filter: 内容被安全系统过滤。tool_calls: 模型决定调用函数。 在流式收集结束时检查最后一个有效chunk的finishReason如果不是stop可以提示用户如“回答因长度限制被截断请尝试缩短问题。”。网络稳定性流式连接对网络稳定性要求更高。确保客户端有妥善的网络状态监听和重连机制。可以考虑在UI层提供“继续生成”的按钮在中断时用已有的对话历史重新发起请求。6.4 多平台项目的特殊问题iOS平台引擎选择在iOS的iosMain源集中依赖io.ktor:ktor-client-darwin引擎。权限如果涉及网络请求确保iOS项目的Info.plist中已配置NSAppTransportSecurity或允许相应域名。并发Kotlin/Native的并发模型与JVM不同。确保在正确的线程/调度器上启动协程和收集Flow。使用Dispatchers.Main来更新UI。JavaScript平台CORS在浏览器中直接调用OpenAI API会遇到CORS限制。通常的解决方案是通过自己的后端服务器进行代理转发而不是从前端直接调用。openai-kotlin在JS环境下的典型用法是在Node.js后端服务中运行。Bundle大小注意引入的库会增加前端Bundle体积如果用于浏览器前端需进行Tree Shaking优化。7. 总结与进阶方向aallam/openai-kotlin库将OpenAI强大的API与Kotlin优雅的语言特性紧密结合为Kotlin开发者提供了高效、安全、愉悦的开发体验。从简单的聊天机器人到复杂的多模态AI应用它都能胜任。掌握其核心用法——类型安全的请求构建、协程与流的异步处理、多平台的支持——是第一步。在实际项目中你还需要关注密钥安全管理永远不要暴露API Key。错误恢复与用户体验设计鲁棒的错误处理给用户清晰的反馈。成本与性能监控建立监控体系了解使用模式和开销。提示工程库是工具模型的效果很大程度上取决于你构建的提示Prompt。深入学习和实践提示工程技巧。随着OpenAI API的迭代如新模型的发布、新参数的加入库也会持续更新。关注项目的GitHub仓库及时了解新特性和Breaking Changes。同时社区也围绕该库构建了一些扩展工具或示例项目值得探索。最终将AI能力无缝、可靠地集成到你的产品中创造真正的用户价值才是这一切技术实践的最终目标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2608392.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;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…