news 2026/9/9 3:25:47

Python与DeepSeek API打造QQ智能机器人:从零到完整接入指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python与DeepSeek API打造QQ智能机器人:从零到完整接入指南

想给 QQ 群加一个能自动回答问题、写文案、查资料的 AI 机器人,在当下已经不算复杂。核心是打通两条链路:一条是 DeepSeek 开放平台提供的模型 API,一条是 QQ 机器人开放平台提供的事件消息通道。真正让新手卡住的,往往是中间那一层:申请凭证、订阅事件、异步调用模型、回复消息,任何一步没接上,机器人都会“假装存在”但完全没有反应。

这篇文章会用 Python 3 从零开始,带你完整实现 DeepSeek 接入 QQ 机器人的全过程。全程使用 DeepSeek 官方 API 和 QQ 官方机器人 SDK,不涉及非官方协议。内容包括:平台注册与凭证申请、本地环境搭建、完整可运行代码、启动验证、高频报错排查,以及工程化建议。即使你之前没有写过 QQ 机器人,只要照着操作,也能跑通。

1. 接入方案与整体原理

1.1 为什么优先选官方渠道

不少人在搜索 QQ 机器人接入时,会看到各种基于第三方协议的方案。这些方案确实功能花哨,但本质上大多通过逆向、模拟客户端等方式接入,存在账号风控、封号、隐私泄露等风险,而且很容易随着 QQ 客户端更新而失效。

本文采用官方渠道,原因很明确:

  • 稳定:官方接口和官方 SDK 会持续维护,不会因为客户端升级而突然失效。
  • 安全:AppID、AppSecret、API Key 都掌握在自己手里,不经过第三方转发。
  • 合规:符合平台规则,适合学习、测试以及正式上线的业务场景。
  • 省事:不需要额外搭建消息中转服务,官方 SDK 使用 WebSocket 长连接收消息,本地就能跑。

1.2 消息链路拆解

整个系统最核心的消息流转过程,可以拆成下面几个步骤:

用户 @机器人 或 私聊机器人 ↓ QQ 服务器推送事件 ↓ 官方 SDK(botpy)收到消息事件 ↓ 程序提取用户文本内容 ↓ 调用 DeepSeek API,携带参数请求模型 ↓ DeepSeek 返回 AI 回复文本 ↓ 程序调用 QQ 官方 API 把回复发回群/私聊

从代码角度来说,我们要做的事其实只有三件:

  1. 收到 QQ 消息事件。
  2. 把消息文本提交给 DeepSeek。
  3. 把 DeepSeek 的回复再发出去。

1.3 技术选型:WebSocket 和 WebHook 怎么选

QQ 机器人官方提供了两种接收消息的方式。

WebSocket 模式:

  • 由 SDK 主动和 QQ 服务器建立长连接。
  • 不需要公网 IP,不需要域名,不需要配置 HTTPS 证书。
  • 适合本地开发和个人项目。
  • 适合新手入门。

WebHook 模式:

  • 由 QQ 服务器向你的公网接口推送事件。
  • 需要公网服务器、域名和 HTTPS 证书。
  • 适合正式线上服务,也适合和现有后端服务集成。
  • 配置相对复杂。

本文选择 WebSocket 模式,原因很简单:零公网成本,本地就能完成全部联调。

2. 前置准备:DeepSeek 开放平台配置

在写代码之前,需要先把几个“通行证”准备好。第一步就是 DeepSeek 开放平台的 API Key。

2.1 注册并创建 API Key

打开 DeepSeek 开放平台,使用手机号或邮箱注册登录。登录后进入控制台,找到 API Key 管理页面。

创建 API Key 时注意以下几点:

  • API Key 通常以sk-开头,创建完成后只会完整显示一次,之后无法再次查看,必须先复制保存到本地。
  • 不要把 API Key 直接写在代码里提交到 GitHub,后面会专门讲密钥管理。
  • 一个账号可以创建多个 Key,建议区分开发环境、测试环境和生产环境,方便出问题时单独吊销。

2.2 确认 API 地址与模型名

