实战:用LangGraph实现“任务拆解→分步执行→结果校验“闭环
算销量增长率为什么要用图把任务拆成检索、计算、校验三个节点用条件边让校验失败的流程自动回头重查。附已实跑验证的完整代码与真实日志。§1 问题背景为什么一个函数写不完销量增长率分析「手机X 的 2024Q2 销量环比增长率」第一版我用一个函数就写完了。跑第一次就翻车数据查回来缺了上季基数增长率算成 None。然后呢函数没有回头路。这种活至少会以三种方式翻车数据查错或缺失RAG 返回的销量数据缺字段算不出数算出来离谱上季基数缺失导致除零增长率越界结果不可信没有校验错误答案直接交付单函数是直通管道数据错一次答案就错到底。更麻烦的是流程问题错误答案看起来有模有样交付就是事故。要救回来流程得能回头。查错了重查算错了重算校验不过不交付。这就是本文要搭的闭环任务拆解分步执行结果校验。三个环节各司其职缺一个都不闭环。§2 节点把任务拆成可独立重试的三个单元LangGraph 把流程拆成离散节点。节点就是做一件具体事的函数里面可以放 LLM也可以只是普通代码。节点之间不直接调用只通过共享 State 协作官方一句话概括nodes do the work, edges tell what to do next。整个图只有两种元素框和箭头框是节点箭头是边。先把闭环拆成三个节点检索查数据计算算增长率校验判合理性。这层隔离是能独立重试的前提retrieve 重跑一次不会把 compute 的脏中间结果带进来。三个节点函数如下def retrieve(state: SalesState) - dict: attempts state[attempts] 1 # 节点内读改写自增计数 data mock_rag(state[product], attempts) msg f[检索] 第{attempts}次调用RAG拿到销量数据: {data} print(msg) return {sales_data: data, attempts: attempts, trace: [msg]} def compute(state: SalesState) - dict: d state[sales_data] # 只读别人写好的字段 if d.get(previous) in (None, 0): msg [计算] 上季基数缺失无法计算增长率growth_rateNone print(msg) return {growth_rate: None, trace: [msg]} rate (d[current] - d[previous]) / d[previous] msg f[计算] 增长率 ({d[current]} - {d[previous]}) / {d[previous]} {rate:.2%} print(msg) return {growth_rate: rate, trace: [msg]} def validate(state: SalesState) - dict: rate state[growth_rate] attempts state[attempts] if rate is None or rate -1.0 or rate 5.0: if attempts 2 and rate is not None: # 重试上限兜底防死循环 msg f[校验] 第{attempts}次仍不通过({rate:.2%})已达重试上限强制放行并告警 print(msg) return {validation: valid, trace: [msg]} msg f[校验] 增长率 {rate} 不合理(缺失或越界)判 invalid → 回检索重试 print(msg) return {validation: invalid, trace: [msg]} msg f[校验] 增长率 {rate:.2%} 合理判 valid → 输出结果 print(msg) return {validation: valid, trace: [msg]}图上的每个框对应代码里的一个函数。retrieve 写 sales_data 和 attemptscompute 读 sales_data 写 growth_ratevalidate 读 growth_rate 写 validation。字段交接就是数据流。compute 拿到脏数据不自己回头只把 growth_rate 写成 None把判断权交给校验。节点不越权才能被独立替换、独立重试。§3 State节点间的共享状态设计State 是所有节点共享的状态容器一个 TypedDict所有跨节点的数据都从这里过。官方给了两条设计原则要跨步骤保留的才进 State能从别处推导的不存。存原始数据不存格式化文本格式化在节点内做。本例的读写规则如下字段类型写入节点读取节点questionstr输入数据检索sales_datadict数据检索计算、校验growth_ratefloat计算校验validationstr校验条件边(router)attemptsint数据检索(自增)校验(限流)final_answerstrEND 前汇总—代码里的 TypedDict 长这样class SalesState(TypedDict): question: str # 原始问题输入数据检索节点读 product: str # 目标产品 sales_data: dict # 销量数据数据检索写计算/校验读 growth_rate: float # 增长率计算写校验读 validation: str # valid/invalid校验写条件边读 attempts: int # 检索/重试计数检索自增限流防死循环 trace: Annotated[list[str], add] # 状态流转日志累加 reducer表里的读写规则与 TypedDict 一一对应真实代码比表多一个 product 字段检索节点实际用产品名查库少一个 final_answer 汇总字段最小实现里 END 直接收尾不单独汇总。字段交接即数据流。State 的合并规则三条就能说清默认 reducer 是覆盖节点返回什么字段就变成什么attempts 在节点内读改写返回 attempts 1不引入额外 reducertrace 用 Annotated[list[str], add] 累加每步日志追加进列表历史不丢为什么不存格式化文本增长率永远从 sales_data 现算不单独存格式化字符串。存了格式化文本数据一变就得同步改两处。State 只放真相不放展示层。§4 条件边用校验结果驱动重试回环普通边是 A 永远去 B。条件边不同一个路由函数读当前 State返回目标节点名可以配一张映射字典。条件边挂在校验节点之后因为 validation 由校验产出。为什么不挂计算节点因为 validation 还没写出来路由函数没东西可读。route_after_validate 读 state[“validation”]valid 去 ENDinvalid 回 retrieve 重查。灵魂代码只有三行def route_after_validate(state: SalesState) - str: # 路由函数读当前 State返回目标节点名 return state[validation] builder.add_conditional_edges( validate, # 条件边挂在校验节点之后 route_after_validate, # 路由函数读 validation 字段 {valid: END, invalid: retrieve}, # valid 结束invalid 回检索重试 )add_conditional_edges 的第三个参数是映射表。路由函数的返回值是键映射表告诉引擎该去哪。不传映射表返回值直接当节点名。返回值与节点名解耦想改去向只动映射表。防死循环有双保险节点内 attempts 上限超过 2 次强制放行并告警graph 级 recursion_limit默认 1000 步超出抛 GraphRecursionErrorrecursion_limit 是全局护栏attempts 是局部护栏两层都设脏数据拖不垮流程。生产环境可以把 recursion_limit 调小让失败来得快一点。共享状态里的 validation 字段加上条件边就是 agent 的纠错能力。§5 代码实现完整闭环与真实运行日志把节点、State、条件边三块拼起来就是下面的完整闭环。核心盯住 validation它是整条闭环的方向盘写在 State 里条件边只读它决定去向。如何跑安装依赖pip install langgraph。mock RAG 是本地销量库不依赖外部 API、密钥。换真实 RAG 时只替换 mock_rag 一个函数把上面代码原样存成 closed_loop.py运行python closed_loop.py预期输出首轮脏数据 → invalid → 回检索 → 二轮正确 → valid → END退出码 0完整代码langgraph 1.2.10 下实跑验证退出码 0 实战闭环用 LangGraph 实现 任务拆解 → 分步执行 → 结果校验 的最小闭环 场景分析某产品季度销量增长率 数据流检索(RAG) → 计算增长率 → 校验合理性 → 不合法则回检索重试 依赖pip install langgraph 说明本例用 mock 本地销量库模拟 RAG无需外部 API / 密钥可直接复现。 第一次检索故意返回脏数据(缺上季基数)以演示闭环自愈重试后返回正确数据。 from typing import TypedDict, Annotated from operator import add from langgraph.graph import StateGraph, START, END import json # ---------- 1. State 设计共享内存各节点只通过它协作---------- class SalesState(TypedDict): question: str # 原始问题输入数据检索节点读 product: str # 目标产品 sales_data: dict # 销量数据数据检索节点写计算/校验读 growth_rate: float # 增长率计算节点写校验节点读 validation: str # 校验结果 valid/invalid校验节点写条件边读 attempts: int # 检索/重试计数数据检索节点自增限流防死循环 trace: Annotated[list[str], add] # 状态流转日志累加 reducer观察每一步 # mock RAG本地销量库。第一次(attempt1)返回脏数据缺上季基数 # 重试(attempt2)返回正确数据以演示闭环自愈。 SALES_DB {手机X: {2024Q1: 1200, 2024Q2: 1500}} # 本季1500, 上季1200 → 增长率25% def mock_rag(product: str, attempts: int) - dict: if attempts 1: # 第一次查脏数据只拿到本季上季缺失 return {product: product, current: SALES_DB[product][2024Q2], previous: None} # 重试后正确数据 return { product: product, current: SALES_DB[product][2024Q2], previous: SALES_DB[product][2024Q1], } # ---------- 2. 三个节点 ---------- def retrieve(state: SalesState) - dict: attempts state[attempts] 1 data mock_rag(state[product], attempts) msg f[检索] 第{attempts}次调用RAG拿到销量数据: {data} print(msg) return {sales_data: data, attempts: attempts, trace: [msg]} def compute(state: SalesState) - dict: d state[sales_data] if d.get(previous) in (None, 0): # 上季基数缺失 → 无法计算增长率记 None交给校验节点判无效 msg [计算] 上季基数缺失无法计算增长率growth_rateNone print(msg) return {growth_rate: None, trace: [msg]} rate (d[current] - d[previous]) / d[previous] msg f[计算] 增长率 ({d[current]} - {d[previous]}) / {d[previous]} {rate:.2%} print(msg) return {growth_rate: rate, trace: [msg]} def validate(state: SalesState) - dict: rate state[growth_rate] attempts state[attempts] # 校验规则增长率必须可计算且在合理区间 [-100%, 500%] if rate is None or rate -1.0 or rate 5.0: # 超过 2 次仍不通过则强制放行并告警防死循环兜底 if attempts 2 and rate is not None: msg f[校验] 第{attempts}次仍不通过({rate:.2%})已达重试上限强制放行并告警 print(msg) return {validation: valid, trace: [msg]} msg f[校验] 增长率 {rate} 不合理(缺失或越界)判 invalid → 回检索重试 print(msg) return {validation: invalid, trace: [msg]} msg f[校验] 增长率 {rate:.2%} 合理判 valid → 输出结果 print(msg) return {validation: valid, trace: [msg]} # ---------- 3. 条件边用 validation 驱动闭环 ---------- def route_after_validate(state: SalesState) - str: # 返回 valid / invalid由下方映射决定去向 return state[validation] # ---------- 4. 组装图 ---------- builder StateGraph(SalesState) builder.add_node(retrieve, retrieve) builder.add_node(compute, compute) builder.add_node(validate, validate) builder.add_edge(START, retrieve) builder.add_edge(retrieve, compute) builder.add_edge(compute, validate) # 校验节点之后挂条件边valid→END(输出)invalid→回 retrieve(重试) builder.add_conditional_edges(validate, route_after_validate, {valid: END, invalid: retrieve}) graph builder.compile() # ---------- 5. 运行 ---------- if __name__ __main__: init { question: 分析手机X的2024Q2销量环比增长率, product: 手机X, attempts: 0, } print( 初始状态 ) print(json.dumps({k: v for k, v in init.items()}, ensure_asciiFalse)) print( 运行stream_modevalues 观察每一步 State 快照) for step in graph.stream(init, {recursion_limit: 10}, stream_modevalues): print(--- State 快照 ---) print(json.dumps(step, ensure_asciiFalse)) print( 运行结束 ) final graph.invoke(init, {recursion_limit: 10}) print(最终增长率:, final.get(growth_rate))真实运行日志主编实跑留底中间快照省略重复字段。stream_modevalues 会把每一步 State 快照打出来这是观察图流转的标准姿势照着自己跑一遍应该逐行一致[检索] 第1次调用RAG拿到销量数据: {product: 手机X, current: 1500, previous: None} [计算] 上季基数缺失无法计算增长率growth_rateNone [校验] 增长率 None 不合理(缺失或越界)判 invalid → 回检索重试 --- State 快照 --- {..., growth_rate: null, validation: invalid, attempts: 1, trace: [...]} [检索] 第2次调用RAG拿到销量数据: {product: 手机X, current: 1500, previous: 1200} [计算] 增长率 (1500 - 1200) / 1200 25.00% [校验] 增长率 25.00% 合理判 valid → 输出结果 --- State 快照 --- {..., growth_rate: 0.25, validation: valid, attempts: 2, trace: [...]} 最终增长率: 0.25读日志看闭环怎么自愈第一次循环脏数据缺 previouscompute 写 growth_rateNone校验判 invalid条件边指回 retrieve第二次循环数据到位算出 0.25判 valid流向 ENDattempts 从 1 变 2validation 从 invalid 变 valid就是一次自愈的全过程。mock_rag 的 attempts1 分支是故意的故障注入先喂一次脏数据验证闭环真会自愈。这种注入测试比读文档管用。§6 原理与边界三类错误来源与适用场景6.1 三类错误从哪来这套拆解思路有出处。Plan-and-Solve 论文指出Zero-shot-CoT 的推理结果有三类错误计算错误、缺失步骤、语义误解。解法是先把大任务 plan 成子任务再按序 solve。论文在 GPT-3 上评测十个数据集Plan-and-Solve 全面超过 Zero-shot-CoT在数学推理任务上与 8-shot CoT 相当。Despite the success of Zero-shot-CoT, it still suffers from three pitfalls: calculation errors, missing-step errors, semantic misunderstanding errors.—— Plan-and-Solve PromptingarXiv:2305.04091论文提的三类错误对应到本文是三处拦截计算错误 → 计算节点先判基数缺失就不硬算缺失步骤 → 校验判 invalid强制回检索补齐语义误解 → 校验的合理区间拦下越界值LangChain 官方博客把同一思想做成 plan-and-execute 架构planner 拆计划executor 按计划执行。ReAct 每走一步都要调一次大模型plan-and-execute 只在拆计划和收尾时调ReAct 一次只规划一个子问题plan-and-execute 先想清楚整条路径executor 执行完planner 再被叫回来决定收尾还是改计划。校验节点 三类错误的兜底拦截器。数据不对就重查算错就重算不让错误答案直接交付。6.2 什么时候别用图反过来也要知道边界一次函数能算完的事别上图。图的收益来自「要回头重试」的场景自检有代价。官方明说 reflection 耗时长低延迟应用不合适适合质量优先的知识密集任务更重的兜底interrupt 人机回环、checkpointer 持久化、多智能体留待下篇判断标准就一条流程里有没有「要回头」的决策点。没有就别上图的复杂度。数据质量越差、越需要自检的任务图的收益越大。§7 小结拆解、执行、校验的三段式条件边加共享状态等于让 agent 拥有纠错能力。全文可归结为一个三段式任务拆解 → 三个节点retrieve / compute / validate分步执行 → State 字段交接sales_data → growth_rate → validation结果校验 → 条件边回环invalid 回 retrievevalid 到 END学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

