作者: 启鑫

  • Pandoc 入门指南:打造自动化、跨平台的文档生产力工具

    Pandoc 被誉为文档界的“瑞士军刀”,是一个强大的通用文档转换工具(Universal Document Converter)。它不仅能实现多种标记语言与出版格式之间的高保真转换,更能通过过滤器(Filters)和模板(Templates)系统,构建出一套自动化、可扩展的文档生产流水线。

    • 多格式支持:涵盖 Markdown, LaTeX, HTML, Word (docx), EPUB, PDF 等数十种格式。
    • 专业级排版:集成 XeLaTeX / LuaLaTeX 引擎,支持复杂公式、中英混排及学术参考文献。
    • 高度可扩展:支持通过 Lua 或 Python 编写过滤器,对文档 AST(抽象语法树)进行深度定制。
    • 自动化友好:命令行操作,可轻松集成至 CI/CD 流程、GitHub Actions 或个人知识管理系统。

    实际应用

    • 学术论文:Markdown / LaTeX 写作 → PDF / DOCX / HTML,自动管理文献引用。
    • 技术文档:统一 Markdown 源文件 → 多格式输出(HTML、PDF、EPUB);可集成 CI/CD 自动发布。
    • 电子书与报告:EPUB、PDF、HTML 输出,自定义模板实现品牌风格。
    • 知识管理:Obsidian、Joplin 等笔记 Markdown → 高质量 PDF 输出,便于归档和分享。

    常用命令

    Pandoc 的基本语法结构为:pandoc [输入文件] -o [输出文件] [参数]

    1. 基础转换(Markdown 转 PDF/Word)

    默认情况下,PDF 导出需要系统安装了 LaTeX 环境。

    • 转为 PDF
    pandoc input.md -o output.pdf
    • 转为 Word (docx)
    pandoc input.md -o output.docx

    2. 中文 PDF 排版优化(重点)

    直接导出中文 PDF 常会遇到乱码或字体问题,建议指定 xelatex 引擎并配置中文字体。

    pandoc input.md -o output.pdf --pdf-engine=xelatex -V mainfont="Noto Sans SC" -V CJKmainfont="Noto Sans SC" -V geometry:margin=1in

    参数说明--pdf-engine 指定引擎;-V 用于定义变量(字体、页边距等)。

    3. 多文件合并处理

    如果你正在写一本书或长篇报告,可以将多个 Markdown 文件合并导出一个文件。

    pandoc chapter1.md chapter2.md chapter3.md -o full_book.pdf

    4. 学术写作:参考文献与引用

    配合 .bib 文献数据库文件,Pandoc 可以自动生成符合标准的引用格式。

    pandoc input.md --bibliography=refs.bib --citeproc -o output.pdf

    注意:较新版本的 Pandoc 使用 --citeproc 代替了旧版的 --filter pandoc-citeproc

    5. 自定义模板转换

    当你需要高度定制的画风(如公司固定报告格式)时,可以使用自定义模板。

    pandoc input.md --template=mytemplate.tex -o output.pdf

    6. 网页与独立文档

    如果你想生成一个可以直接在浏览器打开的 HTML 文件,记得加上 --standalone 以包含 CSS 和头部信息。

    • 输出 HTML
    pandoc input.md -t html -o output.html --standalone
    • 带元数据的 Word 导出
    pandoc input.md -o output.docx --standalone
  • 为什么在外面吃饭,蔬菜越来越少了

    最近外出吃饭,我突然发现一个很具体、又不容易察觉的现象——菜单里的蔬菜,好像越来越少了。

    不是完全没有,每家店总会有几道“时蔬”。但仔细翻看,总是那些熟悉的名字:清炒时蔬、扁豆丝、菜花、圆白菜,烹饪方式也几乎固定——清炒、白灼、干锅、蒸汽。名字略有变化,但内容高度一致,让人产生一种重复感。

    蔬菜并没有消失,但它们被压缩了

    我后来留意了一下。蔬菜类通常只有三到七道,平均下来,大概五道左右。

    这个数字看似合理,但问题在于这五道菜几乎承担不了“选择”的意义

    你不是在挑选真正想吃的蔬菜,而是在确认:

    “哦,原来这家店也有菜花,菜心。”

    蔬菜更像是一种配置,一种心理安慰,而非真正被期待的部分。

    我们也在助长这种局面

    仔细想想,这种现象并非单方责任,我们自己也参与其中。

    朋友聚餐的时候,点菜往往有一个隐形顺序:
    先点几个“撑场面”的肉菜,再看情况补一两个素菜。
    如果人数少或菜点多,最容易被删掉的,往往就是蔬菜。
    它不刺激,不惊艳,也不容易成为记忆点。
    蔬菜逐渐变成了一种“可有可无的存在”。

    餐厅其实很清楚这一点

    从餐厅角度,这个选择并不难理解。

    蔬菜不贵,但不等于好卖。
    它们保鲜周期短,品质波动大,人工处理耗时高,价格却很难抬高。
    同样一口锅、同样一个厨师,做一道肉菜和做一道青菜,人工成本是一样的,但带来的回报完全不同。

    所以蔬菜被留下来的原因,往往不是因为“重要”,而是因为“需要”。

    • 需要让菜单看起来完整。
    • 需要让人觉得这顿饭“不是只有肉”。
    • 需要在心理上保留一个“健康的出口”。

    这并不是哪家餐厅的问题

    餐厅在做它们擅长、也必须做的事情——控制成本、提高效率、迎合大多数人的选择。
    而我们在点菜时,也在用一次次行为投票。

    最终的结果是:
    外面吃饭,越来越擅长提供热量、刺激和满足感,
    却越来越不擅长提供一种均衡的日常饮食。

    后来我意识到的一点小变化

    但至少,我开始不再把“在外面吃”当成“吃得均衡”的一部分。

    外面的饭,解决的是方便、社交和口味。
    蔬菜,反而更像是一件需要自己刻意安排的事情。

    这种变化不是突然发生的,而是慢慢变得“理所当然”。当你意识到它的时候,可能已经持续很久了。

    蔬菜变少这件事,本身并不惊天动地,但它提醒我:外面吃饭无法满足蔬菜均衡,日常生活中仍然需要自己主动补充。

    看见这一点,本身就是一种觉察,也是一种生活上的自我调整。

  • Token 预算是 AI 系统真正的硬约束

    Token 预算是大语言模型(LLM)系统中的核心硬约束,直接限制每次交互可使用的 Token 数量,包括输入、输出及工具调用。它不仅影响计算成本和延迟,也决定系统可用性与任务成功率。有效管理 Token 预算依赖上下文压缩(Summarization、关键状态保留、递归编码)、动态分配策略以及实时消耗监控。在多轮对话、RAG 系统和 LLM Agent 架构中,预算驱动设计可保证信息完整性、生成稳定性和成本可控性。长期优化 Token 使用效率是系统可扩展性、可控性和可靠性提升的关键。

    概念

    Token Budget(Token 预算):在大语言模型(LLM, Large Language Model)系统中,Token 预算指每次模型交互允许消耗的最大 Token 数量,包括输入 Prompt 和模型输出。Token 预算是对计算资源、延迟和成本的直接约束,而非单纯的文本长度限制。

    Token Cost:Token 的计算成本由模型架构、序列长度和硬件资源决定。长序列不仅增加推理时间,也会线性或超线性地增加 GPU 显存占用和运行成本。

    Context Compression(上下文压缩):在 Token 预算限制下,为保持任务信息完整性,需要对历史上下文进行策略性压缩,包括摘要(Summarization)、选择性保留关键状态和递归编码。

    Token-Budget-Driven Design(Token 预算驱动设计):系统架构需以 Token 预算为硬约束来规划任务拆分、状态管理、工具调用和多轮交互流程。

    运作机制

    1. Token 消耗结构分析
    • Input Tokens:用户输入、系统指令、历史上下文。
    • Output Tokens:模型生成的响应。
    • Overhead Tokens:控制符、特殊标记和工具接口调用占用的 Token。
    1. 预算分配策略
    • 静态分配(Static Allocation):为 Prompt、上下文和输出分别预设 Token 上限。适用于确定性任务或单轮交互。
    • 动态分配(Dynamic Allocation):根据任务复杂度、上下文信息密度或工具调用需求动态调整 Token 上限。适用于多轮任务或 Agent 系统。
    1. 上下文压缩方法
    • 摘要压缩(Summarization):将多轮历史对话或文档内容生成简短表示。
    • 关键状态保留(Key-State Retention):只保留对任务决策至关重要的信息。
    • 递归编码(Recursive Encoding):将长序列内容编码成向量或标记化形式,以减少 Token 占用。
    1. Token 消耗监控与反馈
    • 实时跟踪输入、输出和工具调用的 Token 消耗。
    • 根据预算消耗自动触发上下文压缩或任务拆分机制。
    • 对多轮系统提供 Token 使用报告,用于优化系统设计和提示工程(Prompt Engineering)。

    实际应用

    1. 多轮对话系统
    • 确保对话状态管理在 Token 预算内,防止长轮次交互导致上下文截断或生成失败。
    • 对重要信息使用递归摘要,实现长期对话记忆。
    1. RAG 系统(Retrieval-Augmented Generation)
    • 限制检索内容长度,使向模型提供的文档片段不会超过预算。
    • 在检索-生成闭环中动态分配 Token,保证生成质量和上下文完整性。
    1. LLM Agent 架构
    • 工具调用前评估输出 Token 需求,避免因生成过长导致预算溢出。
    • 复杂任务拆解为子任务,每个子任务对应独立 Token 预算管理,确保整体系统稳定。
    1. 成本控制与可扩展性
    • Token 预算直接对应云计算成本,可用于实时估算系统运行成本。
    • 对大规模部署和高并发场景,Token 预算是保证系统稳定性和可预测性的核心指标。

    深刻的见解/反思

    • Token 预算是系统设计的根约束:与模型参数、算法优化相比,Token 预算直接影响系统的可用性、响应时间和成本。任何忽略 Token 预算的系统设计必然导致性能退化或任务失败。
    • 设计思路应“预算优先”:在多轮交互、复杂任务或 Agent 系统中,先规划 Token 预算,再设计上下文管理、工具调用和生成策略,比先生成内容再裁剪更高效。
    • Token 使用效率是长期优化核心:通过上下文压缩、关键状态保留和动态分配,系统可以在固定预算下提高信息利用率和任务成功率。
    • Token 预算驱动的架构演化:随着任务复杂性增加,系统设计会趋向模块化、可递归的上下文管理结构,实现“预算可控 + 信息完整”的最佳平衡。
    • Token 与 AI 可控性关联:预算限制迫使系统选择信息优先级、明确工具调用边界,从而提升生成内容的可靠性和决策可解释性。
  • 使用 nc(netcat)进行网络故障排查

    一、nc 在网络排错体系中的技术定位

    1. nc 解决的核心问题

    nc(netcat)的唯一目标是验证:在指定路径与方向上,L3/L4 层通信是否成立。

    换句话说,nc 回答的是一个极其具体的问题:

    在当前网络拓扑与安全策略下,这个 IP + 端口,是否真的可达?

    nc 不关心:

    • 应用协议是否合法
    • 业务逻辑是否正确
    • 数据是否符合预期

    它只关注 网络层与传输层是否建立通信条件

    2. nc 的能力边界

    从 OSI 分层角度看,nc 的作用严格限定在:

    • L3(IP 路由可达性)
    • L4(TCP / UDP 端口连通性)

    因此,nc 适合用于判断:

    • 是否存在路由问题
    • 防火墙 / ACL 是否阻断
    • NAT / 端口映射是否生效
    • 端口是否存在监听进程
    • TCP 与 UDP 行为差异导致的误判

    但 nc 无法替代

    • 抓包分析(tcpdump / Wireshark)
    • 应用层协议验证(HTTP / TLS / SQL)

    3. nc 在标准排错链路中的位置

    在成熟的网络排错流程中,nc 位于关键的分界点:

    ping → nc → tcpdump → 应用层分析

    其作用是:
    在进入复杂分析之前,先确认“网络是否真的通”。

    二、nc 的工作机制与判定逻辑

    1. TCP 场景的判定模型

    在 TCP 场景中,nc 的行为等同于一个最小化的客户端:

    • 主动发起 TCP 三次握手
    • 根据返回结果判断链路状态

    其输出具有明确语义:

    nc 行为网络含义
    succeededTCP 会话建立成功
    refused对端可达,但端口未监听
    timeout路由或防火墙丢弃

    TCP 场景下,nc 的结论是确定性的。

    2. UDP 场景的判定局限

    UDP 不存在连接状态,nc 在 UDP 场景中仅完成一件事:

    • 发送 UDP 数据包

    这意味着:

    • 无返回 ≠ 不通
    • timeout ≠ 失败
    • nc 输出本身不具备充分判定能力

    UDP 场景下,nc 只能作为发包工具,不能作为结论工具。

    三、典型网络故障场景与应用

    场景一:ICMP 可达,但业务不可用

    问题本质

    • ping 验证的是 ICMP
    • 业务使用的是 TCP / UDP

    ICMP 成功不能推导业务端口可达。

    nc 验证方式

    nc -vz server_ip 443

    判定逻辑

    • succeeded:网络路径与端口策略成立
    • refused:服务未监听或未启动
    • timeout:中间防火墙或路由阻断

    场景二:验证防火墙策略是否生效

    客户端侧验证

    nc -vz -w 3 server_ip 22

    工程化解读

    nc 结果结论
    succeeded策略允许
    refused端口关闭
    timeout高概率被防火墙丢弃

    在 TCP 排错中,timeout 是最典型的安全策略阻断信号

    场景三:VPN / UDP 业务异常(500 / 4500 / DNS)

    nc 的使用方式

    nc -vu -w 3 server_ip 500

    必须明确的事实

    • UDP 无握手
    • nc 不会确认对端状态
    • 无输出是常态

    正确排查模型

    tcpdump -ni any udp port 500

    结论依据:

    • 无出包:本机或路由问题
    • 有出包无回包:防火墙或对端异常

    场景四:NAT / 端口映射验证

    服务端监听

    nc -l 8080

    外部测试

    nc public_ip 8080

    结论判断

    • 成功连接:NAT / DNAT 生效
    • 无法连接:映射或安全策略问题

    场景五:区分网络问题与应用问题

    这是 nc 在工程实践中最核心的价值。

    方法论

    • 使用 nc 直接访问端口
    • 绕过真实应用逻辑
    nc -vz app_server 3306

    结论划分

    • nc 可连:网络层成立,问题属于应用或配置
    • nc 不可连:网络、防火墙或监听异常

    四、标准化 nc 网络排错流程

    在实际运维中,推荐固定以下执行顺序:

    1. DNS 解析是否正确

    nslookup host

    2. IP 层是否可达

    ping host

    3. 端口层是否可达

    nc -vz host port

    4. 是否真实发包

    tcpdump -ni any port port

    5. 检查防火墙、NAT、监听状态

    五、nc 输出结果

    TCP 场景

    输出技术结论
    succeeded端口连通
    refused端口未监听
    timeout路由或防火墙阻断

    UDP 场景

    现象正确理解
    无任何输出正常行为
    timeout无法作为失败依据
    ICMP 不可达明确不通

    UDP 排错必须结合抓包或服务端日志。

    六、常用 nc 排错命令速查

    # TCP 端口连通性测试
    nc -vz -w 3 host port
    
    # UDP 发包测试
    nc -vu -w 3 host port
    
    # 禁用 DNS 解析
    nc -n host port
    
    # 监听端口
    nc -l port
    
    # 抓包辅助分析
    tcpdump -ni any port port

  • Debian 使用 Speedtest CLI 进行网络测速

    Speedtest CLI 让用户能够快速、稳定地测试网络带宽和延迟,适用于服务器运维监控、自动化网络状态记录,以及内网环境下的测速优化。

    安装

    # 安装必要的依赖
    apt-get install curl
    
    # 安装脚本
    curl -s https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh | bash
    
    # 安装
    apt-get install speedtest

    运行测速

    speedtest
  • 企业内网Docker加速方案:基于 Docker Registry 搭建私有镜像缓存代理

    在企业内网环境下,受限于出口带宽与合规性,Docker 镜像拉取缓慢甚至超时已成为研发痛点。利用 Docker Registry 的 Pull-through Cache(拉取透传缓存) 模式,构建一套“一次拉取、全速复用”的内网镜像加速系统。为企业提供低成本、高效率的镜像分发方案。

    一、 部署指南

    1. 编写配置文件

    在服务器创建目录(如 /opt/docker-proxy),并创建 docker-compose.yaml

    services:
      registry:
        image: registry:3
        container_name: registry
        ports:
          - "5000:5000"
        restart: always
        environment:
          REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
        volumes:
          - ./data:/var/lib/registry

    2. 启动服务

    docker-compose up -d

    二、 客户端配置

    配置好加速器后,内网的终端设备(开发者电脑、测试服务器等)可以通过以下两种方式享受加速。

    方式 A:无侵入式拉取(推荐用于脚本)

    直接在镜像名前加上内网代理服务器的 IP 和端口:

    # 格式:docker pull <代理IP>:5000/<镜像名>
    docker pull 192.168.1.100:5000/library/nginx:latest

    注意:对于 Docker Hub 的官方镜像,必须加上 library/ 前缀。

    方式 B:透明加速(推荐用于开发环境)

    修改 Docker 守护进程配置文件 /etc/docker/daemon.json,添加 registry-mirrors

    {
      "registry-mirrors": ["http://192.168.1.100:5000"],
      "insecure-registries": ["192.168.1.100:5000"]
    }

    由于我们默认使用的是 HTTP 协议,需要同时在 insecure-registries 中放行。