DeepSeek 官方接口兼容 OpenAI 的调用格式。也就是说,Python 代码里可以直接使用openai这个包,把base_url指向 DeepSeek 的接口地址。

常用的 model 名称有两个:

  • deepseek-chat:通用对话模型,适合绝大多数问答、写作、总结场景。
  • deepseek-reasoner:深度推理模型,适合复杂逻辑推导,但响应速度通常比 chat 模型慢。

部分第三方中转服务可能提供其他自定义模型名,本文以 DeepSeek 官方模型名为准。

需要注意:平台功能和模型名称可能随着版本调整,具体以 DeepSeek 开放平台文档为准。

2.3 费用与配额提示

DeepSeek 的计费方式是按 token 计费。token 可以简单理解为“模型看到的字符片段”,中文、英文、标点都会消耗 token。

对个人开发来说,日常测试和群聊机器人调用量不大,成本一般可控。但建议:

  • 在控制台设置“余额预警”,避免不知不觉消耗完。
  • 代码中限制单次回复长度,控制max_tokens
  • 不带上下文记忆时,每次请求只包含当前问题,避免历史消息反复计费。

3. 前置准备:QQ 机器人开放平台配置

DeepSeek 这边准备好之后,接下来是 QQ 官方机器人平台。

3.1 创建机器人应用

进入 QQ 开放平台,使用 QQ 扫码登录。登录后找到“机器人”相关入口,创建一个新的机器人应用。

创建时需要填写:

  • 机器人名称。
  • 头像。
  • 功能介绍。

这些信息会和机器人形象直接相关,建议认真填写。名称和头像在审核阶段会被检查,不要包含明显违规或夸张表述。

3.2 获取 AppID 与 AppSecret

机器人创建完成后,进入开发设置页面,能看到两个关键字段:

  • AppID:机器人的唯一身份标识。
  • AppSecret:机器人的密钥,用于 SDK 鉴权连接。

AppSecret 的敏感程度和 DeepSeek API Key 一样,不要泄露、不要提交到公开仓库。后续代码中,这两个值会传给 botpy SDK 的client.run()方法。

3.3 配置事件订阅

要让机器人能处理群消息和私聊消息,必须在开放平台打开对应的事件订阅。

在开发设置里选择 WebSocket 模式,然后申请以下事件权限:

  • 接收群聊消息,通常对应“群 @ 机器人”事件。
  • 接收 C2C 消息,也就是用户私聊机器人。

不同版本的平台界面可能略有差异,但核心逻辑一致:申请权限、等待审核或加入沙箱白名单、然后才能收到对应消息事件。如果只申请了群消息权限,私聊事件就永远不会触发。

3.4 沙箱环境与上线前准备

QQ 开放平台提供了沙箱测试机制。沙箱模式下,机器人不是对所有用户开放,而是只对指定的测试人员或白名单用户生效。这对调试阶段非常友好,可以避免机器人还没写好就被陌生人反复调用。

在沙箱里测试时:

  • 需要把测试 QQ 号添加到白名单。
  • 需要把机器人拉到一个测试群,群里至少要有白名单用户。
  • 群内测试时,必须是“@机器人 内容”的格式,群机器人通常不支持自动响应所有消息。

功能稳定、准备对外发布时,再提交上架审核。审核通过后机器人才能在更多群或用户范围内使用。

4. 本地环境搭建

平台配置完成,接下来进入代码环节。

4.1 安装 Python

本文示例使用 Python 3,建议使用 3.9 及以上版本。可以在终端输入以下命令确认版本:

python --version

如果没有安装 Python,去官网下载对应系统版本安装即可。Windows 用户安装时记得勾选“Add Python to PATH”。

4.2 创建项目目录

在本地新建一个项目目录,例如qq-deepseek-bot

mkdir qq-deepseek-bot cd qq-deepseek-bot

4.3 安装依赖

在项目里创建虚拟环境,然后安装依赖。

Linux / macOS 执行:

python3 -m venv venv source venv/bin/activate

Windows 执行:

python -m venv venv venv\Scripts\activate

