Java工程化落地:封装稳定可复用的大模型对话服务组件
1. 从“能跑”到“好用”为什么第三篇要聊工程化落地前两篇聊完环境搭建和基础对话之后后台收到最多的反馈不是“怎么调用”而是“调通了但一放进项目就乱套”。这个反馈特别真实。用 Java 接大模型接口写个main方法跑通一次请求半小时就能搞定但真要把它塞进一个正经的 Spring Boot 工程让它稳定地服务几十上百个调用方问题就全冒出来了——超时怎么设、重试怎么做、流式响应怎么接、并发上来了线程池怎么配、返回的 JSON 解析偶尔炸掉怎么兜底。这些才是“编程实用”这四个字真正的分量所在。这篇就专门解决这一层。核心关键词还是ChatGPT、Java、编程但视角从“怎么调通”切换到“怎么调得稳、调得省、调得好维护”。我会围绕一个典型的 Java 后端场景展开把大模型对话能力封装成一个可复用的服务组件对外提供同步和流式两种接口内部处理好连接管理、异常重试、响应解析和成本控制。适合已经跑通过一次基础请求、准备把它接入真实业务系统的 Java 工程师也适合正在做技术选型、想评估“这套东西到底能不能上生产”的架构同学。需要先说明一点下面所有代码和配置都是基于常见工程实践给出的参考实现不是某个特定厂商的官方文档。不同服务商的接口路径、鉴权方式、字段命名会有差异但底层的工程思路是通用的——你把 URL 和字段名换掉骨架照样能用。这也是我写这个系列一直坚持的原则教方法不教死记硬背某个接口。2. 整体架构设计一个可复用的对话服务该怎么分层2.1 先想清楚边界哪些事该由 Java 侧负责很多人一上来就纠结“用哪个 HTTP 客户端”其实这是最不该先纠结的问题。真正要先定的是职责边界。我的经验是把整个链路切成四层每层只干一件事接入层对外暴露 REST 接口负责参数校验、鉴权、限流不碰任何模型相关的逻辑。编排层也就是 Service负责组装提示词、管理对话上下文、决定调用哪个模型、处理重试和降级。通信层封装 HTTP 调用处理连接池、超时、序列化反序列化是唯一直接和外部接口打交道的地方。配置层把密钥、模型名、超时时间、重试次数这些全部外置到配置文件代码里不出现任何硬编码。这么分的好处等你要换服务商的时候就体现出来了——只需要改通信层和配置层编排层和接入层几乎不动。我见过太多项目把 URL 和密钥直接写死在 Service 里结果换个模型要改十几个文件那才叫痛苦。2.2 技术选型为什么我最终选了这套组合选型这块我踩过坑直接说结论和理由。HTTP 客户端我用的是OkHttp。原因很实在它对连接池的管理足够成熟支持 HTTP/2流式响应的处理也顺手。有人会问为什么不直接用 Spring 的RestTemplate或WebClient。RestTemplate在处理流式响应SSE时比较别扭需要自己包一层WebClient是响应式的功能没问题但如果你的项目本身是传统阻塞式架构引入它会把整条链路的编程模型搞复杂。OkHttp 在阻塞式场景下最省心而且它本身就是很多框架的底层依赖等于没有额外负担。JSON 解析用Jackson这个基本没争议Spring Boot 默认就带。关键是配置好忽略未知字段因为大模型返回的 JSON 结构偶尔会多出一些你没预期的字段不配置的话直接抛异常。重试和熔断我倾向用Resilience4j而不是老牌的 Hystrix。Hystrix 已经停止维护了Resilience4j 更轻量和 Spring Boot 集成也干净。不过如果你的项目规模不大其实手写一个简单的重试循环也够用不必为了用而用。组件选型核心理由替代方案HTTP 客户端OkHttp连接池成熟、流式处理顺手WebClient响应式项目JSON 解析JacksonSpring 生态默认、配置灵活Gson、Fastjson2重试熔断Resilience4j轻量、维护活跃手写重试、Sentinel配置管理Spring Config外置化、支持多环境环境变量、配置中心2.3 目录结构让新人一眼看懂代码在哪结构清晰比什么都重要。我习惯按职责分包而不是按技术分层com.example.aidialog ├── config // 配置类读取 yml 参数 ├── controller // 接入层REST 接口 ├── service // 编排层业务逻辑 │ ├── DialogService.java │ └── impl ├── client // 通信层HTTP 调用封装 │ └── ChatClient.java ├── model // 请求/响应数据模型 │ ├── request │ └── response └── common // 通用工具、异常、常量这样分包你找“调用外部接口的代码”就去client找“业务逻辑”就去service不用在十几个平铺的类里翻。团队协作时这个优势会被无限放大。3. 核心细节拆解那些文档里不会写的关键点3.1 超时设置一个数字决定系统会不会雪崩超时是新手最容易忽略、老手最重视的参数。大模型接口的响应时间波动很大简单问题可能一两秒复杂推理可能几十秒。如果你把超时设成默认的“无限等待”那么一旦上游变慢你的线程会被大量占住线程池很快耗尽整个服务跟着挂掉——这就是典型的雪崩。我的做法是分两级设置连接超时设短一点5 秒足够。连都连不上等再久也没意义。读取超时设长一点但要结合业务。同步接口我一般设 60 秒流式接口设 120 秒甚至更长因为流式是边生成边返回总时长本来就长。OkHttpClient client new OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .connectionPool(new ConnectionPool(20, 5, TimeUnit.MINUTES)) .build();注意读取超时不是越大越好。设成 300 秒意味着一个卡住的请求会占用线程 5 分钟并发一高照样拖垮服务。合理做法是配合重试和降级超时后快速失败而不是死等。连接池这里我设了最大 20 个空闲连接、保活 5 分钟。这个数字怎么来的假设你的服务 QPS 峰值是 50平均响应 2 秒那么并发连接数大约是 100。连接池不用设到 100因为连接是复用的20 到 30 个空闲连接足够应对大部分波动。设太大反而浪费资源。3.2 重试策略不是所有失败都值得重试重试这件事做对了是救命稻草做错了是火上浇油。核心原则是只重试那些“重试有可能成功”的错误。网络抖动、连接超时、5xx 服务端错误值得重试。401 鉴权失败、400 参数错误、429 限流重试基本没用401 和 400 重试一百次还是错429 重试反而加重限流。我一般用指数退避第一次等 1 秒第二次等 2 秒第三次等 4 秒最多重试 3 次。这样既给了上游恢复的时间又不会把请求堆积起来。int maxRetries 3; long baseDelay 1000L; for (int i 0; i maxRetries; i) { try { return doRequest(); } catch (RetryableException e) { if (i maxRetries) throw e; long delay baseDelay * (1L i); Thread.sleep(delay); } }实操心得重试一定要加“抖动”也就是在延迟时间上加一个随机值。否则多个请求同时失败、同时重试会在同一时刻再次冲击上游形成“重试风暴”。加个 random(0, 500)毫秒就能缓解。3.3 流式响应SSE 解析的正确姿势流式响应是提升用户体验的利器用户不用干等几十秒才看到结果而是像打字一样一个字一个字蹦出来。但它的解析比普通 JSON 麻烦因为返回的是一行一行的文本流格式类似data: {...}。关键点有三个。第一要按行读取遇到空行或特定结束标记就停止。第二每行的data:前缀要剥掉剩下的才是 JSON。第三要处理“半包”问题——网络传输是按块来的一行数据可能被切成两次到达所以要用缓冲区分行不能读一次就当完整行处理。BufferedReader reader new BufferedReader( new InputStreamReader(response.body().byteStream(), StandardCharsets.UTF_8)); String line; while ((line reader.readLine()) ! null) { if (line.startsWith(data:)) { String json line.substring(5).trim(); if ([DONE].equals(json)) break; // 解析 json 并推送 } }readLine()这个方法本身就帮你处理了跨块拼接的问题所以用 BufferedReader 是最省事的方案。如果你自己用字节数组拼很容易在边界上出错。3.4 上下文管理别让对话无限增长多轮对话要带上历史消息但历史不能无限带。一方面模型的上下文窗口有上限超了会报错另一方面历史越长每次请求消耗的 token 越多成本直线上升。我的策略是“滑动窗口 摘要”。保留最近 N 轮完整对话比如 10 轮更早的内容压缩成一段摘要放在系统提示里。这样既保留了长期记忆的轮廓又控制了 token 消耗。private ListMessage trimHistory(ListMessage history, int maxRounds) { if (history.size() maxRounds * 2) return history; ListMessage recent history.subList(history.size() - maxRounds * 2, history.size()); ListMessage result new ArrayList(); result.add(buildSummaryMessage(history.subList(0, history.size() - maxRounds * 2))); result.addAll(recent); return result; }注意摘要本身也要调用模型生成这又是一次成本。所以更省的做法是只保留最近几轮把更早的直接丢弃除非业务确实需要长期记忆。别为了“看起来高级”而增加不必要的开销。4. 完整实操从零封装一个对话服务组件4.1 配置文件把所有可变项外置先看配置。我习惯用application.yml把密钥、模型、超时、重试全部放进去代码里通过ConfigurationProperties读取。ai: dialog: base-url: https://api.example.com/v1 api-key: ${AI_API_KEY} model: gpt-4o-mini connect-timeout: 5 read-timeout: 60 max-retries: 3 max-history-rounds: 10密钥用环境变量注入绝对不要写死在 yml 里提交到代码仓库。这是安全底线我见过太多因为密钥泄露被刷爆账单的案例。对应的配置类Data ConfigurationProperties(prefix ai.dialog) public class DialogProperties { private String baseUrl; private String apiKey; private String model; private int connectTimeout 5; private int readTimeout 60; private int maxRetries 3; private int maxHistoryRounds 10; }4.2 通信层封装 HTTP 调用通信层只干一件事发请求、收响应。它不关心业务也不关心上下文。Slf4j Component public class ChatClient { private final OkHttpClient httpClient; private final DialogProperties props; private final ObjectMapper objectMapper; public ChatClient(DialogProperties props, ObjectMapper objectMapper) { this.props props; this.objectMapper objectMapper; this.httpClient new OkHttpClient.Builder() .connectTimeout(props.getConnectTimeout(), TimeUnit.SECONDS) .readTimeout(props.getReadTimeout(), TimeUnit.SECONDS) .build(); } public ChatResponse send(ChatRequest request) throws IOException { String body objectMapper.writeValueAsString(request); Request httpRequest new Request.Builder() .url(props.getBaseUrl() /chat/completions) .header(Authorization, Bearer props.getApiKey()) .header(Content-Type, application/json) .post(RequestBody.create(body, MediaType.parse(application/json))) .build(); try (Response response httpClient.newCall(httpRequest).execute()) { if (!response.isSuccessful()) { throw new ApiException(response.code(), response.message()); } String respBody response.body().string(); return objectMapper.readValue(respBody, ChatResponse.class); } } }这里有个细节objectMapper要配置FAIL_ON_UNKNOWN_PROPERTIES false否则上游多返回一个字段就炸。objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);4.3 编排层组装请求、管理上下文、处理重试编排层是核心它把零散的能力串成完整的业务逻辑。Slf4j Service public class DialogServiceImpl implements DialogService { private final ChatClient chatClient; private final DialogProperties props; private final MapString, ListMessage sessionStore new ConcurrentHashMap(); Override public String chat(String sessionId, String userInput) { ListMessage history sessionStore.computeIfAbsent(sessionId, k - new ArrayList()); history.add(Message.user(userInput)); ListMessage trimmed trimHistory(history, props.getMaxHistoryRounds()); ChatRequest request ChatRequest.builder() .model(props.getModel()) .messages(trimmed) .build(); ChatResponse response executeWithRetry(request); String reply response.getChoices().get(0).getMessage().getContent(); history.add(Message.assistant(reply)); return reply; } private ChatResponse executeWithRetry(ChatRequest request) { int retries props.getMaxRetries(); for (int i 0; i retries; i) { try { return chatClient.send(request); } catch (ApiException e) { if (!isRetryable(e.getCode()) || i retries) throw e; sleepWithJitter(i); } catch (IOException e) { if (i retries) throw new RuntimeException(请求失败, e); sleepWithJitter(i); } } throw new IllegalStateException(unreachable); } private boolean isRetryable(int code) { return code 500 || code 429; } private void sleepWithJitter(int attempt) { long delay 1000L * (1L attempt) ThreadLocalRandom.current().nextLong(500); try { Thread.sleep(delay); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }这段代码里有几个值得说的点。sessionStore用ConcurrentHashMap是为了线程安全但要注意它只适合单机场景多实例部署时要用 Redis 之类的共享存储替换。isRetryable明确区分了可重试和不可重试的错误码这是前面强调过的原则。sleepWithJitter加了随机抖动避免重试风暴。4.4 接入层对外暴露干净的接口接入层要做的就是把 Service 包一层 HTTP 接口加上参数校验。RestController RequestMapping(/api/dialog) public class DialogController { private final DialogService dialogService; PostMapping(/chat) public ResponseEntityChatResult chat(RequestBody Valid ChatParam param) { String reply dialogService.chat(param.getSessionId(), param.getInput()); return ResponseEntity.ok(new ChatResult(reply)); } }参数校验用Valid配合NotBlank之类的注解把非法请求挡在业务逻辑之前。这样 Service 里就不用写一堆 if 判断了。4.5 流式接口让用户看到“打字”效果流式接口和同步接口的区别在于返回类型。Spring 里可以用SseEmitter来实现。GetMapping(/stream) public SseEmitter stream(RequestParam String sessionId, RequestParam String input) { SseEmitter emitter new SseEmitter(120_000L); executor.execute(() - { try { chatClient.stream(request, chunk - { emitter.send(SseEmitter.event().data(chunk)); }); emitter.complete(); } catch (Exception e) { emitter.completeWithError(e); } }); return emitter; }注意SseEmitter的超时时间要和读取超时匹配否则会出现“上游还在生成下游已经断开”的尴尬情况。另外流式接口一定要放在独立的线程池里执行不能占用 Web 容器的请求线程否则并发一上来就堵死了。5. 常见问题与排查技巧实录5.1 高频问题速查表现象可能原因排查方向解决方式请求一直卡住不返回读取超时未设置检查 OkHttpClient 配置设置合理的 readTimeout偶发 JSON 解析失败上游返回字段变化打印原始响应体关闭 FAIL_ON_UNKNOWN_PROPERTIES并发高时线程耗尽同步调用阻塞线程查看线程池状态用独立线程池 流式异步429 限流频繁请求频率过高统计 QPS加限流 退避重试流式响应断断续续缓冲区未刷新检查输出流每次 send 后 flush上下文超长报错历史消息过多统计 token 数滑动窗口裁剪历史密钥无效 401环境变量未注入检查配置读取确认密钥加载顺序5.2 三个我踩过的坑第一个坑把 ObjectMapper 当全局单例乱配。有一次我在一个工具类里new ObjectMapper()并改了配置结果影响了别的地方的序列化行为排查了半天。后来统一用 Spring 注入的ObjectMapper需要特殊配置就单独建一个实例绝不污染全局。第二个坑重试把非幂等操作搞重复了。对话接口本身是幂等的同样输入同样输出重试没问题。但如果你在调用前后还做了“扣费”“写日志”这类操作重试就会导致重复扣费。所以重试的边界一定要画清楚只包住纯查询的部分。第三个坑流式接口没做背压。上游生成很快下游消费很慢中间没有缓冲结果内存里堆积了大量待发送的数据。解决办法是给发送队列设一个上限超了就暂停读取上游等下游消费完再继续。这个在SseEmitter场景下尤其要注意。5.3 成本控制的几个实用技巧大模型调用是按 token 计费的用不好账单会很吓人。几个我实测有效的做法选对模型简单任务用便宜的小模型复杂推理才上大模型。很多场景小模型完全够用。精简提示词系统提示别写太长每多一个字都是钱。把固定不变的部分缓存起来。限制输出长度设置max_tokens防止模型“话痨”输出一大堆无关内容。缓存重复请求相同的问题直接返回缓存结果尤其是那些高频的固定问答。// 设置最大输出 token控制成本 request.setMaxTokens(500);实操心得上线前一定要做一次压测统计平均每次请求的 token 消耗乘以预估的日调用量算出月度成本。我见过一个项目没算这笔账上线一周账单超预算十倍就是因为没限制输出长度模型每次都返回一大段。6. 工程化收尾让这套东西真正能上生产6.1 可观测性没有监控等于裸奔服务上线后你必须能回答三个问题请求成功了多少、失败了多少、平均耗时多少。这三个指标用 Micrometer 配合 Prometheus 就能搞定。Timer.Sample sample Timer.start(meterRegistry); try { return dialogService.chat(sessionId, input); } finally { sample.stop(meterRegistry.timer(ai.dialog.latency)); }除了耗时还要记录 token 消耗量这样才能和账单对上。每次响应里通常都会带 token 使用信息把它提取出来打到监控里。6.2 降级方案上游挂了怎么办大模型服务不是百分之百可用的总会有抖动的时候。这时候不能直接给用户报错要有降级方案。我的做法是准备一批常见问题的预设答案当检测到上游连续失败超过阈值时切换到本地答案库至少保证服务不中断。if (circuitBreaker.isOpen()) { return fallbackAnswers.getOrDefault(normalize(input), 抱歉服务暂时繁忙请稍后再试。); }这个降级库不用很大覆盖最高频的几十个问题就行能挡住大部分流量。6.3 安全与合规几个必须守住的底线最后说几个安全相关的点这些不是可选项是必须做的。密钥绝对不能硬编码用环境变量或配置中心。用户输入要做长度限制和内容过滤防止有人构造超长输入来消耗你的 token。日志里不要打印完整的请求和响应尤其是涉及用户隐私的内容只记录必要的元数据。这些看起来是小事但真出事的时候都是大事。我个人在实际操作中的体会是把大模型能力接进 Java 工程技术难度其实不高难的是工程化的那些“脏活累活”——超时、重试、并发、监控、降级。这些才是区分“玩具”和“产品”的分水岭。你把这套骨架搭好后面换模型、加功能都是顺手的事。下一篇我打算聊聊怎么把这套东西和具体的业务场景结合比如智能客服、代码助手这些有兴趣的可以继续关注。

