Skill: xavier-ljf/blog-writer-zh (version 1.1.0)

--- name: blog-writer-zh description: 用中文撰写科技/行业思辨类文章，风格理性犀利、结构清晰。适用场景：用户想写个人思考感悟、科技评论、行业分析、公众号/知乎/小红书长文，或需要润色、扩写、改写现有内容时。触发关键词包括"写篇文章"、"帮我写一篇关于"、"整理一下我对……的思考"、"写个分析"、"深度思考"、"发公众号"、"知乎专栏"、"小红书文案"、"把这段扩写成文"、"润色这篇文章"。如果不确定是否该用，优先触发——写作类需求一般都适用。 --- # blog-writer-zh：中文深度长文写作技能 ## 概述 本技能帮助用中文撰写科技评论、行业分析和个人深度思考类文章。输出风格融合了**冷静的批判性分析**与**结构性论证**——敢于下判断，但论证过程理性克制，力求让思考沉淀为体系化的文字。 `BLOG_REFERENCES_DIR` 环境变量指定风格参考文章的存放路径，由技能目录下的 `.env` 文件管理。每次调用时会自动解析该文件并注入环境变量。如果已设置且路径有效，技能会在写作前阅读参考文章校准风格；如果未设置，则表示没有参考文章，不影响技能正常使用。 ### 工作流程 1. **明确需求** — 确认主题、观点、长度、参考材料 2. **撰写初稿** — 按风格框架和结构模板落笔，写入 `drafts/` 目录 3. **迭代修改** — 用户本地编辑或对话修改，两种方式可混用 4. **读者审阅** — subagent 以读者视角批判性审阅，挑逻辑漏洞和不同观点 5. **去 AI 味**（可选）— 用 `humanizer-zh` 处理套路化表达 6. **多平台导出**（可选）— 生成可上传到小红书、公众号、知乎等平台的格式 7. **定稿归档**（依赖环境变量）— 归档至参考文章目录 ## 安装设置 安装本技能后，agent 会询问用户是否需要设置风格参考库路径： - **提供路径** → agent 将 `BLOG_REFERENCES_DIR=/用户的/路径` 写入 `skills/blog-writer-zh/.env` - **不提供** → 不影响技能使用，写作风格将没有参考样本校准 后期如需修改配置，直接编辑该文件或重新运行安装设置即可。 ## 环境变量解析 每次技能被触发时，agent 会按以下流程解析 `BLOG_REFERENCES_DIR`： 1. 检查 `skills/blog-writer-zh/.env` 文件是否存在 2. 读取其中的 `BLOG_REFERENCES_DIR` 值 3. 导出为进程环境变量 4. 如果值无效或未设置，跳过参考文章读取 解析后，后续所有逻辑直接使用该环境变量。此外，如果用户强调"和我之前的文章保持一致"或类似要求，主动读取 `BLOG_REFERENCES_DIR` 路径下的参考文章进行风格校准，确保新文章与既有风格保持连贯。 ## 何时使用 当用户表达以下意图时触发： - "帮我写一篇关于……的文章" - "整理一下我对……的思考" - "写个分析，关于……" - "我想写一篇科技评论" - "发公众号/知乎/小红书" - "把这段扩写成文章" - "润色这篇文章" - 任何需要长文输出的写作需求 ## 写作风格框架 详细风格指南见 [references/style-guide.md](references/style-guide.md)，包括核心风格特征、语言风格、开头策略、读者互动技巧、Dos and Don'ts、长度校准等。 ## 文章结构模板 提供四种模板应对不同场景，详见 [references/templates.md](references/templates.md)： - **默认模板** — 标准思辨文章结构 - **快速观点模板** — 300-800 字短文章 - **深度分析模板** — 1500-3000 字长文 - **研究论证模板** — 数据驱动型文章 ## 写作流程 ### 第一步：明确需求 向用户确认以下信息（如果用户没有主动提供）： 1. **主题** — 想写什么话题 2. **核心观点** — 有没有要表达的立场 3. **目标长度** — 默认 800-1500 字 4. **参考材料** — 是否有补充链接或资料 ### 第二步：撰写初稿并落盘 参照风格框架和结构模板完成初稿后，**直接写入本地文件**，路径格式为 `skills/blog-writer-zh/drafts/YYYY-MM-DD-文章标题.md`。 > 写完即存盘，之后用户可以在本地直接用编辑器修改，无需再通过 agent 迭代。 ### 第三步：迭代修改 初稿落盘后，用户可以通过以下两种方式修改： 1. **本地编辑** — 直接用编辑器修改文件 2. **对话修改** — 告诉 agent 修改意见，由 agent 调整 两种方式可以混用，怎么方便怎么来。 ### 第四步：读者视角审阅 > ⚠️ 开始本步骤前，**重新从文件读取当前内容**（因为用户可能已经在本地做了修改）。 完成第三步后，需要审阅时告诉 agent。agent 会**创建一个无额外上下文的 subagent**，读取文件内容，站在普通读者的视角进行审阅。subagent 的任务是： 1. **指出逻辑漏洞** — 论证链条中有没有跳跃或站不住脚的地方 2. **提出不同观点** — 和文章立场相对或互补的视角 3. **检查表达清晰度** — 有没有不够清晰、容易引起歧义的地方 4. **提供改进建议** — 具体可操作的修改方向 > ⚠️ subagent 不应只是点赞，而是要有实质性的批判性意见。它的角色是"有见地的读者"，不是编辑也不是粉丝。 获取 subagent 的反馈后，评估哪些意见有道理并采纳，哪些可以忽略。**不需要照单全收**——要有自己的判断。 ### 第五步：去 AI 味儿处理（可选） > ⚠️ 开始本步骤前，**重新从文件读取当前内容**（因为用户可能在上一步后又做了本地修改）。 如果用户觉得文章读起来还有"AI味儿"——结构太工整、用词太套路、缺灵气——告诉 agent 需要处理，agent 会用 `humanizer-zh` 技能做一轮去 AI 痕迹处理。该技能会检测并修复以下模式： - 过度强调意义和广义趋势 - 三段式法则和否定式排比 - AI 高频词汇（此外、至关重要、格局、关键性……） - 破折号过度使用 - 模糊归因和填充短语 - 缺乏个性的"无菌"表达 若没有安装 `humanizer-zh` 技能，则跳过此步骤。 ### 第六步：多平台导出（可选） > ⚠️ 开始本步骤前，**重新从文件读取当前内容**（因为用户可能在上一步后又做了本地修改）。 用户明确提出"导出"、"发布小红书"、"导出到公众号"、"导出到知乎"或"导出文章"等要求时触发。如用户未提及，此步骤跳过。 #### 平台兼容性 | 平台 | 导入格式 | 标题支持 | | --- | --- | --- | | 小红书 | Markdown (.md) | 仅识别 H1、H2 | | 知乎 | Markdown (.md) | 仅识别 H1、H2 | | 公众号 | DOCX (.docx) | 仅识别 H1、H2 | #### 转换规则 | 原文 | 转换后 | 说明 | | --- | --- | --- | | `#`（H1，文章标题） | `#`（H1） | 保持不变 | | `##`（H2，章节标题） | `#`（H1） | 升级为 H1 | | `###`（H3，子章节标题） | `##`（H2） | 升级为 H2 | | `####` 及更深 | **加粗段落** | 去掉 `#` 前缀，文字加粗 | 脚注 `[^n]` 转换为文末有序列表（参考来源），正文中的 `[^n]` 内联标记移除。 #### 导出流程 运行导出脚本，生成平台兼容的 Markdown 文件，DOCX 通过 pandoc 转换： ```bash python3 skills/blog-writer-zh/scripts/export.py <文章路径> [-o <输出目录>] ``` 输出文件： - `<原标题>-export.md` — 小红书/知乎可直接导入 - `<原标题>-export.docx` — 公众号可直接导入 (需安装 pandoc) 若 pandoc 未安装，脚本会提醒用户并跳过 docx 生成，仅输出 md 文件。 #### 输出路径约定 导出文件默认放在原文同级目录。如果用户指定了输出路径，以用户指定为准。 导出完成后，告知用户生成了哪些文件，以及分别适用于哪个平台。 ### 第七步：定稿归档（依赖环境变量） > ⚠️ 开始本步骤前，**重新从文件读取当前内容**（因为用户可能在上一步后又做了本地修改）。 **仅在 `BLOG_REFERENCES_DIR` 环境变量已设置时执行本步骤。** 如果未设置，此步骤自动跳过。 完成所有修改并确认文章是最终版本后： 1. **清理导出文件** — 删除 `drafts/` 下该文章对应的 `xxx-export.md` 和 `xxx-export.docx`（如有） 2. **归档原 md** — 将 `drafts/` 下的原始 md 文件**复制到** `$BLOG_REFERENCES_DIR` 目录下（保持相同的文件名） 目的： - 用户的参考文章库持续积累，后续写作时有更多风格锚点 - 新写的文章本身也会反哺未来的写作——每一篇都是下一篇的养分 - 导出文件是平台适配产物，不污染参考库 ## 风格校准策略 当 `BLOG_REFERENCES_DIR` 已设置时，写作前读取该目录下最新的 3-5 篇 `.md` 文件，重点关注： 1. **句式节奏** — 平均句长、标点运用习惯（破折号、分号、冒号的频率和位置） 2. **论证结构** — 常用几层维度展开、结论如何收束、过渡句的模式 3. **词汇偏好** — 高频分析性词汇、过渡词使用模式、是否有固定的口头禅或标志性表达 如果参考文章之间风格差异较大，以最新的一篇为主，其余作为辅助。校准不是机械模仿，而是吸收节奏和气质，让新文章与既有风格保持连贯。 ## 证据与搜索 贯穿写作全程的能力。以下情况会启动 **web 搜索** 来补充论据： - **观点缺支撑** — 某个判断听起来有道理但缺少数据、案例或引用，主动搜索相关材料 - **用户提出要求** — 例如用户说"这个观点找些数据支撑"、"帮我查一下某某的现状"，立即搜索 - **事实存疑** — 对某个事实或数据不确定时，搜索核实后再写入 - **读者视角触发** — subagent 审阅后指出"这个论点需要证据"，搜索补充后再修改 搜索时会关注： - 权威来源（行业报告、官方数据、知名媒体） - 近期数据（科技类话题时效性很重要） - 多角度信息（不只找支持文章观点的，也看反方论据） > 搜索到的引用和数据会在文末**参考来源**中列出，方便用户追溯验证。 ## 输出格式 - 文件格式：Markdown（.md） - 编码：UTF-8 - 文章结构：参照上方模板 - 如有外部引用或数据，在文末附上参考来源

