AI内容生成管线:从提示词工程到多阶段质量控制的架构实践
AI内容生成管线:从提示词工程到多阶段质量控制的架构实践

一、当生成内容不可控:AIGC生产落地的质量困境
大模型内容生成能力在 Demo 阶段看起来很惊艳,但一旦进入生产环境,质量不可控的问题立刻浮现。一个技术博客生成系统,用户输入主题后,模型有时输出结构清晰、论据扎实的文章,有时却生成空洞的套话、重复的段落甚至事实错误。这种不一致性让 AIGC 产品难以建立用户信任。
更具体的场景是:一个营销文案生成平台需要为不同品牌生成风格各异的文案。同一个模型、同一个提示词,不同次调用的输出风格可能差异巨大。品牌 A 需要专业严谨的语气,品牌 B 需要活泼口语化的表达,但模型经常在两种风格之间摇摆。当生成量达到每天数千篇时,人工审核根本跟不上,而自动质量评估又缺乏可靠的标准。
这些问题的根源在于:将内容生成当作单次 LLM 调用,缺乏对生成过程的分阶段控制和输出质量的闭环验证。生产级的内容生成不是"一次调用出结果",而是一个包含意图解析、内容规划、分步生成、质量校验和迭代优化的多阶段管线。
二、多阶段生成管线:从意图到成稿的工程化流程
将内容生成拆分为多个阶段,每个阶段有明确的输入输出和质量标准,是控制生成质量的核心策略。
graph TD
A[用户输入主题/需求] --> B[意图解析与约束提取]
B --> C[内容大纲生成]
C --> D{大纲审核}
D -->|不通过| C
D -->|通过| E[分段内容生成]
E --> F[内容质量校验]
F --> G{质量达标?}
G -->|否| H[定位问题段落]
H --> I[定向重写]
I --> F
G -->|是| J[全文润色与格式化]
J --> K[最终输出]
subgraph 质量控制层
D
F
G
end
subgraph 生成层
C
E
I
J
end
意图解析阶段将用户的模糊需求转化为结构化的生成约束:目标读者、文章长度、语气风格、必须包含的要点、禁止出现的内容。这些约束作为后续所有生成阶段的上下文,确保输出始终在预期范围内。
大纲生成阶段让模型先规划结构再填充内容,避免直接生成全文时出现的逻辑混乱和重复。大纲审核可以基于规则(检查是否包含必需章节)或基于 LLM(评估大纲的逻辑完整性)。
分段生成阶段按大纲逐段生成,每段独立调用 LLM,上下文窗口只需要包含当前段落的要求和前文摘要,而非全文。这种方式既降低了 Token 消耗,也提高了每段的生成质量。
三、生产级内容生成管线实现
3.1 意图解析与约束提取
package contentgen
import (
"context"
"encoding/json"
"fmt"
)
// GenerationConstraint 生成约束
type GenerationConstraint struct {
Topic string `json:"topic"` // 主题
TargetReader string `json:"target_reader"` // 目标读者
Tone string `json:"tone"` // 语气风格
Length int `json:"length"` // 目标字数
RequiredPoints []string `json:"required_points"` // 必须包含的要点
ForbiddenWords []string `json:"forbidden_words"` // 禁止出现的词汇
Format string `json:"format"` // 输出格式
}
// IntentParser 意图解析器
type IntentParser struct {
llmClient LLMClient
}
// Parse 从用户输入中提取结构化约束
func (ip *IntentParser) Parse(ctx context.Context, userInput string) (*GenerationConstraint, error) {
prompt := `从以下用户输入中提取内容生成的结构化约束,以JSON格式返回。
用户输入:` + userInput + `
返回格式:
{
"topic": "文章主题",
"target_reader": "目标读者描述",
"tone": "语气风格(如专业/活泼/严谨)",
"length": 目标字数,
"required_points": ["必须包含的要点1", "要点2"],
"forbidden_words": ["禁止词汇1", "禁止词汇2"],
"format": "输出格式(如markdown/纯文本)"
}
只返回JSON,不要其他内容:`
resp, err := ip.llmClient.Chat(ctx, ChatRequest{
Messages: []Message{{Role: "user", Content: prompt}},
Temperature: 0.1,
})
if err != nil {
return nil, fmt.Errorf("意图解析失败: %w", err)
}
var constraint GenerationConstraint
if err := json.Unmarshal([]byte(resp.Message.Content), &constraint); err != nil {
return nil, fmt.Errorf("约束解析失败: %w", err)
}
return &constraint, nil
}
3.2 大纲生成与审核
// Outline 大纲结构
type Outline struct {
Title string `json:"title"`
Sections []SectionSpec `json:"sections"`
}
// SectionSpec 章节规格
type SectionSpec struct {
Heading string `json:"heading"` // 章节标题
KeyPoints []string `json:"key_points"` // 必须覆盖的要点
WordCount int `json:"word_count"` // 目标字数
}
// OutlineGenerator 大纲生成器
type OutlineGenerator struct {
llmClient LLMClient
}
// Generate 根据约束生成大纲
func (og *OutlineGenerator) Generate(ctx context.Context, constraint *GenerationConstraint) (*Outline, error) {
prompt := fmt.Sprintf(`根据以下约束生成文章大纲,以JSON格式返回。
主题:%s
目标读者:%s
语气:%s
目标字数:%d
必须包含的要点:%v
返回格式:
{
"title": "文章标题",
"sections": [
{"heading": "章节标题", "key_points": ["要点1"], "word_count": 300}
]
}
要求:
1. 章节数量4-5个
2. 各章节字数之和约等于目标字数
3. 所有必须包含的要点都要分配到具体章节
4. 只返回JSON:`, constraint.Topic, constraint.TargetReader,
constraint.Tone, constraint.Length, constraint.RequiredPoints)
resp, err := og.llmClient.Chat(ctx, ChatRequest{
Messages: []Message{{Role: "user", Content: prompt}},
Temperature: 0.3,
})
if err != nil {
return nil, fmt.Errorf("大纲生成失败: %w", err)
}
var outline Outline
if err := json.Unmarshal([]byte(resp.Message.Content), &outline); err != nil {
return nil, fmt.Errorf("大纲解析失败: %w", err)
}
return &outline, nil
}
// ValidateOutline 大纲审核
func ValidateOutline(outline *Outline, constraint *GenerationConstraint) error {
// 检查必须要点是否都被覆盖
covered := make(map[string]bool)
for _, sec := range outline.Sections {
for _, pt := range sec.KeyPoints {
covered[pt] = true
}
}
for _, req := range constraint.RequiredPoints {
if !covered[req] {
return fmt.Errorf("大纲缺少必需要点: %s", req)
}
}
// 检查总字数是否合理
totalWords := 0
for _, sec := range outline.Sections {
totalWords += sec.WordCount
}
if totalWords < constraint.Length*80/100 || totalWords > constraint.Length*120/100 {
return fmt.Errorf("大纲字数%d与目标%d偏差过大", totalWords, constraint.Length)
}
return nil
}
3.3 分段生成与质量校验
// SectionGenerator 分段内容生成器
type SectionGenerator struct {
llmClient LLMClient
}
// GenerateSection 生成单个章节内容
func (sg *SectionGenerator) GenerateSection(ctx context.Context, section SectionSpec, constraint *GenerationConstraint, prevSummary string) (string, error) {
prompt := fmt.Sprintf(`根据以下要求生成一个章节的内容。
章节标题:%s
必须覆盖的要点:%v
目标字数:%d字
语气风格:%s
目标读者:%s
禁止使用的词汇:%v
%s
请直接输出章节正文,不要输出标题:`,
section.Heading, section.KeyPoints, section.WordCount,
constraint.Tone, constraint.TargetReader, constraint.ForbiddenWords,
conditionalStr(prevSummary != "", "前文摘要(保持衔接):"+prevSummary, ""))
resp, err := sg.llmClient.Chat(ctx, ChatRequest{
Messages: []Message{{Role: "user", Content: prompt}},
Temperature: 0.5,
})
if err != nil {
return "", fmt.Errorf("章节生成失败: %w", err)
}
return resp.Message.Content, nil
}
// QualityChecker 内容质量校验器
type QualityChecker struct {
llmClient LLMClient
}
// QualityReport 质量报告
type QualityReport struct {
Score float64 `json:"score"` // 总分 0-100
Passed bool `json:"passed"` // 是否达标
Issues []string `json:"issues"` // 问题列表
Suggestions []string `json:"suggestions"` // 改进建议
}
// Check 校验内容质量
func (qc *QualityChecker) Check(ctx context.Context, content string, constraint *GenerationConstraint) (*QualityReport, error) {
prompt := fmt.Sprintf(`评估以下内容的质量,以JSON格式返回评估结果。
评估维度:
1. 主题相关性(0-25分):内容是否紧扣主题"%s"
2. 要点覆盖率(0-25分):是否覆盖了所有要点%v
3. 语气一致性(0-25分):是否符合"%s"语气
4. 内容充实度(0-25分):是否有实质性内容,而非空洞套话
待评估内容:
%s
返回格式:
{
"score": 总分,
"passed": 总分>=70为true,
"issues": ["问题1", "问题2"],
"suggestions": ["建议1", "建议2"]
}
只返回JSON:`, constraint.Topic, constraint.RequiredPoints, constraint.Tone, content)
resp, err := qc.llmClient.Chat(ctx, ChatRequest{
Messages: []Message{{Role: "user", Content: prompt}},
Temperature: 0.1,
})
if err != nil {
return nil, fmt.Errorf("质量校验失败: %w", err)
}
var report QualityReport
if err := json.Unmarshal([]byte(resp.Message.Content), &report); err != nil {
return nil, fmt.Errorf("质量报告解析失败: %w", err)
}
return &report, nil
}
四、内容生成管线的成本与延迟权衡
多阶段管线的最大代价是 LLM 调用次数增加。一次完整的生成流程可能需要 5-8 次 LLM 调用(意图解析、大纲生成、3-5 段内容生成、质量校验),Token 消耗和延迟都是单次调用的数倍。在成本敏感的场景中,可以通过以下策略优化:使用小模型做意图解析和质量校验(这些任务的复杂度较低),只在大纲生成和内容生成阶段使用大模型;缓存相似主题的大纲模板,减少从零生成的次数。
质量校验的准确性本身也是一个问题。用 LLM 评估 LLM 的输出,存在"同源偏差"——评估模型和生成模型的训练数据重叠,可能对同类错误不敏感。更可靠的做法是结合规则校验(检查必需要点是否出现、字数是否达标、禁止词汇是否包含)和 LLM 校验(评估语义连贯性和逻辑合理性),形成互补。
管线中的重试策略需要谨慎设计。质量不达标时,应该定向重写问题段落而非全文重生成,否则成本和延迟都会失控。定向重写需要质量校验报告精确定位问题所在(如"第二段缺少要点X"),这要求校验阶段的输出足够结构化。
五、总结
AI 内容生成管线的核心设计思想是将"一次生成"拆分为"意图解析-大纲规划-分段生成-质量校验-定向重写"的多阶段流程。每个阶段有明确的输入输出和质量标准,通过结构化约束控制生成方向,通过质量校验闭环保证输出一致性。工程实现中需要平衡调用成本与生成质量:小模型处理低复杂度任务,大模型聚焦核心生成;规则校验兜底确定性要求,LLM 校验评估语义质量。管线化不是增加复杂度,而是将不可控的单次生成转化为可监控、可干预、可迭代的生产流程。
更多推荐



所有评论(0)