相关新闻

变频器载波频率如何影响电机噪声与损耗?

变频器载波频率如何影响电机噪声与损耗?

1. 变频器载波频率到底在调什么1.1 从一个现场调试案例说起前年冬天,我在一个纺织厂的细纱车间做变频器调试。车间主任拉着我走到一台37kW的细纱机旁边,说这台机器一开起来,旁边三台机器的操作工就投诉,说耳朵里一直有“吱——”的…

2026/10/12 5:17:19 阅读更多 →
同步发电机突然三相短路:从磁链守恒到Simulink仿真全解析

同步发电机突然三相短路:从磁链守恒到Simulink仿真全解析

同步发电机突然三相短路,这个话题差不多是每个电气专业学生都绕不过去的必修课。也难怪,它是电力系统里最典型、也最极端的一类暂态过程:定子电流在故障瞬间可以冲到额定值的十几倍,电磁转矩剧烈振荡,继电保护的定值整…

2026/10/12 9:18:01 阅读更多 →
基于支路电流分析的永磁电机退磁与偏心故障诊断方法

基于支路电流分析的永磁电机退磁与偏心故障诊断方法

这个项目我做了断断续续快三个月,中间推倒重来两回,最后稳定下来的方案其实挺朴素的。先给结论:用支路电流做永磁电机的退磁和偏心诊断,核心思路就一句话,“把支路电流里的不平衡和周期性分量当成指纹”,退…

