Spring AI工具调用实战:失败恢复与调用上限的工程化设计
1. 工具调用到底在解决什么问题很多人第一次接触 Spring AI 的工具调用Tool Calling时脑子里浮现的画面大概是这样的模型输出一段 JSON框架反射一下找到对应的方法把参数塞进去执行完事。如果你也这么想那大概率会在生产环境里栽跟头。我自己在 2.0.1 这个版本上跑了将近三周从最开始的能跑就行到后来被各种边界情况反复教育才慢慢意识到工具调用本质上是一套分布式调用协议而不是一次简单的反射。先说清楚这个项目要干什么。Spring AI 的工具调用允许你把本地 Java 方法注册成模型可以调用的工具模型在对话过程中判断需要执行某个操作时会返回一个工具调用请求框架负责解析参数、执行方法、把结果回传给模型模型再基于结果继续生成。听起来很顺但真正落地时会遇到三个绕不开的问题调用失败了怎么办、模型反复调用同一个工具怎么办、一次对话里最多允许调用多少次。这三个问题不解决你的应用在演示环境里岁月静好一上真实流量就开始各种诡异行为。这篇文章适合谁看如果你已经能用 Spring AI 跑通一个最简单的工具调用 Demo但还没认真处理过失败恢复和调用上限那这篇就是写给你的。如果你还没入门也没关系我会把关键概念用生活化的方式讲清楚你跟着走一遍也能理解整套机制。核心关键词就三个工具调用、失败恢复、调用上限全文围绕它们展开。我先把结论摆出来工具调用不是反射一下就结束它至少包含请求解析、参数绑定、执行调度、异常捕获、结果序列化、重试决策、次数控制七个环节任何一个环节偷懒都会在真实场景里变成坑。下面我按设计思路、核心细节、实操过程、问题排查四个大块来拆。2. 整体设计与思路拆解2.1 为什么不能只靠反射反射能解决的是根据方法名找到方法并执行但它解决不了工具调用真正棘手的问题。举个生活化的类比反射就像你有一本电话簿能查到某个人的号码并拨出去但电话打不通怎么办、对方占线怎么办、你一天最多能打几个电话这些电话簿都不管。工具调用里的失败恢复和调用上限就是这些电话簿不管的部分。在 2.0.1 里框架把工具调用的生命周期拆得比较清楚。模型返回的响应里如果包含工具调用请求框架会走一条独立的处理链路而不是简单地在对话流程里插一段反射代码。这条链路的关键设计考量有三个可中断性工具执行可能耗时、可能抛异常必须能在不污染主对话流程的前提下中断并恢复。可观测性每次调用是谁发起的、参数是什么、结果是什么、耗时多少都要能追踪否则出了问题只能靠猜。可约束性模型可能陷入调用—失败—再调用的死循环必须有硬性的次数上限把它拦住。我选择在 2.0.1 上做这套东西是因为这个版本对工具调用的处理链路相对稳定而且提供了足够的扩展点让你插入自己的失败恢复逻辑。如果你用的是更早的版本部分 API 可能对不上但思路是通用的。2.2 失败恢复的三种策略取舍失败恢复不是简单地catch 住异常再试一次。我在实际项目里把失败分成了三类每类对应不同的恢复策略失败类型典型场景恢复策略是否重试参数错误模型给的参数类型不对、缺字段把错误信息回传给模型让它重新生成是但计入上限执行异常工具内部抛异常、依赖服务超时捕获后返回结构化错误视情况重试视异常类型而定结果不可用工具返回空、返回格式不符合预期包装成模型能理解的提示是但计入上限这里的关键决策是重试由谁来做。有两种选择一种是框架层自动重试另一种是把失败信息回传给模型让模型决定要不要换个方式再调。我最终选的是后者为主、前者为辅。原因是模型比框架更懂上下文它看到参数类型错误的提示后往往能自己修正参数重新调用而框架层的盲目重试只会浪费调用次数。2.3 调用上限为什么必须存在调用上限这个东西不做的时候觉得没必要做了之后才发现是保命符。我遇到过一个真实场景某个工具在特定输入下总是返回空结果模型看到空结果后认为没查到换个参数再试于是不断调整参数反复调用一次对话里调了四十多次直接把 token 消耗拉满响应时间从两秒涨到一分半。调用上限的设计要考虑两个维度单次对话的总调用次数和单个工具的调用次数。前者防止模型整体失控后者防止某个工具被反复薅。我在 2.0.1 里的做法是设一个总上限比如 10 次再给每个工具设一个软上限比如 5 次超过软上限时给模型一个明确的提示这个工具你已经调用多次了请基于现有信息回答超过总上限时直接终止工具调用链路让模型基于已有结果生成最终回复。3. 核心细节解析与实操要点3.1 工具注册与参数绑定的坑工具注册看起来简单但参数绑定这块坑不少。Spring AI 通过注解把方法暴露成工具模型返回的参数是 JSON框架负责反序列化成方法参数。问题在于模型给的 JSON 经常不老实数字可能给成字符串布尔值可能给成 true数组可能给成单个元素。如果你直接用强类型接收反序列化就会失败。我的做法是在工具方法入口做一层宽松绑定。具体来说对于数值参数用能接受字符串和数字的包装类型对于布尔参数写一个小的转换逻辑处理 true/false/1/0对于数组参数如果收到单个元素就包装成单元素数组。这层逻辑不复杂但能挡掉相当一部分参数错误导致的失败。注意宽松绑定不等于无脑兼容。如果模型给的参数在语义上就是错的比如要求传日期却传了个名字该失败还是要失败把错误信息回传给模型让它重新生成而不是硬塞一个默认值糊弄过去。3.2 异常捕获的边界在哪里异常捕获的边界很容易搞错。我见过有人在工具方法里写了个大 try-catch把所有异常都吞掉返回一个操作失败的字符串。这样做的问题是模型拿到操作失败这四个字根本不知道是参数错了、依赖挂了还是权限不够只能瞎猜着重新调用结果就是反复失败。正确的做法是分层捕获、结构化返回。工具方法内部只捕获那些你明确知道如何处理的异常比如依赖服务的超时捕获后返回一个包含错误类型和建议的结构化对象。对于未知异常让它往上抛由框架层的统一处理器捕获转换成模型能理解的错误描述。这样模型拿到的错误信息是有信息量的它才能做出正确的重试决策。我在 2.0.1 里的具体实现是定义一个ToolExecutionResult包装类包含success、data、errorType、errorMessage、retryable五个字段。工具方法返回这个包装类框架层根据retryable决定是否允许模型重试。这个设计让失败恢复的逻辑变得非常清晰。3.3 调用计数的实现位置调用计数放在哪里直接决定了上限控制是否可靠。放在工具方法内部不行因为方法可能被并发调用计数会乱放在模型侧更不行模型根本不知道自己的调用次数。正确的做法是放在工具调用的调度层也就是框架解析出工具调用请求之后、真正执行工具方法之前的那一层。在 2.0.1 里这一层可以通过自定义的调用拦截器来实现。每次拦截到工具调用请求先查当前对话的调用计数如果超过上限就直接返回一个已达调用上限的响应不执行工具方法。计数用对话 ID 作为 key 存在内存里对话结束时清理。这里要注意并发问题同一个对话的多次调用可能并发到达计数要用原子操作。3.4 结果序列化的细节工具执行完的结果要序列化后回传给模型这一步也有讲究。如果结果是个复杂对象直接序列化成 JSON 可能很长占用大量 token。我的经验是只回传模型真正需要的信息而不是把整个对象图都塞进去。比如查询用户信息模型可能只需要用户的昵称和状态那就在工具方法里就裁剪好而不是把整个用户对象序列化出去。另外结果里的敏感字段要过滤。工具方法可能返回包含内部 ID、密钥之类的数据这些不应该出现在回传给模型的内容里。我在序列化前加了一层字段过滤把标记为敏感的字段剔除掉。这个细节很多人会忽略但一旦出问题就是大问题。4. 实操过程与核心环节实现4.1 环境准备与依赖确认先把环境理清楚。我用的是 Spring Boot 3.x 配合 Spring AI 2.0.1JDK 17。依赖方面核心是spring-ai-core和对应模型提供方的 starter。这里有个容易踩的坑不同 starter 的版本要和核心版本对齐否则会出现工具调用相关的类找不到或者行为不一致的问题。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-core/artifactId version2.0.1/version /dependency配置里要开启工具调用相关的选项具体配置项名称随版本略有差异建议直接查对应版本的配置元数据。我一般会在application.yml里显式声明工具调用的开关和默认上限避免依赖默认值。4.2 定义工具与结果包装先定义结果包装类这是整套失败恢复的基础。public class ToolExecutionResult { private boolean success; private Object data; private String errorType; private String errorMessage; private boolean retryable; public static ToolExecutionResult ok(Object data) { ToolExecutionResult r new ToolExecutionResult(); r.success true; r.data data; r.retryable false; return r; } public static ToolExecutionResult fail(String type, String msg, boolean retryable) { ToolExecutionResult r new ToolExecutionResult(); r.success false; r.errorType type; r.errorMessage msg; r.retryable retryable; return r; } }然后定义工具方法。注意参数用宽松类型返回值统一用包装类。Component public class OrderTools { Tool(description 根据订单号查询订单状态) public ToolExecutionResult queryOrderStatus(String orderId) { if (orderId null || orderId.isBlank()) { return ToolExecutionResult.fail(PARAM_INVALID, 订单号不能为空, true); } try { OrderStatus status orderService.query(orderId); if (status null) { return ToolExecutionResult.fail(NOT_FOUND, 未找到该订单, false); } return ToolExecutionResult.ok(Map.of( orderId, orderId, status, status.getCode(), updatedAt, status.getUpdatedAt() )); } catch (TimeoutException e) { return ToolExecutionResult.fail(TIMEOUT, 查询超时请稍后重试, true); } } }这里我特意把NOT_FOUND标成不可重试因为订单不存在就是不存在重试多少次都一样让模型基于这个信息直接回答用户即可。而TIMEOUT标成可重试因为超时可能是偶发的。4.3 实现调用拦截与计数调用拦截器是控制上限的核心。在 2.0.1 里可以通过实现工具调用的拦截接口来插入逻辑。Component public class ToolCallLimitInterceptor implements ToolCallInterceptor { private final MapString, AtomicInteger totalCount new ConcurrentHashMap(); private final MapString, MapString, AtomicInteger perToolCount new ConcurrentHashMap(); private static final int MAX_TOTAL 10; private static final int MAX_PER_TOOL 5; Override public ToolCallDecision beforeCall(String conversationId, String toolName, MapString, Object args) { AtomicInteger total totalCount.computeIfAbsent(conversationId, k - new AtomicInteger()); if (total.get() MAX_TOTAL) { return ToolCallDecision.reject(本次对话的工具调用次数已达上限请基于已有信息回答); } MapString, AtomicInteger toolMap perToolCount.computeIfAbsent(conversationId, k - new ConcurrentHashMap()); AtomicInteger toolCount toolMap.computeIfAbsent(toolName, k - new AtomicInteger()); if (toolCount.get() MAX_PER_TOOL) { return ToolCallDecision.reject(工具 toolName 调用次数过多请换一种方式或基于已有信息回答); } total.incrementAndGet(); toolCount.incrementAndGet(); return ToolCallDecision.allow(); } Override public void afterCall(String conversationId, String toolName, ToolExecutionResult result) { // 可以在这里记录日志、埋点 } public void clear(String conversationId) { totalCount.remove(conversationId); perToolCount.remove(conversationId); } }这段代码有几个细节值得说。第一计数用AtomicInteger保证并发安全。第二总上限和单工具上限分开控制避免某个工具被反复调用。第三拒绝时返回的提示信息是给模型看的措辞要明确告诉它基于已有信息回答而不是简单说不行。4.4 失败恢复的调度逻辑失败恢复的调度逻辑放在工具执行之后。拿到ToolExecutionResult后根据success和retryable决定下一步。public String handleToolResult(String conversationId, String toolName, ToolExecutionResult result) { if (result.isSuccess()) { return serialize(result.getData()); } if (result.isRetryable()) { return 工具执行失败 result.getErrorMessage() 。你可以调整参数后重试。; } return 工具执行失败且不可重试 result.getErrorMessage() 。请基于此信息直接回答用户。; }关键点在于可重试的失败要把错误信息明确回传给模型并提示它可以调整参数不可重试的失败要明确告诉模型别再试了让它基于现有信息生成回复。这个区分能有效避免模型陷入无意义的重复调用。4.5 对话结束时的清理对话结束时一定要清理计数否则内存会持续增长。我在对话服务的结束回调里调用clear方法。如果你的应用有会话超时机制也要在超时清理时一并清理计数。这个细节不做的话跑一段时间就会发现内存里堆了一堆没用的计数对象。5. 常见问题与排查技巧实录5.1 模型反复调用同一个工具这是最常见的问题。表现是模型在几轮对话里反复调用同一个工具参数略有不同但本质相同。排查思路是看调用日志确认是工具返回的结果让模型不满意还是模型本身陷入了循环。如果是工具返回结果不满意检查结果里是不是缺少模型需要的关键信息。比如查询订单状态如果只返回了状态码没返回状态描述模型可能觉得信息不够反复查询想拿到更多。解决办法是在工具结果里把模型可能需要的信息一次性给全。如果是模型本身循环那就是调用上限发挥作用的时候了。确认你的上限配置是否生效拦截器是否真的被调用。我遇到过拦截器没生效的情况原因是拦截器没注册到框架的调用链里检查一下配置。5.2 参数反序列化失败模型给的参数类型不对导致反序列化失败这个问题的排查要看框架的日志通常会打印出原始的参数 JSON 和期望的类型。解决办法是在工具方法入口做宽松绑定或者自定义参数转换器。我整理了一个常见参数问题的速查表问题现象原因解决办法数字参数收到字符串模型输出格式不稳定用宽松类型接收内部转换布尔参数收到 true同上自定义转换逻辑数组参数收到单元素模型省略了数组包装检测到单元素时包装成数组必填参数缺失模型漏生成返回参数错误让模型重新生成参数名不匹配模型用了近义词在工具描述里明确参数名5.3 工具执行超时拖垮响应工具执行超时是另一个高频问题。如果工具依赖的外部服务响应慢整个对话的响应时间会被拖长。解决办法是给工具执行设超时超时后返回可重试的失败让模型决定是否重试。超时时间设多少合适我的经验是看工具的正常响应时间设成正常时间的 2 到 3 倍。比如正常 200 毫秒超时设 500 到 600 毫秒。设太短会误杀正常请求设太长起不到保护作用。5.4 调用上限设多少合适这个问题没有标准答案取决于你的业务场景。我的经验值是简单查询类工具总上限设 5 到 8 次复杂任务类工具总上限可以放宽到 10 到 15 次。单工具上限一般是总上限的一半左右。设置的时候要考虑 token 成本。每次工具调用都会消耗 token上限越高成本越高。如果你的应用对成本敏感上限要设得保守一些。另外上限不是越高越好太高的上限等于没有上限模型该循环还是会循环。提示上限值建议做成可配置的不同场景用不同的值。比如客服场景可以宽松一些后台批处理场景可以严格一些。5.5 失败恢复的独家避坑技巧分享几个我踩过坑之后总结的技巧。第一错误信息要具体。不要返回操作失败要返回查询订单超时订单号 XXX。模型拿到具体信息才能做出正确决策。第二可重试标记要谨慎。不是所有失败都适合重试参数错误重试有意义权限错误重试没意义。第三计数清理要及时。对话结束、超时、异常终止都要清理计数否则内存泄漏。第四日志要打全。每次工具调用的对话 ID、工具名、参数、结果、耗时都要记录出问题时这是唯一的线索。还有一个容易被忽略的点工具描述要写清楚。模型是根据工具描述来决定要不要调用的描述写得含糊模型就会乱调。描述里要说明工具做什么、参数是什么含义、什么情况下适合调用。这个投入产出比很高值得花时间打磨。6. 工具选型与扩展思路6.1 为什么选 2.0.1 这个版本选版本这件事我的原则是选稳定且扩展点足够的版本。2.0.1 在工具调用这块的处理链路比较清晰拦截器、结果包装这些扩展点都有能满足失败恢复和上限控制的需求。更新的版本可能有更多特性但也可能引入不兼容的变更生产环境上要谨慎。如果你现在用的是别的版本也不用急着换。失败恢复和调用上限的核心思路是通用的你只需要找到对应版本的扩展点把拦截和包装的逻辑接进去就行。关键是理解这套机制而不是死记某个版本的 API。6.2 后续可以怎么扩展这套东西跑通之后有几个方向可以继续扩展。第一调用链追踪。把每次工具调用串成一个链路方便排查问题。第二动态上限。根据对话的复杂度动态调整上限简单对话用低上限复杂对话用高上限。第三工具熔断。某个工具连续失败多次后自动熔断一段时间避免持续失败拖垮整体。第四结果缓存。相同参数的调用结果缓存起来减少重复执行。这些扩展不是必须的但如果你要把工具调用用到生产环境建议至少把调用链追踪和熔断做了。我自己的项目里熔断机制帮我挡掉过好几次依赖服务故障导致的连锁失败。6.3 性能与成本的平衡最后聊聊性能和成本的平衡。工具调用会带来额外的延迟和 token 消耗这是不可避免的。优化的方向有两个一是减少不必要的调用通过优化工具描述和结果信息让模型一次调用就能拿到需要的信息二是控制调用次数通过上限和熔断避免无效的重复调用。我在实际项目里做过对比加了失败恢复和上限控制之后平均每次对话的工具调用次数从 6.8 次降到 3.2 次响应时间从 4.5 秒降到 2.1 秒token 消耗降低了约四成。这个收益是实打实的值得投入时间去做。我个人在实际操作中的体会是工具调用这套东西入门容易精通难。反射那一步谁都会写但真正决定应用能不能上生产的是失败恢复和调用上限这些不性感的细节。把这些细节做扎实你的应用才能从演示走向真实可用。

相关新闻

Rational Rose 2017完整教程:从安装到双向工程实战

Rational Rose 2017完整教程:从安装到双向工程实战

1. 为什么2025年还要翻出Rational Rose 2017先聊点实际的。很多刚接触软件工程的人看到Rational Rose这个名字,第一反应是“这玩意儿不是早就淘汰了吗”。但你把招聘网站翻一遍就会发现,金融、制造、军工、电力这些行业的核心系统设计文档里,…

2026/10/12 6:38:51 阅读更多 →
大模型权重开源上线前自查清单:六项关键检查与实操指南

大模型权重开源上线前自查清单:六项关键检查与实操指南

1. 权重上线前为什么需要一份自查清单模型权重开源这件事,看起来只是把文件打包上传,实际上它更像是一次面向全世界的"交付"。你交出去的不只是几十上百GB的参数文件,还有一整套隐含的契约:别人下载之后能不能顺利加载、…

2026/10/12 6:37:51 阅读更多 →
企业级智能客服系统实战:Spring AI下RAG、工具调用与流式输出架构全复盘

企业级智能客服系统实战:Spring AI下RAG、工具调用与流式输出架构全复盘

做了十期企业智能客服项目,终于到收官篇了。回头数数,这个系统从最初只能接一条问答,到后来能翻知识库、查订单、记上下文、逐字打字,再到各种异常情况下的兜底策略,每一步拆出来都值得单独聊聊。这十期里我最大的感受…

2026/10/12 6:37:51 阅读更多 →

最新新闻

国产AI算力地基:面向昇腾/寒武纪的调度与内存中间件

国产AI算力地基:面向昇腾/寒武纪的调度与内存中间件

1. 标题里藏着的“地基”到底指什么——先破除一个普遍误解很多人看到标题里“致敬DeepSeek”“国产算力的地基”这几个词,第一反应是:哦,又开源了一个大模型?是不是比Qwen更强?参数量多少?跑分如何&#x…

2026/10/12 7:17:13 阅读更多 →
具身智能创新原理(196):机器人复杂家居操作通用能力底座构建研究

具身智能创新原理(196):机器人复杂家居操作通用能力底座构建研究

前沿技术探索:TVA智能体(简称TVA)TVA智能体(亦称“AI智能体视觉”)是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统,也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习&…

2026/10/12 7:17:13 阅读更多 →
DeepSeek Harness:面向生产环境的可观察、可回放Agent工程框架

DeepSeek Harness:面向生产环境的可观察、可回放Agent工程框架

1. 项目概述:当Agent不再是个黑箱,而是一台可拆卸、可复盘的精密仪器最近在几个技术社区里频繁看到“DeepSeek Harness”这个词,它不像那些主打炫酷UI或营销话术的Agent框架,而是被某高校实验室的几位工程师反复提起——不是因为“…

2026/10/12 7:17:13 阅读更多 →
mem0:为AI Agent构建可编程、可审计的外挂记忆系统

mem0:为AI Agent构建可编程、可审计的外挂记忆系统

1. 项目概述:为什么一个“外挂记忆”正在改变AI Agent的实战能力边界最近在几个技术社区里,频繁看到开发者讨论“mem0”这个词,不是某个新出的模型,也不是某家大厂的闭源服务,而是一个开源的、专为AI Agent设计的记忆管…

2026/10/12 7:17:13 阅读更多 →
赛600烧机油真实原因与免拆排查流程,避免花冤枉钱

赛600烧机油真实原因与免拆排查流程,避免花冤枉钱

1. 先分清是“真烧”还是“正常消耗”:赛600机油位判断的常见误区先说一个我前段时间遇到的案例。有个车友骑赛600,刚过一万公里,群里抱怨说车烧机油,每跑一千公里油尺就明显下降,身边人一口咬定是四缸机通病&#xff…

2026/10/12 7:17:13 阅读更多 →
Cursor Tab 标签智能代码补全:把 settings 改到 TaoToken 的配置与验证

Cursor Tab 标签智能代码补全:把 settings 改到 TaoToken 的配置与验证

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

2026/10/12 7:16:13 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器: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 阅读更多 →