相关新闻

亚马逊运营高效工具链与实战资源全解析

亚马逊运营高效工具链与实战资源全解析

1. 亚马逊运营资源全解析:从入门到精通的必备工具箱做亚马逊运营这些年,我收集整理了大量实用资源,今天把这些压箱底的干货一次性分享给大家。这份资源合集不是简单的链接堆砌,而是经过实战验证、能真正提升运营效率的工具和方法论…

2026/10/20 18:22:05 阅读更多 →
千牛客服系统:夜间全自动客服,3分钟内回复率100%

千牛客服系统:夜间全自动客服,3分钟内回复率100%

千牛客服系统:夜间全自动客服,3分钟内回复率100% 电商这行没有护城河,唯一壁垒就是自动化程度。千牛的自动回复与客服,是店群运营中最耗人力也最容易出错的环节。 店群客服是纯人力消耗战。一个店日均50条咨询,20个店…

2026/10/17 2:40:20 阅读更多 →
PyQt5 UI自适应与缩放:从布局管理到高DPI支持的完整实现方案

PyQt5 UI自适应与缩放:从布局管理到高DPI支持的完整实现方案

1. 项目概述:为什么UI自适应与缩放是PyQt5开发的必修课在桌面应用开发领域,尤其是使用PyQt5这类成熟框架时,开发者常常会遇到一个看似基础却极易被忽视的挑战:如何让精心设计的用户界面(UI)在不同尺寸、不同…

