Spring AI Function Calling 实战:Java 后端从环境搭建到生产级落地
Function Calling 这个词在过去一年里被聊得很多但真正落到 Java 后端项目里跑通的人其实没想象中多。大部分资料要么停留在 Python 示例要么只讲概念不讲工程落地。我最近用 Spring AI 完整走了一遍从环境搭建到生产级 Function Calling 的链路踩了不少坑也积累了一些文档里不会写的经验。这篇内容就是把这套流程完整拆开从依赖选型、接口设计、参数映射、异常处理到和 MySQL 的结合一步步讲清楚怎么在 Spring Boot 项目里把 Function Calling 真正用起来。适合有 Java 基础、想在自己的后端服务里接入大模型能力的开发者也适合正在做 AI Agent 相关项目、需要让模型调用本地业务方法的朋友。读完你应该能独立搭出一套可运行的 Function Calling 服务并且知道哪些地方容易翻车。1. 先把 Function Calling 这件事的本质说透1.1 它到底解决了什么问题很多人第一次接触 Function Calling会以为这是模型在执行代码。其实不是。模型本身不会去连你的数据库也不会去调你的 Service 方法。它做的事情只有一件根据用户的自然语言输入判断现在需要调用哪个函数、传什么参数然后输出一段结构化的 JSON。真正执行函数的永远是你自己的 Java 代码。这个认知非常关键。因为一旦你误以为模型会帮你执行就会在架构设计上走偏比如把数据库连接信息塞进 prompt或者指望模型自己处理事务。正确的分工是模型负责意图识别 参数抽取你的后端负责参数校验 业务执行 结果回传。举个具体场景。用户说帮我查一下订单号 20240512001 的物流状态。传统做法你要写正则去解析订单号要写意图分类模型去判断这是查询物流。有了 Function Calling你只需要定义一个queryLogistics(String orderNo)函数把函数签名和描述告诉模型模型就会返回{orderNo: 20240512001}这样的结构化参数。剩下的查询逻辑还是你自己写。1.2 Spring AI 在其中的角色Spring AI 本质上是把上面这套告诉模型有哪些函数、解析模型返回的函数调用、执行后把结果再喂回模型的流程做了封装。它提供了一套统一的抽象让你不用直接去拼各家大模型的 HTTP 请求体。你定义好Bean形式的 FunctionSpring AI 会自动把它转换成模型能理解的工具描述tool schema并在模型返回 tool_calls 时帮你路由到对应的 Java 方法。这里有个容易忽略的点Spring AI 的 Function 注册机制是基于 Spring 容器的。也就是说你的函数得是一个 Spring Bean或者至少能被容器管理。这跟直接写 Python 脚本里随手定义一个函数完全不是一个思路。理解这一点后面配置的时候就不会迷糊。1.3 和 Agent、工作流的边界现在热词里经常出现 spring ai agent、dify 工作流转 spring ai java 代码 这类词。我的理解是Function Calling 是 Agent 的底层能力之一但 Agent 还包含规划、记忆、多轮决策等更上层的东西。如果你只是想让模型调用一两个业务方法Function Calling 就够了不用上 Agent 框架。反过来如果你要做多步骤任务编排那 Function Calling 只是其中一环还需要考虑状态管理和循环控制。我个人的建议是先把单轮 Function Calling 跑稳再考虑往上叠 Agent。很多项目一上来就搞复杂编排结果连最基本的参数映射都没搞对调试起来非常痛苦。2. 环境搭建依赖选型和版本坑2.1 Spring Boot 版本与 Spring AI 的匹配关系Spring AI 对 Spring Boot 版本是有要求的。目前主流的 Spring AI 1.0.x 系列建议搭配 Spring Boot 3.2 及以上。如果你还在用 Spring Boot 2.3.x 或 2.6.x那基本没法直接用得先升级。这一点在热词里也有人问 spring boot 2.3.x 2.6.x我的建议是别硬扛升级到 3.x 是更省事的路。JDK 方面Spring Boot 3.x 要求 JDK 17 起步。如果你本地还是 JDK 8IntelliJ IDEA 社区版里配置项目 SDK 的时候记得切到 17。我见过有人编译报错半天最后发现是 IDEA 里项目结构还挂着 1.8。依赖引入大概是这样dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version1.0.0/version /dependency如果你用的是国内模型平台比如百炼上的 qwen 系列那 starter 要换成对应的适配包。热词里提到 spring ai 2.0 连接百炼 qwen3.7说明这块需求确实存在。不同平台的 starter 名字不一样引入之前先确认清楚别拿 OpenAI 的包去连别的平台那样请求格式对不上。2.2 配置文件里最容易写错的三处第一处是base-url。很多平台的接口地址不是默认的https://api.openai.com你得改成平台给的地址。写错的话报错通常是 401 或者 404但错误信息不一定直白。第二处是模型名称。不同平台模型名差异很大有的叫qwen-plus有的叫gpt-4o-mini。名字写错会直接返回模型不存在的错误。第三处是temperature和max-tokens这类参数。Function Calling 场景下temperature 建议调低一点比如 0.1 到 0.3。因为你要的是稳定的参数抽取不是创意写作。temperature 太高模型可能给你返回格式飘忽的 JSON解析起来很头疼。spring: ai: openai: base-url: https://your-platform-endpoint api-key: ${API_KEY} chat: options: model: your-model-name temperature: 0.2提示api-key 千万别硬编码在配置文件里提交到仓库。用环境变量或者配置中心注入这是基本的安全习惯。2.3 本地要不要装 MySQLFunction Calling 本身不依赖数据库。但如果你要做的场景是让模型查订单让模型查用户信息那数据库就是必须的。热词里大量出现 mysql 安装、mysql 8.0 安装教程、mysql 在 windows10 上怎么安装说明很多人的卡点其实在环境。我的经验是本地开发用 Docker 起一个 MySQL 最省事一条命令搞定不用折腾安装向导。docker run -d --name mysql-dev \ -e MYSQL_ROOT_PASSWORDroot123 \ -e MYSQL_DATABASEdemo \ -p 3306:3306 \ mysql:8.0如果 Docker 拉镜像失败检查一下镜像源配置。这个问题在热词里也有人提到 docker安装mysql失败多半是网络或者镜像源的问题换个源基本能解决。3. 定义你的第一个 Function从接口设计开始3.1 函数签名怎么设计才合理这是整个 Function Calling 里最考验功力的地方。模型能不能正确抽取参数很大程度上取决于你的函数签名和描述写得清不清楚。先说命名。函数名要语义明确用动词开头比如queryOrderStatus、calculateShippingFee、getUserProfile。别用doSomething、handleData这种含糊的名字模型看了也不知道什么时候该调。再说参数。参数类型尽量用基础类型或者简单的 POJO别搞嵌套很深的泛型结构。模型对复杂结构的理解能力有限参数一复杂抽取准确率就掉。如果确实需要多个参数宁可拆成多个函数也别硬塞进一个。public record OrderQueryRequest(String orderNo, String phoneLast4) {} Bean public FunctionOrderQueryRequest, String queryOrderStatus() { return request - { // 实际查询逻辑 return orderService.queryStatus(request.orderNo(), request.phoneLast4()); }; }这里用 record 是个好选择因为它是不可变的而且字段语义清晰。Spring AI 会通过反射读取字段名和类型生成对应的 JSON Schema。3.2 函数描述模型判断要不要调的唯一依据很多人只写函数名不写描述结果模型要么不调要么乱调。函数描述description是模型判断当前用户输入是否需要调用这个函数的核心依据。描述要写清楚三件事这个函数做什么、什么情况下该调、参数分别代表什么。我一般会这样写查询订单的物流状态。当用户询问某个订单的配送进度、快递位置、预计到达时间时调用此函数。orderNo 是订单编号phoneLast4 是下单手机号后四位用于身份校验。这段描述里当用户询问……时调用就是给模型的触发条件。写得越具体模型判断越准。如果你有多个功能相近的函数描述之间的区分度就更重要否则模型容易调错。3.3 参数校验不能省模型返回的参数不能直接信。它可能返回空字符串可能返回格式不对的订单号甚至可能幻觉出一个不存在的参数。所以函数内部第一件事就是校验。return request - { if (request.orderNo() null || !request.orderNo().matches(\\d{11,20})) { return 订单号格式不正确请提供有效的订单编号; } // 继续业务逻辑 };注意这里返回的是给模型看的提示文本不是抛异常。因为抛异常会中断整个调用链而返回一段说明文字模型可以据此告诉用户订单号格式不对请重新提供。这个区别很关键是 Function Calling 里处理错误的基本姿势。4. 把 Function 注册进 ChatClient 并跑通第一轮4.1 注册方式与常见报错Spring AI 里注册 Function 有几种方式。一种是通过Bean定义 Function 类型的 Bean然后在构建 ChatClient 时用.functions(beanName)指定。另一种是用Description注解配合方法引用。我倾向于用 Bean 方式因为依赖注入更自然测试也方便。Configuration public class FunctionConfig { Bean Description(查询订单物流状态用户询问配送进度时调用) public FunctionOrderQueryRequest, String queryOrderStatus(OrderService orderService) { return request - orderService.queryStatus(request.orderNo(), request.phoneLast4()); } }构建 ChatClientChatClient chatClient ChatClient.builder(chatModel) .defaultFunctions(queryOrderStatus) .build();常见报错是 No function found with name xxx。这通常是 Bean 名字和注册时写的名字对不上。Bean 默认名字是方法名如果你用了Bean(customName)改了名字注册时就得用改后的名字。4.2 一次完整的调用链路拆解用户输入帮我查下订单 20240512001 到哪了整个链路是这样的第一步Spring AI 把你的问题和已注册函数的 schema 一起发给模型。schema 里包含函数名、描述、参数结构。第二步模型判断需要调用queryOrderStatus返回一个 tool_call参数是{orderNo: 20240512001}。第三步Spring AI 拦截这个 tool_call找到对应的 Bean把参数反序列化成OrderQueryRequest执行你的 lambda。第四步你的函数返回结果字符串Spring AI 把这个结果作为 tool 消息追加到对话历史再次发给模型。第五步模型根据函数返回结果生成自然语言回复给用户。理解这五步调试的时候就知道问题出在哪一环。比如模型没调函数那是第一步 schema 或描述的问题参数不对那是第二步抽取的问题执行报错那是第三步你代码的问题。4.3 多函数场景下的选择逻辑当你有多个函数时模型需要自己选。这时候描述之间的边界就很重要。我做过一个测试同时注册queryOrderStatus和queryRefundStatus两个函数如果描述都写得很笼统模型经常把退款查询走到订单查询上。后来我把描述改成查询订单的物流配送状态和查询订单的退款处理进度区分度上来了准确率明显提升。注意函数数量不是越多越好。我实测下来单次注册超过 10 个函数后模型选择准确率会下降。如果业务函数很多考虑按场景分组或者用路由层先做一轮筛选。5. 和 MySQL 结合让模型真正查到数据5.1 数据访问层的设计Function 内部要查数据库走的就是常规的 Spring Boot MyBatis 或者 JPA 那套。热词里 spring boot mybatis 的 java 开源多商户跨境商城源码 说明 MyBatis 在业务系统里用得很多。我这边用 MyBatis 举例。Mapper public interface OrderMapper { Select(SELECT status, logistics_info FROM orders WHERE order_no #{orderNo} AND phone_last4 #{phoneLast4}) OrderInfo selectByOrderNo(Param(orderNo) String orderNo, Param(phoneLast4) String phoneLast4); }注意 SQL 里带了phone_last4条件这是身份校验的一部分。Function Calling 场景下模型可能被诱导去查别人的订单所以权限校验必须在数据层做不能只靠模型自觉。5.2 返回结果怎么组织给模型看函数返回给模型的内容直接影响模型最终回复的质量。如果你返回一大坨 JSON模型可能抓不住重点。我的做法是返回一段结构清晰的文本把关键字段列出来。public String queryStatus(String orderNo, String phoneLast4) { OrderInfo info orderMapper.selectByOrderNo(orderNo, phoneLast4); if (info null) { return 未找到该订单请确认订单号和手机号后四位是否正确; } return String.format(订单状态%s物流信息%s更新时间%s, info.getStatus(), info.getLogisticsInfo(), info.getUpdateTime()); }这样模型拿到的是人话它转述给用户的时候也更自然。如果你返回原始 JSON模型有时候会直接把 JSON 念出来体验很差。5.3 事务和超时控制Function 执行是在模型调用链路里的如果函数里做了耗时操作整个响应会很慢。所以数据库查询要加超时复杂操作要考虑异步。另外Function 内部如果涉及写操作事务边界要自己控制好别指望模型帮你管事务。我一般会给 Function 内部的数据库操作设一个 3 秒超时超过就返回查询超时请稍后重试。这样即使用户体验有损也不会把整个请求拖死。6. 踩坑实录那些文档里不会写的问题6.1 参数反序列化失败最常见的一个坑是模型返回的参数类型和你的 POJO 对不上。比如你定义的是Integer count模型返回了count: 3字符串。Spring AI 底层用的 Jackson 有时候能自动转换有时候不能取决于配置。我的做法是参数尽量用 String在函数内部自己转这样最稳。还有一个坑是模型返回了额外的字段。比如你只定义了orderNo模型返回了{orderNo: 123, reason: 用户查询}。如果 Jackson 配置了FAIL_ON_UNKNOWN_PROPERTIES就会直接报错。建议在 ObjectMapper 里关掉这个选项。6.2 模型不调用函数有时候用户明明问的是订单模型却直接编了个答案没调函数。原因通常有三个一是函数描述没写触发条件二是 temperature 太高三是系统提示词里没强调涉及订单查询必须调用工具。我的解决办法是在 system prompt 里明确写当用户询问订单、物流、退款相关问题时必须调用相应工具获取真实数据不得凭空回答。 这句话加上之后不调用的情况明显减少。6.3 多轮对话里的上下文丢失Function Calling 在多轮对话里有个细节函数调用的结果需要作为消息历史的一部分保留下来。如果你每轮都新建 ChatClient 或者清空历史模型就记不住上一轮查了什么。Spring AI 的 ChatMemory 可以帮忙管理但要注意配置合适的窗口大小太小会丢上下文太大又费 token。6.4 中文参数的处理中文场景下模型抽取的中文参数有时候会带多余空格或者标点。比如用户说查一下订单 12345 的物流模型可能返回orderNo: 12345 带个尾空格。函数内部记得 trim 一下不然数据库查不到。7. 从能跑到好用几个提升稳定性的实践7.1 给函数加日志和埋点Function 执行是黑盒出问题不好查。我习惯在每个 Function 入口打一条日志记录入参和出参。这样线上出问题的时候能快速判断是模型抽取错了还是业务逻辑错了。return request - { log.info(Function queryOrderStatus called with: {}, request); String result orderService.queryStatus(request.orderNo(), request.phoneLast4()); log.info(Function queryOrderStatus returned: {}, result); return result; };7.2 降级和兜底模型服务本身可能不稳定超时或者限流都可能发生。Function Calling 链路里如果模型这一步挂了整个功能就不可用。我的做法是加一层降级模型调用失败时返回一个引导用户走传统表单查询的提示而不是直接报错。7.3 参数白名单校验对于枚举类参数比如订单状态查询模型可能返回一个不存在的状态值。函数内部要做白名单校验只接受预定义的几个值其他一律拒绝。这既是安全考虑也是数据质量考虑。7.4 控制函数粒度我见过有人把一个函数写成万能查询参数里带个 type 字段根据 type 走不同分支。这种设计模型很难用对因为描述里说不清楚每种 type 的适用场景。正确做法是按业务语义拆成独立函数每个函数职责单一。8. 关于 Spring AI 版本演进的一点个人观察Spring AI 这个项目迭代挺快的从早期版本到 1.0 再到现在的 2.0.xAPI 有不小变化。热词里有人问 spring ai alibaba 停更了吗也有人关注 spring ai 2.0.1。我的建议是生产项目锁定一个稳定版本别追最新。因为 Function Calling 这块的 API 在不同版本间改过好几次升级一次可能要改不少代码。如果你现在开始一个新项目用 1.0.x 的稳定版就够了功能完全够用。等 2.0 生态成熟了再考虑迁移。迁移的时候重点看 Function 注册方式和 ChatClient 构建方式这两块这两处变动最大。另外不同模型平台对 Function Calling 的支持程度不一样。有的平台支持并行调用多个函数有的只支持单个。选平台的时候要确认这一点不然设计多函数协作的时候会受限。9. 一个完整的可运行示例结构把上面的东西串起来一个典型的项目结构大概是这样config/FunctionConfig.java定义所有 Function Beanservice/OrderService.java业务逻辑mapper/OrderMapper.java数据访问controller/ChatController.java对外接口config/ChatClientConfig.java构建 ChatClientController 层大概长这样RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient chatClient) { this.chatClient chatClient; } PostMapping(/chat) public String chat(RequestBody String message) { return chatClient.prompt() .user(message) .call() .content(); } }这个结构跑通之后你就可以往里加更多函数、加记忆、加流式输出。但基础链路一定是先跑稳。我在实际项目里最大的体会是Function Calling 的难点不在模型而在工程。模型能力已经够用了真正花时间的是参数设计、错误处理、权限校验、日志埋点这些脏活累活。把这些做扎实功能才敢上生产。另外一个小技巧是调试阶段把模型的原始返回打出来看很多时候问题一眼就能定位比猜快得多。

相关新闻

AI-IDE-Agent:构建多角色协同开发操作系统的实战指南

AI-IDE-Agent:构建多角色协同开发操作系统的实战指南

1. 这不是又一个“AI写代码”玩具,而是一套可落地的协同开发操作系统你有没有遇到过这样的场景:一个新项目启动,前端同学刚搭完Vue脚手架,后端还在纠结用Spring Boot还是Go Gin,测试同学翻着Postman文档找接口地址&…

2026/10/6 6:10:31 阅读更多 →
LDO不能当电压基准用?揭秘ADC精度失效的根源

LDO不能当电压基准用?揭秘ADC精度失效的根源

1. 为什么工程师总把LDO当电压基准用?——一个被忽视的精度陷阱我第一次在客户现场看到这个问题,是在调试一款高精度温度采集板。客户抱怨ADC读数漂移严重,标定后24小时就偏了3℃。板子用的是TI的ADS1256——24位ΔΣ ADC,理论分辨…

2026/10/6 6:10:31 阅读更多 →
AI-IDE-Agent:多角色协同开发的智能体实践指南

AI-IDE-Agent:多角色协同开发的智能体实践指南

1. 这不是又一个“AI写代码”玩具:为什么AI-IDE-Agent项目真正值得开发者花三天时间啃透你有没有过这种体验:深夜改一个接口,突然发现前端调用的字段名和后端文档对不上,查Git历史发现是两周前某次重构悄悄改的;或者团…