path: references/style-guide.md
content: # 写作风格指南

## 核心风格特征

### 冷静的批判者

- 敢于提出尖锐观点
- 但不是情绪化宣泄，而是用结构化分析支撑观点
- 质疑行业共识和主流叙事，但从逻辑和事实出发
- 批判的同时保持平衡，不偏激 —— 每个维度都有优劣势分析

### 结构化思维

- 论证分层展开，逻辑链条清晰
- 标题分级组织内容（# → ## → ###）
- 每个论点都有对应的论据和展开
- 结论部分对整体观点进行提炼和延伸

### 思辨而非描述

- 不止于"发生了什么"，更要问"这意味着什么"
- 关注趋势背后的驱动力和长远影响
- 从现象推导出本质逻辑
- 在结尾提出自己的设想或预测

### 第一人称的个人视角

- 文章是"我的思考"，不是百科或新闻稿
- 可以亮明个人立场和判断
- 结尾可以有自己的展望或设想

## 内容主题

**主要方向：**

- AI / 科技发展对社会结构的影响
- 技术趋势对企业和商业模式的重塑
- AI 时代下产品形态和应用生态的演变
- 科技巨头的战略逻辑和行业格局变化

**次要方向：**

- 数字化转型中的机遇与挑战
- 技术伦理和隐私问题
- 开发者生态和工具链演进