2026/10/20 16:08:42 阅读更多 →

最新新闻

智能助手技能机制全链路拆解:存放、加载、更新与维护实战

智能助手技能机制全链路拆解:存放、加载、更新与维护实战

1. 从一次技能失效说起:为什么我要拆解这套机制去年冬天,我负责维护的一个智能协作助手突然在某个任务上"失忆"了。前一天还能准确调用的技能,第二天就像从没存在过一样,用户问它问题,它只会礼貌地回复"…

2026/10/20 18:22:01 阅读更多 →
Hello world!:从第一行代码到环境自检与冒烟测试

Hello world!:从第一行代码到环境自检与冒烟测试

每个程序员的电脑里,都住着一行 Hello world!。不管是写前端的、做嵌入式的,还是半路出家搞数据分析的,第一次敲下这行代码、按下运行键、盯着终端里的输出愣住两秒的时刻,基本可以算作职业生涯里的第一个"高光瞬间"。这…

2026/10/20 18:22:01 阅读更多 →
DeepSeek开源Agent框架插件化设计深度拆解:从注册到执行链路

DeepSeek开源Agent框架插件化设计深度拆解:从注册到执行链路

1. 拆之前先想清楚:为什么要看这个框架第一次看到 DeepSeek 开源 Agent 框架的消息,我其实没太当回事。市面上 Agent 框架已经多到数不过来,从早期的任务编排库到后来的多智能体协作平台,大部分都是把 LLM 调用、工具注册、对话循…

