第1649篇:内容创作平台的AI辅助写作——从灵感生成到全文润色的产品工程
第1649篇:内容创作平台的AI辅助写作——从灵感生成到全文润色的产品工程
说一件真实发生的事。
去年有个做自媒体创作工具的朋友找我,说他们要做AI写作功能,目标是"用户输入一个标题,AI自动生成5000字爆款文章"。他很兴奋,觉得这是降维打击。
我问他:"生成的文章,读者觉得有价值吗?"
他愣了一下。
这个问题其实是整个AI辅助写作产品的核心命题。一键生成文章技术上做到了,但生成的内容是否有真正的信息量、观点深度、作者个人风格?大概率没有。而缺乏这些的文章,在越来越成熟的读者面前越来越没价值。
所以我们最终选了另一个方向:不是替代写作,而是辅助写作。帮作者更快写出更好的文章,而不是帮平台生成没有灵魂的内容填充物。
这个方向不那么性感,但更扎实,也真正创造了价值。
产品定位决定技术架构
这个区分非常重要,"替代写作"和"辅助写作"在产品架构上是完全不同的。
替代写作路线: 输入题目 → 大模型全文生成 → 输出文章 辅助写作路线: 作者写作全流程 → AI在每个环节介入 → 提升效率和质量
我们选了后者。具体拆解每个环节:
每个环节的AI介入程度是不同的,这样设计有几个好处:
- 作者始终是内容主导者,保持了原创性
- 每个环节可以独立开发和迭代
- 作者可以选择性使用某些功能,不是all-or-nothing
创意阶段:选题和热点分析
很多创作者最难的不是写,而是不知道写什么。选题决定了内容的天花板。
@Service
public class TopicInspirationService {
@Autowired
private ChatClient chatClient;
@Autowired
private TrendingTopicsService trendingService;
/**
* 基于作者领域和当前热点生成选题建议
*/
public List<TopicSuggestion> generateTopicSuggestions(
AuthorProfile author,
int count) {
// 获取近期热点(来自搜索指数、热搜等数据)
List<TrendingTopic> trends = trendingService.getForDomain(
author.getDomain(), 24 // 最近24小时
);
String trendStr = trends.stream()
.map(t -> String.format("「%s」(热度:%d,趋势:%s)",
t.getKeyword(), t.getHotScore(), t.getTrend()))
.collect(Collectors.joining("\n"));
String prompt = """
你是一位资深内容策划,请为以下作者生成选题建议:
【作者信息】
领域:%s
已有粉丝:%d(平台:%s)
近期爆款文章:%s
写作风格:%s
【当前热点话题】
%s
请生成%d个选题,每个选题包括:
1. 标题(有吸引力,但不是标题党)
2. 核心观点(这篇文章想说什么,20字)
3. 目标读者(谁会对这个话题感兴趣)
4. 角度亮点(为什么作者写这个有优势或不同视角)
5. 与热点的关联度(如何借助热点提高传播)
注意:
- 选题要符合该作者的领域和风格,不要推荐明显不符合的
- 至少2个是结合当前热点的
- 至少1个是深度长线选题(不追热点,但有持久价值)
以JSON数组返回。
""".formatted(
author.getDomain(),
author.getFollowerCount(),
author.getPlatforms(),
author.getRecentTopArticles(),
author.getWritingStyle(),
trendStr,
count
);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parseTopicSuggestions(response);
}
/**
* 竞品文章分析:同类选题别人怎么写的
*/
public CompetitorAnalysis analyzeCompetitors(String topic) {
List<Article> similarArticles = contentSearchService.findSimilar(
topic, 10 // 找最近10篇同类
);
String articlesStr = similarArticles.stream()
.map(a -> String.format("标题:%s\n阅读量:%d\n摘要:%s\n",
a.getTitle(), a.getPageviews(), a.getSummary()))
.collect(Collectors.joining("---\n"));
String prompt = """
请分析以下同类文章,帮助作者找到差异化角度:
话题:%s
已有文章:
%s
请分析:
1. 已有文章的主要角度覆盖了什么
2. 哪些角度被遗漏了(空白点)
3. 哪种角度的文章表现最好(从阅读量判断)
4. 如果要写这个话题,最有差异化的3个切入角度
""".formatted(topic, articlesStr);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parseCompetitorAnalysis(response);
}
}构思阶段:大纲生成和结构优化
选题定了,怎么写是下一个难题。大纲生成要有逻辑性,不是简单地列几个标题:
@Service
public class OutlineGenerationService {
@Autowired
private ChatClient chatClient;
public ArticleOutline generateOutline(
String topic,
String coreArgument,
ArticleType articleType,
int targetWordCount,
String authorNotes) {
String prompt = """
请为以下文章生成详细大纲:
【文章基本信息】
话题:%s
核心观点:%s
文章类型:%s
目标字数:%d字
【作者补充说明】
%s
请生成:
1. 文章整体结构建议(为什么选择这种结构)
2. 各节标题和内容要点(每节列出3-5个要写的点)
3. 开头建议(用什么方式开头更有吸引力)
4. 结尾建议(如何有力收束)
5. 需要哪些支撑素材(数据、案例、引用等)
文章类型说明:
- OPINION:观点型,需要有鲜明立场和论证
- HOW_TO:方法型,需要清晰可操作的步骤
- STORY:故事型,需要有情节起伏
- ANALYSIS:分析型,需要数据和逻辑
以JSON格式返回大纲结构。
""".formatted(
topic, coreArgument,
articleType.getLabel(),
targetWordCount,
authorNotes != null ? authorNotes : "无"
);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parseOutline(response);
}
/**
* 大纲优化:作者写了草稿大纲,AI帮改进
*/
public OutlineImprovement improveOutline(
String draftOutline,
String targetAudience,
String mainPoint) {
String prompt = """
请优化以下文章大纲:
【目标读者】%s
【核心观点】%s
【作者草稿大纲】
%s
请指出:
1. 大纲的逻辑是否清晰(问题出在哪)
2. 结构是否适合目标读者
3. 是否有重复或可以合并的部分
4. 是否有重要内容缺失
5. 给出优化版大纲
""".formatted(targetAudience, mainPoint, draftOutline);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parseOutlineImprovement(response);
}
}写作阶段:实时辅助功能
这是产品里最复杂的部分,因为要嵌入写作编辑器,实时响应作者的动作。
功能1:智能续写(作者卡壳时)
@Service
public class SmartContinuationService {
@Autowired
private ChatClient chatClient;
/**
* 根据已写内容续写下一段
* 要模仿作者的写作风格
*/
public String suggestContinuation(
String writtenContent,
String outline,
AuthorStyleProfile styleProfile) {
// 分析已写内容的风格特征
String styleAnalysis = analyzeWrittenStyle(writtenContent);
String prompt = """
请续写以下文章的下一段,要求完全匹配作者的写作风格:
【文章大纲(参考)】
%s
【作者已写内容】
%s
【作者风格特征(从以上内容分析)】
%s
【作者历史风格偏好】
句子长度:%s
用词风格:%s
常用表达方式:%s
请续写100-200字,要求:
1. 语气和风格要与已有内容完全匹配
2. 内容要自然衔接,不要重复已有内容
3. 要推进文章的主题
4. 如果有好的举例或数据可以自然加入(但要有根据,不要编造)
直接返回续写内容,不要说明和前缀。
""".formatted(
outline,
writtenContent,
styleAnalysis,
styleProfile.getSentenceLengthPreference(),
styleProfile.getVocabularyStyle(),
styleProfile.getCommonExpressions()
);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
}功能2:段落扩写
作者有时候列了一个要点,但不知道怎么展开:
public String expandParagraph(
String briefPoint,
String articleContext,
int targetLength) {
String prompt = """
请将以下简短观点扩写为完整段落:
原始观点:%s
文章背景:%s
扩写要求:
- 目标长度:%d--%d字
- 可以加入具体例子或类比说明
- 要有论据支撑(可以举例说明,但不要凭空编造具体数据)
- 语言风格要自然,不要太学术
直接返回扩写内容。
""".formatted(
briefPoint, articleContext,
targetLength, targetLength + 100
);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}功能3:写作中的实时建议(类似grammar check但更智能)
这个功能需要在前端编辑器中做实时检测,用WebSocket推送建议:
@Service
public class RealTimeWritingAdvisor {
// 每隔30秒或作者停止打字后触发
public List<WritingAdvice> analyzeCurrentParagraph(
String currentParagraph,
String articleContext) {
List<WritingAdvice> advices = new ArrayList<>();
// 快速规则检测(不调用大模型)
advices.addAll(quickRuleCheck(currentParagraph));
// 只有规则检测发现问题,才调用大模型深度分析
if (needsDeepAnalysis(currentParagraph)) {
advices.addAll(deepAnalysis(currentParagraph, articleContext));
}
return advices;
}
private List<WritingAdvice> quickRuleCheck(String text) {
List<WritingAdvice> advices = new ArrayList<>();
// 检查句子过长(超过100字)
String[] sentences = text.split("[。!?]");
for (String sentence : sentences) {
if (sentence.length() > 100) {
advices.add(WritingAdvice.builder()
.type(AdviceType.SENTENCE_TOO_LONG)
.message("这句话较长,考虑拆分为两句")
.severity(Severity.LOW)
.build());
}
}
// 检查重复词语
if (hasRepeatWords(text)) {
advices.add(WritingAdvice.builder()
.type(AdviceType.WORD_REPETITION)
.message("发现重复用词,建议换个表达")
.severity(Severity.LOW)
.build());
}
return advices;
}
}润色阶段:这是最容易踩坑的地方
全文润色是个很容易做错的功能。
最常见的错误:让AI直接改写全文,结果作者的个人风格全没了,变成千篇一律的"AI腔"。这是最糟糕的结果。
正确的做法是:AI提出修改建议,作者决定是否采纳。
@Service
public class ArticlePolishingService {
@Autowired
private ChatClient chatClient;
/**
* 不直接改文章,而是生成修改建议列表
*/
public PolishingSuggestions generatePolishingSuggestions(
String articleContent,
AuthorStyleProfile authorStyle,
PolishingFocus focus) {
String focusInstruction = switch (focus) {
case READABILITY -> "重点关注:长句拆分、逻辑连接词、段落过渡";
case ENGAGEMENT -> "重点关注:开头吸引力、金句提炼、结尾收束";
case ACCURACY -> "重点关注:表述是否准确、是否有歧义、数据/引用是否需要核实";
case STYLE -> "重点关注:风格一致性、是否有段落风格突兀";
default -> "全面审查";
};
String prompt = """
请审阅以下文章,给出具体的修改建议(不要直接改写):
【审阅重点】
%s
【作者风格偏好】
%s
【文章内容】
%s
请以"段落编号 + 具体问题 + 修改建议"的格式列出建议。
要求:
1. 只指出真正值得改的问题,不要为改而改
2. 修改建议要具体,不要说"可以写得更好"这种废话
3. 保留作者的个人风格,不要把所有独特表达都"纠正"掉
4. 最多提10条建议,宁缺毋滥
以JSON数组格式返回,每条包含:
{
"paragraphRef": "相关段落的开头几个字",
"issueType": "问题类型",
"issue": "具体问题描述",
"suggestion": "修改建议",
"priority": "HIGH/MEDIUM/LOW"
}
""".formatted(
focusInstruction,
formatStyleProfile(authorStyle),
articleContent
);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parsePolishingSuggestions(response);
}
/**
* 标题优化:生成多个候选标题
*/
public List<TitleCandidate> generateTitleCandidates(
String articleContent,
String platform,
int count) {
String prompt = """
请为以下文章生成%d个候选标题:
发布平台:%s(不同平台读者口味不同)
文章核心内容摘要:
%s
生成要求:
- 覆盖不同风格:有直接型、有悬念型、有数字型、有故事型
- 避免标题党(不要承诺文章里没有的内容)
- 字数:15-30字为宜
- 每个标题注明类型和适合原因
以JSON数组返回。
""".formatted(
count, platform,
extractCoreSummary(articleContent)
);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
return parseTitleCandidates(response);
}
}个性化:学习作者风格
这是让产品有粘性的核心功能。AI要能学习并适应每个作者的个人风格,而不是给所有人一样的输出。
@Service
public class AuthorStyleLearningService {
@Autowired
private ChatClient chatClient;
/**
* 分析作者历史文章,提取风格特征
*/
public AuthorStyleProfile learnStyle(
Long authorId,
List<Article> historicalArticles) {
// 取最近10篇
List<Article> recentArticles = historicalArticles.stream()
.sorted((a, b) -> b.getPublishDate().compareTo(a.getPublishDate()))
.limit(10)
.collect(Collectors.toList());
String samplesStr = recentArticles.stream()
.map(a -> "文章:" + a.getTitle() + "\n片段:" +
a.getContent().substring(0, Math.min(500, a.getContent().length())))
.collect(Collectors.joining("\n---\n"));
String prompt = """
请分析以下作者的写作风格,提取可复现的风格特征:
文章样本:
%s
请分析:
1. 句式风格(长句还是短句?多用设问吗?)
2. 用词倾向(口语化还是书面语?专业词汇多吗?)
3. 结构习惯(喜欢用什么方式开头/结尾?)
4. 情感表达(克制还是直接?有没有幽默感?)
5. 常用表达模式(有哪些标志性的表达方式?)
6. 独特语气(读起来给人什么感觉)
这些特征将用于AI辅助时保持风格一致,请务必具体准确。
以JSON格式返回。
""".formatted(samplesStr);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
AuthorStyleProfile profile = parseStyleProfile(response);
profile.setAuthorId(authorId);
profile.setLastUpdated(Instant.now());
styleProfileRepo.save(profile);
return profile;
}
}成本控制与性能
内容创作产品的大模型调用很密集,成本控制是运营成功的关键。
我们的分级策略:
@Configuration
public class AiModelTierConfig {
// 不同功能用不同等级的模型
// 轻量功能用便宜小模型,核心功能用大模型
@Bean
public Map<AiFeature, ModelConfig> featureModelMapping() {
return Map.of(
// 简单功能:小模型
AiFeature.TITLE_GENERATION,
ModelConfig.of("gpt-3.5-turbo", 0.5),
AiFeature.TAG_SUGGESTION,
ModelConfig.of("gpt-3.5-turbo", 0.3),
AiFeature.QUICK_RULE_CHECK,
ModelConfig.of("gpt-3.5-turbo", 0.3),
// 核心功能:大模型
AiFeature.STYLE_CONTINUATION,
ModelConfig.of("gpt-4o", 0.7),
AiFeature.FULL_ARTICLE_POLISH,
ModelConfig.of("gpt-4o", 0.6),
AiFeature.OUTLINE_GENERATION,
ModelConfig.of("gpt-4o", 0.5),
// 风格学习:批处理,用性价比高的
AiFeature.STYLE_LEARNING,
ModelConfig.of("gpt-4o-mini", 0.4)
);
}
}还有一个重要的成本控制:对用户的AI功能使用做配额管理,不同会员级别有不同的每日用量。免费用户每天10次,付费用户不限次。
产品效果
运营3个月的数据:
- 日活跃创作者使用AI功能比例:68%
- 使用AI辅助的文章,完成率(开始写到发布)比不用AI高41%
- 作者反馈"AI改变了我的风格"的投诉率:2%(这个要严格控制,说明个性化做得还可以)
- 付费转化率:用了AI功能的用户,付费率是不用的3.2倍
最出乎意料的发现:用了AI写作辅助之后,作者的发文频率平均提升了2.3倍,但单篇文章阅读量没有下降。说明AI帮助作者降低了写作门槛,让他们能在保持质量的同时多产出。
这个结果验证了我们最初的产品方向:AI是放大器,不是替代者。