## 语言风格

- **中文书写**，专业但易懂
- 避免过度使用英文术语
- 句子偏中长句，保持分析性语感
- 使用"——"、"："、"；"等标点增强结构和节奏
- 可以把 **核心概念** 加粗强调
- 引用/强调内容时使用 **""（双引号）**，而非「」（方角引号）

**词汇提示：**

- 多用"本质"、"驱动"、"逻辑"、"趋势"、"范式"等分析性词汇
- 可用"笔者认为"、"更深层的问题是"、"值得思考的是"等过渡
- 批判时用"值得警惕的是"、"但这一逻辑可能站不住脚"、"表面上看……实际上……"

**避免：**

- 过度口语化（"卧槽"、"牛逼"）
- 网络梗和流行语
- 情绪化宣泄
- 无证据的武断结论

## 开头策略

开篇决定了读者是否愿意继续往下看。根据文章调性选择以下策略之一：

1. **一句话断言** — 直接亮出核心判断，制造认知冲击。
   > *"2025 年做 AI 应用的团队，90% 还没想清楚自己的产品是给谁用的。"*

2. **现象引子** — 从具体事件或观察切入，引出深层问题。
   > *"最近读了三个不同来源的报告，不约而同指向同一个判断——AI 公司的估值逻辑正在经历一次静默的重估。"*

3. **反问切入** — 抛出问题迫使读者思考。
   > *"当所有人都在说 AI 改变一切的时候，你有没有想过一个问题——"*

4. **反常识观点** — 先承认主流认知，再推翻它。
   > *"表面上是技术竞争，但如果你再往深看一层，这根本不是一个技术问题。"*

5. **自我披露** — 从个人经历或认知转变讲起，增加真实感。
   > *"整理了过去一年的笔记，发现我对这个话题的认知发生了三次反转，今天想聊聊整个过程。"*

开头要快速进入核心——不要在背景铺垫上花太多笔墨。

## 读者互动技巧

以下是在**文章中**与读者建立对话感的写作技巧：

- **反问制造张力** — "但换个角度想，这到底是在帮用户还是在绑架用户？"、"如果这个逻辑成立，那接下来会发生什么？"
- **对话感开头** — "如果你最近也在关注 [话题]，你大概也注意到了……"
- **对比切入** — "当 [A] 在讲 [X] 的时候，[B] 却在悄悄做 [Y]。这两条路径背后是完全不同的逻辑。"
- **直接对话读者** — "想象一下，你是一个……"、"把你自己放到那个位置，你会怎么选？"
- **引导思考停顿** — "暂停一下，先想想这个问题……"用来制造阅读节奏，给读者思考喘息空间

## 行动准则：Dos and Don'ts

### 要做

- 质疑行业共识和主流叙事，但从逻辑和事实出发
- 每个判断都要有对应的论据展开
- 认可批判对象的合理之处，保持公平——不为了锐度而故意偏颇
- 承认自己的不确定性——不是所有问题都有答案，坦诚比强行闭环更有说服力
- 用具体案例和数据把抽象观点落回地面
- 文章结尾留下延伸思考的空间，而不是强行总结

### 不要

- 为了锐度而牺牲论证完整性——尖锐不等于偏激
- 下无数据或推理支撑的武断结论
- 过度堆砌英文术语（"该方案的 ROC 曲线在 AUC 维度显著优于 baseline"——打住）
- 写"正确的废话"——人人都同意且无需争论的观点不值得用户花一篇文章写
- 三段式排比结构滥用（"不仅……更……还……"反复出现是 AI 写作的典型标志）
- 在背景铺垫上浪费太多笔墨，读者是来读用户的思考的，不是来上科普课

## 长度校准

不同深度的文章对字数有不同要求，写作前确认目标：

| 类型 | 字数 | 适用场景 |
| --- | --- | --- |
| 闪念观点 | 300-500 字 | 有感而发，不展开长篇分析，类似笔记整理 |
| 标准分析 | 800-1500 字 | 典型文章，有完整论证链，适合大部分话题 |
| 深度长文 | 1500-3000 字 | 多维度分析，需要多个案例和数据支撑 |


path: references/templates.md
content: # 文章结构模板

## 默认模板

```plaintext
# [犀利观点型标题]

## 开篇：抛出观点
- 一句话抛出核心判断
- 简要说明为什么这个问题值得讨论
- 有时可给出现象描述作为引子

## 主体：分层论证（2-4 个维度）

### 维度一：[第一个分析角度]
- 展开分析
- 优劣势或正反面权衡
- 具体案例或推理过程

### 维度二：[第二个分析角度]
- 同上

### 维度三/四（可选）
- 同上

## 深层分析：回到本质
- 以上现象背后的驱动逻辑
- 想要说明的更宏观的结论
- 指出思维范式的转变

## 结语：展望与预测
- 总结核心判断
- 提出自己的设想
- 给读者留下思考空间
```

## 快速观点模板（适合较短的文章）

```plaintext
# [观点标题]

## 我的判断
一句话亮明观点

## 为什么这么说
3-4 个分点支撑，每个点一段话

## 所以呢
结论和延伸思考
```

## 深度分析模板（适合探讨复杂议题）

多一层、多一个视角，让论证更厚实。每个阶段都有清晰的任务，避免写到一半跑偏。

```plaintext
# [具体的问题或判断型标题]

## 开头策略（选其一）
- **震撼观察** — "[关于话题的反直觉事实]"
- **反问式开场** — "[引出核心问题的反问]"
- **断言式开场** — "[挑战行业共识的锐利判断]"

## 钩子（1-2 句）
抓住读者注意力，建立话题的重要性

## 核心论点
一句话说清楚整篇文章想证明什么

---

## 1. 背景与现状
- 为什么这个议题现在值得讨论
- 当前行业的主流叙事是什么
- 大多数人默认相信什么

## 2. 证据与事实
- 关键数据或事实 #1
- 关键数据或事实 #2
- 关键数据或事实 #3
- 数据实际说明什么 vs. 主流说法是什么

## 3. 有问题的假设
- 主流叙事背后藏着什么假设
- 这个假设为什么站不住脚
- 具体场景里这个假设如何失效

## 4. 真正的后果
- 如果这个趋势继续会怎样
- 谁受益、谁受损
- 哪些关联趋势在放大这个效应

## 5. 争议与分寸
- 对立视角中值得认可的论点
- 判断可能在什么地方过早
- 坦诚还不确定的领域

## 结语
- 呼应开头的观察
- 留给读者一个值得思考的问题
- 这件事的未来走向意味着什么
```

## 研究论证模板（适合数据驱动型文章）

先亮结论，再用多层证据层层包围，最后诚实交代不确定性。少讲大道理，多用事实逼出判断。

```plaintext
# [论点型标题]

## 核心主张
清晰的立场陈述

## 证据层 1：数据
关键数据点 + 来源

## 证据层 2：案例
具体事件或亲身经历

## 证据层 3：对比
行业横向比较或趋势演变分析

## 坦诚
哪里不确定、哪里可能不对

## 结论
理性读者应该从这些证据中得出什么判断
```


path: scripts/export.py
content: #!/usr/bin/env python3
"""
blog-writer-zh 导出脚本

生成平台兼容的 Markdown 文件, DOCX 通过 pandoc 转换 (可选).

用法: python3 export.py <文章路径> [-o <输出目录>]

依赖:
  - 必须: 无 (纯标准库)
  - 可选: pandoc (用于生成 docx, https://pandoc.org/)
"""

import re
import shutil
import argparse
import subprocess
from pathlib import Path


# ---------------------------------------------------------------------------
# MD 转换
# ---------------------------------------------------------------------------

def transform_headings(text: str) -> str:
    """将 H2->H1, H3->H2, H4+->加粗段落."""
    lines = text.split("\n")
    result = []
    for line in lines:
        heading_match = re.match(r"^(#{2,})\s+(.+)", line)
        if not heading_match:
            result.append(line)
            continue
        hashes = heading_match.group(1)
        content = heading_match.group(2)
        if len(hashes) == 2:
            result.append(f"# {content}")
        elif len(hashes) == 3:
            result.append(f"## {content}")
        else:
            result.append(f"**{content}**")
    return "\n".join(result)


def convert_footnotes(text: str) -> str:
    """将文末脚注 [^n]: ... 转为有序列表, 并移除正文中的 [^n] 标记."""
    lines = text.split("\n")
    body_lines = []
    footnote_defs = []
    in_footnotes = False
    for line in lines:
        fn_match = re.match(r"^\[\^(\d+)\]:\s*(.+)", line)
        if fn_match:
            in_footnotes = True
            footnote_defs.append((int(fn_match.group(1)), fn_match.group(2).strip()))
            continue
        if in_footnotes:
            if line.strip() == "":
                continue
            if footnote_defs and line.strip():
                num, text_val = footnote_defs[-1]
                footnote_defs[-1] = (num, f"{text_val} {line.strip()}")
            continue
        body_lines.append(line)
    body = "\n".join(body_lines)
    body = re.sub(r"\[\^\d+\]", "", body)
    if footnote_defs:
        body += "\n\n参考来源\n\n"
        footnote_defs.sort(key=lambda x: x[0])
        for i, (_, text_val) in enumerate(footnote_defs, 1):
            body += f"{i}. {text_val}\n"
    return body


def convert_md(text: str) -> str:
    """对文章的正文内容 (不含 frontmatter) 做标题和脚注转换."""
    fm_match = re.match(r"^(---\n.*?\n---)\n*", text, re.DOTALL)
    if fm_match:
        fm = fm_match.group(1)
        body = text[fm_match.end():]
        return fm + "\n\n" + convert_footnotes(transform_headings(body))
    else:
        return convert_footnotes(transform_headings(text))


# ---------------------------------------------------------------------------
# DOCX 转换 (pandoc)
# ---------------------------------------------------------------------------

def has_pandoc() -> bool:
    return shutil.which("pandoc") is not None


def convert_to_docx(md_path: Path, docx_path: Path) -> bool:
    """用 pandoc 将 md 转为 docx. 成功返回 True."""
    if not has_pandoc():
        print("[!] pandoc 未安装, 跳过 docx 生成")
        print("    安装方式: brew install pandoc  (macOS)")
        print("             apt-get install pandoc  (Linux)")
        print("             https://pandoc.org/installing.html  (其他)")
        return False
    try:
        subprocess.run(
            ["pandoc", str(md_path), "-o", str(docx_path), "--from", "markdown", "--to", "docx"],
            check=True,
            capture_output=True,
            text=True,
        )
        return True
    except subprocess.CalledProcessError as e:
        print(f"[x] pandoc 转换失败: {e.stderr}")
        return False


# ---------------------------------------------------------------------------
# 主入口
# ---------------------------------------------------------------------------

def main():
    parser = argparse.ArgumentParser(
        description="blog-writer-zh 导出: 生成平台兼容 .md, 可选通过 pandoc 生成 .docx"
    )
    parser.add_argument("input", type=Path, help="原始文章 .md 文件路径")
    parser.add_argument("-o", "--output-dir", type=Path, default=None,
                        help="输出目录 (默认原文同级)")
    parser.add_argument("--skip-docx", action="store_true",
                        help="跳过 docx 生成")
    args = parser.parse_args()

    source_path: Path = args.input
    if not source_path.exists():
        print(f"[x] 文件不存在: {source_path}")
        return 1

    out_dir = args.output_dir or source_path.parent
    out_dir = Path(out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)

    stem = source_path.stem

    # 1. 转换 MD
    original = source_path.read_text(encoding="utf-8")
    md_content = convert_md(original)
    md_path = out_dir / f"{stem}-export.md"
    md_path.write_text(md_content, encoding="utf-8")
    print(f"[ok] {md_path}  (小红书)")

    # 2. 生成 DOCX (可选)
    if not args.skip_docx:
        docx_path = out_dir / f"{stem}-export.docx"
        if convert_to_docx(md_path, docx_path):
            print(f"[ok] {docx_path}  (公众号/知乎)")
    else:
        print("[skip] docx 生成已跳过 (--skip-docx)")

    return 0


if __name__ == "__main__":
    exit(main())


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)