然后安装两个核心库:

pip install qq-botpy openai

说明一下它们的作用:

  • qq-botpy:腾讯官方提供的 QQ 机器人 Python SDK,封装了 WebSocket 连接、事件接收、消息发送等能力。
  • openai:官方 OpenAI Python SDK,DeepSeek 接口兼容 OpenAI 格式,因此可以直接用它来调用 DeepSeek 模型。

为了统一管理依赖,可以在项目目录下创建requirements.txt

qq-botpy openai

后续换环境时,直接执行:

pip install -r requirements.txt

5. 完整代码实现

环境准备完毕后,开始编写核心代码。

5.1 目录结构与配置入口

建议把代码拆成三个文件,职责清晰,后面扩展也方便:

qq-deepseek-bot/ ├── config.py # 配置文件,负责读取环境变量 ├── deepseek_client.py # DeepSeek 调用封装 ├── bot.py # QQ 机器人主程序 └── requirements.txt # 依赖清单

先创建config.py

# 文件路径:config.py import os # DeepSeek 配置 DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "") DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com") DEEPSEEK_MODEL = os.getenv("DEEPSEEK_MODEL", "deepseek-chat") # QQ 机器人配置 QQ_APP_ID = os.getenv("QQ_APP_ID", "") QQ_APP_SECRET = os.getenv("QQ_APP_SECRET", "") # 回复消息最大长度,避免触发平台长度限制 MAX_REPLY_LEN = 500

这里使用os.getenv读取环境变量,好处是敏感信息不会硬编码在代码文件里。如果某个环境变量没有设置,程序会使用空字符串,后续启动时会统一检查。

5.2 封装 DeepSeek 客户端

接下来创建deepseek_client.py,负责调用 DeepSeek API:

# 文件路径:deepseek_client.py import asyncio from openai import AsyncOpenAI from config import ( DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL, ) _client = None def get_client(): global _client if _client is None: _client = AsyncOpenAI( api_key=DEEPSEEK_API_KEY, base_url=DEEPSEEK_BASE_URL, ) return _client async def ask_deepseek(user_content: str, system_content: str = ""): """ 调用 DeepSeek 对话接口,返回文本回复。 """ if not DEEPSEEK_API_KEY: return "DeepSeek API Key 未配置,请检查环境变量 DEEPSEEK_API_KEY。" if not user_content.strip(): return "你好像没有输入内容哦。" system_content = system_content or "你是一个友好的QQ群AI助手,回答简洁、准确、友好。" try: # 使用 wait_for 设置 30 秒超时,避免一直等待模型响应 resp = await asyncio.wait_for( get_client().chat.completions.create( model=DEEPSEEK_MODEL, messages=[ {"role": "system", "content": system_content}, {"role": "user", "content": user_content}, ], temperature=0.7, max_tokens=1024, ), timeout=30, ) return resp.choices[0].message.content.strip() except asyncio.TimeoutError: return "抱歉,AI 响应超时了,请稍后再试。" except Exception as e: return f"抱歉,调用 DeepSeek 时出现异常:{e}"

这段代码有几个细节值得说明:

使用AsyncOpenAI是因为 QQ 机器人的 SDK 是异步框架,事件回调本身就是async函数。如果在这里使用同步请求,会阻塞整个事件循环,导致机器人同时只能处理一条消息,体验很差。

asyncio.wait_for用于设置超时时间,防止 DeepSeek 接口迟迟不返回时,机器人卡死。

msg_id在原生 OpenAI SDK 里并不是一个参数,不需要传;消息的msg_id是在 QQ 机器人层控制的。

5.3 编写 QQ 机器人主程序

创建bot.py,这是整个机器人的入口:

# 文件路径:bot.py import re import botpy from botpy.message import C2CMessage, GroupMessage from config import ( DEEPSEEK_API_KEY, MAX_REPLY_LEN, QQ_APP_ID, QQ_APP_SECRET, ) from deepseek_client import ask_deepseek SYSTEM_PROMPT = "你是一个跑在QQ群和私聊里的AI助手,回答要简洁、准确、友好。" def clean_message(text: str) -> str: """ 清洗消息内容,去掉 QQ 消息里的 @ 占位符。 不同版本 SDK 返回的格式可能不同,这里做通用处理。 """ if not text: return "" # 去掉 <@!123456> 或 <@123456> 这类占位符 text = re.sub(r"<@!?\d+>", "", text).strip() return text def cut_reply(text: str, max_len: int = MAX_REPLY_LEN) -> str: """超长回复截断,避免触发平台长度限制。""" if len(text) <= max_len: return text return text[:max_len] + "……(消息过长已截断)" class QQDeepSeekBot(botpy.Client): async def on_group_at_message_create(self, message: GroupMessage): """群聊中 @ 机器人 时触发。""" prompt = clean_message(message.content) if not prompt: await message._api.post_group_message( group_openid=message.group_openid, msg_type=0, msg_id=message.id, content="请直接在群里 @我 并输入你想问的问题~", ) return reply = await ask_deepseek(prompt, system_content=SYSTEM_PROMPT) reply = cut_reply(reply) await message._api.post_group_message( group_openid=message.group_openid, msg_type=0, msg_id=message.id, content=reply, ) async def on_c2c_message_create(self, message: C2CMessage): """用户私聊机器人时触发。""" prompt = clean_message(message.content) if not prompt: await message._api.post_c2c_message( openid=message.author.user_openid, msg_type=0, msg_id=message.id, content="请输入你想问的问题~", ) return reply = await ask_deepseek(prompt, system_content=SYSTEM_PROMPT) reply = cut_reply(reply) await message._api.post_c2c_message( openid=message.author.user_openid, msg_type=0, msg_id=message.id, content=reply, ) def main(): if not QQ_APP_ID or not QQ_APP_SECRET: raise RuntimeError("请先配置 QQ_APP_ID 和 QQ_APP_SECRET 环境变量") if not DEEPSEEK_API_KEY: raise RuntimeError("请先配置 DEEPSEEK_API_KEY 环境变量") intents = botpy.Intents( group_message=True, c2c_message=True, ) client = QQDeepSeekBot(intents=intents) client.run(appid=QQ_APP_ID, secret=QQ_APP_SECRET) if __name__ == "__main__": main()

这段代码看起来不长,但它已经覆盖了完整闭环。

关键点说明:

  • on_group_at_message_create是群聊 @ 事件回调方法,SDK 收到事件后会自动调用。
  • on_c2c_message_create是私聊事件回调方法。
  • message._api是 SDK 内部封装的消息发送 API,可以直接调用发送接口。
  • post_group_messagepost_c2c_message都是被动回复消息,msg_id用于告诉平台“这是对某条消息的回复”。
  • botpy.Intents用于声明要订阅哪些事件,这里订阅了群消息和私聊消息。

5.4 配置环境变量

在运行之前,需要把密钥配置到环境变量里。

Linux / macOS:

export DEEPSEEK_API_KEY="sk-你的key" export QQ_APP_ID="你的AppID" export QQ_APP_SECRET="你的AppSecret"

Windows CMD:

set DEEPSEEK_API_KEY=sk-你的key set QQ_APP_ID=你的AppID set QQ_APP_SECRET=你的AppSecret

Windows PowerShell:

$env:DEEPSEEK_API_KEY="sk-你的key" $env:QQ_APP_ID="你的AppID" $env:QQ_APP_SECRET="你的AppSecret"

如果你不想每次打开终端都重新设置,也可以在项目目录下创建.env文件并交给加载工具处理。但要注意,.env文件同样不能提交到 git 仓库。

6. 运行与效果验证

6.1 启动机器人

在项目目录下执行:

python bot.py

如果配置无误,SDK 会输出类似“连接成功”或开始接收事件的相关日志。此时程序会一直前台运行,不要关闭窗口。

6.2 在群里 @ 机器人

打开测试群,确保机器人已经被拉进群。发送:

@机器人 你好,请介绍一下你自己

正常情况下,机器人会很快回复一段 AI 生成的自我介绍。