2026/10/11 7:54:36 阅读更多 →

最新新闻

基于模型压缩的识别算法Python源码:蒸馏与剪枝实战

基于模型压缩的识别算法Python源码:蒸馏与剪枝实战

简介:这份资源是面向高校毕业设计与深度学习入门者的模型压缩识别算法Python源码包,聚焦知识蒸馏与剪枝两类主流压缩技术,帮助读者在有限算力下完成识别模型的轻量化改造与对比实验。包内共185个文件,以79个py源码为核心&#xff…

2026/10/12 10:02:52 阅读更多 →
小波神经网络在光伏辐照预测中的工程落地实践

小波神经网络在光伏辐照预测中的工程落地实践

简介:本资源是一篇发表于《可再生能源》期刊的学术论文,面向新能源、电力系统、人工智能交叉领域的研究者与工程技术人员,聚焦太阳能发电中关键的超短期辐照强度预测难题。论文提出一种融合小波分析与神经网络优势的WNN模型,针对春…

2026/10/12 10:02:52 阅读更多 →
数学证明的事件化记录:构建可追溯、可验证的AI推理过程

数学证明的事件化记录:构建可追溯、可验证的AI推理过程

1. 这不是“AI写证明”,而是让数学推理过程真正可追溯、可验证、可复盘的底层重构“事件模型下AI数学证明的事件化记录与透明性架构”——这个标题里没有一个字是虚的,它直指当前AI数学推理系统最痛的软肋:我们能看到结论,却看不见…