2026/10/6 6:10:31 阅读更多 →

最新新闻

JAVAWEB校园二手平台毕设源码:部署、模块拆解与避坑指南

JAVAWEB校园二手平台毕设源码:部署、模块拆解与避坑指南

简介:面向JavaWeb课程设计及毕业设计学生的校园二手平台完整项目,覆盖用户注册登录、个人资料修改、商品信息管理、二手商品发布与分类检索等核心模块,适合作为毕设选题、课程项目或练手仿写参考。压缩包为rar格式,约29.02MB&…

2026/10/7 9:33:23 阅读更多 →
腾讯云一键开服实战:Minecraft、饥荒、幻兽帕鲁服务器搭建与配置指南

腾讯云一键开服实战:Minecraft、饥荒、幻兽帕鲁服务器搭建与配置指南

1. 从一条链接说起:游戏开服这件事到底被简化到了什么程度第一次看到“一键开服”这四个字的时候,我脑子里冒出来的画面是那种点一下按钮、进度条走完、控制台刷出一行“Done”的场景。实际用下来,腾讯云这套面向游戏服务器的开服入口&#x…

2026/10/7 9:33:23 阅读更多 →
农产品自主供销小程序毕设源码全解析:从部署到避坑

农产品自主供销小程序毕设源码全解析:从部署到避坑