这里要特别注意:群机器人通常只能响应“@机器人”的消息,不会自动回复群内所有消息。如果希望机器人只被 @ 时响应,也就是说,群内所有消息都处理,需要额外申请“接收群聊消息”权限,并且在代码里做更多过滤逻辑。本文示例默认只处理 @ 事件,比较安全。

6.3 私聊机器人

在 QQ 上找到机器人,发送:

帮我写一段关于机器学习的 100 字介绍

机器人会通过on_c2c_message_create事件收到这条消息,然后调用 DeepSeek 生成内容,再通过post_c2c_message回复。

6.4 观察日志

运行期间,终端会打印 SDK 日志和可能的异常信息。建议保持终端可见。如果 DeepSeek 调用失败,ask_deepseek会把错误信息拼在回复里返回到 QQ,方便排查。

一个比较实用的调试技巧:在启动机器人之前,直接单独测试 DeepSeek 链路。可以写一个临时脚本:

import asyncio from deepseek_client import ask_deepseek async def main(): result = await ask_deepseek("你好") print(result) asyncio.run(main())

这样可以做到“先验证模型接口通不通,再验证 QQ 消息链路通不通”,问题定位会高效很多。

7. 常见问题与排查清单

7.1 高频问题对照表

问题现象常见原因解决思路
机器人启动报缺少 AppID/AppSecret环境变量未设置或设置后未在当前终端生效检查 export/set 命令;重新打开终端再试
机器人不掉线,但群里收不到消息开放平台事件订阅未开启,或沙箱白名单未配置检查 QQ 开放平台事件权限;确认机器人已拉入测试群
私聊机器人无反应未申请 C2C 消息权限,或用户不在白名单检查开放平台 C2C 权限和白名单
调用 DeepSeek 报 401API Key 错误、过期,或 Key 复制多了空格重新生成 Key;检查环境变量前后是否有空格
机器人回复超时网络问题或 DeepSeek 响应较慢增大asyncio.wait_for超时时间;检查网络连通性
回复内容被平台拒绝回复内容过长,或包含敏感词cut_reply中缩短 max_len;设置更严格的内容校验
运行报ModuleNotFoundError: No module named 'botpy'未安装qq-botpy执行pip install qq-botpy
WebSocket 连接频繁断开网络不稳定,或长时间没有心跳官方 SDK 通常会自动重连;检查本地网络

7.2 深挖两个典型错误

第一个典型错误:DeepSeek 返回401 Authentication Fails

这个错误绝大多数情况下是 API Key 没配好:

  • Key 是否复制完整?sk-开头,末尾没有空格。
  • 是否在启动python bot.py之前设置环境变量?export只对当前终端会话生效。
  • 是否使用了错误的 Key?可以在 DeepSeek 平台重新创建。

第二个典型错误:机器人能跑,但群里 @ 之后没有任何反应。

这个问题大概率不在代码,而在平台配置。按顺序检查:

  1. 机器人的“事件订阅”是否勾选了群聊消息。
  2. 机器人是否真的在测试群里。
  3. 测试号是否在白名单里。
  4. 是否发送了 @ 机器人的消息,而不是普通群消息。

如果这些都确认没问题,再看本地日志。日志中如果没有任何事件输出,说明事件根本没推到本地,问题依然在平台侧。

8. 工程化建议与安全边界

个人小玩具能跑通之后,如果要进一步做成稳定的服务,需要考虑下面几个方面。

8.1 密钥管理

现在很多项目的翻车现场,都是把 API Key 或 AppSecret 提交到了 GitHub。建议从一开始就养成习惯:

  • 所有密钥通过环境变量注入。
  • 项目根目录添加.gitignore,把.env、venv、日志文件排除在外。
  • 不同环境使用不同的 API Key,方便单独吊销。
  • 定期检查代码仓库历史,一旦发现密钥泄露,立即去平台吊销并重新生成。

8.2 超时与重试

DeepSeek API 偶尔会因为网络波动或高峰期排队而变慢。asyncio.wait_for设置了超时时间,但超时后直接返回错误,用户会看到“响应超时”的提示。

