Spring AI 2.0 结构化输出企业级实战:从 BeanOutputConverter 源码到生产级解析容错
模型说我返回 JSON 了和你的系统能解析出业务对象中间隔着 Markdown 围栏、字段漂移、枚举幻觉和 maxTokens 截断。结构化输出不是格式偏好而是一份 API 契约——这篇文章把 Spring AI 2.0 的结构化输出机制拆到源码层再给你一套带修复重试和降级熔断的生产级解析管道。一、为什么结构化输出是 2026 年 Java 团队的第一优先级最近开发者社区有一篇流传很广的文章《2026 AI Priorities for Java Developers》把结构化输出、RAG、可观测性列为今年 Java 团队最该投入的三个方向而不是继续追逐炫酷的 Agent 演示。理由很朴素当 AI 功能进入真实业务系统模型说得漂亮一文不值输出能被 Java 对象可靠承接才是一切的前提。想想这些场景订单抽取从用户混乱的自然语言描述里抽出商品、数量、地址写入订单系统工单分类把客服对话分类到 20 个业务类目并打优先级路由到不同队列合同审查从 PDF 抽取甲方、金额、违约条款进入风控流程。这些任务里模型输出的每一个字段都会被下游的数据库、工作流引擎、审批流程消费。一次解析失败不是回答不好而是脏数据进入生产库。而实践中的残酷现实是HTTP 200 不等于成功。模型请求可以正常返回但输出被 Markdown 代码围栏包裹、必填字段缺失、数字变字符串、枚举里出现从未定义的值、JSON 后面还跟了一段希望对你有帮助。大多数团队把结构化输出当提示词工程处理——在 prompt 里加一句请返回 JSONdemo 能跑上了生产就撞墙。正确的认知是结构化输出是一条管道——模型响应 → 语法解析 → Schema 校验 → 业务规则校验 → 接受或恢复。Spring AI 2.0 把这条管道的前两环做成了框架能力后两环需要你自己补齐。这篇文章就把整条链路讲透。二、源码分析Spring AI 2.0 结构化输出的三层实现2.1 顶层接口StructuredOutputConverterSpring AI 的结构化输出抽象非常克制一个接口两个能力public interface StructuredOutputConverterT extends ConverterString, T, FormatProvider { // ConverterString, T: T convert(String text) —— 把模型输出文本转成目标类型 // FormatProvider: String getFormat() —— 提供注入提示词的格式说明 }设计上有两个值得注意的点第一它继承的是 Spring 自带的org.springframework.core.convert.converter.Converter而不是自造轮子。这也是 2024 年从旧OutputParser体系重命名到StructuredOutputConverter体系的原因之一——官方文档明确说这里其实没有 parsing只是命名对齐同时借用了 Spring 转换服务的生态。第二getFormat()与convert()分别对应 LLM 调用的前后两端。调用前getFormat()返回的格式说明被追加到提示词末尾充当输出蓝图调用后convert()把原始文本反序列化成目标类型。这是一个尽力而为best effort的契约——官方文档原话是The StructuredOutputConverter is a best effort to convert the model output into a structured output. The AI Model is not guaranteed to return the structured output as requested.这句话是理解后面所有生产踩坑的钥匙。三个开箱实现各有分工实现目标类型典型场景BeanOutputConverterT任意 Java Bean / Record / 泛型抽取业务对象最常用MapOutputConverterMapString, Object动态键值、无需建类ListOutputConverterListString逗号分隔的简单列表2.2 BeanOutputConverter 源码Schema 从哪来格式说明长什么样BeanOutputConverter是重头戏。它做了两件事基于目标 Java 类反射生成 JSON SchemaDRAFT_2020_12并把 Schema 渲染进格式说明模板。getFormat()的核心逻辑剥掉细节后是这样Override public String getFormat() { String template Your response should be in JSON format. Do not include any explanations, only provide a RFC8259 compliant JSON response \ following this format without deviation. Do not include markdown code blocks in your response. Remove the json markdown from the output. Here is the JSON Schema instance your output must adhere to: %s ; return String.format(template, this.jsonSchema); }几个源码级的细节值得记住Schema 生成底层是 victools 的jsonschema-generator通过反射扫描目标类的字段、Jackson 注解JsonProperty、JsonPropertyDescription、JsonPropertyOrder来构建 Schema。这意味着你给字段写的JsonPropertyDescription(订单金额单位分整数)会原样进入模型看到的 Schema——这是提升字段语义准确率几乎零成本的手段后面踩坑清单里会展开。格式说明里明确要求模型去掉 Markdown 代码围栏Remove thejson markdown说明官方早就知道模型爱用 json包裹输出。但提示词约束挡不住所有模型convert() 内部仍有围栏剥离兜底。支持泛型通过ParameterizedTypeReference构造器处理ListContract这类参数化类型避免泛型擦除。convert()则是纯粹的 Jackson 反序列化外加对常见污染的清洗。2.3 entity()一行代码背后的完整流水线ChatClient的.entity()是大多数人的入口表面一行内部流水线是.entity(ContractExtract.class) ① new BeanOutputConverter(ContractExtract.class) ② 反射字段 → 生成 JSON Schema模型的输出说明书 ③ 格式说明拼接进提示词{format} 占位符或自动追加 ④ call() 拿到模型原始文本 ⑤ 剥离可能的 Markdown 代码围栏 ⑥ Jackson 反序列化 → ContractExtract 实例一个容易被忽略的精髓目标类不需要任何 Spring AI 依赖就是个普通 POJO/Record。你的业务对象长什么样模型就被迫输出成什么样——领域模型本身就是输出契约。2.4 两条技术路线提示词注入 vs 原生 JSON SchemaSpring AI 的结构化输出默认走提示词注入路线Schema 塞进 prompt靠模型自觉。但它不是唯一路线。现代主流模型OpenAI、Anthropic、DeepSeek、通义都支持原生结构化输出——在请求参数里声明response_format/json_schema由推理端做约束解码constrained decoding每一步生成只允许符合 Schema 的 token从结构上保证输出合规。在 Spring AI 2.0 中通过 Options 透传即可启用// OpenAI 兼容端点的原生 strict 结构化输出 OpenAiChatOptions options OpenAiChatOptions.builder() .model(gpt-6.1-sol) .responseFormat(new OpenAiChatOptions.ResponseFormat(json_schema)) .build();两条路线的取舍维度提示词注入entity() 默认原生 JSON Schema结构保证尽力而为可能失败推理端约束结构基本保证模型兼容性任意模型需要模型/网关支持Schema 子集限制无完整 JSON Schema有不支持根级 oneOf、无约束 additionalProperties、深度递归等超出可能被拒或静默降级语义正确性都不保证——结构对不等于值对都不保证生产建议优先原生提示词注入兜底。两者都不保证值是对的所以业务校验层无论如何都不能省。三、代码实战企业级合同抽取系统 ContractIQ围绕一个完整项目来落地法务部门的合同抽取服务——上传合同文本模型抽取关键结构甲方、乙方、金额、期限、违约条款、风险等级写入风控数据库。技术栈Spring Boot 4 Spring AI 2.0 JDK 25 虚拟线程 Micrometer。3.1 定义输出契约领域模型即 Schemapublic record ContractExtract( JsonProperty(required true) JsonPropertyDescription(甲方全称合同文本未出现时填 null) String partyA, JsonProperty(required true) JsonPropertyDescription(乙方全称合同文本未出现时填 null) String partyB, JsonProperty(required true) JsonPropertyDescription(合同总金额单位为人民币分必须是整数未出现时填 null) Long amountCents, JsonPropertyDescription(合同期限格式 yyyy-MM-dd未出现时填 null) LocalDate endDate, JsonProperty(required true) JsonPropertyDescription(风险等级只能取 LOW / MEDIUM / HIGH 之一) RiskLevel riskLevel, JsonPropertyDescription(违约条款摘要最多 3 条每条不超过 100 字没有则返回空数组) ListViolationClause violationClauses, JsonPropertyDescription(抽取依据原文中的关键句用于人工复核) ListString evidences) { public enum RiskLevel { LOW, MEDIUM, HIGH } public record ViolationClause( JsonPropertyDescription(条款原文编号如 第 12 条) String clauseNo, JsonPropertyDescription(违约责任描述) String liability) { } }注意三个设计决策金额用分Long避免浮点误差未出现的信息允许 null 而不是逼模型编造假完整比诚实的缺失更可怕枚举只给 3 个值模型在 2~6 个值的小枚举上准确率极高20 类目要改用分层 Schema。3.2 快速版entity() 一行接入Service public class QuickExtractService { private final ChatClient chatClient; public QuickExtractService(ChatModel chatModel) { this.chatClient ChatClient.builder(chatModel) .defaultSystem( 你是合同审查助手。只依据合同文本抽取信息不得编造。 合同文本未包含的信息一律填 null禁止猜测。 ) .build(); } public ContractExtract extract(String contractText) { return chatClient.prompt() .user(u - u.text( 请抽取以下合同的关键信息 --- {contract} ).param(contract, contractText)) .call() .entity(ContractExtract.class); } }demo 到此为止。生产版本还差三样业务校验、失败修复重试、降级熔断。3.3 生产版带校验-修复-降级的解析管道核心思想来自生产实践的最佳共识校验失败时不要盲目重发同样的 prompt要把具体错误反馈给模型——带上精确错误信息的重试首次修复成功率通常在 80% 以上同时重试必须有预算超过阈值转人工队列。Service public class StructuredExtractionService { private static final Logger log LoggerFactory.getLogger(StructuredExtractionService.class); private static final int MAX_REPAIR_ATTEMPTS 2; private final ChatClient chatClient; private final MeterRegistry registry; private final ContractValidator validator; // 业务规则校验器 private final CircuitBreaker extractionCircuit; // Resilience4j 熔断器 public StructuredExtractionService(ChatModel chatModel, MeterRegistry registry, ContractValidator validator) { this.chatClient ChatClient.builder(chatModel).build(); this.registry registry; this.validator validator; this.extractionCircuit CircuitBreaker.of(contract-extraction, CircuitBreakerConfig.custom() .failureRateThreshold(30) // 失败率超 30% 熔断 .slidingWindowSize(50) .waitDurationInOpenState(Duration.ofSeconds(30)) .build()); } /** * 完整管道解析 → Schema 校验 → 业务校验 → 错误反馈修复 → 降级 */ public ContractExtract extractWithRecovery(String contractText) { return Try.ofSupplier(extractionCircuit::executeSupplier) .recoverCall() .get(() - doExtractWithRecovery(contractText)); } private ContractExtract doExtractWithRecovery(String contractText) { String lastRawOutput null; String lastErrors null; for (int attempt 0; attempt MAX_REPAIR_ATTEMPTS; attempt) { Timer.Sample sample Timer.start(registry); String raw (attempt 0) ? callModel(contractText, null) : callModel(contractText, lastErrors); // 带错误反馈的修复重试 lastRawOutput raw; try { ContractExtract result parse(raw); // 解析 Schema 反序列化 ListString violations validator.validate(result); // 业务校验 if (violations.isEmpty()) { sample.stop(registry.timer(ai.structured.success, attempt, String.valueOf(attempt))); return result; } lastErrors String.join(; , violations); } catch (JsonProcessingException e) { // 解析失败把 Jackson 的精确错误位置反馈给模型 lastErrors 上次输出无法解析为 JSON: e.getOriginalMessage() 。请只返回符合 JSON Schema 的 JSON不要任何解释和 Markdown 代码块。; } finally { sample.stop(registry.timer(ai.structured.parse.duration)); } } // 修复预算耗尽记录原始输出供排查转人工队列 registry.counter(ai.structured.failed).increment(); log.error(结构化抽取失败原始输出已存档。output{}, lastRawOutput); throw new ExtractionFailedException(lastRawOutput); // 上层入人工复核队列 } private String callModel(String contractText, String repairHint) { String userText (repairHint null) ? 请抽取以下合同的关键信息\n---\n contractText : 修复要求 repairHint \n\n请重新抽取以下合同\n---\n contractText; return chatClient.prompt() .options(OpenAiChatOptions.builder() .temperature(0.1) // 结构化任务用低温 .build()) .user(u - u.text(userText \n\n{format}) .param(format, new BeanOutputConverter(ContractExtract.class).getFormat())) .call() .content(); } private ContractExtract parse(String raw) throws JsonProcessingException { // 兜底剥离代码围栏即使格式说明已要求模型仍可能违规 String cleaned stripCodeFence(raw); return new BeanOutputConverter(ContractExtract.class).convert(cleaned); } private String stripCodeFence(String text) { String t text.trim(); if (t.startsWith()) { int firstLineEnd t.indexOf(\n); int lastFence t.lastIndexOf(); if (firstLineEnd 0 lastFence firstLineEnd) { t t.substring(firstLineEnd 1, lastFence).trim(); } } return t; } }/** * 业务规则校验结构正确 ≠ 语义可用 */ Component public class ContractValidator { public ListString validate(ContractExtract r) { ListString errors new ArrayList(); if (r.amountCents() ! null r.amountCents() 0) { errors.add(amountCents 必须为正整数当前值 r.amountCents()); } if (r.endDate() ! null r.endDate().isBefore(LocalDate.now())) { errors.add(endDate 不能早于今天当前值 r.endDate()); } if (r.violationClauses() ! null r.violationClauses().size() 3) { errors.add(violationClauses 最多 3 条当前 r.violationClauses().size() 条); } if (r.riskLevel() RiskLevel.HIGH r.evidences().isEmpty()) { errors.add(riskLevel 为 HIGH 时 evidences 不能为空需提供原文依据); } return errors; } }管道的关键设计点解析、Schema 校验、业务校验是三层不同的活分开写、分开测失败时才知道该把什么信息反馈给模型重试带错误反馈而非原样重发且预算封顶2 次熔断器防雪崩当某类输入的结构化失败率超过 30%直接熔断转人工不再烧 token原始输出必须落日志——没有它生产排查就是黑盒Micrometer 记录首次通过率 / 修复成功率 / 每次尝试次数——首次通过率低说明 prompt 或 Schema 设计有问题修复成功率高反而是坏消息的信号。四、生产踩坑清单8 条每条都疼过1. Markdown 代码围栏包裹直接 Jackson 炸掉。最高频的失败。即使getFormat()里明确写了Remove thejson markdown部分模型尤其是小参数量的国产开源模型依然会用 json包裹输出。convert()内部有剥离逻辑但对付围栏内嵌套围栏JSON 后还跟一段话这类脏输出必须自己再兜一层stripCodeFence 定位首个{到末个} 的提取逻辑。2. maxTokens 截断JSON 只有一半。maxTokens设太小或推理型模型 thinking tokens 吃掉预算输出在对象中途被掐断Jackson 报unexpected end of input。这种错误重试 10 次也不会好——要靠调大 maxTokens 或精简 Schema 解决。修复重试的错误分类里要把它和格式漂移区分开否则白白烧钱。3. temperature 太高同一份合同两次抽取字段名都不一样。结构化任务必须低温0~0.1。有团队在 0.7 的配置上跑抽取发现偶发性多字段/少字段查了两天才发现是温度问题。原则分类、抽取、解析类任务全部低温只有生成类文案才允许高温。4. 严格模式 Schema 子集限制超出范围会静默降级。原生 JSON Schema 的 strict 模式不支持根级oneOf、无约束的additionalProperties、过深的递归 Schema——有的 provider 直接 400有的静默降级回 best-effort你以为有约束解码兜底实际上早就没了。Schema 保持扁平、显式别复用为其他用途设计的通用 Schema。5. 可选字段的语义歧义缺字段是 0、是不适用、还是不知道让字段可选是语义灾难——模型没法理解没有 score 字段到底是 0 分还是未知。正确做法字段全部 required 用显式的 null / unknown / 约定值表达缺失并在JsonPropertyDescription里写清楚见 3.1 的契约定义。6. 大枚举分类准确率崩塌。20 类目的扁平枚举模型准确率显著下降且类目间互相混淆退款问题vs退货问题。改用分层 Schema第一层粗分类4~6 个第二层按第一层结果再细分类目。或者干脆给每个类目写一段判别式描述进 description。7. 流式场景下 entity() 不能直接用。ChatClient的流式调用返回FluxString逐 token 的 JSON 无法直接entity()解析。要么聚合完整输出后再解析牺牲首字延迟要么用增量/部分 JSON 解析器逐字段填充 UI——不要手写括号计数器字符串里嵌套的花括号会教做人。只在流结束stop 事件时才把解析结果当作最终态。8. 盲目重试 无预算 成本泄漏黑洞。校验失败就原样重发 prompt是懒惰的工程——大概率得到同样的错误外加双倍延迟。修复必须带具体错误反馈预算封顶 1~2 次超限走人工队列或降级响应部分结果 待复核标记而不是无限重试。持续重试既烧 token 又放大延迟还掩盖了 Schema 与真实输入分布不匹配的根本问题。五、总结结构化输出是 LLM 从聊天玩具变成生产组件的关键一跃也是 2026 年 Java 团队最值得投入的 AI 工程方向之一。回顾本文的核心脉络三层机制StructuredOutputConverter接口Converter FormatProvider→BeanOutputConverter反射生成 JSON Schema 格式注入 →entity()一行流水线。领域模型即输出契约。两条路线提示词注入是 best effort原生json_schema约束解码是结构保证——生产优先原生但两者都不保证语义正确业务校验层永远不能省。一条管道解析 → Schema 校验 → 业务校验 → 错误反馈修复封顶 2 次→ 熔断降级转人工。HTTP 200 只是管道的起点。一条铁律把模型输出的原始文本当成不可信的第三方 API 响应来对待——校验、记录、修复、降级一样都不能少。对 Java 工程师而言这正是我们最熟悉的战场校验管道、熔断器、指标监控、降级策略全是后端工程的基本功。模型能力是厂商的事输出可靠性是工程的事——工程化能力才是我们的护城河。

相关新闻

永磁同步电机无位置传感器控制:DSP28335滑模观测器工程实践

永磁同步电机无位置传感器控制:DSP28335滑模观测器工程实践

简介:基于TI TMS320F28335 DSP的永磁同步电机无位置传感器控制完整例程,适合电机控制、电力电子及嵌入式方向开发者,也可用于学习FOC/DTC算法与DSP28335工程配置。压缩包共52个文件,包括C源码、汇编启动与延时程序、头文件、CMD链…

2026/10/14 17:49:13 阅读更多 →
3D Slicer 色表文件格式全解析:CSV/文本色表格式、读写源码机制与 Color Legend 调试

3D Slicer 色表文件格式全解析:CSV/文本色表格式、读写源码机制与 Color Legend 调试

医疗健康图像处理数据可视化桌面应用3D渲染 【免费下载链接】Slicer Multi-platform, free open source software for visualization and image computing. 项目地址: https://gitcode.com/gh_mirrors/sl/Slicer 点击查看 免费下载 本篇围绕 3D Slicer 的色表&…

2026/10/14 17:48:12 阅读更多 →
Sabaki 调试指南:开启 DevTools、settings.json 配置机制与 Electron 调试通道详解

Sabaki 调试指南:开启 DevTools、settings.json 配置机制与 Electron 调试通道详解

桌面应用 【免费下载链接】Sabaki An elegant Go board and SGF editor for a more civilized age. 项目地址: https://gitcode.com/gh_mirrors/sa/Sabaki 点击查看 免费下载 本文基于 docs/guides/debugging.md 展开,讲解如何为 Sabaki 这款基于 Elect…

2026/10/14 17:48:12 阅读更多 →

最新新闻

Python+Vue协同过滤电影推荐系统:从算法到前后端完整实现

Python+Vue协同过滤电影推荐系统:从算法到前后端完整实现

如果你在网上搜“协同过滤 电影推荐系统”,十份资料里有八份是直接拿现成评分数据跑一个相似度矩阵,再贴一张看着不错的排名表。可一旦真要把这套东西做成能演示、能提交的完整项目,问题马上就会冒出来:后端接口写在Flask还是Djan…

2026/10/14 18:33:53 阅读更多 →
遗传算法求解TSP问题的Matlab实现与优化

遗传算法求解TSP问题的Matlab实现与优化

1. 项目概述:遗传算法在TSP问题中的实战应用旅行商问题(TSP)作为组合优化领域的经典NP难问题,在物流配送、无人机航迹规划、电路板钻孔路径等场景中具有广泛的应用价值。这个Matlab实现项目通过遗传算法(GA&#xff09…

2026/10/14 18:33:53 阅读更多 →
栈的两个经典应用:括号匹配与表达式求值

栈的两个经典应用:括号匹配与表达式求值

栈这名字听起来挺简单——一摞盘子,后放先取。但真把它用在问题里,最经典的莫过于两个场景:括号匹配和表达式求值。这两个问题几乎出现在每一本数据结构的教材里,也出现在每一场笔试和面试中。这篇我打算把这两块掰开揉碎&#xf…

2026/10/14 18:33:53 阅读更多 →
死锁的四个必要条件:从多线程事故到系统化排查

死锁的四个必要条件:从多线程事故到系统化排查

1. 死锁不是玄学:从一次真实的多线程事故说起三年前我在某团队维护一个订单处理服务,有一阵子线上频繁报警,线程池被占满,请求大量超时。翻日志发现一段很诡异的循环:A任务在等B任务释放锁,B任务又在等A任务…

2026/10/14 18:33:53 阅读更多 →
栈与队列经典应用:括号匹配与表达式求值详解

栈与队列经典应用:括号匹配与表达式求值详解

1. 栈与队列的底层逻辑:为什么这两个问题是经典入门题先聊点背景。刚接触数据结构时,很多人会有一个困惑:栈和队列不就是两个很简单的线性结构吗?一个后进先出,一个先进先出,规则几句话就讲完了&#xff0c…

2026/10/14 18:33:53 阅读更多 →
基于麻雀搜索算法优化LSSVM的回归预测

基于麻雀搜索算法优化LSSVM的回归预测

我注意到你还没有提供具体的项目信息。为了让我为你生成一篇贴合实际、高质量的博文,请按以下格式补充内容:项目标题:(必填,例如“基于麻雀搜索算法优化LSSVM的回归预测”这类主题)项目正文:&am…

2026/10/14 18:32:53 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →