1. 从“黑盒神话”到工程现实Agent 框架到底卡在哪过去一年我几乎把市面上叫得出名字的 Agent 框架都跑了一遍。从最早期那种“给个目标就自动干活”的演示到后来接入真实业务系统的项目踩过的坑比写过的提示词还多。标题里说的“黑盒神话”其实特别贴切——很多框架在 Demo 阶段看起来无所不能一旦进入真实工程环境问题就全暴露出来了。先说清楚这篇文章要聊什么。Agent 框架指的是帮开发者构建、编排、运行智能体的一套工具和抽象层它负责把大模型的推理能力、工具调用、记忆管理、任务规划这些环节串起来。LLM是这套体系的大脑提示词工程和上下文工程是控制大脑怎么思考的手段。而“物理外化”这个说法是我自己总结的一个词意思是把原本藏在框架内部、看不见摸不着的执行逻辑外化成可观测、可干预、可复现的物理实体——比如显式的状态机、独立部署的工具服务、落盘的中间结果。这篇文章适合谁看如果你正在选型 Agent 框架或者已经用上了但总觉得“它到底在干嘛”说不清楚又或者你是个后端工程师想把这套东西接进 SpringBoot、若依这类现有系统里那接下来的内容应该能帮你省下不少试错时间。我不打算吹某个框架多牛而是想从工程角度把“为什么很多 Agent 项目做不下去”这件事拆开讲透。核心问题其实就一句话大多数 Agent 框架把太多东西藏在了黑盒里。模型为什么选这个工具记忆为什么丢了任务为什么卡住你只能看日志猜。这在 Demo 里无所谓在真实业务里就是灾难。我见过一个团队用某框架做客服 Agent上线三天就回滚了原因很简单——客户问“我的订单到哪了”Agent 调了三次查询接口每次参数都不一样最后返回了一个完全无关的答案而开发团队根本不知道中间发生了什么。所以“物理外化”不是赶时髦是被逼出来的。当你的 Agent 要处理钱、处理订单、处理真实用户的时候你必须能看见每一步、能干预每一步、能复现每一步。接下来的内容我会从框架设计思路、核心细节、实操落地、问题排查几个层面把这件事讲清楚。2. 主流 Agent 框架的设计思路与选型逻辑2.1 为什么“全自动”框架在工程里容易翻车先说说我观察到的现象。早期 Agent 框架的设计哲学基本是“让模型自己决定一切”——你给一个目标模型自己拆任务、自己选工具、自己判断是否完成。这套逻辑在论文里很漂亮在演示视频里很惊艳但落到工程里第一个问题就是不可控。我拿一个真实场景举例。假设你要做一个“自动整理会议纪要并发送邮件”的 Agent。全自动框架的做法是模型读会议记录自己决定要不要查日历、要不要查参会人邮箱、要不要分段总结、要不要加附件。听起来很智能对吧但实际跑起来模型可能因为某句话的措辞不同这次查了日历下次没查这次把纪要分成三段下次分成五段这次发送前确认了收件人下次直接发了。你没法跟业务方解释“为什么这次和上次不一样”。更深层的问题是错误归因困难。当 Agent 输出错误结果时你面对的是一个黑盒是提示词写得不好是工具描述有歧义是模型本身能力不够还是框架的编排逻辑有 bug在全自动框架里这些因素搅在一起排查成本极高。我试过用某框架做一个数据查询 Agent明明工具返回了正确数据但最终答案就是错的。查了两天才发现框架在中间做了一次“自动摘要”把关键数字截断了。这种问题你不把中间步骤外化出来根本找不到。所以选型时第一个要问自己的问题不是“这个框架功能多不多”而是“它让我看见多少”。如果一个框架连中间步骤的输入输出都不给你看那它在工程环境里的价值就要打问号。2.2 三类框架的工程适配度对比我把用过的框架大致分成三类每类的工程适配度差别很大。第一类是编排型框架代表思路是把 Agent 的执行流程画成图或者状态机节点和边由开发者定义模型只在节点内部做决策。这类框架的好处是流程可控你知道每一步在干嘛。缺点是灵活性受限遇到没预设的路径就抓瞎。适合业务流程相对固定的场景比如审批、数据同步、报表生成。第二类是自主型框架代表思路是给模型一个目标和一个工具箱剩下全交给模型。这类框架灵活度最高但工程风险也最大。我一般只在探索性任务里用比如“帮我调研一下这个技术方向”不会用在核心业务链路上。第三类是混合型框架也是我现在比较倾向的。它把流程分成“确定段”和“自主段”确定段用状态机控制自主段让模型发挥。比如一个客服 Agent意图识别和路由用确定逻辑具体回答生成用模型自主。这样既保证了主干可控又保留了灵活性。下面这张表是我自己整理的对比供参考维度编排型自主型混合型流程可控性高低中高灵活度低高中排查难度低高中适合场景固定流程探索任务真实业务上手成本中低中高生产可用性高低高选型时我的建议是先问业务能不能接受不确定性再问团队能不能扛住排查成本。两个答案都是“不能”那就老老实实选编排型或者混合型。2.3 “物理外化”范式的核心主张“物理外化”这个词听起来玄其实核心就三条。第一条状态外化。Agent 当前处于什么阶段、已经完成了哪些步骤、下一步该干嘛这些信息不能只存在模型的上下文里必须落到外部存储。我一般用 Redis 或者数据库存一个显式的状态对象每次模型调用前后都更新。这样即使服务重启Agent 也能从断点继续而不是从头再来。第二条决策外化。模型为什么选这个工具、为什么给这个参数这些决策依据要记录下来。我的做法是在提示词里要求模型输出结构化的决策理由然后单独存一张表。排查问题时直接看这张表比翻日志快得多。第三条工具外化。工具不要以函数的形式嵌在框架里而是独立部署成服务通过标准接口调用。这样做的好处是工具可以单独测试、单独扩容、单独监控而且换框架的时候工具层不用动。我用 SpringBoot 把常用工具包成 REST 接口Agent 框架通过 HTTP 调用实测下来很稳。这三条做下来Agent 就从“黑盒”变成了“白盒”。你能看见它、能干预它、能复现它。这才是工程该有的样子。3. 核心细节解析把黑盒拆开需要哪些关键设计3.1 状态管理Agent 的“记忆”到底该怎么存状态管理是 Agent 工程里最容易被低估的环节。很多框架把状态存在模型的上下文窗口里对话一长就丢或者压缩之后关键信息没了。这在 Demo 里不明显在真实业务里就是致命伤。我的做法是分层存储。第一层是会话状态存当前对话的短期上下文用 Redis 存设置合理的过期时间。第二层是任务状态存当前任务的执行进度、已完成步骤、待办事项用数据库存持久化。第三层是长期记忆存用户偏好、历史交互摘要用向量库存按需检索。这里有个关键细节状态更新要幂等。Agent 执行过程中可能因为网络问题重试如果状态更新不是幂等的就会出现重复记录。我的做法是给每个状态变更分配一个唯一 ID更新前先检查这个 ID 是否已处理过。还有一个坑是状态膨胀。任务跑久了状态对象越来越大每次读写都慢。我的经验是给状态设一个上限超过之后把历史状态归档到冷存储只保留最近 N 步的详细状态和全部步骤的摘要。这样既保证了可追溯又控制了性能开销。3.2 工具调用从“函数注册”到“服务化”的转变工具调用这块我踩过的坑最多。早期框架流行“函数注册”你把 Python 函数注册进去模型生成调用参数框架执行函数。这套在单机 Demo 里没问题在分布式环境里问题就大了函数和框架耦合太紧没法单独扩容没法单独监控换个语言就得重写。后来我改成服务化。每个工具是一个独立的 HTTP 服务有明确的输入输出 schema有独立的健康检查和监控。Agent 框架只负责生成调用参数和解析返回结果不关心工具怎么实现。这样做的好处很明显工具可以用任何语言写可以独立部署可以单独压测出问题的时候直接看工具服务的监控面板就行。工具描述也很关键。模型选错工具很多时候不是模型笨是工具描述写得含糊。我的经验是工具描述要包含三部分做什么、什么时候用、参数含义。比如“查询订单”这个工具描述不能只写“查询订单”要写“根据订单号查询订单状态和物流信息当用户询问订单进度时使用参数 order_id 为订单编号”。这样模型选错的概率会低很多。3.3 提示词工程与上下文工程的边界提示词工程和上下文工程经常被混为一谈但在 Agent 场景里它们解决的是不同问题。提示词工程解决的是“怎么让模型理解任务”。比如你写“你是一个客服助手”这是提示词。上下文工程解决的是“怎么让模型在正确的时间看到正确的信息”。比如用户问“我的订单到哪了”你需要把订单查询结果放进上下文这是上下文工程。在 Agent 里上下文工程比提示词工程更重要。因为 Agent 是多轮执行的每一轮需要看到的上下文都不一样。我的做法是按需注入每一步只把当前步骤需要的信息放进上下文而不是把所有历史都塞进去。这样既节省 token又减少干扰。这里有个实操技巧给上下文加优先级标记。比如用[必须]、[参考]、[忽略]这样的标签让模型知道哪些信息重要。实测下来这比单纯堆信息效果好很多。3.4 可观测性没有日志和追踪Agent 就是玄学可观测性是“物理外化”的核心支撑。没有可观测性前面说的状态外化、决策外化都是空谈。我的做法是三层追踪。第一层是请求级追踪每次 Agent 调用生成一个 trace_id贯穿所有步骤。第二层是步骤级追踪每个步骤记录输入、输出、耗时、模型调用参数。第三层是决策级追踪记录模型选择某个工具的理由、生成的参数、置信度。这些数据我一般存到 Elasticsearch 或者 ClickHouse方便查询和聚合。排查问题时输入 trace_id 就能看到完整链路。我试过用这套方法排查一个“Agent 偶尔返回空结果”的问题十分钟就定位到是某个工具在特定参数下超时而不是模型的问题。4. 实操落地从零搭一个“物理外化”的 Agent 服务4.1 整体架构与技术选型这一节我拿一个真实项目举例讲怎么从零搭一个符合“物理外化”理念的 Agent 服务。项目背景是帮一家电商公司做售后咨询 Agent能查订单、查物流、发起退款、转人工。技术选型上我用SpringBoot做工具服务层因为团队熟悉 Java而且 SpringBoot 的生态成熟监控、限流、熔断都有现成方案。Agent 编排层用 Python因为大模型相关的库 Python 生态最好。两层之间通过 HTTP 通信接口用 OpenAPI 规范定义。状态存储用Redis存会话状态MySQL存任务状态和决策记录。可观测性用OpenTelemetry做追踪数据落到 ClickHouse。模型调用层做了一个适配器支持切换不同的大模型服务。整体架构分四层接入层负责接收用户请求和鉴权编排层负责 Agent 流程控制工具层负责具体业务能力存储层负责状态和日志。每层独立部署独立扩容。4.2 状态机的定义与实现编排层的核心是一个显式状态机。我用 Python 的transitions库定义状态和转移条件。状态包括INIT、INTENT_RECOGNITION、ORDER_QUERY、LOGISTICS_QUERY、REFUND_PROCESS、HUMAN_TRANSFER、COMPLETE。每个状态对应一个处理函数函数内部调用模型或者工具。转移条件由模型输出或者业务规则决定。比如在INTENT_RECOGNITION状态模型输出意图分类根据分类结果转移到不同状态。关键设计是状态转移必须显式记录。每次转移都写一条记录到 MySQL包含 trace_id、from_state、to_state、触发条件、时间戳。这样任何一次执行都能完整回放。# 状态机定义示例 from transitions import Machine class AgentStateMachine: states [INIT, INTENT_RECOGNITION, ORDER_QUERY, LOGISTICS_QUERY, REFUND_PROCESS, HUMAN_TRANSFER, COMPLETE] def __init__(self, trace_id): self.trace_id trace_id self.machine Machine(modelself, statesAgentStateMachine.states, initialINIT) self.machine.add_transition(recognize, INIT, INTENT_RECOGNITION) self.machine.add_transition(query_order, INTENT_RECOGNITION, ORDER_QUERY) # ... 其他转移4.3 工具服务的独立部署与接口定义工具层我用 SpringBoot 写每个工具一个 Controller。接口定义遵循 OpenAPI 规范方便生成客户端和文档。以订单查询为例接口定义如下RestController RequestMapping(/api/tools) public class OrderToolController { PostMapping(/query-order) public OrderQueryResponse queryOrder(RequestBody OrderQueryRequest request) { // 参数校验 // 调用订单服务 // 返回结构化结果 } }请求和响应都用明确的 DTO 定义字段含义写在 Swagger 注解里。这样 Agent 编排层调用时参数含义一目了然。工具服务独立部署的好处是可以单独压测。我做过测试订单查询接口在 200 QPS 下平均响应 50msP99 在 120ms。这个数据直接决定了 Agent 的超时设置——我设的是 3 秒留足余量。4.4 决策记录与回放机制决策记录是排查问题的利器。我的做法是每次模型调用都记录输入提示词、模型输出、选择的工具、生成的参数、执行结果、耗时。这些记录存到 ClickHouse按 trace_id 分区。回放的时候输入 trace_id 就能看到完整执行链路。我甚至做了一个简单的回放界面可以按时间轴看每一步的状态变化。这里有个细节记录要脱敏。用户手机号、地址这些敏感信息记录前要脱敏。我的做法是在记录层做一次过滤把敏感字段替换成哈希值。4.5 性能优化低延迟与高并发下的取舍Agent 服务的性能瓶颈通常在模型调用和工具调用。我的优化经验有三条。第一并行化能并行的步骤。比如查订单和查物流可以并行不用串行等。我用 Python 的asyncio做并发实测下来整体耗时降低 40%。第二缓存高频结果。比如用户问“退货政策”这个答案不常变可以缓存。我用 Redis 做缓存命中率大概 60%省了不少模型调用。第三设置合理的超时和重试。模型调用超时设 10 秒工具调用超时设 3 秒重试最多 2 次。超过就降级返回兜底话术或者转人工。不要无限重试否则雪崩。5. 常见问题与排查技巧实录5.1 模型选错工具或参数错误的排查思路这是最高频的问题。排查步骤我一般分三步。第一步看决策记录。模型选了什么工具、生成了什么参数、理由是什么。如果理由是“用户询问订单”但用户其实问的是退货那就是意图识别的问题。第二步看工具描述。工具描述是否清晰有没有歧义我遇到过“查询订单”和“查询退款”两个工具描述太像模型经常选错。后来把描述改得更具体问题就解决了。第三步看提示词。提示词里有没有给模型足够的判断依据比如有没有说明“如果用户问的是退货用退款工具”。下面这张表是我整理的常见问题速查现象可能原因排查方法解决思路选错工具工具描述模糊看决策记录细化工具描述参数错误提示词缺示例看模型输出加 few-shot 示例重复调用状态未更新看状态记录检查状态更新逻辑结果为空工具超时看工具监控调超时或降级上下文丢失存储过期看 Redis TTL调整过期时间5.2 状态丢失与上下文膨胀的平衡状态丢失和上下文膨胀是一对矛盾。存太少会丢信息存太多会拖慢速度。我的经验是分级存储。最近 5 步的详细状态存 Redis全部步骤的摘要存 MySQL历史详情归档到冷存储。这样既保证了当前执行的效率又保留了完整追溯能力。还有一个技巧是状态压缩。对于重复性的状态比如多轮对话中的用户意图可以只存最新值加变更历史而不是每轮都存全量。5.3 工具超时与降级策略工具超时是生产环境最常见的问题。我的策略是分级降级。第一级重试。超时后重试一次如果还是超时进入第二级。第二级降级返回。返回缓存结果或者兜底话术。比如查物流超时返回“物流信息暂时查询不到请稍后再试”。第三级转人工。如果关键工具持续不可用直接转人工不要让用户干等。降级策略要提前配置好不要等出问题了再临时想。我一般会在配置中心里配好每个工具的降级方案支持热更新。5.4 多轮对话中的意图漂移问题多轮对话里用户可能中途换话题。比如先问订单再问退货再问优惠券。如果 Agent 不处理意图漂移就会一直沿着第一个意图走。我的做法是每轮都做意图识别而不是只在第一轮做。如果检测到意图变化就重置任务状态开始新任务。同时保留历史意图记录方便后续分析。这里有个细节意图切换要有确认。如果用户从“查订单”突然跳到“退货”Agent 应该确认一下“您是想要退货吗”避免误判。6. 从“能用”到“好用”Agent 工程的下一步6.1 评测体系的建立Agent 好不好用不能靠感觉要靠数据。我一般建三个评测集功能评测、性能评测、体验评测。功能评测看准确率比如意图识别准确率、工具选择准确率、参数生成准确率。性能评测看响应时间和成功率。体验评测看用户满意度可以通过人工标注或者用户反馈收集。评测要定期跑每次改动后都跑一遍防止回归。我用 pytest 写评测脚本集成到 CI 里每次提交自动跑。6.2 持续迭代与反馈闭环Agent 上线不是终点是起点。我的做法是建立反馈闭环用户反馈和 bad case 自动收集定期分析找出共性问题优化提示词或者工具描述。我一般每周做一次 bad case 复盘把典型问题整理成测试用例加到评测集里。这样评测集越来越丰富Agent 也越来越稳。6.3 团队协作与工程规范Agent 工程不是一个人能搞定的需要算法、后端、产品一起配合。我的经验是接口先行工具接口、状态结构、决策记录格式这些都要提前定义好各方按接口开发。工程规范上我要求所有工具必须有单元测试所有状态变更必须有日志所有模型调用必须有决策记录。这些规范看起来麻烦但出问题的时候能救命。我个人在实际操作中的体会是Agent 工程最难的不是技术是预期管理。业务方总觉得 Agent 应该像人一样聪明但实际它就是个概率系统会犯错。所以从一开始就要把边界说清楚什么能做什么不能做做错了怎么兜底。把预期管理好了项目就成功了一半。最后再分享一个小技巧给 Agent 加一个“思考时间”。在返回结果前如果模型置信度低可以多花几百毫秒做一次自我检查。实测下来这能减少不少低级错误用户也感觉不到明显延迟。这个度怎么把握得根据你的业务场景慢慢调。
企业数字化 ERP 产品动态
相关推荐
大模型参数量为什么这么大?详解原理、算力与显存估算 “大模型的参数量为什么那么大?”——这个问题我刚接触大模型时也困扰了很久。那时候看到 GPT-3 有 1750 亿参数,第一反应是“这数字也太夸张了”,第二反应是“这么多参数到底在干什么?”后来自己动手训练过小模型、看过 Transfor… · 2026/11/4 4:45:46
DSP28335 Flash操作实战:API集成、参数配置与避坑指南 简介:Flash28335_API_V210 是 TI 官方为 C2000 系列 DSP28335 提供的 Flash 固件库,面向从事工业自动化、电机控制与电源管理等嵌入式开发的工程师及学习者,用于解决片内闪存的读取、写入、擦除与校验等底层操作问题。压缩包共 16 个文件、约… · 2026/11/4 4:45:46
JumpServer v2.1.0 安装指南:环境核对、依赖配置与避坑排查 简介:面向运维工程师与IT基础设施学习者的JumpServer v2.1.0部署资源包,聚焦堡垒机快速搭建与源码研究场景。JumpServer作为开源跳板机系统,常用于统一管理服务器资产、审计运维操作与权限控制,本包适合需要快速验证环境或研读源码… · 2026/11/4 4:45:46
GEO优化与三维九项认证技术解析 1. 项目背景与行业趋势解析"GEO优化"这个概念最近在空间数据服务领域频繁出现,它本质上是指基于地理空间信息(Geospatial)的优化技术体系。我注意到2026年3月即将实施的三维九项认证标准,这标志着行业即将进入一个全新的… · 2026/11/4 5:24:14
省市区街道村五级联动SQL:编码规则、导入校验与查询优化 简介:面向数据库初学者及需要实现多层级级联选择功能的开发者,这套三级、四级、五级联动SQL资料围绕层级数据表设计、外键关联与联合查询展开,可用于行政区划等分层信息的建模与检索场景。压缩包共25个文件,约22.91MB,… · 2026/11/4 5:24:14
狂牛启动副图指标拆解:源码结构、参数与回测验证 上周有个做短线的朋友甩给我一张图,标注写着“狂牛启动副图”,问我能不能照着那份流传的源码抄一份出来。我点开看了一眼,副图上一排红柱,每次柱子冒头之后那几根K线确实都往上走,图裁得干干净净。我跟他说,… · 2026/11/4 5:24:14
ARTEMIS:基于无障碍服务与大模型的移动端AI自动化框架解析 1. 移动端 AI 自动化的核心命题1.1 为什么手机上的 AI 助手一直“不好用”过去两年,大模型在 PC 端的落地速度远超移动端。你在电脑上可以让 AI 帮你写代码、整理文档、操作浏览器,但一到手机上,AI 能做的事情就急剧缩水——要么只能聊天&… · 2026/11/4 5:24:14
百度网盘批量转存工具的技术原理与实践 1. 项目背景与核心功能解析最近在整理网盘资源时,发现一个痛点:当我们需要将大量文件从公开分享链接转存到自己账号时,传统的手动操作方式效率极低。特别是遇到需要批量转存到多个子账号,或者处理数百GB的大文件集合时,… · 2026/11/4 5:23:14
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46