2026/10/20 18:22:01 阅读更多 →
插件化Agent框架源码拆解:工具、执行器、记忆与规划器四层设计

插件化Agent框架源码拆解:工具、执行器、记忆与规划器四层设计

1. 拆之前先想清楚:为什么要看这个 Agent 框架大模型圈子里做应用的人,最近一年绕不开一个词——Agent。但真正动手写过 Agent 的人都知道,从"能聊天"到"能干活"之间隔着一道巨大的鸿沟。你让模型调用一个工具&#xff0…

2026/10/20 18:22:01 阅读更多 →
AI中台数据资产智能清查指令与核验模板实战指南

AI中台数据资产智能清查指令与核验模板实战指南

1. 数据资产清查为什么需要一套“指令模板”做过企业级AI中台落地的人都有一个共同感受:模型训练、推理服务、知识库检索这些“显性能力”往往被反复讨论,但真正拖慢项目进度的,反而是最不起眼的一环——系统里到底有哪些数据资产、它们分布在…

2026/10/20 18:22:01 阅读更多 →
cgroups 核心模型与实操:从 v1 到 v2 的资源限制机制详解

cgroups 核心模型与实操:从 v1 到 v2 的资源限制机制详解

这段时间在帮人排查一套测试环境,机器一早就卡住,SSH 敲半天都进不去。登上去一看,好几个容器在抢 CPU,内存也快被打穿。想定位到底是哪个容器干的,光靠 namespace 根本看不出来——namespace 只解决“容器能看到什么”…

2026/10/20 18:21:00 阅读更多 →

日新闻

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 阅读更多 →