SpringBoot AOP统一Web请求日志:从原理到生产级实现
1. 项目缘起为什么我们需要统一处理Web请求日志在任何一个后端服务里日志都是我们排查问题的“眼睛”。尤其是Web请求日志它记录了谁、在什么时候、用什么方式、访问了哪个接口、得到了什么结果。当线上出现一个诡异的接口超时或者用户反馈“我的操作没生效”时第一反应是什么对就是去翻日志。但如果你还在用最原始的方式在每个Controller方法里手动写log.info(“收到请求参数是{}”, param)那很快就会陷入几个困境。首先代码严重重复每个方法开头结尾都是那几行日志代码枯燥且容易出错。其次日志格式不统一张三喜欢打印JSON李四喜欢用逗号分隔排查时看得眼花缭乱。最关键的是你很容易遗漏关键信息比如处理耗时、用户IP、请求IDTraceId等而这些信息在分布式链路追踪时至关重要。所以统一处理Web请求日志本质上是在做两件事一是通过技术手段消灭重复劳动提升开发效率二是标准化日志输出为后续的监控、告警、链路追踪打下坚实基础。SpringBoot AOP的组合正是解决这个问题的“银弹”。AOP面向切面编程允许我们将这些横跨多个模块的公共行为日志记录从业务逻辑中剥离出来集中到一个地方进行声明和管理。这不仅仅是写几行代码更是一种工程化的思维。2. AOP核心概念扫盲切面、连接点与通知在动手之前我们得先统一语言。AOP里有些概念听起来有点玄乎但其实用生活中的例子一比喻就懂了。假设你的项目是一栋大楼每个Controller方法就是一个房间。连接点 (Join Point) 这栋楼里所有可能被“增强”的地方比如每个房间的门口方法执行前、窗户方法异常时、后门方法执行后。在Spring AOP中连接点特指方法的执行。切点 (Pointcut) 你不是要对所有房间都做同样的事。你可能只想监控“所有总经理办公室”或者“所有带窗户的会议室”。切点就是一个表达式用来匹配和筛选你感兴趣的连接点。比如execution(* com.example.controller..*.*(..))这个表达式就匹配了com.example.controller包及其子包下所有类的所有方法。通知 (Advice) 你想在那些被选中的地方切点具体做什么。这就是通知。它定义了增强行为的时机和内容。Before: 在房间门口放个迎宾员方法执行前。AfterReturning: 客人满意离开后在门口做个登记方法成功返回后。AfterThrowing: 客人生气摔门而出时记录下投诉原因方法抛出异常后。After: 不管客人是满意还是生气只要他离开了房间就打扫一下卫生方法执行后无论成功或异常。Around: 这是最强大的保安他可以在客人进门前检查证件前置处理在客人进入后全程陪同执行原方法在客人离开时出具访客记录后置处理甚至有权不让客人进入阻止方法执行。切面 (Aspect) 把上面这些概念组合起来形成一个完整的方案。比如“大楼安全监控方案”这个切面就包含了监控哪些房间切点、在什么时机通知类型、做什么具体动作通知内容。在我们的项目里“统一请求日志切面”就是一个具体的Aspect。理解了这些你就知道我们要做的就是定义一个切面写一个切点来匹配所有Web请求方法然后用Around通知把这些方法的进、出、耗时、参数、结果都记录下来。3. 实战构建从零搭建一个生产可用的日志切面光说不练假把式我们直接上代码。我会用一个围绕Controller层设计的Around通知作为核心因为它能提供最全面的控制。3.1 基础依赖与环境准备首先确保你的pom.xml里已经引入了SpringBoot的Web和AOP依赖。一般来说用Spring Initializr创建项目时勾选Spring Web和Spring AOP即可。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-aop/artifactId /dependency如果你需要更丰富的日志内容比如获取HTTP请求对象spring-boot-starter-web已经包含了必要的Servlet API。另外推荐使用SLF4J Logback/Log4j2作为日志框架SpringBoot默认已经集成好了。3.2 核心切面类设计与实现我们来创建一个名为WebLogAspect的切面类。这里有几个关键设计点使用Around因为它能完全控制方法的执行方便计算耗时和在异常情况下也能记录日志。定义清晰的切点精准匹配Web控制器层的方法避免切入到Service或Dao层造成日志泛滥。获取完整的上下文信息包括请求IP、URL、参数、方法、用户标识等。使用MDC实现请求链路追踪为同一个请求的所有日志打上同一个traceId这在微服务环境下是黄金标准。package com.example.demo.aspect; import com.fasterxml.jackson.databind.ObjectMapper; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.util.ContentCachingRequestWrapper; import javax.servlet.http.HttpServletRequest; import java.util.UUID; /** * 统一Web请求日志处理切面 */ Aspect Component public class WebLogAspect { private static final Logger LOGGER LoggerFactory.getLogger(WebLogAspect.class); private final ObjectMapper objectMapper new ObjectMapper(); /** * 定义切点匹配controller包下的所有公有方法 * execution(* com.example.demo.controller..*.*(..)) * 第一个*返回值任意 * com.example.demo.controller..controller包及其所有子包 * 第二个*类名任意 * 第三个*方法名任意 * (..)参数任意 */ Pointcut(execution(public * com.example.demo.controller..*.*(..))) public void webLog() {} /** * 环绕通知 */ Around(webLog()) public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { // 1. 请求开始时间 long startTime System.currentTimeMillis(); // 2. 获取当前HTTP请求对象 ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes null) { // 非Web请求上下文直接执行原方法 return joinPoint.proceed(); } HttpServletRequest request attributes.getRequest(); // 3. 生成或获取本次请求的唯一追踪ID并放入MDC String traceId request.getHeader(X-Trace-Id); if (traceId null || traceId.isEmpty()) { traceId UUID.randomUUID().toString().replace(-, ).substring(0, 16); } MDC.put(traceId, traceId); // 关键设置到MDC后续所有日志自动携带 // 4. 构建请求日志信息 String requestLog buildRequestLog(request, joinPoint); LOGGER.info([Request Start] {}, requestLog); Object result null; try { // 5. 执行目标方法 result joinPoint.proceed(); // 6. 计算耗时并记录响应日志 long endTime System.currentTimeMillis(); long costTime endTime - startTime; String responseLog buildResponseLog(result, costTime); LOGGER.info([Request End] Cost: {}ms, Response: {}, costTime, responseLog); return result; } catch (Throwable e) { // 7. 异常处理日志 long endTime System.currentTimeMillis(); long costTime endTime - startTime; LOGGER.error([Request Error] Cost: {}ms, Exception: {}, costTime, e.getMessage(), e); // 异常需要继续抛出让全局异常处理器或上层处理 throw e; } finally { // 8. 最终清理务必清除MDC中的traceId防止内存泄漏和上下文污染 MDC.clear(); } } /** * 构建请求日志字符串 */ private String buildRequestLog(HttpServletRequest request, ProceedingJoinPoint joinPoint) { StringBuilder sb new StringBuilder(); sb.append(TraceId).append(MDC.get(traceId)).append( | ); sb.append(IP).append(getClientIp(request)).append( | ); sb.append(Method).append(request.getMethod()).append( | ); sb.append(URI).append(request.getRequestURI()).append( | ); sb.append(Class.Method).append(joinPoint.getSignature().getDeclaringTypeName()) .append(.).append(joinPoint.getSignature().getName()).append( | ); // 谨慎记录参数敏感信息如密码需要脱敏大参数可能影响性能 Object[] args joinPoint.getArgs(); if (args ! null args.length 0) { try { // 简单示例生产环境建议自定义序列化过滤敏感字段 String params objectMapper.writeValueAsString(args); // 对参数进行脱敏处理示例隐藏密码 params maskSensitiveInfo(params); sb.append(Args).append(params); } catch (Exception e) { sb.append(Args[Serialization Error]); } } else { sb.append(Args[]); } return sb.toString(); } /** * 构建响应日志字符串 */ private String buildResponseLog(Object result, long costTime) { try { String resultStr objectMapper.writeValueAsString(result); // 响应结果也可能需要脱敏或截断 if (resultStr.length() 500) { // 避免日志过长 resultStr resultStr.substring(0, 500) ...(truncated); } return resultStr; } catch (Exception e) { return [Serialization Error]; } } /** * 获取客户端真实IP处理代理情况 */ private String getClientIp(HttpServletRequest request) { String ip request.getHeader(X-Forwarded-For); if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(Proxy-Client-IP); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(WL-Proxy-Client-IP); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(HTTP_CLIENT_IP); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(HTTP_X_FORWARDED_FOR); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getRemoteAddr(); } // 对于通过多个代理的情况第一个IP为客户端真实IP if (ip ! null ip.contains(,)) { ip ip.split(,)[0].trim(); } return ip; } /** * 简单的敏感信息脱敏示例 */ private String maskSensitiveInfo(String jsonStr) { // 这是一个非常简单的示例实际应用中应使用更健壮的方式如注解或配置中心 return jsonStr.replaceAll((?i)\password\\\s*:\\s*\[^\]*\, \password\:\******\) .replaceAll((?i)\token\\\s*:\\s*\[^\]*\, \token\:\******\); } }3.3 日志配置优化光有切面还不够我们需要配置日志框架让输出的日志格式美观且包含我们注入的traceId。在application.yml或logback-spring.xml中配置logging: pattern: console: %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} - %msg%n level: com.example.demo.aspect: INFO关键部分是[%X{traceId}]它会从MDCMapped Diagnostic Context中取出我们设置的traceId并打印出来。这样同一个请求下的所有日志包括切面里的、Service里手动打的都会自动带上这个ID用grep traceIdxxx就能轻松串起整个请求链路的所有日志。4. 深入细节那些容易踩坑的“暗礁”代码跑起来不难但想在生产环境稳定运行以下几个坑你必须提前知道。4.1 切点表达式失效为什么我的Controller没被切入这是新手最高频的问题。首先检查你的切面类是否被Spring管理加了Component或Aspect。其次确保你的Controller方法是通过Spring代理调用的。如果一个Controller方法内部调用了另一个Controller方法或者被同一个类内部的其他方法调用由于不是通过代理对象调用AOP会失效。这是Spring AOP基于代理机制的本质决定的。解决方案避免在Controller内部进行方法调用。如果架构上必须可以考虑使用AopContext.currentProxy()来获取当前代理对象然后通过它来调用但这会引入代码耦合不推荐。更优雅的方式是重新审视职责划分将需要AOP增强的逻辑提取到独立的Bean中。4.2 请求体Request Body只能读一次的问题在buildRequestLog方法中我们通过joinPoint.getArgs()获取参数。但如果参数中有RequestBody注解的对象并且你在Controller里已经通过HttpServletRequest.getInputStream()读取了那么在切面里再读可能会报错因为流只能读一次。解决方案使用ContentCachingRequestWrapper。你可以配置一个Filter在最开始将原生的HttpServletRequest包装一下。Component public class CachingRequestBodyFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper wrappedRequest new ContentCachingRequestWrapper(request); filterChain.doFilter(wrappedRequest, response); } }然后在切面中判断如果是ContentCachingRequestWrapper就可以通过wrappedRequest.getContentAsByteArray()安全地多次读取请求体。不过要注意这会把整个请求体缓存到内存对于上传大文件等场景需要谨慎评估。4.3 异步线程导致MDC上下文丢失如果你的服务中使用了Async或线程池处理异步任务你会发现子线程里的日志丢失了traceId。因为MDC是基于ThreadLocal实现的线程切换时上下文不会自动传递。解决方案需要手动传递。在提交异步任务前先获取当前的MDC上下文MapString, String context MDC.getCopyOfContextMap(); CompletableFuture.runAsync(() - { // 在子线程开始时设置 if (context ! null) { MDC.setContextMap(context); } try { // 你的异步逻辑 } finally { MDC.clear(); } }, executor);对于Spring的Async可以定义一个AsyncConfigurer配置一个TaskDecorator来包装任务自动完成MDC的传递。4.4 日志性能与磁盘I/O瓶颈全量、详细的日志打印尤其是将大对象序列化为JSON在高并发下会成为性能杀手甚至打满磁盘I/O。优化策略异步日志配置Logback或Log4j2的异步Appender让日志写入操作由独立的线程池完成不阻塞主业务线程。采样打印非核心查询接口可以按比例采样打印日志比如只记录1%的请求详情。条件化日志使用LOGGER.isDebugEnabled()或LOGGER.isInfoEnabled()判断后再进行昂贵的字符串拼接或序列化操作。精简日志内容对于大的列表返回结果只记录条数或摘要而非全部数据。敏感信息和超大参数体要有选择地过滤或截断。4.5 循环依赖与初始化顺序如果你的切面Autowired了某个Bean而这个Bean又间接依赖了被切面拦截的Bean可能会导致循环依赖。或者切面在Spring容器初始化早期就被加载但此时一些它依赖的Bean如ObjectMapper可能还未完全初始化。解决方案尽量避免在切面中注入复杂的Bean。如果必须注入考虑使用Lazy注解进行延迟加载。确保切面本身的逻辑尽可能轻量只做日志记录这一件事。5. 进阶与扩展让日志系统更具价值基础功能实现后我们可以思考如何让它更好地服务于监控和运维。5.1 集成Metrics与告警日志不仅是事后排查的也可以做实时的健康度指标。我们可以在切面中将请求耗时、状态成功/失败等信息推送到时序数据库如Prometheus或监控系统。// 伪代码示例 Around(webLog()) public Object doAroundWithMetrics(ProceedingJoinPoint joinPoint) throws Throwable { String metricName http.request; Timer.Sample sample Timer.start(); boolean isSuccess false; try { Object result joinPoint.proceed(); isSuccess true; return result; } finally { sample.stop(Metrics.timer(metricName, uri, request.getRequestURI(), method, request.getMethod(), status, isSuccess ? success : error)); } }这样你可以在Grafana上绘制接口的P99耗时、QPS、错误率大盘并设置规则当某个接口错误率突增或耗时飙升时自动告警。5.2 基于注解的精细化控制不是所有接口都需要记录详细日志。我们可以自定义一个注解Loggable通过它来控制日志级别、是否记录参数/返回值、是否忽略该接口等。Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Loggable { boolean recordParams() default true; boolean recordResult() default true; Level level() default Level.INFO; }然后在切点表达式中可以结合annotation()来匹配带有该注解的方法实现更灵活的日志策略。5.3 与分布式链路追踪系统集成我们手动生成的traceId是一个简易方案。在生产级的微服务体系中应该集成SkyWalking、Zipkin、Jaeger这样的专业APM应用性能管理工具。它们提供了自动注入的TraceId并且能跨服务、跨进程传递。我们的切面可以调整为优先使用这些工具提供的TraceId并确保日志格式与其兼容实现日志与链路的关联查询。6. 测试与验证如何确保切面按预期工作写完代码不上线测试等于闭着眼睛开车。验证AOP切面我习惯用三层测试法单元测试隔离测试切面逻辑使用SpringBootTest但只加载切面所在的上下文Mock一个HttpServletRequest和ProceedingJoinPoint验证你的buildRequestLog等方法逻辑是否正确特别是脱敏和IP获取逻辑。集成测试验证切面与Controller的编织写一个简单的Test Controller使用MockMvc发起HTTP请求然后断言日志是否被正确打印。这里可以检查日志输出中是否包含了预期的URL、方法、traceId等信息。生产预览测试在预发布环境通过真实的网关或前端调用观察ELKElasticsearch, Logstash, Kibana或你的日志平台上日志格式是否规整traceId是否能成功串联起一个完整请求的多个步骤如网关-服务A-服务B。一个常见的验证点是故意在Controller里抛出一个异常看看错误日志是否被切面的AfterThrowing或Around中的catch块捕获并记录同时确保异常依然向上抛出了没有被“吞掉”。走到这一步你的统一请求日志切面就不再是一个简单的工具类而是一个融入了可观测性思维的、为生产环境准备的基础设施组件。它带来的不仅是开发时的便利更是线上问题定位效率的质变。当你下次凌晨三点被告警电话叫醒能在一分钟内通过traceId定位到问题根因时你会感谢今天花时间搭建了它。

相关新闻

唐诗宋词知识图谱构建完整实施方案

唐诗宋词知识图谱构建完整实施方案

一、项目概述1.1 项目目标要构建出结构化、同时关联化、并且可推理的唐诗宋词领域知识图谱, 还要打通诗人、以及词作、再加上朝代、还有意象、包括典故、涉及地理、有关格律、关乎情感这八大核心维度的关联关系, 最终实现将古典诗词知识予以系统化进行梳理、能够智能检索、可以…

2026/10/18 2:41:45 阅读更多 →
制造业企业文件管理方案选型:从存储架构到AI集成能力的技术视角

制造业企业文件管理方案选型:从存储架构到AI集成能力的技术视角

前言最近在制造业IT交流群里看到一个讨论:一位负责某汽车零部件企业信息化的朋友提到,他们公司图纸版本管理混乱的问题困扰已久——设计部门改完图纸发到生产,生产用的却是旧版本,等发现时已经加工了一批料。群里响应的人不少&…

2026/10/20 4:31:36 阅读更多 →
虚幻引擎Niagara粒子系统性能优化实战指南:从CPU/GPU瓶颈到渲染器选型

虚幻引擎Niagara粒子系统性能优化实战指南:从CPU/GPU瓶颈到渲染器选型

1. 项目概述:为什么Niagara粒子性能优化是技术美术的必修课? 在虚幻引擎项目里,Niagara粒子系统是创造视觉奇观的利器,从漫天飞舞的魔法光点,到爆炸后四散的碎片,再到环境中的雾气尘埃,都离不开…

2026/10/17 9:24:29 阅读更多 →

最新新闻

Django生产级博客骨架源码:零配置启动+可部署结构

Django生产级博客骨架源码:零配置启动+可部署结构

简介:这是一套基于Django框架从零开始构建的个人博客网站完整源码,面向Python后端初学者与Web开发入门者,帮助学习者系统掌握Django项目结构、ORM建模、模板渲染、静态资源管理及基础部署流程。压缩包共421个文件,涵盖26个核心Pyt…

2026/10/20 19:41:21 阅读更多 →
PyTorch项目实战:从零搭建图像分类的避坑指南

PyTorch项目实战:从零搭建图像分类的避坑指南

1. 从零手搓一个PyTorch项目:一个老手的踩坑与实战笔记搞深度学习这几年,PyTorch几乎成了我每天都要打交道的工具。但说实话,真正让我头疼的从来不是写模型结构本身,而是从环境配置到训练调优这一整条链路上那些琐碎又致命的细节。…

2026/10/20 19:41:21 阅读更多 →
多虚拟电厂主从博弈与ACPSO-EI-Kriging及APVP-MHA-MTL预测框架全解析

多虚拟电厂主从博弈与ACPSO-EI-Kriging及APVP-MHA-MTL预测框架全解析

先说结论:这个标题的含金量主要在“组合方式”,而不是单点技术。ACPSO、EI、Kriging、主从博弈、APVP、MHA、MTL,每一个单拎出来都有大量现成资料,但把它们按“上层优化下层代理博弈交互”和“多任务注意力共享表征预测”两条线组…

2026/10/20 19:41:21 阅读更多 →
改进DINO-4scale模型实现棉田作物生长监测与目标检测

改进DINO-4scale模型实现棉田作物生长监测与目标检测

棉田生长监测这件事,做农业视觉的人应该深有体会:无人机拍回来的正射影像分辨率很高,但地面棉株一进入封行期,棉铃、棉蕾全被叶片盖住,人工看图数起来又慢又晕。更麻烦的是,棉田目标天生就“小、密、遮挡多…

2026/10/20 19:41:21 阅读更多 →
降AI率实操指南:6类免费工具与人工精修方法

降AI率实操指南:6类免费工具与人工精修方法

每年四五月份,总有学弟学妹半夜给我发消息,上来就问:“论文AI率80%多,学校查重前要求降到10%以下,怎么办?”说实话,这个问题我自己当年也撞上过,被检测报告上的高百分比吓得连夜改稿…

2026/10/20 19:41:21 阅读更多 →
WebSocket消息推送实战:从轮询到高并发长连接的全流程拆解

WebSocket消息推送实战:从轮询到高并发长连接的全流程拆解

接手过一个实时通知服务,业务上要求订单状态变更、客服会话、后台告警都要在秒级内推到用户端。最开始图省事用HTTP轮询,连接一多业务一复杂就明显顶不住——服务端压力大、客户端拿到的数据也不是实时的,高峰时段光无效请求就能把接口拖垮。…

2026/10/20 19:40:18 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →