在 Java 中本地运行 LLM:Jlama 与 LangChain4j 集成实战指南
示例工程【免费下载链接】langchain4j-examples项目地址https://gitcode.com/GitHub_Trending/la/langchain4j-examples点击查看免费下载导读Jlama 是一个基于纯 Java 实现的现代 LLM 推理库它利用 Java 20 的 Panama Vector API 实现快速推理让开发者无需 GPU 集群即可在本地 JVM 环境中运行 Llama、Mistral 等开源模型。本文基于langchain4j-examples仓库中的 jlama-examples 模块完整讲解 Jlama 与 LangChain4j 的集成方式从环境准备、Maven 依赖配置到聊天对话、流式输出、RAG 检索增强生成、Function Calling函数调用四类典型场景的可运行示例。读完本文你将掌握在 Java 应用中落地本地 LLM 应用的完整技术栈与全部 JVM 参数配置细节。Jlama 是什么纯 Java 的本地 LLM 推理引擎Jlama 是一个快速、现代的 Java 库专为在 JVM 上运行多种 LLM 而设计。其核心特点可从 jlama-examples/README.md 概括为两点纯 Java 实现基于 Java 20 构建不依赖外部 Python 运行时或独立推理进程整个推理管线都运行在 JVM 内向量加速推理利用 Panama Vector APIJEP 448实现快速推理。这是一套面向向量计算的孵化器 API允许 Java 代码直接映射到 CPU 的 SIMD 指令从而显著加速矩阵运算等深度学习核心操作。正因如此Jlama 适合在本地开发机、内网服务器等场景下以较低资源开销完成模型推理与 LangChain4j 的ChatModel/StreamingChatModel/EmbeddingModel抽象天然契合。环境准备Java 20 与三项 JVM 参数运行 jlama-examples 的首要前提是安装Java 20 或更高版本。官方示例工程将编译器目标直接设为 Java 21见 jlama-examples/pom.xml 中的maven.compiler.source/target因此在 JDK 21 环境下可直接编译运行。除了 JDK 版本还需在启动 JVM 时附加三个关键参数缺一不可--add-modulesjdk.incubator.vector --enable-native-accessALL-UNNAMED --enable-preview三个参数的作用分别是JVM 参数作用--add-modulesjdk.incubator.vector显式加入jdk.incubator.vector孵化模块使 Jlama 能使用 Panama Vector API 进行 SIMD 加速推理--enable-native-accessALL-UNNAMED允许 Jlama 通过 JNI 访问 jlama-native 本地绑定库读取平台原生实现--enable-preview启用预览语言特性流式与基础聊天示例需要见下文需要特别说明的是在仓库的 exec 配置中chat与stream两个执行目标使用了--enable-preview而rag与functions两个目标未使用见 jlama-examples/pom.xml。因此即便命令行示例只展示通用参数你依然需要按示例逐一为每个目标补全对应参数否则对应的示例类将无法启动。若在自己的应用中使用建议四个参数全部加上以覆盖所有 Jlama 能力。Maven 依赖配置langchain4j-jlama 与原生绑定要在自己的 LangChain4j 应用中使用 Jlama需在 pom.xml 中引入三个核心依赖。仓库的 jlama-examples/pom.xml 给出了完整可用的配置版本号以仓库当前值为准dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-jlama/artifactId version1.17.0-beta27/version exclusions exclusion groupIdcom.github.tjake/groupId artifactIdjlama-core/artifactId /exclusion /exclusions /dependency !-- Add native jlama bindings -- dependency groupIdcom.github.tjake/groupId artifactIdjlama-native/artifactId classifier${os.detected.classifier}/classifier version0.8.3/version /dependency dependency groupIdcom.github.tjake/groupId artifactIdjlama-core/artifactId version0.8.3/version /dependency要点解读langchain4j-jlamaLangChain4j 官方提供的 Jlama 集成适配层其中ChatModel、StreamingChatModel、EmbeddingModel等抽象接口的 Jlama 实现都在此包中排除jlama-core再显式引入集成包默认传递的jlama-core被主动排除转而显式声明版本一致的jlama-core与jlama-native依赖。jlama-native带有os.detected.classifier分类器通过 os-maven-pluginpom 中已注册为 build extension自动探测操作系统与 CPU 架构加载对应平台的本地绑定库从而获得原生性能日志依赖示例还引入了logback-classic/logback-core1.5.6配合 logback.xml 将日志级别设为info输出到控制台方便观察推理过程。运行四个示例一条命令一个场景仓库为每个示例配置了独立的exec-maven-plugin执行目标execution id因此可以通过一条 Maven 命令直接运行无需手动指定主类。完整命令如下cd jlama-examples # Build and run basic chat response example ./mvnw compile exec:execchat # Build and run streaming example ./mvnw compile exec:execstream # Build and run Rag example ./mvnw compile exec:execrag # Build and run function calling example ./mvnw compile exec:execfunctions其中./mvnw是仓库自带的 Maven Wrapper无需预先安装 Maven。compile阶段完成源码编译exec:execxxx则按 id 找到 pom 中对应 execution 的配置以指定 JVM 参数启动目标类执行目标id启动类内部类使用场景chatJlamaChatModelExamples$Simple_Prompt一次性对话同步返回完整回答streamJlamaStreamingChatModelExamples$Simple_Streaming_Prompt流式逐 token 输出ragJlamaBasicRagEmbedExamples$Chat_Story_From_My_Document本地文档检索增强问答functionsJlamaAiFunctionCallingExamples$Payment_Data_From_AiServicesAI 服务 工具函数调用首次运行任一目标时Jlama 会自动下载指定的模型权重如tjake/Llama-3.2-1B-Instruct-JQ4请确保网络可访问模型托管源。模型采用JQ4 量化格式体积远小于原始权重可在普通开发机上运行。示例一基础聊天ChatModel对应文件 JlamaChatModelExamples.java演示最核心的同步对话能力ChatModel model JlamaChatModel.builder() .modelName(tjake/Llama-3.2-1B-Instruct-JQ4) .temperature(0.3f) .build(); ChatResponse chatResponse model.chat( SystemMessage.from(You are helpful chatbot who is a java expert.), UserMessage.from(Write a java program to print hello world.) ); System.out.println(\n chatResponse.aiMessage().text() \n);关键点JlamaChatModel.builder()采用 LangChain4j 统一的构建器风格与 OpenAI、Ollama 等模型的用法一致modelName指定 Hugging Face 模型坐标tjake/Llama-3.2-1B-Instruct-JQ4组织/仓库/量化标识temperature(0.3f)控制采样随机性数值越低输出越确定此处偏保守以获得稳定的代码生成结果消息通过SystemMessage.from(...)与UserMessage.from(...)构造调用model.chat(...)后从chatResponse.aiMessage().text()取回模型回答。这段代码展示了 LangChain4j 的模型抽象价值业务代码只依赖dev.langchain4j.model.chat.ChatModel接口底层无论是 Jlama、OpenAI 还是本地 Ollama切换几乎零成本。示例二流式聊天StreamingChatModel对应文件 JlamaStreamingChatModelExamples.java适合需要边生成边显示的对话型应用CompletableFutureChatResponse futureResponse new CompletableFuture(); StreamingChatModel model JlamaStreamingChatModel.builder() .modelName(tjake/Llama-3.2-1B-Instruct-JQ4) .temperature(0.3f) .build(); ListChatMessage messages List.of( SystemMessage.from(You are a helpful chatbot that answers questions in under 30 words.), UserMessage.from(What is the best part of France and why?)); model.chat(messages, new StreamingChatResponseHandler() { Override public void onPartialResponse(String partialResponse) { System.out.print(partialResponse); } Override public void onCompleteResponse(ChatResponse completeResponse) { futureResponse.complete(completeResponse); } Override public void onError(Throwable error) { futureResponse.completeExceptionally(error); } }); futureResponse.join();关键点StreamingChatResponseHandler是回调式处理器onPartialResponse在每段增量文本到达时触发此处直接System.out.print实现打字机效果onCompleteResponse在完整响应结束时触发onError负责异常传递CompletableFuturejoin()让示例在异步回调结束后才退出主线程避免程序提前终止——这是流式 API 在命令行演示中的标准配套写法流式示例同时使用--add-modules、--enable-native-access与--enable-preview三个参数见 jlama-examples/pom.xml。示例三RAG 检索增强生成Embedding 向量检索对应文件 JlamaBasicRagEmbedExamples.java完整走了一遍 RAG 全流程加载文档 → 切分 → 向量化 → 入库 → 检索 → 组装 Prompt → 生成回答。1. 加载并切分文档Document document loadDocument(toPath(example-files/story-about-origin-of-the-llama.txt), new TextDocumentParser()); DocumentSplitter splitter DocumentSplitters.recursive(200, 0); ListTextSegment segments splitter.split(document);示例文档是 story-about-origin-of-the-llama.txt一份关于美洲驼起源的传说短文。DocumentSplitters.recursive(200, 0)采用递归切分器200为每段最大字符数0为相邻段重叠长度。2. 向量化并存入向量库EmbeddingModel embeddingModel JlamaEmbeddingModel.builder().modelName(intfloat/e5-small-v2).build(); ListEmbedding embeddings embeddingModel.embedAll(segments).content(); EmbeddingStoreTextSegment embeddingStore new InMemoryEmbeddingStore(); embeddingStore.addAll(embeddings, segments);此处体现了 Jlama 的另一项能力JlamaEmbeddingModel可加载intfloat/e5-small-v2等嵌入模型将文本转为向量随后写入InMemoryEmbeddingStore内存向量库示例为求简单而使用生产环境可换成 pgvector、Redis、Milvus 等外部存储。3. 检索最相关片段String question Who create the llamas?; Embedding questionEmbedding embeddingModel.embed(question).content(); EmbeddingSearchRequest embeddingSearchRequest EmbeddingSearchRequest.builder() .queryEmbedding(questionEmbedding) .maxResults(3) .minScore(0.7) .build(); ListEmbeddingMatchTextSegment relevantEmbeddings embeddingStore.search(embeddingSearchRequest).matches();用户提问同样用同一个嵌入模型向量化然后检索maxResults(3)取最相似的 3 段minScore(0.7)过滤相似度低于 0.7 的结果。4. 组装上下文 Prompt 并生成回答PromptTemplate promptTemplate PromptTemplate.from( Context information is below.:\n ------------------\n {{information}}\n ------------------\n Given the context information and not prior knowledge, answer the query.\n Query: {{question}}\n Answer:); ChatModel chatModel JlamaChatModel.builder() .modelName(tjake/Llama-3.2-1B-Instruct-JQ4) .temperature(0.2f) // expect a more focused and deterministic answer .build(); AiMessage aiMessage chatModel.chat(prompt.toUserMessage()).aiMessage();提示词模板把检索到的information与用户question填入占位符并通过仅依据给定上下文回答not prior knowledge约束模型。生成阶段temperature(0.2f)进一步压低随机性。示例运行输出为According to Inca legend, the llamas were created by the mythical founders of the Inca Empire....与文档内容吻合证明检索与生成链路完整可用。示例四Function Calling 函数调用AiServices Tool对应文件 JlamaAiFunctionCallingExamples.java演示了 LangChain4jAiServices与 Jlama 模型的 Agent 式用法模型在对话中自主决定调用哪个工具、以什么参数调用再基于工具返回结果作答。定义工具类Tool(Get payment status of a transaction) // function description static String retrievePaymentStatus(P(Transaction id to search payment data) String transactionId) { return getPaymentDataField(transactionId, payment_status); } Tool(Get payment date of a transaction) // function description static String retrievePaymentDate(P(Transaction id to search payment data) String transactionId) { return getPaymentDataField(transactionId, payment_date); }Tool注解声明工具名称与功能描述P注解描述参数含义——这些元数据会被序列化给模型作为它选择函数的依据。Payment_Transaction_Tool内部维护了一个内存支付数据表交易号、客户、金额、日期、状态供两个工具查询。构建 AI 服务并对话interface Assistant { SystemMessage({ You are a payment transaction support agent., You MUST use the payment transaction tool to search the payment transaction data., If there is a date, convert it in a human readable format. }) String chat(String userMessage); } ChatModel model JlamaChatModel.builder() .modelName(tjake/Mistral-7B-Instruct-v0.3-JQ4) .temperature(0.0f) //Force same output every run .build(); Assistant agent AiServices.builder(Assistant.class) .chatModel(model) .tools(paymentTool) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build(); String answer agent.chat(What is the status and the payment date of transaction T1005?); System.out.println(answer);关键点函数调用模型选择示例使用tjake/Mistral-7B-Instruct-v0.3-JQ4Mistral 7B 的 JQ4 量化版并设置temperature(0.0f)强制每次输出一致保证工具调用的确定性AiServices 装配AiServices.builder(Assistant.class)绑定聊天模型、工具实例与MessageWindowChatMemory10 条消息窗口记忆自动生成Assistant接口实现声明式系统提示接口方法上的SystemMessage用自然语言约束 Agent 行为必须使用支付工具日期转人类可读格式执行链路模型先返回工具调用请求 → LangChain4j 通过ToolExecutorDefaultToolExecutor执行retrievePaymentStatus/retrievePaymentDate→ 把ToolExecutionResultMessage回填给模型 → 模型汇总得出最终答案例如the payment status of transaction T1005 is Pending and the payment date is 2021-10-08。在自有应用中集成 Jlama 的完整清单将以上内容收敛为可直接对照实施的操作清单JDK 版本安装 Java 20仓库示例按 Java 21 编译推荐使用 21JVM 参数启动时追加--add-modulesjdk.incubator.vector、--enable-native-accessALL-UNNAMED、--enable-preview依赖按上文 pom 配置引入langchain4j-jlama并显式声明jlama-core与带平台 classifier 的jlama-native模型选择对话与 RAG 生成用tjake/Llama-3.2-1B-Instruct-JQ4函数调用用tjake/Mistral-7B-Instruct-v0.3-JQ4嵌入用intfloat/e5-small-v2编码统一使用 LangChain4j 抽象ChatModel/StreamingChatModel/EmbeddingModel/AiServices模型实现细节全部封装在dev.langchain4j.model.jlama包内运行方式直接复用mvnw compile exec:execid或参照 jlama-examples/pom.xml 的 exec-maven-plugin 配置为自己的项目定制启动目标。这套组合让 Java 开发者无需搭建外部模型服务、无需 GPU即可在本地 JVM 中完成从对话、流式输出、RAG 到 Agent 工具调用的完整 LLM 应用开发验证是 LangChain4j 生态中全栈纯 Java路线的重要一环。赞分享示例工程【免费下载链接】langchain4j-examples项目地址https://gitcode.com/GitHub_Trending/la/langchain4j-examples点击查看免费下载相关推荐LangChain4j 集成 LocalAI 本地 Embedding 模型实战指南LangChain4j 集成 LocalAI 本地 Embedding 模型实战指南 本文以 LangChain4j 官方 LocalAI 集成模块 langc人工智能AI 应用RAGAI Agent工具调用Earthly 集成测试指南在本地与 CI 中可复现地运行集成测试Earthly 集成测试指南在本地与 CI 中可复现地运行集成测试 单元测试只验证单一模块自身的行为天然没有外部依赖而集成测试需要验证服务与外部系统文件CI/CDDevOps构建工具langchain4j-examples 实战绕过 Tornado launcher用 java 命令直接运行 GPULlama3 本地 GPU 推理langchain4j examples 实战绕过 Tornado launcher用 java 命令直接运行 GPULlama3 本地 GPU 推理 本指示例工程上一篇GPU显存稳定性终极测试如何用memtest_vulkan确保你的显卡健康下一篇3步彻底解决《恶霸鲁尼》Windows 10崩溃问题终极兼容性修复方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Gopeed:跨平台下载管理器从安装到接入 API 的完整指南

Gopeed:跨平台下载管理器从安装到接入 API 的完整指南

Gopeed:跨平台下载管理器从安装到接入 API 的完整指南 【免费下载链接】gopeed A fast, modern download manager for HTTP, BitTorrent, Magnet, and ed2k. Cross-platform, built with Golang and Flutter. 项目地址: https://gitcode.com/GitHub_Trending/go/…

2026/10/3 17:34:59 阅读更多 →
Operit 局域网 External HTTP Chat API 实战指南:从鉴权到同步/SSE/异步回调三种调用模式

Operit 局域网 External HTTP Chat API 实战指南:从鉴权到同步/SSE/异步回调三种调用模式

AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆 【免费下载链接】Operit The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent 项目地址: https://gitcode.com/gh_mirrors/o…

2026/10/3 17:34:58 阅读更多 →
本地补丁彻底解除 Wand 免费时长限制,全程不碰服务器

本地补丁彻底解除 Wand 免费时长限制,全程不碰服务器

本地补丁彻底解除 Wand 免费时长限制,全程不碰服务器 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 每天用到第二小时,弹窗…

2026/10/3 17:34:58 阅读更多 →

最新新闻

Python实现绘制同切圆

Python实现绘制同切圆

程序源码:# 绘制同切圆 import turtle as t # 导入turtle绘图库,取别名t t.pensize(3) # 设置画笔粗细为3像素 t.circle(10) # 画半径为10的圆 t.circle(20) # 画半径为20的圆 t.circle(40) …