简介:这是一套面向高校毕业设计与课程设计的农产品自主供销小程序源码,将Java后端与小程序前端结合,完整实现管理员、用户、农户三个角色的业务闭环,包含首页、个人中心、用户管理、农户管理、产品分类管理、农产品管理、咨询信息…

2026/10/7 9:33:23 阅读更多 →
JavaWeb学生成绩管理系统实现:从MySQL建库到Tomcat部署的完整避坑指南

JavaWeb学生成绩管理系统实现:从MySQL建库到Tomcat部署的完整避坑指南

简介:基于JavaWeb技术实现的高分学生成绩管理系统源码与数据库,面向计算机相关专业期末大作业、课程设计学习者,是一款经过导师指导、最终评定98分的完整实训项目。系统采用模块化设计,涵盖学生信息管理、成绩录入与查询、统计分析…

2026/10/7 9:33:23 阅读更多 →
FOC电机控制中的串级PID原理与实战调参

FOC电机控制中的串级PID原理与实战调参

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

2026/10/7 9:33:23 阅读更多 →
C23标准中的#embed预处理指令深度实战:编译期零拷贝内嵌二进制资产

C23标准中的#embed预处理指令深度实战:编译期零拷贝内嵌二进制资产

C23标准中的#embed预处理指令深度实战:编译期零拷贝内嵌二进制资产在嵌入式 Linux 系统、Bootloader、工业人机界面(HMI)以及无文件系统的裸机固件开发中,将静态资源直接打包内嵌到只读代码段(.rodata)是一…

2026/10/7 9:32:23 阅读更多 →

日新闻

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

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

2026/10/7 1:01:58 阅读更多 →
用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

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

2026/10/7 1:02:00 阅读更多 →
芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

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

2026/10/7 1:02:00 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/6 7:15:40 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/6 5:29:09 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/7 9:29:10 阅读更多 →

月新闻

我发现了一个新思路:用 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/6 8:21:32 阅读更多 →
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/6 4:21:51 阅读更多 →
黑夜航拍船只数据集训练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/6 1:18:13 阅读更多 →