更健壮的做法是加入重试机制:

  • 第一次调用失败后,等待 1-2 秒重试一次。
  • 重试次数建议不超过 3 次。
  • 针对 401/403 等鉴权错误不要重试,因为重试也没用。

8.3 消息长度与频率控制

QQ 官方接口对单条消息长度有限制,群聊和私聊可能不完全一样。代码里的cut_reply函数只做了简单截断。更优雅的方案是:

  • 超长回复拆成多条消息按顺序发送。
  • 根据问题类型决定是否启用deepseek-reasoner,因为推理模型生成内容更长。
  • 对同一用户的请求做频率限制,防止有人恶意刷消息,导致 API 费用飙升。

8.4 内容安全问题

DeepSeek 本身有一定的内容安全机制,但接入 QQ 群后,机器人会被很多人使用。建议:

  • 在 system prompt 中明确说明“拒绝回答违法、暴力、低俗内容”。
  • 对用户输入和 AI 输出都做简单敏感词过滤。
  • 保留运行日志,但日志中不要记录完整消息内容,尤其是包含手机号、身份证号等个人信息时,要做脱敏处理。

8.5 关于第三方协议的风险提示

市面上存在着大量基于非官方协议的 QQ 机器人框架,它们最吸引人的地方是“功能多、不需要审核、什么都能做”。但代价也很明显:

  • 违反平台用户协议,账号可能被限制或封禁。
  • 通过逆向和模拟客户端实现,一旦协议更新,随时失效。
  • 中间可能经过第三方服务器,消息内容存在泄露风险。
  • 很多“免费框架”会夹带广告、挖矿脚本等不可控代码。

如果你的目标是长期稳定运行,建议老老实实使用官方平台能力。官方权限不够用,就去申请更多官方权限。

9. 最后给你一个调试建议

把整个流程跑通之后,你会发现代码本身并不复杂,复杂的是环境配置和平台权限。

最后一个实用的调试技巧:开发阶段不要把验证步骤耦合在一起。先把ask_deepseek()单独测试,确认 DeepSeek 链路是通的;再启动机器人,确认 QQ 事件能收到;最后再合到一起测完整流程。很多“机器人没反应”的问题,其实都是因为 DeepSeek 调用抛了异常,而异常信息只打印在终端里没有注意。

如果你按本文操作成功跑通了机器人,下一步可以考虑加离线记忆、关键词指令、多轮上下文,甚至用 Docker 部署到服务器上常驻运行。如果这篇文章对你有帮助,可以收藏备用;运行中遇到其他问题,欢迎在评论区留言交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 3:25:30

自动化测试用例设计与工程化落地:从框架选择到稳定性治理

我入行做自动化测试这么多年&#xff0c;回头看最核心的一关其实就是“用例”这两个字。很多人学了一堆框架和工具&#xff0c;selenium、appium、pytest、playwright都能跑起来&#xff0c;但真正到了项目里要写一套能长期稳定运转的自动化测试用例时&#xff0c;马上就露怯了…

作者头像 李华
网站建设 2026/9/9 3:25:08

2026国产AI工具选型指南:从大模型到工作流,按场景挑不踩坑

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

作者头像 李华
网站建设 2026/9/9 3:24:39

QQ机器人开发入门:基于官方API与Python,快速接入AI模型

做 QQ 机器人&#xff0c;最值得先确定的不是代码能不能写&#xff0c;而是走哪条 API 路线。目前最稳妥、也最适合快速启动的&#xff0c;就是在 QQ 开放平台申请官方机器人&#xff0c;用官方接口接收群聊或私聊消息&#xff0c;再把这些消息交给 AI 模型生成回复&#xff0c…

作者头像 李华
网站建设 2026/9/9 3:23:39

STM32F407移植lwIP并搭建HTTPD嵌入式Web服务器实战

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

作者头像 李华
网站建设 2026/9/9 3:23:23

AD8676ARZ超低噪声运放原理与高精度信号链设计

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

作者头像 李华