2026/10/3 20:39:41 阅读更多 →
数据管理与论文写作并行:按阶段推进的研究节奏怎么排

数据管理与论文写作并行:按阶段推进的研究节奏怎么排

数据工作和论文写作挤在同一段时间里,几乎是每位研究生都会遇到的排期难题。多数人卡住的不是不会写,而是两条线的节拍没有对齐。我们在梳理用户反馈时发现,把研究数据与论文写作按成熟度切成四段、给每段设定明确的两线配比,返工…

2026/10/3 20:39:41 阅读更多 →
双向分流FIN标记、TCB服务逻辑与TCP断开连接流程介绍

双向分流FIN标记、TCB服务逻辑与TCP断开连接流程介绍

文章目录 一、TCP双向分流里的FIN 1.FIN信息 1.1放置FIN 1.1.1处前预剩发 1.1.2处后被遗漏 1.2发送FIN 1.2.1剩余已发完 1.2.2独立仍接收 1.3接收FIN 1.3.1现在已收完 1.3.2独立仍在发 二、数据的需求与TCB的服务 1.数据需求TCB的发收服务 1.1需本端TCB可靠发送 …

2026/10/3 20:39:40 阅读更多 →
大表加索引太慢?一文搞懂 KingbaseES 并行查询:原理、参数与实战

大表加索引太慢?一文搞懂 KingbaseES 并行查询:原理、参数与实战

金仓社区精华|banjin 的并行查询实战 前两天同事问一个表很大,要加索引很慢怎么办,当时回复可以使用并行啊,parallel ( degree 32)启用32并行来创建,创建完后关闭索引并行,在信创国产化替代持续…

2026/10/3 20:38:40 阅读更多 →
AI怎么做表格才放心?联网写好脚本、断网跑真实数据

AI怎么做表格才放心?联网写好脚本、断网跑真实数据

先说结论:AI怎么做表格,关键不在"会不会算",而在三件事——数据能不能留在自己电脑上、重复活能不能不一次次重做、断网的时候还能不能把表跑完。 我前后试过不少在线表格AI,最后留下的是数以轻舟:它把"…

2026/10/3 20:38:39 阅读更多 →
【毕业设计】校园爱心捐赠管理系统的设计与实现

【毕业设计】校园爱心捐赠管理系统的设计与实现

❤小编介绍:小编所在团队为图灵学术中心,我们专注于Java领域,提供程序设计开发、源码分享、技术指导及定制服务。凭借丰富经验和专业团队,满足客户多样化需求。从精准选题到顺利毕业,我们致力于助力大家的技术成长&…

2026/10/3 20:37:37 阅读更多 →

日新闻

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南 【免费下载链接】ex-skill 前任 skill 项目地址: https://gitcode.com/gh_mirrors/exsk/ex-skill 前任.skill 是一个运行在 Claude Code 上的开源 Skill:导入微信、iMessage、短信、…

2026/10/3 0:00:27 阅读更多 →
45个经典Linux面试题:从命令到网络排障的完整考点解析

45个经典Linux面试题:从命令到网络排障的完整考点解析

刚开始带应届生的时候,我最头疼的就是他们拿着一摞Linux面试题背得滚瓜烂熟,一上机全露馅。后来自己从被面的人变成面别人的人,才慢慢摸清楚:Linux面试题考的根本不是答案本身,而是你面对一个不确定的系统问题时&#…

2026/10/3 0:01:28 阅读更多 →
SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

简介:本资源是一份面向SAP ABAP开发人员、生产计划专员及ERP实施顾问的实操型操作指南,聚焦SAP生产预留核心业务场景,系统解决物料预留创建、查询、校验与批量处理等高频问题。文档以结构化方式覆盖预留背景原理、OMC2编码规则、工厂级参数配…

2026/10/3 0:01:28 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/3 9:14:33 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/3 9:47:50 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/3 9:42:31 阅读更多 →

月新闻

我发现了一个新思路:用 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/2 10:36:31 阅读更多 →
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/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练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/3 9:42:36 阅读更多 →