AI 辅助技术博客选题:从社区热点到个性化内容规划
技术博客最难的不是写,而是定题。灵感昨天还在,今天打开编辑器就一片空白。热点想追但怕同质化,冷门想写但怕没人看。本文介绍一套用 AI 辅助选题的工作流:从社区热点抓取、竞争度评估,到基于个人技术栈的个性化选题推荐,最后生成可执行的月度内容日历。
flowchart TB A[数据采集层] --> B[GitHub Trending] A --> C[Hacker News / V2EX] A --> D[技术周刊 Newsletter] B --> E[热点聚合与去重] C --> E D --> E E --> F[竞争度评分] E --> G[个人匹配度计算] F --> H[选题综合排序] G --> H H --> I[月度内容日历生成]一、选题的本质:在热点、能力和差异化之间找交集
选题不是找"最热的话题",而是找"你最擅长的领域中,有足够关注度且竞争不太激烈的那个方向"。三个维度的权衡:
- 热度:这个话题最近有多少人在讨论,值不值得写
- 能力匹配:你有没有第一手的实践经验能支撑这篇文章
- 竞争度:已经有多少篇类似文章,你的文章凭什么脱颖而出
理想选题是热度中高、能力匹配高、竞争度低的组合。AI 的作用不是替你拍板,而是帮你把这三个维度量化,缩小选择范围。
二、热点数据采集:多源聚合与去重
热点信息源分三类:代码社区(GitHub Trending)、技术讨论(Hacker News、V2EX、Reddit)、技术周刊(JavaScript Weekly、Node Weekly)。
// sources/aggregator.ts interface HotTopic { source: string; title: string; url: string; score: number; keywords: string[]; timestamp: number; } async function aggregateHotTopics(): Promise<HotTopic[]> { const sources = [ fetchGitHubTrending(), fetchHackerNews(50), fetchV2EXHot(), ]; try { const results = await Promise.allSettled(sources); const topics: HotTopic[] = []; for (const result of results) { if (result.status === 'fulfilled') { topics.push(...result.value); } } // 基于标题相似度去重 return deduplicateTopics(topics); } catch (error) { console.error('热点采集失败:', error); return []; } } function deduplicateTopics(topics: HotTopic[]): HotTopic[] { const seen = new Set<string>(); return topics.filter((t) => { const normalized = t.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]/g, ''); if (seen.has(normalized)) return false; seen.add(normalized); return true; }); }采集踩坑:GitHub Trending 没有官方 API,只能抓取 HTML 页面,页面结构变更会导致解析失败。用cheerio解析并设置降级策略——失败时返回最近一次成功缓存的快照。Hacker News API 限速 10000 次/天,本地缓存 10 分钟可避免频繁请求。V2EX 热门话题接口偶尔返回空数组(服务器维护期),需用Promise.allSettled容错而非Promise.all,否则一个源失败会导致全部采集结果丢失。
三、竞争度评估:衡量已有内容的覆盖程度
热点高不代表值得写——如果已有 50 篇相似文章,你的文章很难获得流量。竞争度评分的思路是:搜索该话题的现有文章,评估覆盖度和质量。
// analysis/competition.ts interface CompetitionScore { topic: string; existingArticles: number; avgQuality: number; // 0-10 coverageDepth: number; // 0-10,覆盖深度 competitionIndex: number; // 越低越好 } async function evaluateCompetition( topic: string, ): Promise<CompetitionScore> { // 用搜索引擎 API 查询已有文章 const searchResults = await searchArticles(topic); if (searchResults.length === 0) { return { topic, existingArticles: 0, avgQuality: 0, coverageDepth: 0, competitionIndex: 0, }; } const avgQuality = calculateAvgQuality(searchResults); return { topic, existingArticles: searchResults.length, avgQuality, coverageDepth: evaluateCoverage(searchResults), competitionIndex: searchResults.length * avgQuality * 0.1, }; }如果竞争度指标显示已有大量高质量文章,AI 会建议你调整切入角度,而不是直接放弃。例如:"React 性能优化"这个主题已充分覆盖,但"React Server Components 下的性能优化策略"仍然是内容缺口。
实际案例:热门话题"Vite 配置优化"已有 23 篇中文文章,竞争度评分 7.8/10(分数越高代表竞争越激烈)。但 AI 分析发现,所有文章都只讲基础配置(alias、proxy、css),没有一篇涉及"Vite 插件的执行顺序与钩子生命周期"。这个细分方向的竞争度为 1.2/10,且与前端的技能树高度匹配。最终这篇文章获得了 3 倍于平均值的阅读量。
四、个性化匹配与综合排序
把个人技能树结构化为知识图谱,每个话题自动映射到你的技术栈中:
// matching/skill-match.ts interface SkillNode { name: string; level: number; // 1-5 children: SkillNode[]; } const skillTree: SkillNode = { name: '前端工程化', level: 5, children: [ { name: 'React', level: 5, children: [] }, { name: 'Vite', level: 4, children: [] }, { name: '微前端', level: 4, children: [] }, { name: '设计系统', level: 3, children: [] }, ], }; function calculateTopicMatch( topic: HotTopic, skills: SkillNode, ): number { const relevantSkills = findRelevantSkills(topic.keywords, skills); if (relevantSkills.length === 0) return 0; // 取最匹配技能的平均等级,加权实践深度 return relevantSkills.reduce( (sum, skill) => sum + skill.level, 0, ) / relevantSkills.length / 5; // 归一化到 0-1 }个人匹配度保证了选题在你的能力范围内——你不会被推荐去写"Rust 编译器优化"如果你从未接触过 Rust。
最终排序采用加权公式,三个维度的权重可根据个人策略调整:
// ranking/sorter.ts interface TopicScore { topic: HotTopic; heatScore: number; competitionScore: number; // 越低越好 matchScore: number; finalScore: number; } function rankTopics( topics: HotTopic[], competitionMap: Map<string, CompetitionScore>, matchMap: Map<string, number>, ): TopicScore[] { const W_HEAT = 0.3; const W_COMPETITION = 0.3; const W_MATCH = 0.4; return topics .map((topic) => { const competition = competitionMap.get(topic.title); const match = matchMap.get(topic.title) || 0; const heatNorm = topic.score / 100; // 归一化 const competitionNorm = competition ? 1 - Math.min(competition.competitionIndex / 50, 1) : 1; const finalScore = heatNorm * W_HEAT + competitionNorm * W_COMPETITION + match * W_MATCH; return { topic, heatScore: heatNorm, competitionScore: competitionNorm, matchScore: match, finalScore, }; }) .sort((a, b) => b.finalScore - a.finalScore); }最终输出一份月度内容日历,将高分段选题分配到每周,确保发布节奏稳定:
function generateCalendar( rankedTopics: TopicScore[], startDate: Date, ): ContentCalendar { const calendar: ContentCalendar = { months: [] }; const topPicks = rankedTopics.slice(0, Math.min(rankedTopics.length, 12)); let currentDate = new Date(startDate); for (const topic of topPicks) { calendar.months.push({ date: currentDate.toISOString().split('T')[0], title: topic.topic.title, heatScore: topic.heatScore, keywords: topic.topic.keywords, }); currentDate.setDate(currentDate.getDate() + 7); } return calendar; }4.1 内容日历的执行与调整
生成内容日历后,需要根据实际执行情况动态调整。建议每周回顾选题完成情况,对于未完成的选题分析原因(是技术难度过大还是热度已过),并将其重新评估后放入下月候选池。同时,应该关注已发布文章的数据反馈(阅读量、点赞、评论),将表现好的选题方向在后续日历中加大权重,形成正向循环。
五、总结
AI 辅助选题不是让 AI 替你决定写什么,而是把"凭感觉选题目"变成"看数据定方向"。三步走:第一步聚合社区热点,了解现在大家在讨论什么;第二步评估竞争度,找到有流量但有空间的切入角度;第三步计算个人匹配度,确保选题在自己能力半径内。加权排序后自动生成月度内容日历,从此告别选题焦虑。技术写作的产出稳定性,就藏在这个选题流程的自动化里。