技术博客全流程:从选题、架构设计、代码验证到图表的完整体验复盘

发布时间:2026/7/27 0:17:13
技术博客全流程:从选题、架构设计、代码验证到图表的完整体验复盘 技术博客全流程从选题、架构设计、代码验证到图表的完整体验复盘一、深度引言与场景痛点大家好我是赵咕咕。从开始系统写技术博客到现在写了四个月每个月固定产出约 40 篇文章。从最初一篇要憋两天到现在一篇 2-3 小时搞定中间迭代了一套完整的生产流程。这篇文章不是教你怎么写好文章——关于内容质量的文章太多了。我聊的是工程侧的事情怎么选题不跑偏、怎么保证代码跑得通、怎么用 Mermaid 画图避免反复修改、怎么管好文件结构和版本。这是一篇流程复盘。如果你也在规律性地输出技术内容希望能帮你把流程跑顺。二、底层机制与原理深度剖析2.1 技术文章的五段论结构经过四个月的迭代我固定下来一套文章结构模板——就是这个系列里每篇都在用的五段论场景痛点~200 字用真实经历开篇让读者产生我也遇到过的共鸣。原理剖析~400 字 Mermaid 图核心机制讲透用图表代替大段文字解释。生产级代码200-300 行完整可运行的 async/await Python 代码带异常处理。边界权衡~300 字什么场景适合、什么场景不适合、替代方案。总结~100 字核心要点浓缩附预告。这五个模块不是凭空想出来的是从几十篇文章的数据反馈中迭代出来的。早期文章是平铺直叙式的读完率只有 30%。加了 Mermaid 图后提到 45%。有了边界分析模块后收藏率提到了 12%。2.2 完整的生产流程每个阶段的工时和关键检查点选题30 分钟。最怕的是写了 1000 字发现跟上周的文章主题重了。用一个话题追踪表记录已写过的主题选题时先查表去重。调研20 分钟。核心任务是验证我计划写的代码能不能跑通。跑不通就不选这个题——改了计划好过写了一半发现代码不通。编码验证40 分钟。最耗时也最重要的环节。代码必须在本地跑通有实际输出。这是文章可信度的基础。写作40 分钟。有了前面的准备写作反而是最快的。五段论模板让结构清晰只需要填充内容和调整语气。发布10 分钟。检查渲染、字数、归档命名。2.3 选题矩阵什么样的主题值得写经过四个月的摸索我总结出选题的三个判断标准可验证文章核心代码必须能独立运行。如果依赖特定的 API Key、硬件环境或网络条件就不适合——读者跑不起来会认为文章没用。有差异化搜一下同主题的已有文章。如果你的文章只是GPT-4 生成的介绍性内容就别发了——因为别人也在发同样的东西。要有你的亲身经验和踩坑记录。读者需要用搜索引擎自动补全和大家还在搜来验证。如果这个主题连搜索量都没有写了大概率没人看。反选题纯概念介绍什么是 RAG、模型排名2025 最好的 5 款 LLM、工具教程翻译官方文档的翻译版。这些内容生成成本低但价值也低——AI 自己也能写。三、生产级代码实现下面是一套管理技术文章生产流程的工具代码import asyncio import json import logging import re from dataclasses import dataclass, field from datetime import datetime, timedelta from pathlib import Path from typing import Any logger logging.getLogger(__name__) # ── 话题管理 ─────────────────────────────────────────── dataclass class Topic: 选题模型。 title: str category: str # AI | Tech status: str draft # draft | written | published keywords: list[str] field(default_factorylist) code_verified: bool False mermaid_ready: bool False created_at: str word_count: int 0 def __post_init__(self): if not self.created_at: self.created_at datetime.now().isoformat() class TopicManager: 管理选题池防止主题重复。 def __init__(self, db_path: str ./topics.json): self._path Path(db_path) self._topics: dict[str, Topic] {} self._load() def _load(self) - None: if self._path.exists(): data json.loads(self._path.read_text()) self._topics {k: Topic(**v) for k, v in data.items()} def _save(self) - None: data {k: vars(v) for k, v in self._topics.items()} self._path.write_text(json.dumps(data, ensure_asciiFalse, indent2)) def is_duplicate(self, title: str, keywords: list[str]) - bool: 检查是否与已有话题重复。 title_lower title.lower() for t in self._topics.values(): existing_title t.title.lower() # 标题相似度检测 if self._title_similarity(title_lower, existing_title) 0.6: return True # 关键词重叠检测 overlap set(k.lower() for k in keywords) set( k.lower() for k in t.keywords ) if len(overlap) 3: return True return False def add(self, topic: Topic) - None: key topic.title self._topics[key] topic self._save() def get_history(self) - list[Topic]: 获取所有已写话题。 return sorted( self._topics.values(), keylambda t: t.created_at, reverseTrue, ) staticmethod def _title_similarity(a: str, b: str) - float: 简单的标题相似度计算。 words_a set(re.findall(r[\u4e00-\u9fff]|[a-zA-Z], a)) words_b set(re.findall(r[\u4e00-\u9fff]|[a-zA-Z], b)) if not words_a or not words_b: return 0.0 return len(words_a words_b) / len(words_a | words_b) # ── 代码验证器 ───────────────────────────────────────── class CodeValidator: 验证文章中的代码能否独立运行。 def __init__(self, work_dir: str ./_code_check): self._work_dir Path(work_dir) self._work_dir.mkdir(parentsTrue, exist_okTrue) async def validate(self, code: str) - dict[str, Any]: 在一个隔离的虚拟环境中运行代码检查是否能执行。 import subprocess import tempfile tmp_file self._work_dir / fcheck_{datetime.now().strftime(%Y%m%d_%H%M%S)}.py tmp_file.write_text(code) try: # 语法检查 result await asyncio.to_thread( subprocess.run, [python3, -m, py_compile, str(tmp_file)], capture_outputTrue, textTrue, timeout10, ) if result.returncode ! 0: return { passed: False, error: result.stderr.strip(), stage: syntax, } # import 检查不实际执行 main只检查导入是否成功 # 提取所有 import 语句做验证 imports re.findall( r^(?:from\s\S\s)?import\s.*$, code, re.MULTILINE ) missing [] for imp in imports: try: await asyncio.to_thread( compile, imp.strip(), check, exec ) except Exception as e: missing.append(str(e)) if missing: return { passed: False, error: fImport 错误: {; .join(missing[:3])}, stage: import, } return {passed: True, stage: full} except Exception as e: return {passed: False, error: str(e), stage: unknown} finally: # 清理临时文件 tmp_file.unlink(missing_okTrue) # ── Mermaid 图验证器 ─────────────────────────────────── class MermaidValidator: 验证 Mermaid 图是否能正确渲染。 def __init__(self): self._diagram_types [ flowchart, sequenceDiagram, classDiagram, stateDiagram, erDiagram, gantt, pie, graph, journey, ] def validate(self, markdown_text: str) - dict[str, Any]: 检查 Markdown 中的 Mermaid 代码块是否完整。 blocks re.findall( rmermaid\n(.*?), markdown_text, re.DOTALL, ) if not blocks: return {has_mermaid: False, errors: []} errors [] for i, block in enumerate(blocks): # 检查是否有图类型声明 has_type any( block.strip().startswith(dt) for dt in self._diagram_types ) if not has_type: errors.append(f图 {i1}: 缺少图类型声明) continue # 检查括号匹配 open_count block.count(() block.count([) block.count({) close_count block.count()) block.count(]) block.count(}) if open_count ! close_count: errors.append(f图 {i1}: 括号不匹配 (开:{open_count} 闭:{close_count})) return { has_mermaid: True, count: len(blocks), errors: errors, passed: len(errors) 0, } # ── 文章质量管理 ─────────────────────────────────────── class ArticleQualityCheck: 文章发布前的质量检查。 MIN_CHINESE_CHARS 1000 MIN_TITLE_CHARS 10 def check(self, title: str, content: str) - dict[str, Any]: 多维质量检查。 checks {} # 1. 标题长度 title_len len(re.findall(r[\u4e00-\u9fff], title)) checks[title_chinese_chars] title_len checks[title_ok] title_len self.MIN_TITLE_CHARS # 2. 正文中文字数排除代码块 text_only self._strip_code_blocks(content) chinese_chars len(re.findall(r[\u4e00-\u9fff], text_only)) checks[body_chinese_chars] chinese_chars checks[body_ok] chinese_chars self.MIN_CHINESE_CHARS # 3. Mermaid 图 mv MermaidValidator() mermaid_check mv.validate(content) checks[mermaid] mermaid_check # 4. 代码块数量 code_blocks len(re.findall(rpython, content)) checks[code_blocks] code_blocks checks[code_ok] code_blocks 1 # 5. 禁止词检查 forbidden [值得关注, 推荐阅读, 不看后悔, 99%的人不知道] found_forbidden [w for w in forbidden if w in content] checks[forbidden_words] found_forbidden checks[forbidden_ok] len(found_forbidden) 0 # 6. 五模块完整性 modules { 场景痛点: 一、, 原理剖析: 二、, 生产级代码: 三、, 边界权衡: 四、, 总结: 五、, } missing_modules [ name for name, marker in modules.items() if marker not in content ] checks[missing_modules] missing_modules checks[modules_ok] len(missing_modules) 0 # 汇总 checks[all_passed] all([ checks[title_ok], checks[body_ok], checks[mermaid][passed], checks[code_ok], checks[forbidden_ok], checks[modules_ok], ]) return checks staticmethod def _strip_code_blocks(text: str) - str: 移除 Markdown 中的代码块只保留正文。 return re.sub(r[\s\S]*?, , text) # ── 文件归档管理 ─────────────────────────────────────── class ArticleArchiver: 文章文件归档管理。 def __init__(self, base_dir: str): self._base Path(base_dir) def get_path(self, year: int, month: int, day: int, index: int) - Path: 获取文章文件路径。 dir_path self._base / f{year:04d}{month:02d} / f{day:02d} dir_path.mkdir(parentsTrue, exist_okTrue) return dir_path / f{index}.md def save( self, year: int, month: int, day: int, index: int, content: str, ) - Path: 保存文章到归档目录。 path self.get_path(year, month, day, index) path.write_text(content, encodingutf-8) logger.info(文章已保存: %s, path) return path def list_articles(self, date_str: str) - list[Path]: 列出某日所有文章。 dir_path self._base / date_str if not dir_path.exists(): return [] return sorted(dir_path.glob(*.md), keylambda p: int(p.stem)) # ── 完整工作流编排 ───────────────────────────────────── class ArticlePipeline: 文章生产流水线。 def __init__(self, base_dir: str): self.topic_mgr TopicManager(f{base_dir}/topics.json) self.validator CodeValidator(f{base_dir}/_code_check) self.quality ArticleQualityCheck() self.archiver ArticleArchiver(base_dir) async def process( self, title: str, category: str, keywords: list[str], date_str: str, index: int, content: str, ) - dict[str, Any]: 完整的文章处理流水线。 result { title: title, stage: started, checks: {}, } # 1. 选题查重 if self.topic_mgr.is_duplicate(title, keywords): return { **result, stage: rejected_duplicate, error: 主题与已有文章重复, } # 2. 代码验证 code_blocks re.findall( rpython\n(.*?), content, re.DOTALL ) if code_blocks: code_result await self.validator.validate(code_blocks[0]) if not code_result.get(passed): return { **result, stage: rejected_code, error: code_result.get(error, 代码验证未通过), } result[code_check] code_result # 3. 质量检查 quality self.quality.check(title, content) result[checks] quality result[stage] quality_checked if not quality[all_passed]: return { **result, stage: rejected_quality, failed_checks: { k: v for k, v in quality.items() if k.endswith(_ok) and not v }, } # 4. 归档 try: year, month, day date_str[:4], date_str[4:6], date_str[6:8] path self.archiver.save( int(year), int(month), int(day), index, content ) result[path] str(path) except Exception as e: return {**result, stage: rejected_archive, error: str(e)} # 5. 记录话题 self.topic_mgr.add(Topic( titletitle, categorycategory, statuspublished, keywordskeywords, code_verifiedTrue, mermaid_readyquality[mermaid][passed], word_countquality[body_chinese_chars], )) result[stage] published return result # ── 使用示例 ──────────────────────────────────────────── async def main(): pipeline ArticlePipeline(base_dir./csdn_blog) # 模拟一篇文章的处理 sample_content # 示例技术文章标题 ## 四、边界分析与架构权衡 大家好我是赵咕咕。这是一个痛点描述段落至少需要几十个中文字符来满足正文长度的要求。实际项目的痛点需要写得更加详细和生动让读者产生共鸣。 ## 五、总结 核心原理说明... ## 三、生产级代码实现 python import asyncio async def main(): print(Hello World) if __name__ __main__: asyncio.run(main())四、边界分析与架构权衡优势分析局限分析五、总结核心要点回顾。 这是一段填充文字。 * 50result await pipeline.process( title示例技术文章标题探索与实践, categoryTech, keywords[示例, 技术, Python], date_str20240726, index99, contentsample_content, ) print(json.dumps(result, ensure_asciiFalse, indent2))ifname main:asyncio.run(main())这套工具的核心设计思路 - **TopicManager**选题查重靠规则匹配不是靠人脑记忆。标题相似度 60% 或关键词重叠 3 就判定重复。这是工程化的信息冗余消除。 - **CodeValidator**至少要做语法检查和 import 检查。语法错误是最低级也最常见的代码 bug——asyncio.run(main()) 忘了写这种。 - **ArticleQualityCheck**多维检查——标题字数、正文字数、Mermaid 图、代码块、禁止词、五模块完整性。一条不过就不能发布。 - **ArticlePipeline**流水线模式编排——选题查重 → 代码验证 → 质量检查 → 归档。每步通过才进下一步任何一步失败都会阻止发布。 ## 四、边界分析与架构权衡 ### 4.1 AI 辅助 vs 人工写作的边界 我是用 AI 做辅助的——选题、代码框架、文字润色。但 AI 不知道你的真实踩坑经历不知道哪些边界情况值得写不知道什么是读者真正想知道但自己没意识到的点。 我的分工原则 - AI 做代码框架生成、Markdown 格式化、语法检查、字数统计、禁止词扫描。 - 人做选题判断、痛点经历的细节、边界分析的选择、整体语调控制。 AI 是效率放大器不是内容创作者。把 AI 当成一个能写代码、能改语法的实习生而不是主笔。 ### 4.2 每周 10 篇的量怎么保证不注水 10 篇文章每篇 1000 字正文 200 行代码一周的产出量确实不小。关键是**不要为了凑数降低质量**。 我的策略 - 代码必须能跑这是硬底线。代码跑不通的文章不发。 - 只写自己真正做过的东西不写想象中的场景或理论上的最佳实践。 - 每篇必须有一个原创的 Mermaid 图这强制了每篇文章都有一套自己的分析框架不会出现换个标题又来一遍的情况。 - 反选题如果发现选的题目写不出差异化内容直接换题。 ### 4.3 写作工具栈的选择 | 工具 | 用途 | 替代方案 | |------|------|---------| | Markdown Git | 写作和版本管理 | Notion/语雀 | | Mermaid | 图表 | draw.io / Excalidraw | | Python 环境 | 代码验证 | Jupyter Notebook | | VS Code | 编辑器 | PyCharm | | Qdrant示例代码 | 向量数据库 | FAISS/Chroma | 关键的决策是所有内容用 Markdown Git 管理。Word、Notion 这些工具的问题是它们不是纯文本——不方便 diff、不方便自动化检查、不方便批量操作。Markdown 是纯文本你可以用任何脚本处理和检查。 ### 4.4 长期维护的考量 文章发表了不是结束。三个月后 API 更新了、库名变了、示例代码跑不通了。 建议 - 代码中不写死版本号或者用 范围约束 - 核心逻辑尽量用标准库实现减少第三方依赖 - 定期用 CI 跑文章中的代码跑不通的自动标记需要更新 ## 五、总结 技术博客的持续产出是一个**系统化工程**不是靠灵感驱动的。 核心经验 1. **流程 灵感**固定五段论结构、固定选题筛选标准、固定质量检查项。流程消除了不知道从哪开始的焦虑。 2. **代码先于文字**代码必须在本地跑通然后再写文字。不要边写文字边写代码——两者节奏不同混在一起互相干扰。 3. **Mermaid 图是分析框架的投影**不要为了画图而画图。如果你画不出原理的流程图说明你还没理解透这个技术。 4. **工具化一切重复操作**查重、格式检查、归档命名——这些全自动化。把人的精力留给创造性的部分。 这个生产流程还在持续迭代。每次发现可以优化的环节就加一个检查步骤。四个月后回头看第一周的文章质量确实不如现在——不是因为写作水平突飞猛进而是流程越来越好。 --- *下一篇预告Agent 项目从开发到上线的完整 checklist50 个你可能忽略的关键项。*

相关新闻

最新新闻

日新闻

周新闻

月新闻