2026/10/12 10:02:52 阅读更多 →
轻型AI中台:解决中小企业重复录入与对账困难的工程化方案

轻型AI中台:解决中小企业重复录入与对账困难的工程化方案

1. 项目概述:为什么一个“轻型AI中台”能真正解决财务与运营一线的痛感“部署轻型AI中台,消除重复录入、消减对账困难”——这句话不是PPT里的口号,而是我去年在三家中小制造企业、两家连锁零售服务商现场蹲点三个月后,亲手推出来…

2026/10/12 10:02:52 阅读更多 →
Hive外部表映射HBase已有数据实战指南

Hive外部表映射HBase已有数据实战指南

1. 项目概述:为什么非得用 Hive 外部表去“看” HBase 已有数据? 在某次数据平台升级中,我接手了一个典型的老系统迁移任务:上游业务系统多年积累的用户行为日志,早已稳定写入 HBase 集群,表名 user_acti…

2026/10/12 10:02:52 阅读更多 →
three.js编辑器开发实战:从渲染循环到撤销重做的完整指南

three.js编辑器开发实战:从渲染循环到撤销重做的完整指南

1. 为什么我不建议你从零手写渲染循环很多人第一次接触 three.js 编辑器开发,脑子里蹦出来的第一个念头是"我要自己写一套渲染管线"。这个想法本身没错,但如果你真的从requestAnimationFrame开始一行行搭,大概率会在第三天卡在&quo…

2026/10/12 10:01:51 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →