Skip to content

LangChain 教程 35|项目实战:自动化内容创作系统

📖 本篇导读:这是 LangChain 系列教程的第 35 篇。本篇将构建一个智能内容创作平台,支持素材收集、多平台适配、SEO 优化、质量检查和一键发布。读完预计需要 20 分钟。

项目概述

简单来说

构建一个智能内容创作平台,用户只需输入一个主题或关键词,系统就能自动:

  • 收集相关素材和资料
  • 生成高质量的原创文章
  • 针对不同平台(微信公众号、知乎、小红书、头条等)进行适配
  • 自动优化 SEO 关键词
  • 进行质量检查和原创性检测
  • 一键发布到多个平台

核心功能

功能描述
智能素材收集自动搜索相关资料、热点话题、竞品文章
多平台适配针对不同平台的风格和规范自动调整内容
SEO 优化自动提取关键词、优化标题、生成摘要
质量检查原创性检测、事实核查、语法纠错
批量生产支持批量生成系列文章
版本管理保存修改历史,支持回滚

传统内容创作 vs 智能创作系统对比

技术亮点

┌─────────────────────────────────────────────────────────────────┐
│              自动化内容创作系统技术架构                           │
├─────────────────────────────────────────────────────────────────┤
│  前端:React 18 + TypeScript + Ant Design + Zustand             │
│  后端:Express + Prisma + MySQL + Redis                         │
│  AI:LangChain 1.x + Subagents + 中间件 + 结构化输出             │
│  外部API:搜索引擎 + 各平台 Open API                             │
└─────────────────────────────────────────────────────────────────┘

一、系统架构

1.1 整体架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                              前端层                                          │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│  │  创作台   │  │  素材库   │  │  文章管理 │  │  发布中心 │  │  数据分析 │      │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘      │
│       └──────────────┴──────────────┴──────────────┴──────────────┘          │
│                                     │                                        │
│                              ┌──────┴───────┐                                │
│                              │ Zustand Store │  ← 状态管理                    │
│                              └──────┬────────┘                                │
└─────────────────────────────────────┼────────────────────────────────────────┘
                                      │ HTTP/SSE
┌─────────────────────────────────────┼────────────────────────────────────────┐
│                                     ▼              后端层                     │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                         Express API Server                            │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐              │  │
│  │  │/articles │  │/materials│  │/publish  │  │/generate │              │  │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘              │  │
│  └───────┼──────────────┼──────────────┼──────────────┼──────────────────┘  │
│          │              │              │              │                      │
│  ┌───────┴──────────────┴──────────────┴──────────────┴──────────────────┐  │
│  │                         AI Content Pipeline                           │  │
│  │                                                                       │  │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │  │
│  │  │                    Orchestrator Agent (编排器)                   │ │  │
│  │  │                                                                 │ │  │
│  │  │   调度以下 Sub-Agents:                                         │ │  │
│  │  │   ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐      │ │  │
│  │  │   │ Researcher│ │  Writer   │ │  Editor   │ │ Publisher │      │ │  │
│  │  │   │ Sub-Agent │ │ Sub-Agent │ │ Sub-Agent │ │ Sub-Agent │      │ │  │
│  │  │   │  素材收集  │ │  内容生成  │ │  编辑优化  │ │  发布分发  │      │ │  │
│  │  │   └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘      │ │  │
│  │  └─────────┼─────────────┼─────────────┼─────────────┼────────────┘ │  │
│  │            │             │             │             │              │  │
│  │  ┌─────────┴─────────────┴─────────────┴─────────────┴────────────┐ │  │
│  │  │                     Middleware Pipeline                        │ │  │
│  │  │   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │  │
│  │  │   │原创检测  │→│SEO优化  │→│格式转换  │→│质量评分  │→│敏感词过滤│ │ │  │
│  │  │   └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │  │
│  │  └────────────────────────────────────────────────────────────────┘ │  │
│  └─────────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────┼────────────────────────────────────────┐
│                                     ▼         外部服务层                      │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐        │
│  │  搜索引擎 API │ │  平台 API    │ │  图片服务    │ │  原创检测    │        │
│  │  (Bing/Google)│ │ (微信/知乎)  │ │  (Unsplash) │ │   API        │        │
│  └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘        │
└──────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────┼────────────────────────────────────────┐
│                                     ▼            数据层                       │
│                    ┌──────────────┐           ┌──────────────┐               │
│                    │    MySQL     │           │    Redis     │               │
│                    │  (Prisma)    │           │   (缓存)     │               │
│                    └──────────────┘           └──────────────┘               │
└──────────────────────────────────────────────────────────────────────────────┘

自动化内容创作系统四层架构

1.2 内容创作流水线

用户输入:"写一篇关于 AI 编程助手的文章,面向开发者,发布到知乎"


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 1: 需求分析                                                           │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  Orchestrator Agent 解析:                                            │  │
│  │  • 主题:AI 编程助手                                                  │  │
│  │  • 受众:开发者                                                       │  │
│  │  • 目标平台:知乎                                                     │  │
│  │  • 内容类型:科普/评测                                                │  │
│  │  • 预估字数:2000-3000字                                              │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 2: 素材收集 (Researcher Sub-Agent)                                   │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  并行执行:                                                           │  │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐     │  │
│  │  │ 搜索热点文章 │ │ 收集产品信息 │ │ 查找数据统计 │ │ 获取用户评价 │     │  │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘     │  │
│  │                                                                       │  │
│  │  输出:MaterialCollection { articles, products, statistics, reviews } │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 3: 大纲生成 (Writer Sub-Agent - Outline)                             │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  基于素材生成文章大纲:                                                │  │
│  │  1. 引言:AI 编程助手的崛起                                           │  │
│  │  2. 主流 AI 编程助手盘点(GitHub Copilot、Cursor、通义灵码...)        │  │
│  │  3. 核心功能对比分析                                                  │  │
│  │  4. 实际使用体验                                                      │  │
│  │  5. 选型建议                                                          │  │
│  │  6. 总结与展望                                                        │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 4: 内容生成 (Writer Sub-Agent - Content)                             │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  按大纲逐章节生成:                                                    │  │
│  │  • 每个章节独立生成,保证质量                                         │  │
│  │  • 融入收集的素材和数据                                               │  │
│  │  • 保持语言风格一致                                                   │  │
│  │  • 添加代码示例(针对开发者)                                         │  │
│  │                                                                       │  │
│  │  输出:RawArticle { title, sections[], wordCount }                    │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 5: 编辑优化 (Editor Sub-Agent)                                       │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  流水线处理:                                                          │  │
│  │  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐            │  │
│  │  │ 语法纠错 │ → │ 风格润色 │ → │ 事实核查 │ → │ 原创检测 │            │  │
│  │  └─────────┘    └─────────┘    └─────────┘    └─────────┘            │  │
│  │                                                                       │  │
│  │  输出:EditedArticle { content, corrections[], factChecks[] }         │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 6: 平台适配 (Publisher Sub-Agent)                                    │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  针对知乎平台:                                                        │  │
│  │  • 标题优化(适合知乎的提问式/干货式标题)                             │  │
│  │  • 格式转换(Markdown → 知乎格式)                                    │  │
│  │  • 封面图生成/选择                                                    │  │
│  │  • SEO 关键词提取                                                     │  │
│  │  • 话题标签推荐                                                       │  │
│  │                                                                       │  │
│  │  输出:PublishReadyArticle { platformContent, seo, coverImage, tags } │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 7: 质量检查 (Middleware Pipeline)                                    │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  ┌─────────────┐                                                      │  │
│  │  │ 原创性评分   │ → 相似度 < 15% ✓                                     │  │
│  │  └─────────────┘                                                      │  │
│  │  ┌─────────────┐                                                      │  │
│  │  │ 可读性评分   │ → Flesch Score > 60 ✓                                │  │
│  │  └─────────────┘                                                      │  │
│  │  ┌─────────────┐                                                      │  │
│  │  │ SEO 评分     │ → 关键词密度 2-3% ✓                                  │  │
│  │  └─────────────┘                                                      │  │
│  │  ┌─────────────┐                                                      │  │
│  │  │ 敏感词检测   │ → 无违规内容 ✓                                       │  │
│  │  └─────────────┘                                                      │  │
│  │                                                                       │  │
│  │  输出:QualityReport { scores, passed, suggestions }                  │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│  Phase 8: 人工确认 & 发布                                                   │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  • 展示最终文章预览                                                    │  │
│  │  • 显示质量检查报告                                                    │  │
│  │  • 用户可手动编辑                                                      │  │
│  │  • 确认后自动发布到目标平台                                            │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘

内容创作8阶段流水线流程


二、AI Agent 架构设计

2.1 整体架构模式

本项目采用 Subagents 模式,由一个 Orchestrator(编排器)调度多个专业 Sub-Agent:

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Subagents 架构                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│                     ┌────────────────────────┐                               │
│                     │   Orchestrator Agent   │                               │
│                     │       (编排器)          │                               │
│                     │                        │                               │
│                     │  • 理解用户创作需求     │                               │
│                     │  • 分解任务给子Agent    │                               │
│                     │  • 协调执行顺序        │                               │
│                     │  • 整合最终结果        │                               │
│                     └───────────┬────────────┘                               │
│                                 │                                            │
│           ┌─────────────────────┼─────────────────────┐                      │
│           │                     │                     │                      │
│           ▼                     ▼                     ▼                      │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐              │
│  │   Researcher    │  │     Writer      │  │     Editor      │              │
│  │   Sub-Agent     │  │   Sub-Agent     │  │   Sub-Agent     │              │
│  │                 │  │                 │  │                 │              │
│  │  职责:         │  │  职责:         │  │  职责:         │              │
│  │  • 搜索资料     │  │  • 生成大纲     │  │  • 语法纠错     │              │
│  │  • 收集素材     │  │  • 撰写内容     │  │  • 风格润色     │              │
│  │  • 分析热点     │  │  • 代码示例     │  │  • 事实核查     │              │
│  │  • 整理数据     │  │  • 保持一致性   │  │  • 原创优化     │              │
│  │                 │  │                 │  │                 │              │
│  │  工具:         │  │  工具:         │  │  工具:         │              │
│  │  • web_search   │  │  • (无工具)     │  │  • grammar_check│              │
│  │  • fetch_url    │  │  • 纯 LLM 推理  │  │  • fact_check   │              │
│  │  • trend_search │  │                 │  │  • plagiarism   │              │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘              │
│                                                                              │
│                                 │                                            │
│                                 ▼                                            │
│                     ┌─────────────────┐                                      │
│                     │    Publisher    │                                      │
│                     │   Sub-Agent     │                                      │
│                     │                 │                                      │
│                     │  职责:         │                                      │
│                     │  • 平台适配     │                                      │
│                     │  • SEO 优化     │                                      │
│                     │  • 格式转换     │                                      │
│                     │  • 封面生成     │                                      │
│                     │                 │                                      │
│                     │  工具:         │                                      │
│                     │  • seo_analyze  │                                      │
│                     │  • format_convert│                                     │
│                     │  • image_search │                                      │
│                     │  • platform_post│                                      │
│                     └─────────────────┘                                      │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Subagents 架构:Orchestrator 与 4 个 Sub-Agent

2.2 为什么选择 Subagents 模式?

┌─────────────────────────────────────────────────────────────────────────────┐
│                        架构选型分析                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  内容创作的特点:                                                            │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  1. 多阶段流水线任务(研究→写作→编辑→发布)                            │  │
│  │  2. 每个阶段需要不同的专业能力                                         │  │
│  │  3. 阶段之间有明确的输入输出依赖                                       │  │
│  │  4. 每个阶段可能需要迭代优化                                           │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  架构对比:                                                                  │
│                                                                              │
│  ┌──────────────────┬───────────────────┬────────────────────────────────┐ │
│  │     架构模式      │      适用场景      │           评估              │ │
│  ├──────────────────┼───────────────────┼────────────────────────────────┤ │
│  │ 单 Agent + 多工具 │ 简单任务           │ ❌ 内容创作太复杂            │ │
│  │ Router 模式      │ 独立任务分发        │ ❌ 任务间有依赖,不适合       │ │
│  │ Handoffs 模式    │ 对话式任务移交      │ ❌ 不需要对话式移交           │ │
│  │ Subagents 模式 ✅ │ 流水线式复杂任务   │ ✅ 完美匹配内容创作流程       │ │
│  │ Custom Workflow  │ 需要精细控制的流程  │ ⚠️ 可以,但 Subagents 更简洁 │ │
│  └──────────────────┴───────────────────┴────────────────────────────────┘ │
│                                                                              │
│  Subagents 模式的优势:                                                      │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  ✓ 任务分解清晰:每个 Sub-Agent 专注一个领域                          │  │
│  │  ✓ 易于维护:修改某个阶段不影响其他阶段                                │  │
│  │  ✓ 可扩展性强:轻松添加新的 Sub-Agent(如 Translator)                 │  │
│  │  ✓ 结果可控:每个阶段都可以输出中间结果供审核                          │  │
│  │  ✓ 错误隔离:某个 Agent 失败不会影响已完成的工作                       │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.3 中间件设计

除了 Sub-Agents,本项目还使用 中间件模式 处理横切关注点:

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Middleware Pipeline(中间件流水线)                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  什么是中间件?                                                              │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  中间件是在主流程之外执行的"横切"处理逻辑。                             │  │
│  │  它们不改变核心业务流程,但对内容进行增强、检查、转换。                  │  │
│  │                                                                       │  │
│  │  类比:                                                                │  │
│  │  • 主流程 = 工厂生产线(研究→写作→编辑→发布)                          │  │
│  │  • 中间件 = 质检站(在各环节检查产品质量)                              │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  中间件列表:                                                                │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                                                                     │    │
│  │    输入内容                                                         │    │
│  │        │                                                            │    │
│  │        ▼                                                            │    │
│  │   ┌─────────────────┐                                               │    │
│  │   │ 1. 敏感词过滤    │  检测并处理违规内容                           │    │
│  │   │   Middleware    │  → 替换敏感词 / 标记警告                       │    │
│  │   └────────┬────────┘                                               │    │
│  │            ▼                                                        │    │
│  │   ┌─────────────────┐                                               │    │
│  │   │ 2. 原创性检测    │  检测内容相似度                               │    │
│  │   │   Middleware    │  → 相似度 > 30% 时重写提示                     │    │
│  │   └────────┬────────┘                                               │    │
│  │            ▼                                                        │    │
│  │   ┌─────────────────┐                                               │    │
│  │   │ 3. SEO 优化      │  关键词密度、标题优化                         │    │
│  │   │   Middleware    │  → 自动调整关键词分布                          │    │
│  │   └────────┬────────┘                                               │    │
│  │            ▼                                                        │    │
│  │   ┌─────────────────┐                                               │    │
│  │   │ 4. 格式规范化    │  统一格式、修复排版                           │    │
│  │   │   Middleware    │  → Markdown 规范化                            │    │
│  │   └────────┬────────┘                                               │    │
│  │            ▼                                                        │    │
│  │   ┌─────────────────┐                                               │    │
│  │   │ 5. 质量评分      │  综合评估内容质量                             │    │
│  │   │   Middleware    │  → 输出质量报告                               │    │
│  │   └────────┬────────┘                                               │    │
│  │            ▼                                                        │    │
│  │    输出内容 + 质量报告                                               │    │
│  │                                                                     │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Middleware Pipeline 中间件流水线

2.4 Agent 间数据流

┌─────────────────────────────────────────────────────────────────────────────┐
│                         Agent 间数据流设计                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  用户输入                                                           │    │
│  │  {                                                                  │    │
│  │    topic: "AI 编程助手",                                            │    │
│  │    targetAudience: "开发者",                                        │    │
│  │    platforms: ["zhihu"],                                            │    │
│  │    style: "professional",                                           │    │
│  │    wordCount: { min: 2000, max: 3000 }                              │    │
│  │  }                                                                  │    │
│  └────────────────────────────────┬────────────────────────────────────┘    │
│                                   │                                         │
│                                   ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Orchestrator → Researcher                                          │    │
│  │  {                                                                  │    │
│  │    task: "research",                                                │    │
│  │    topic: "AI 编程助手",                                            │    │
│  │    requirements: {                                                  │    │
│  │      collectCompetitors: true,      // 收集竞品信息                 │    │
│  │      collectStatistics: true,       // 收集数据统计                 │    │
│  │      collectUserReviews: true,      // 收集用户评价                 │    │
│  │      collectTrends: true            // 收集热点趋势                 │    │
│  │    }                                                                │    │
│  │  }                                                                  │    │
│  └────────────────────────────────┬────────────────────────────────────┘    │
│                                   │                                         │
│                                   ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Researcher → Writer                                                │    │
│  │  {                                                                  │    │
│  │    materials: {                                                     │    │
│  │      competitors: [                                                 │    │
│  │        { name: "GitHub Copilot", features: [...], pricing: "..." },│    │
│  │        { name: "Cursor", features: [...], pricing: "..." },        │    │
│  │        ...                                                          │    │
│  │      ],                                                             │    │
│  │      statistics: [                                                  │    │
│  │        { source: "...", data: "开发者使用率增长 300%..." }          │    │
│  │      ],                                                             │    │
│  │      trends: [                                                      │    │
│  │        { topic: "AI 编程效率", heat: 95 }                           │    │
│  │      ],                                                             │    │
│  │      references: [...]                                              │    │
│  │    }                                                                │    │
│  │  }                                                                  │    │
│  └────────────────────────────────┬────────────────────────────────────┘    │
│                                   │                                         │
│                                   ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Writer → Editor                                                    │    │
│  │  {                                                                  │    │
│  │    article: {                                                       │    │
│  │      title: "2024年 AI 编程助手终极指南:从入门到精通",              │    │
│  │      outline: [...],                                                │    │
│  │      sections: [                                                    │    │
│  │        { heading: "引言", content: "..." },                         │    │
│  │        { heading: "主流工具盘点", content: "..." },                 │    │
│  │        ...                                                          │    │
│  │      ],                                                             │    │
│  │      wordCount: 2500,                                               │    │
│  │      codeExamples: [...]                                            │    │
│  │    }                                                                │    │
│  │  }                                                                  │    │
│  └────────────────────────────────┬────────────────────────────────────┘    │
│                                   │                                         │
│                                   ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Editor → Publisher                                                 │    │
│  │  {                                                                  │    │
│  │    editedArticle: {                                                 │    │
│  │      ...article,                                                    │    │
│  │      corrections: [                                                 │    │
│  │        { type: "grammar", original: "...", fixed: "..." }           │    │
│  │      ],                                                             │    │
│  │      factChecks: [                                                  │    │
│  │        { claim: "...", verified: true, source: "..." }              │    │
│  │      ],                                                             │    │
│  │      originalityScore: 0.92                                         │    │
│  │    }                                                                │    │
│  │  }                                                                  │    │
│  └────────────────────────────────┬────────────────────────────────────┘    │
│                                   │                                         │
│                                   ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Publisher → 最终输出                                               │    │
│  │  {                                                                  │    │
│  │    publishReady: {                                                  │    │
│  │      zhihu: {                                                       │    │
│  │        title: "...",                                                │    │
│  │        content: "...",  // 知乎格式                                 │    │
│  │        topics: ["AI", "编程", "效率工具"],                          │    │
│  │        coverImage: "https://...",                                   │    │
│  │        seo: { keywords: [...], description: "..." }                 │    │
│  │      }                                                              │    │
│  │    },                                                               │    │
│  │    qualityReport: {                                                 │    │
│  │      overallScore: 85,                                              │    │
│  │      originalityScore: 92,                                          │    │
│  │      readabilityScore: 78,                                          │    │
│  │      seoScore: 88,                                                  │    │
│  │      suggestions: [...]                                             │    │
│  │    }                                                                │    │
│  │  }                                                                  │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

三、数据库设计

3.1 ER 图

┌──────────────────┐       ┌──────────────────┐
│      users       │       │     articles     │
├──────────────────┤       ├──────────────────┤
│ id (PK)          │───┐   │ id (PK)          │
│ email            │   │   │ userId (FK)      │──┐
│ password         │   └──→│ title            │  │
│ nickname         │       │ content          │  │
│ avatar           │       │ topic            │  │
│ plan             │       │ status           │  │
│ createdAt        │       │ wordCount        │  │
│ updatedAt        │       │ createdAt        │  │
└──────────────────┘       │ updatedAt        │  │
                           └────────┬─────────┘  │
                                    │            │
┌──────────────────┐                │            │
│    materials     │←───────────────┘            │
├──────────────────┤                             │
│ id (PK)          │                             │
│ articleId (FK)   │                             │
│ type             │  (link/text/image/data)     │
│ title            │                             │
│ content          │                             │
│ source           │                             │
│ metadata         │  (JSON)                     │
│ createdAt        │                             │
└──────────────────┘                             │

┌──────────────────┐       ┌──────────────────┐ │
│ article_versions │       │ article_platforms│ │
├──────────────────┤       ├──────────────────┤ │
│ id (PK)          │       │ id (PK)          │ │
│ articleId (FK)   │←──────│ articleId (FK)   │←┘
│ version          │       │ platform         │
│ content          │       │ platformContent  │
│ title            │       │ platformTitle    │
│ changeLog        │       │ seoData (JSON)   │
│ createdAt        │       │ coverImage       │
└──────────────────┘       │ tags (JSON)      │
                           │ publishStatus    │
┌──────────────────┐       │ publishedAt      │
│  quality_reports │       │ publishUrl       │
├──────────────────┤       │ createdAt        │
│ id (PK)          │       └──────────────────┘
│ articleId (FK)   │
│ overallScore     │
│ originalityScore │
│ readabilityScore │
│ seoScore         │
│ details (JSON)   │
│ suggestions(JSON)│
│ createdAt        │
└──────────────────┘

数据库 ER 实体关系图

3.2 Prisma Schema

prisma
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id        String    @id @default(uuid())
  email     String    @unique
  password  String
  nickname  String?
  avatar    String?
  plan      String    @default("free") // free, pro, enterprise
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt
  articles  Article[]

  @@map("users")
}

model Article {
  id         String            @id @default(uuid())
  userId     String
  user       User              @relation(fields: [userId], references: [id], onDelete: Cascade)
  title      String
  content    String            @db.LongText
  topic      String
  status     String            @default("draft") // draft, generating, editing, ready, published
  style      String            @default("professional") // professional, casual, humorous
  audience   String?           // 目标受众描述
  wordCount  Int               @default(0)
  createdAt  DateTime          @default(now())
  updatedAt  DateTime          @updatedAt
  
  materials      Material[]
  versions       ArticleVersion[]
  platforms      ArticlePlatform[]
  qualityReports QualityReport[]

  @@index([userId])
  @@index([status])
  @@map("articles")
}

model Material {
  id        String   @id @default(uuid())
  articleId String
  article   Article  @relation(fields: [articleId], references: [id], onDelete: Cascade)
  type      String   // link, text, image, data, competitor, statistic
  title     String?
  content   String   @db.Text
  source    String?  // 来源 URL
  metadata  Json?    // 额外元数据
  createdAt DateTime @default(now())

  @@index([articleId])
  @@map("materials")
}

model ArticleVersion {
  id        String   @id @default(uuid())
  articleId String
  article   Article  @relation(fields: [articleId], references: [id], onDelete: Cascade)
  version   Int
  title     String
  content   String   @db.LongText
  changeLog String?  @db.Text
  createdAt DateTime @default(now())

  @@unique([articleId, version])
  @@index([articleId])
  @@map("article_versions")
}

model ArticlePlatform {
  id              String   @id @default(uuid())
  articleId       String
  article         Article  @relation(fields: [articleId], references: [id], onDelete: Cascade)
  platform        String   // zhihu, wechat, xiaohongshu, toutiao, juejin
  platformTitle   String
  platformContent String   @db.LongText
  seoData         Json?    // { keywords: [], description: "" }
  coverImage      String?
  tags            Json?    // ["AI", "编程"]
  publishStatus   String   @default("pending") // pending, published, failed
  publishedAt     DateTime?
  publishUrl      String?
  errorMessage    String?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([articleId, platform])
  @@index([articleId])
  @@map("article_platforms")
}

model QualityReport {
  id               String   @id @default(uuid())
  articleId        String
  article          Article  @relation(fields: [articleId], references: [id], onDelete: Cascade)
  overallScore     Int      // 0-100
  originalityScore Int      // 原创性评分
  readabilityScore Int      // 可读性评分
  seoScore         Int      // SEO评分
  grammarScore     Int      // 语法评分
  details          Json?    // 详细检查结果
  suggestions      Json?    // 改进建议列表
  createdAt        DateTime @default(now())

  @@index([articleId])
  @@map("quality_reports")
}

// 素材库 - 用户收藏的素材
model MaterialLibrary {
  id        String   @id @default(uuid())
  userId    String
  category  String   // 分类
  title     String
  content   String   @db.Text
  source    String?
  tags      Json?
  createdAt DateTime @default(now())

  @@index([userId])
  @@index([category])
  @@map("material_library")
}

// 创作模板
model Template {
  id          String   @id @default(uuid())
  userId      String?  // null 表示系统模板
  name        String
  description String?
  platform    String   // 适用平台
  category    String   // 模板分类
  structure   Json     // 文章结构模板
  styleGuide  String?  @db.Text
  isPublic    Boolean  @default(false)
  usageCount  Int      @default(0)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([userId])
  @@index([platform])
  @@map("templates")
}

四、AI Agent 详细实现

4.1 状态定义

typescript
// src/agent/types.ts
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";

// 创作请求
export interface ContentRequest {
  topic: string;
  targetAudience: string;
  platforms: string[];
  style: "professional" | "casual" | "humorous" | "storytelling";
  wordCount: { min: number; max: number };
  keywords?: string[];
  references?: string[];
  specialRequirements?: string;
}

// 素材
export interface Material {
  type: "competitor" | "statistic" | "trend" | "reference" | "quote";
  title: string;
  content: string;
  source?: string;
  relevance: number;
  metadata?: Record<string, any>;
}

// 文章大纲
export interface ArticleOutline {
  title: string;
  hook: string;
  sections: Array<{
    heading: string;
    keyPoints: string[];
    estimatedWords: number;
  }>;
  conclusion: string;
  estimatedTotalWords: number;
}

// 文章章节
export interface ArticleSection {
  heading: string;
  content: string;
  wordCount: number;
}

// 原始文章
export interface RawArticle {
  title: string;
  sections: ArticleSection[];
  wordCount: number;
  codeExamples?: Array<{
    language: string;
    code: string;
    description: string;
  }>;
}

// 编辑结果
export interface EditedArticle extends RawArticle {
  corrections: Array<{
    type: "grammar" | "style" | "fact" | "clarity";
    original: string;
    fixed: string;
    explanation?: string;
  }>;
  factChecks: Array<{
    claim: string;
    verified: boolean;
    source?: string;
    note?: string;
  }>;
  originalityScore: number;
}

// 平台适配内容
export interface PlatformContent {
  platform: string;
  title: string;
  content: string;
  seo: {
    keywords: string[];
    description: string;
    keywordDensity: number;
  };
  coverImage?: string;
  tags: string[];
  formatting: {
    hasImages: boolean;
    hasCode: boolean;
    estimatedReadTime: number;
  };
}

// 质量报告
export interface QualityReport {
  overallScore: number;
  originalityScore: number;
  readabilityScore: number;
  seoScore: number;
  grammarScore: number;
  passed: boolean;
  issues: Array<{
    severity: "error" | "warning" | "info";
    category: string;
    message: string;
    suggestion?: string;
  }>;
}

// Agent 状态
export const ContentCreatorState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
  
  // 输入
  request: Annotation<ContentRequest>(),
  
  // 中间状态
  currentPhase: Annotation<string>({
    default: () => "init",
  }),
  
  // 各阶段输出
  materials: Annotation<Material[]>({
    default: () => [],
  }),
  outline: Annotation<ArticleOutline | null>({
    default: () => null,
  }),
  rawArticle: Annotation<RawArticle | null>({
    default: () => null,
  }),
  editedArticle: Annotation<EditedArticle | null>({
    default: () => null,
  }),
  platformContents: Annotation<PlatformContent[]>({
    default: () => [],
  }),
  qualityReport: Annotation<QualityReport | null>({
    default: () => null,
  }),
  
  // 错误处理
  errors: Annotation<string[]>({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
});

export type ContentCreatorStateType = typeof ContentCreatorState.State;

4.2 Orchestrator Agent(编排器)

typescript
// src/agent/orchestrator.agent.ts
import { ChatOpenAI } from "@langchain/openai";
import { AIMessage } from "@langchain/core/messages";
import type { ContentCreatorStateType } from "./types";

const ORCHESTRATOR_PROMPT = `你是内容创作编排器,负责协调整个内容创作流程。

## 你的职责
1. 分析用户的创作需求
2. 决定任务执行顺序
3. 在各阶段之间传递上下文
4. 处理异常情况

## 创作流程
1. research - 素材收集(Researcher Sub-Agent)
2. outline - 大纲生成(Writer Sub-Agent)
3. write - 内容撰写(Writer Sub-Agent)
4. edit - 编辑优化(Editor Sub-Agent)
5. adapt - 平台适配(Publisher Sub-Agent)
6. quality - 质量检查(Middleware)

## 决策原则
- 如果素材不足,可以要求 Researcher 补充
- 如果大纲不满意,可以要求 Writer 重新生成
- 如果质量检查不通过,可以要求 Editor 修改
- 每个阶段完成后都要检查结果质量

## 输出格式
返回当前应该执行的阶段和原因。`;

export async function orchestratorAgent(state: ContentCreatorStateType) {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0,
  });

  const { request, currentPhase, materials, outline, rawArticle, editedArticle, qualityReport } = state;

  // 构建当前状态描述
  let statusDescription = `
当前阶段: ${currentPhase}
创作请求: ${JSON.stringify(request, null, 2)}
已收集素材数量: ${materials.length}
大纲状态: ${outline ? "已生成" : "未生成"}
文章状态: ${rawArticle ? `已生成 (${rawArticle.wordCount}字)` : "未生成"}
编辑状态: ${editedArticle ? "已完成" : "未完成"}
质量报告: ${qualityReport ? `得分 ${qualityReport.overallScore}` : "未检查"}
`;

  const result = await model.invoke([
    { role: "system", content: ORCHESTRATOR_PROMPT },
    { role: "user", content: statusDescription },
  ]);

  return {
    messages: [new AIMessage({
      content: `[编排器] ${result.content}`,
    })],
  };
}

// 路由决策函数
export function routeNextPhase(state: ContentCreatorStateType): string {
  const { currentPhase, materials, outline, rawArticle, editedArticle, qualityReport, request } = state;

  // 状态机逻辑
  switch (currentPhase) {
    case "init":
      return "researcher"; // 开始收集素材
      
    case "research":
      if (materials.length < 5) {
        return "researcher"; // 素材不足,继续收集
      }
      return "writer_outline"; // 素材足够,开始写大纲
      
    case "outline":
      if (!outline) {
        return "writer_outline"; // 大纲未生成,重试
      }
      return "writer_content"; // 开始写内容
      
    case "write":
      if (!rawArticle) {
        return "writer_content"; // 内容未生成,重试
      }
      return "editor"; // 开始编辑
      
    case "edit":
      if (!editedArticle) {
        return "editor"; // 编辑未完成,重试
      }
      return "publisher"; // 开始平台适配
      
    case "adapt":
      return "quality_check"; // 进入质量检查
      
    case "quality":
      if (qualityReport && !qualityReport.passed) {
        // 质量不达标,需要修改
        if (qualityReport.originalityScore < 70) {
          return "editor"; // 原创性问题,重新编辑
        }
        if (qualityReport.grammarScore < 70) {
          return "editor"; // 语法问题,重新编辑
        }
      }
      return "complete"; // 完成
      
    default:
      return "complete";
  }
}

4.3 Researcher Sub-Agent(素材收集器)

typescript
// src/agent/researcher.agent.ts
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
import { SystemMessage, AIMessage } from "@langchain/core/messages";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import type { ContentCreatorStateType, Material } from "./types";

// 工具定义
const webSearchTool = tool(
  async ({ query, count }) => {
    // 调用搜索 API(如 Bing Search API)
    const searchService = new SearchService();
    const results = await searchService.search(query, count);
    
    return JSON.stringify({
      query,
      results: results.map((r: any) => ({
        title: r.title,
        snippet: r.snippet,
        url: r.url,
        date: r.date,
      })),
    });
  },
  {
    name: "web_search",
    description: "搜索网络获取相关资料,返回标题、摘要和链接",
    schema: z.object({
      query: z.string().describe("搜索关键词"),
      count: z.number().default(10).describe("结果数量"),
    }),
  }
);

const fetchUrlTool = tool(
  async ({ url }) => {
    // 抓取网页内容
    const fetcher = new WebFetcher();
    const content = await fetcher.fetch(url);
    
    return JSON.stringify({
      url,
      title: content.title,
      content: content.text.slice(0, 5000), // 限制长度
      publishDate: content.publishDate,
    });
  },
  {
    name: "fetch_url",
    description: "获取指定 URL 的网页内容",
    schema: z.object({
      url: z.string().url().describe("要抓取的网页 URL"),
    }),
  }
);

const trendSearchTool = tool(
  async ({ topic, platform }) => {
    // 搜索热点趋势
    const trendService = new TrendService();
    const trends = await trendService.search(topic, platform);
    
    return JSON.stringify({
      topic,
      platform,
      trends: trends.map((t: any) => ({
        title: t.title,
        heat: t.heat,
        url: t.url,
        summary: t.summary,
      })),
    });
  },
  {
    name: "trend_search",
    description: "搜索特定主题在各平台的热点趋势",
    schema: z.object({
      topic: z.string().describe("主题关键词"),
      platform: z.enum(["zhihu", "weibo", "toutiao", "all"]).default("all"),
    }),
  }
);

const competitorAnalysisTool = tool(
  async ({ topic, count }) => {
    // 分析竞品文章
    const searchService = new SearchService();
    const results = await searchService.search(`${topic} 评测 对比`, count);
    
    // 抓取并分析前几篇文章
    const analyses = [];
    for (const r of results.slice(0, 3)) {
      const fetcher = new WebFetcher();
      const content = await fetcher.fetch(r.url);
      analyses.push({
        title: r.title,
        url: r.url,
        wordCount: content.text.length,
        structure: extractStructure(content.text),
        keyPoints: extractKeyPoints(content.text),
      });
    }
    
    return JSON.stringify({
      topic,
      competitorArticles: analyses,
    });
  },
  {
    name: "competitor_analysis",
    description: "分析同主题的竞品文章,了解他们的写法和结构",
    schema: z.object({
      topic: z.string().describe("主题"),
      count: z.number().default(5).describe("分析数量"),
    }),
  }
);

const RESEARCHER_PROMPT = `你是内容研究专家,负责为文章创作收集全面的素材。

## 你的任务
根据创作主题,收集以下类型的素材:
1. **竞品/产品信息** - 相关产品的功能、价格、评价
2. **数据统计** - 行业数据、用户调研、市场分析
3. **热点趋势** - 当前热门话题、讨论焦点
4. **参考文章** - 高质量的相关文章
5. **权威引用** - 专家观点、官方声明

## 工作原则
1. 确保信息来源可靠(优先官方、权威媒体)
2. 收集多角度的观点,保持客观
3. 记录所有来源,便于引用
4. 标注信息的时效性
5. 评估每条素材的相关性(1-10分)

## 素材收集顺序
1. 先用 web_search 广泛搜索
2. 用 fetch_url 深入阅读重要文章
3. 用 trend_search 了解热点
4. 用 competitor_analysis 分析竞品文章

确保收集至少 10 条高质量素材。`;

export function createResearcherAgent() {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0.3,
  });

  const tools = [
    webSearchTool,
    fetchUrlTool,
    trendSearchTool,
    competitorAnalysisTool,
  ];

  return createReactAgent({
    llm: model,
    tools,
    messageModifier: new SystemMessage(RESEARCHER_PROMPT),
  });
}

export async function researcherNode(state: ContentCreatorStateType) {
  const agent = createResearcherAgent();
  const { request } = state;

  const instruction = `
请为以下创作需求收集素材:

主题:${request.topic}
目标受众:${request.targetAudience}
目标平台:${request.platforms.join(", ")}
风格:${request.style}
字数要求:${request.wordCount.min}-${request.wordCount.max}字
${request.keywords ? `关键词:${request.keywords.join(", ")}` : ""}
${request.specialRequirements ? `特殊要求:${request.specialRequirements}` : ""}

请全面收集素材,确保涵盖:
1. 该主题的核心产品/工具信息
2. 相关的数据和统计
3. 当前的热点讨论
4. 值得参考的优秀文章

最后,整理成结构化的素材列表。
`;

  const result = await agent.invoke({
    messages: [{ role: "user", content: instruction }],
  });

  // 解析收集到的素材
  const materials = parseMaterials(result.messages);

  return {
    currentPhase: "research",
    materials,
    messages: [new AIMessage({
      content: `[素材收集] 已收集 ${materials.length} 条素材`,
    })],
  };
}

function parseMaterials(messages: any[]): Material[] {
  const materials: Material[] = [];
  
  for (const msg of messages) {
    if (msg._getType() === "tool") {
      try {
        const content = JSON.parse(msg.content);
        
        // 解析搜索结果
        if (content.results) {
          for (const r of content.results) {
            materials.push({
              type: "reference",
              title: r.title,
              content: r.snippet,
              source: r.url,
              relevance: 7,
            });
          }
        }
        
        // 解析竞品分析
        if (content.competitorArticles) {
          for (const a of content.competitorArticles) {
            materials.push({
              type: "competitor",
              title: a.title,
              content: JSON.stringify(a.keyPoints),
              source: a.url,
              relevance: 8,
              metadata: { structure: a.structure },
            });
          }
        }
        
        // 解析趋势
        if (content.trends) {
          for (const t of content.trends) {
            materials.push({
              type: "trend",
              title: t.title,
              content: t.summary,
              source: t.url,
              relevance: t.heat / 10,
              metadata: { heat: t.heat },
            });
          }
        }
      } catch (e) {
        // 忽略解析错误
      }
    }
  }
  
  return materials;
}

4.4 Writer Sub-Agent(内容撰写器)

typescript
// src/agent/writer.agent.ts
import { ChatOpenAI } from "@langchain/openai";
import { AIMessage } from "@langchain/core/messages";
import { z } from "zod";
import type { ContentCreatorStateType, ArticleOutline, RawArticle } from "./types";

// 大纲 Schema
const OutlineSchema = z.object({
  title: z.string().describe("文章标题,吸引人且准确"),
  hook: z.string().describe("开篇钩子,引起读者兴趣"),
  sections: z.array(z.object({
    heading: z.string().describe("章节标题"),
    keyPoints: z.array(z.string()).describe("该章节要覆盖的要点"),
    estimatedWords: z.number().describe("预估字数"),
  })).describe("文章各章节"),
  conclusion: z.string().describe("结论要点"),
  estimatedTotalWords: z.number().describe("预估总字数"),
});

// 章节内容 Schema
const SectionContentSchema = z.object({
  heading: z.string(),
  content: z.string().describe("章节完整内容,Markdown 格式"),
  wordCount: z.number(),
});

const OUTLINE_PROMPT = `你是资深内容策划师,负责规划文章大纲。

## 大纲原则

### 1. 标题设计
- 数字型:《2024年 X 大 AI 编程工具盘点》
- 疑问型:《AI 编程助手真的能提升效率吗?》
- 干货型:《AI 编程助手完全指南:从入门到精通》
- 对比型:《GitHub Copilot vs Cursor:谁是最强 AI 编程助手》

### 2. 结构设计
- 金字塔结构:重要内容放前面
- 故事弧线:引入→发展→高潮→结尾
- 问题解决:痛点→方案→效果

### 3. 章节安排
- 引言(10%):建立话题,引起兴趣
- 主体(70%):分 3-5 个小节展开
- 结尾(20%):总结、建议、展望

### 4. 受众适配
- 开发者:可加入代码示例
- 普通用户:多用类比,少用术语
- 决策者:强调 ROI 和商业价值`;

const CONTENT_PROMPT = `你是专业内容创作者,负责撰写高质量文章。

## 写作原则

### 1. 开篇
- 用数据、故事或问题抓住注意力
- 明确文章价值,告诉读者能获得什么
- 控制在 200 字以内

### 2. 正文
- 每段一个核心观点
- 使用过渡句连接段落
- 适当使用小标题、列表、引用
- 用具体例子支撑观点
- 融入提供的素材和数据

### 3. 代码示例(如需)
- 简洁易懂
- 添加注释说明
- 展示实际效果

### 4. 结尾
- 总结核心观点
- 给出行动建议
- 可适当展望未来

### 5. 语言风格
- professional:专业严谨,数据支撑,逻辑清晰
- casual:轻松活泼,口语化表达,增加互动
- humorous:幽默风趣,加入段子,引人发笑
- storytelling:故事驱动,人物叙事,情感共鸣`;

export async function writerOutlineNode(state: ContentCreatorStateType) {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0.7,
  }).withStructuredOutput(OutlineSchema);

  const { request, materials } = state;

  const prompt = `
## 创作需求
- 主题:${request.topic}
- 目标受众:${request.targetAudience}
- 目标平台:${request.platforms.join(", ")}
- 风格:${request.style}
- 字数:${request.wordCount.min}-${request.wordCount.max}字

## 已收集素材
${materials.map((m, i) => `
${i + 1}. [${m.type}] ${m.title}
   ${m.content.slice(0, 200)}...
   来源:${m.source || "无"}
   相关性:${m.relevance}/10
`).join("\n")}

请基于以上素材,生成一个吸引人的文章大纲。
`;

  const outline = await model.invoke([
    { role: "system", content: OUTLINE_PROMPT },
    { role: "user", content: prompt },
  ]);

  return {
    currentPhase: "outline",
    outline,
    messages: [new AIMessage({
      content: `[大纲生成] ${outline.title}\n\n章节:\n${outline.sections.map(s => `- ${s.heading}`).join("\n")}`,
    })],
  };
}

export async function writerContentNode(state: ContentCreatorStateType) {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0.7,
  }).withStructuredOutput(SectionContentSchema);

  const { request, materials, outline } = state;

  if (!outline) {
    throw new Error("大纲未生成,无法撰写内容");
  }

  // 逐章节生成内容
  const sections = [];
  
  for (const section of outline.sections) {
    // 找出与该章节相关的素材
    const relevantMaterials = findRelevantMaterials(materials, section.heading);

    const prompt = `
## 任务
撰写文章章节:${section.heading}

## 文章信息
- 标题:${outline.title}
- 风格:${request.style}
- 目标受众:${request.targetAudience}

## 章节要点
${section.keyPoints.map(p => `- ${p}`).join("\n")}

## 可用素材
${relevantMaterials.map(m => `
[${m.type}] ${m.title}
${m.content}
来源:${m.source || "无"}
`).join("\n---\n")}

## 要求
- 字数约 ${section.estimatedWords} 字
- 融入提供的素材,但要自然
- 保持与其他章节的风格一致
- ${request.targetAudience === "开发者" ? "可包含代码示例" : ""}
- 使用 Markdown 格式
`;

    const sectionContent = await model.invoke([
      { role: "system", content: CONTENT_PROMPT },
      { role: "user", content: prompt },
    ]);

    sections.push(sectionContent);
  }

  // 生成引言和结尾
  const introContent = await generateIntro(model, outline, request);
  const conclusionContent = await generateConclusion(model, outline, request);

  // 组装完整文章
  const rawArticle: RawArticle = {
    title: outline.title,
    sections: [
      { heading: "引言", content: introContent, wordCount: countWords(introContent) },
      ...sections,
      { heading: "总结", content: conclusionContent, wordCount: countWords(conclusionContent) },
    ],
    wordCount: sections.reduce((sum, s) => sum + s.wordCount, 0) + 
               countWords(introContent) + countWords(conclusionContent),
  };

  return {
    currentPhase: "write",
    rawArticle,
    messages: [new AIMessage({
      content: `[内容生成] 已生成 ${rawArticle.wordCount} 字文章`,
    })],
  };
}

function findRelevantMaterials(materials: any[], heading: string) {
  // 简单的相关性匹配,实际可用更复杂的算法
  return materials.filter(m => {
    const headingWords = heading.toLowerCase().split(/\s+/);
    const materialText = `${m.title} ${m.content}`.toLowerCase();
    return headingWords.some(word => materialText.includes(word));
  }).slice(0, 5);
}

async function generateIntro(model: any, outline: any, request: any) {
  const result = await model.invoke([
    { role: "system", content: "生成文章引言,吸引读者,引出主题" },
    { role: "user", content: `
文章标题:${outline.title}
钩子:${outline.hook}
风格:${request.style}
字数:150-250字
    ` },
  ]);
  return result.content;
}

async function generateConclusion(model: any, outline: any, request: any) {
  const result = await model.invoke([
    { role: "system", content: "生成文章结尾,总结要点,给出建议" },
    { role: "user", content: `
文章标题:${outline.title}
结论要点:${outline.conclusion}
风格:${request.style}
字数:200-300字
    ` },
  ]);
  return result.content;
}

function countWords(text: string): number {
  return text.replace(/\s+/g, "").length;
}

4.5 Editor Sub-Agent(编辑器)

typescript
// src/agent/editor.agent.ts
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
import { SystemMessage, AIMessage } from "@langchain/core/messages";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import type { ContentCreatorStateType, EditedArticle } from "./types";

// 语法检查工具
const grammarCheckTool = tool(
  async ({ text }) => {
    // 调用语法检查 API 或使用 LLM
    const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
    
    const result = await model.invoke([
      { role: "system", content: `你是语法检查专家。检查以下文本的语法错误、标点错误、用词不当等问题。
返回 JSON 格式:
{
  "errors": [
    { "original": "错误原文", "corrected": "修正后", "type": "grammar/punctuation/wording", "explanation": "说明" }
  ],
  "score": 0-100
}` },
      { role: "user", content: text },
    ]);
    
    return result.content;
  },
  {
    name: "grammar_check",
    description: "检查文本的语法、标点和用词错误",
    schema: z.object({
      text: z.string().describe("要检查的文本"),
    }),
  }
);

// 事实核查工具
const factCheckTool = tool(
  async ({ claims }) => {
    // 对声明进行核查
    const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
    const searchService = new SearchService();
    
    const results = [];
    for (const claim of claims) {
      // 搜索相关信息
      const searchResults = await searchService.search(claim, 3);
      
      // LLM 判断
      const verification = await model.invoke([
        { role: "system", content: "你是事实核查专家。根据搜索结果判断声明是否属实。" },
        { role: "user", content: `
声明:${claim}
搜索结果:${JSON.stringify(searchResults)}
请判断该声明是否属实,返回 JSON:{ "verified": true/false, "confidence": 0-100, "source": "来源", "note": "备注" }
` },
      ]);
      
      results.push({
        claim,
        ...JSON.parse(verification.content as string),
      });
    }
    
    return JSON.stringify(results);
  },
  {
    name: "fact_check",
    description: "核查文章中的事实声明是否准确",
    schema: z.object({
      claims: z.array(z.string()).describe("需要核查的声明列表"),
    }),
  }
);

// 原创性检测工具
const plagiarismCheckTool = tool(
  async ({ text }) => {
    // 检测原创性
    // 实际项目中可调用专门的 API(如 Copyscape、Turnitin 等)
    // 这里使用 LLM 模拟
    const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
    const searchService = new SearchService();
    
    // 取文章的几个片段进行搜索
    const segments = extractSegments(text, 5);
    let similarCount = 0;
    const matches = [];
    
    for (const segment of segments) {
      const results = await searchService.search(`"${segment}"`, 3);
      if (results.length > 0) {
        similarCount++;
        matches.push({
          segment,
          matchedUrl: results[0].url,
        });
      }
    }
    
    const originalityScore = Math.round((1 - similarCount / segments.length) * 100);
    
    return JSON.stringify({
      originalityScore,
      matches,
      recommendation: originalityScore < 70 ? "建议重写部分内容" : "原创性良好",
    });
  },
  {
    name: "plagiarism_check",
    description: "检测文章的原创性,识别可能的抄袭内容",
    schema: z.object({
      text: z.string().describe("要检测的文章内容"),
    }),
  }
);

const EDITOR_PROMPT = `你是资深编辑,负责优化和完善文章。

## 编辑任务

### 1. 语法纠错
使用 grammar_check 工具检查语法、标点、用词

### 2. 风格润色
- 保持语言流畅
- 消除冗余表达
- 增强可读性
- 确保风格一致

### 3. 事实核查
使用 fact_check 工具核查重要声明:
- 数据和统计
- 引用和来源
- 产品功能描述

### 4. 原创性检测
使用 plagiarism_check 工具检测原创性
- 原创性 < 70% 需要重写
- 标记相似内容

### 5. 整体优化
- 检查逻辑连贯性
- 优化段落过渡
- 确保论点支撑充分

## 输出要求
1. 修改后的完整文章
2. 修改记录(原文/修改后/原因)
3. 事实核查结果
4. 原创性得分`;

export function createEditorAgent() {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0.3,
  });

  const tools = [
    grammarCheckTool,
    factCheckTool,
    plagiarismCheckTool,
  ];

  return createReactAgent({
    llm: model,
    tools,
    messageModifier: new SystemMessage(EDITOR_PROMPT),
  });
}

export async function editorNode(state: ContentCreatorStateType) {
  const { rawArticle, request } = state;

  if (!rawArticle) {
    throw new Error("文章未生成,无法编辑");
  }

  const agent = createEditorAgent();
  
  // 将文章转为纯文本
  const fullText = rawArticle.sections.map(s => `## ${s.heading}\n\n${s.content}`).join("\n\n");

  const instruction = `
请编辑和优化以下文章:

## 文章标题
${rawArticle.title}

## 文章内容
${fullText}

## 编辑要求
1. 检查并修正语法错误
2. 按照 "${request.style}" 风格润色
3. 核查文中的事实声明
4. 检测原创性

请依次使用工具完成检查,然后提供:
1. 修改后的完整文章
2. 所有修改的详细记录
3. 事实核查结果
4. 原创性得分
`;

  const result = await agent.invoke({
    messages: [{ role: "user", content: instruction }],
  });

  // 解析编辑结果
  const editedArticle = parseEditedArticle(result.messages, rawArticle);

  return {
    currentPhase: "edit",
    editedArticle,
    messages: [new AIMessage({
      content: `[编辑完成] 原创性得分:${editedArticle.originalityScore},修正 ${editedArticle.corrections.length} 处`,
    })],
  };
}

function extractSegments(text: string, count: number): string[] {
  const sentences = text.match(/[^。!?.!?]+[。!?.!?]/g) || [];
  const step = Math.floor(sentences.length / count);
  return sentences.filter((_, i) => i % step === 0).slice(0, count);
}

function parseEditedArticle(messages: any[], rawArticle: any): EditedArticle {
  // 从消息中解析编辑结果
  let corrections: any[] = [];
  let factChecks: any[] = [];
  let originalityScore = 85; // 默认值

  for (const msg of messages) {
    if (msg._getType() === "tool") {
      try {
        const content = JSON.parse(msg.content);
        
        if (content.errors) {
          corrections = content.errors.map((e: any) => ({
            type: e.type,
            original: e.original,
            fixed: e.corrected,
            explanation: e.explanation,
          }));
        }
        
        if (Array.isArray(content) && content[0]?.claim) {
          factChecks = content;
        }
        
        if (content.originalityScore !== undefined) {
          originalityScore = content.originalityScore;
        }
      } catch (e) {
        // 忽略解析错误
      }
    }
  }

  return {
    ...rawArticle,
    corrections,
    factChecks,
    originalityScore,
  };
}

4.6 Publisher Sub-Agent(发布器)

typescript
// src/agent/publisher.agent.ts
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
import { SystemMessage, AIMessage } from "@langchain/core/messages";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import type { ContentCreatorStateType, PlatformContent } from "./types";

// SEO 分析工具
const seoAnalyzeTool = tool(
  async ({ text, targetKeywords }) => {
    const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
    
    const result = await model.invoke([
      { role: "system", content: `你是 SEO 专家。分析文本的 SEO 质量,返回 JSON:
{
  "keywords": ["提取的关键词"],
  "keywordDensity": { "关键词": 密度百分比 },
  "suggestions": ["优化建议"],
  "score": 0-100,
  "titleSuggestions": ["优化后的标题建议"],
  "descriptionSuggestion": "meta description 建议"
}` },
      { role: "user", content: `
文本:${text.slice(0, 3000)}
目标关键词:${targetKeywords.join(", ")}
` },
    ]);
    
    return result.content;
  },
  {
    name: "seo_analyze",
    description: "分析内容的 SEO 质量,提供优化建议",
    schema: z.object({
      text: z.string().describe("要分析的文本"),
      targetKeywords: z.array(z.string()).describe("目标关键词"),
    }),
  }
);

// 格式转换工具
const formatConvertTool = tool(
  async ({ content, fromFormat, toFormat, platform }) => {
    // 不同平台的格式要求
    const platformFormats: Record<string, any> = {
      zhihu: {
        maxImageWidth: 690,
        codeBlockStyle: "highlight",
        linkStyle: "inline",
        supportedTags: ["h1", "h2", "h3", "p", "ul", "ol", "blockquote", "code", "img"],
      },
      wechat: {
        maxImageWidth: 640,
        codeBlockStyle: "screenshot",
        linkStyle: "footnote", // 公众号链接只能放文末
        supportedTags: ["h1", "h2", "h3", "p", "ul", "ol", "blockquote", "pre"],
      },
      xiaohongshu: {
        maxImageWidth: 1080,
        codeBlockStyle: "image", // 小红书不支持代码块
        linkStyle: "none",
        maxLength: 1000,
        emojiRequired: true,
      },
      toutiao: {
        maxImageWidth: 640,
        codeBlockStyle: "highlight",
        linkStyle: "card",
        supportedTags: ["h1", "h2", "h3", "p", "ul", "ol", "blockquote", "code", "img"],
      },
      juejin: {
        maxImageWidth: 800,
        codeBlockStyle: "highlight",
        linkStyle: "inline",
        supportedTags: ["h1", "h2", "h3", "p", "ul", "ol", "blockquote", "code", "img"],
      },
    };

    const format = platformFormats[platform];
    
    // 根据平台规则转换内容
    let convertedContent = content;
    
    // 处理代码块
    if (format.codeBlockStyle === "image" || format.codeBlockStyle === "screenshot") {
      // 将代码块转为图片(实际实现中调用截图服务)
      convertedContent = convertedContent.replace(/```[\s\S]*?```/g, "[代码图片]");
    }
    
    // 处理链接
    if (format.linkStyle === "footnote") {
      // 将内联链接转为脚注
      const links: string[] = [];
      convertedContent = convertedContent.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => {
        links.push(url);
        return `${text}[${links.length}]`;
      });
      if (links.length > 0) {
        convertedContent += "\n\n---\n参考链接:\n" + links.map((l, i) => `[${i + 1}] ${l}`).join("\n");
      }
    } else if (format.linkStyle === "none") {
      // 移除链接
      convertedContent = convertedContent.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
    }
    
    // 长度限制
    if (format.maxLength && convertedContent.length > format.maxLength) {
      convertedContent = convertedContent.slice(0, format.maxLength - 100) + "...\n\n(完整内容见评论区)";
    }
    
    return JSON.stringify({
      platform,
      originalLength: content.length,
      convertedLength: convertedContent.length,
      convertedContent,
      notes: [],
    });
  },
  {
    name: "format_convert",
    description: "将内容转换为目标平台的格式",
    schema: z.object({
      content: z.string().describe("原始内容(Markdown)"),
      fromFormat: z.string().default("markdown"),
      toFormat: z.string().default("platform"),
      platform: z.enum(["zhihu", "wechat", "xiaohongshu", "toutiao", "juejin"]),
    }),
  }
);

// 图片搜索工具
const imageSearchTool = tool(
  async ({ query, count }) => {
    // 调用图片搜索 API(如 Unsplash、Pexels)
    const imageService = new ImageService();
    const images = await imageService.search(query, count);
    
    return JSON.stringify({
      query,
      images: images.map((img: any) => ({
        url: img.url,
        thumbnailUrl: img.thumbnailUrl,
        description: img.description,
        author: img.author,
        license: img.license,
      })),
    });
  },
  {
    name: "image_search",
    description: "搜索免费可商用的图片作为封面或配图",
    schema: z.object({
      query: z.string().describe("搜索关键词"),
      count: z.number().default(5).describe("结果数量"),
    }),
  }
);

// 标签推荐工具
const tagRecommendTool = tool(
  async ({ content, platform }) => {
    const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0.3 });
    
    const result = await model.invoke([
      { role: "system", content: `你是${platform}平台的运营专家。根据内容推荐合适的标签/话题。
返回 JSON:{ "tags": ["标签1", "标签2", ...], "reasoning": "推荐理由" }` },
      { role: "user", content: content.slice(0, 2000) },
    ]);
    
    return result.content;
  },
  {
    name: "tag_recommend",
    description: "根据内容推荐平台话题标签",
    schema: z.object({
      content: z.string().describe("文章内容"),
      platform: z.string().describe("目标平台"),
    }),
  }
);

const PUBLISHER_PROMPT = `你是内容发布专家,负责将文章适配到不同平台。

## 各平台特点

### 知乎
- 标题:干货型、疑问型效果好
- 内容:深度长文,可带代码
- 标签:选择相关话题,增加曝光
- 封面:可选,建议信息图

### 微信公众号
- 标题:吸睛、引导点击
- 内容:图文并茂,链接放文末
- 代码:建议截图展示
- 封面:必须,尺寸 900x383

### 小红书
- 标题:emoji + 关键词
- 内容:口语化,分段短
- 图片:必须多图
- 长度:控制在 1000 字内

### 头条号
- 标题:数字、悬念效果好
- 内容:小标题分隔,易读
- 封面:三图或大图

### 掘金
- 标题:技术关键词 + 价值
- 内容:代码示例丰富
- 标签:技术栈相关

## 任务流程
1. 使用 seo_analyze 分析和优化 SEO
2. 使用 format_convert 转换平台格式
3. 使用 image_search 选择封面图
4. 使用 tag_recommend 推荐标签`;

export function createPublisherAgent() {
  const model = new ChatOpenAI({
    model: "gpt-4o",
    temperature: 0.5,
  });

  const tools = [
    seoAnalyzeTool,
    formatConvertTool,
    imageSearchTool,
    tagRecommendTool,
  ];

  return createReactAgent({
    llm: model,
    tools,
    messageModifier: new SystemMessage(PUBLISHER_PROMPT),
  });
}

export async function publisherNode(state: ContentCreatorStateType) {
  const { editedArticle, request } = state;

  if (!editedArticle) {
    throw new Error("文章未编辑,无法发布");
  }

  const agent = createPublisherAgent();
  const platformContents: PlatformContent[] = [];

  // 为每个目标平台生成适配内容
  for (const platform of request.platforms) {
    const instruction = `
请将以下文章适配到 ${platform} 平台:

## 文章标题
${editedArticle.title}

## 文章内容
${editedArticle.sections.map(s => `## ${s.heading}\n\n${s.content}`).join("\n\n")}

## 关键词
${request.keywords?.join(", ") || "无指定"}

请执行以下操作:
1. SEO 分析和优化
2. 格式转换适配 ${platform}
3. 搜索合适的封面图
4. 推荐话题标签

最后输出 ${platform} 平台的:
1. 优化后的标题
2. 适配后的内容
3. SEO 数据
4. 封面图 URL
5. 推荐标签
`;

    const result = await agent.invoke({
      messages: [{ role: "user", content: instruction }],
    });

    // 解析平台内容
    const platformContent = parsePlatformContent(result.messages, platform, editedArticle);
    platformContents.push(platformContent);
  }

  return {
    currentPhase: "adapt",
    platformContents,
    messages: [new AIMessage({
      content: `[平台适配] 已适配 ${platformContents.length} 个平台`,
    })],
  };
}

function parsePlatformContent(messages: any[], platform: string, article: any): PlatformContent {
  let seo = { keywords: [], description: "", keywordDensity: 0 };
  let coverImage = "";
  let tags: string[] = [];
  let content = article.sections.map((s: any) => `## ${s.heading}\n\n${s.content}`).join("\n\n");

  for (const msg of messages) {
    if (msg._getType() === "tool") {
      try {
        const data = JSON.parse(msg.content);
        
        if (data.keywords) {
          seo = {
            keywords: data.keywords,
            description: data.descriptionSuggestion || "",
            keywordDensity: Object.values(data.keywordDensity || {})[0] as number || 0,
          };
        }
        
        if (data.convertedContent) {
          content = data.convertedContent;
        }
        
        if (data.images) {
          coverImage = data.images[0]?.url || "";
        }
        
        if (data.tags) {
          tags = data.tags;
        }
      } catch (e) {
        // 忽略
      }
    }
  }

  return {
    platform,
    title: article.title,
    content,
    seo,
    coverImage,
    tags,
    formatting: {
      hasImages: content.includes("[图片]") || content.includes("!["),
      hasCode: content.includes("```"),
      estimatedReadTime: Math.ceil(content.length / 500),
    },
  };
}

4.7 Middleware(中间件)

typescript
// src/agent/middleware/index.ts
import type { PlatformContent, QualityReport } from "../types";

// 中间件接口
interface Middleware {
  name: string;
  process: (content: PlatformContent) => Promise<MiddlewareResult>;
}

interface MiddlewareResult {
  passed: boolean;
  score?: number;
  issues?: Array<{
    severity: "error" | "warning" | "info";
    message: string;
    suggestion?: string;
  }>;
  modifiedContent?: string;
}

// 敏感词过滤中间件
const sensitiveWordMiddleware: Middleware = {
  name: "sensitiveWord",
  async process(content) {
    const sensitiveWords = await loadSensitiveWords();
    const issues: MiddlewareResult["issues"] = [];
    let modifiedContent = content.content;
    
    for (const word of sensitiveWords) {
      if (modifiedContent.includes(word)) {
        issues.push({
          severity: "error",
          message: `检测到敏感词:${word}`,
          suggestion: "建议替换或删除",
        });
        // 可选:自动替换
        modifiedContent = modifiedContent.replace(new RegExp(word, "g"), "***");
      }
    }
    
    return {
      passed: issues.filter(i => i.severity === "error").length === 0,
      issues,
      modifiedContent,
    };
  },
};

// SEO 优化中间件
const seoOptimizeMiddleware: Middleware = {
  name: "seoOptimize",
  async process(content) {
    const issues: MiddlewareResult["issues"] = [];
    let score = 100;
    
    // 检查标题长度
    if (content.title.length < 10) {
      issues.push({
        severity: "warning",
        message: "标题过短,建议 10-30 字",
        suggestion: "增加描述性词语",
      });
      score -= 10;
    }
    if (content.title.length > 50) {
      issues.push({
        severity: "warning",
        message: "标题过长,可能被截断",
        suggestion: "精简标题,控制在 30 字内",
      });
      score -= 10;
    }
    
    // 检查关键词密度
    const density = content.seo.keywordDensity;
    if (density < 1) {
      issues.push({
        severity: "info",
        message: "关键词密度偏低",
        suggestion: "适当增加关键词出现频率",
      });
      score -= 5;
    }
    if (density > 5) {
      issues.push({
        severity: "warning",
        message: "关键词密度过高,可能影响阅读",
        suggestion: "适当减少关键词堆砌",
      });
      score -= 15;
    }
    
    // 检查 meta description
    if (!content.seo.description || content.seo.description.length < 50) {
      issues.push({
        severity: "info",
        message: "缺少或过短的描述",
        suggestion: "添加 100-150 字的描述",
      });
      score -= 5;
    }
    
    return {
      passed: true,
      score: Math.max(0, score),
      issues,
    };
  },
};

// 可读性评分中间件
const readabilityMiddleware: Middleware = {
  name: "readability",
  async process(content) {
    const text = content.content;
    const issues: MiddlewareResult["issues"] = [];
    
    // 计算句子平均长度
    const sentences = text.match(/[^。!?.!?]+[。!?.!?]/g) || [];
    const avgSentenceLength = text.length / sentences.length;
    
    // 计算段落平均长度
    const paragraphs = text.split(/\n\n+/);
    const avgParagraphLength = text.length / paragraphs.length;
    
    let score = 80;
    
    if (avgSentenceLength > 50) {
      issues.push({
        severity: "warning",
        message: "句子平均长度过长",
        suggestion: "拆分长句,每句控制在 30 字内",
      });
      score -= 15;
    }
    
    if (avgParagraphLength > 300) {
      issues.push({
        severity: "info",
        message: "段落较长,建议适当分段",
        suggestion: "每段 3-5 句话为宜",
      });
      score -= 5;
    }
    
    // 检查是否有小标题
    const hasHeadings = /#{1,3}\s/.test(text);
    if (!hasHeadings && text.length > 500) {
      issues.push({
        severity: "info",
        message: "长文缺少小标题",
        suggestion: "添加小标题帮助读者浏览",
      });
      score -= 10;
    }
    
    return {
      passed: true,
      score,
      issues,
    };
  },
};

// 质量评分中间件
const qualityScoreMiddleware: Middleware = {
  name: "qualityScore",
  async process(content) {
    // 综合各项指标评分
    const metrics = {
      length: content.content.length >= 800 ? 20 : Math.round(content.content.length / 40),
      structure: /#{1,3}\s/.test(content.content) ? 20 : 10,
      hasImage: content.formatting.hasImages ? 15 : 10,
      hasList: /[-*]\s/.test(content.content) || /\d+\.\s/.test(content.content) ? 15 : 10,
      seoScore: Math.round((content.seo.keywords.length > 0 ? 15 : 5) + 
                           (content.seo.description ? 15 : 0)),
    };
    
    const totalScore = Object.values(metrics).reduce((a, b) => a + b, 0);
    
    return {
      passed: totalScore >= 60,
      score: totalScore,
      issues: totalScore < 60 ? [{
        severity: "warning",
        message: `质量评分 ${totalScore}/100,建议优化`,
        suggestion: "参考各项指标进行改进",
      }] : [],
    };
  },
};

// 中间件管道
export async function runMiddlewarePipeline(
  content: PlatformContent
): Promise<QualityReport> {
  const middlewares = [
    sensitiveWordMiddleware,
    seoOptimizeMiddleware,
    readabilityMiddleware,
    qualityScoreMiddleware,
  ];
  
  const allIssues: QualityReport["issues"] = [];
  let overallScore = 0;
  let seoScore = 0;
  let readabilityScore = 0;
  let originalityScore = 85; // 从 Editor 获取
  let grammarScore = 90; // 从 Editor 获取
  
  let processedContent = content;
  
  for (const middleware of middlewares) {
    const result = await middleware.process(processedContent);
    
    if (result.issues) {
      allIssues.push(...result.issues);
    }
    
    if (result.modifiedContent) {
      processedContent = { ...processedContent, content: result.modifiedContent };
    }
    
    // 收集各项得分
    if (middleware.name === "seoOptimize") {
      seoScore = result.score || 0;
    }
    if (middleware.name === "readability") {
      readabilityScore = result.score || 0;
    }
    if (middleware.name === "qualityScore") {
      overallScore = result.score || 0;
    }
  }
  
  // 综合计算
  const passed = allIssues.filter(i => i.severity === "error").length === 0 &&
                 overallScore >= 60;
  
  return {
    overallScore,
    originalityScore,
    readabilityScore,
    seoScore,
    grammarScore,
    passed,
    issues: allIssues,
  };
}

async function loadSensitiveWords(): Promise<string[]> {
  // 加载敏感词库
  return ["敏感词1", "敏感词2"]; // 示例
}

4.8 组装完整 Graph

typescript
// src/agent/content-creator.graph.ts
import { StateGraph, END, START } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph";
import { AIMessage, HumanMessage } from "@langchain/core/messages";

import { ContentCreatorState, type ContentCreatorStateType } from "./types";
import { orchestratorAgent, routeNextPhase } from "./orchestrator.agent";
import { researcherNode } from "./researcher.agent";
import { writerOutlineNode, writerContentNode } from "./writer.agent";
import { editorNode } from "./editor.agent";
import { publisherNode } from "./publisher.agent";
import { runMiddlewarePipeline } from "./middleware";

// 质量检查节点
async function qualityCheckNode(state: ContentCreatorStateType) {
  const { platformContents } = state;
  
  if (!platformContents.length) {
    return {
      currentPhase: "quality",
      qualityReport: null,
      messages: [new AIMessage({ content: "[质量检查] 无内容可检查" })],
    };
  }
  
  // 对第一个平台的内容进行检查(可扩展为全部检查)
  const qualityReport = await runMiddlewarePipeline(platformContents[0]);
  
  return {
    currentPhase: "quality",
    qualityReport,
    messages: [new AIMessage({
      content: `[质量检查] 总分:${qualityReport.overallScore},${qualityReport.passed ? "通过" : "未通过"}`,
    })],
  };
}

// 完成节点
async function completeNode(state: ContentCreatorStateType) {
  const { platformContents, qualityReport } = state;
  
  return {
    messages: [new AIMessage({
      content: `内容创作完成!
      
生成了 ${platformContents.length} 个平台的内容:
${platformContents.map(p => `- ${p.platform}: ${p.title}`).join("\n")}

质量报告:
- 总体评分:${qualityReport?.overallScore || "N/A"}
- 原创性:${qualityReport?.originalityScore || "N/A"}
- 可读性:${qualityReport?.readabilityScore || "N/A"}
- SEO:${qualityReport?.seoScore || "N/A"}

${qualityReport?.issues.length ? `
注意事项:
${qualityReport.issues.map(i => `- [${i.severity}] ${i.message}`).join("\n")}
` : ""}`,
    })],
  };
}

// 构建 Graph
export function createContentCreatorGraph() {
  const workflow = new StateGraph(ContentCreatorState)
    // 添加节点
    .addNode("orchestrator", orchestratorAgent)
    .addNode("researcher", researcherNode)
    .addNode("writer_outline", writerOutlineNode)
    .addNode("writer_content", writerContentNode)
    .addNode("editor", editorNode)
    .addNode("publisher", publisherNode)
    .addNode("quality_check", qualityCheckNode)
    .addNode("complete", completeNode)
    
    // 添加边
    .addEdge(START, "orchestrator")
    .addConditionalEdges("orchestrator", routeNextPhase, {
      researcher: "researcher",
      writer_outline: "writer_outline",
      writer_content: "writer_content",
      editor: "editor",
      publisher: "publisher",
      quality_check: "quality_check",
      complete: "complete",
    })
    .addEdge("researcher", "orchestrator")
    .addEdge("writer_outline", "orchestrator")
    .addEdge("writer_content", "orchestrator")
    .addEdge("editor", "orchestrator")
    .addEdge("publisher", "orchestrator")
    .addEdge("quality_check", "orchestrator")
    .addEdge("complete", END);

  const checkpointer = new MemorySaver();
  
  return workflow.compile({ checkpointer });
}

// 工作流可视化
export function visualizeWorkflow() {
  return `
┌─────────────────────────────────────────────────────────────────────────────┐
│                        Content Creator Workflow                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│    ┌─────────┐                                                               │
│    │  START  │                                                               │
│    └────┬────┘                                                               │
│         │                                                                    │
│         ▼                                                                    │
│    ┌─────────────┐                                                           │
│    │ Orchestrator│◄───────────────────────────────────────┐                 │
│    └──────┬──────┘                                        │                 │
│           │                                               │                 │
│     ┌─────┴─────────────────────────────────────────┐    │                 │
│     │                                               │    │                 │
│     ▼                 ▼                 ▼           │    │                 │
│ ┌──────────┐   ┌────────────┐   ┌────────────┐     │    │                 │
│ │Researcher│   │Writer      │   │Writer      │     │    │                 │
│ │(素材收集)│   │(大纲生成)   │   │(内容撰写)   │     │    │                 │
│ └────┬─────┘   └─────┬──────┘   └─────┬──────┘     │    │                 │
│      │               │               │             │    │                 │
│      └───────────────┴───────────────┘             │    │                 │
│                                               │    │                 │
│     ▼                 ▼                 ▼     │    │                 │
│ ┌──────────┐   ┌────────────┐   ┌────────────┐│    │                 │
│ │  Editor  │   │ Publisher  │   │  Quality   ││    │                 │
│ │(编辑优化)│   │(平台适配)   │   │  Check     ││    │                 │
│ └────┬─────┘   └─────┬──────┘   └─────┬──────┘│    │                 │
│      │               │               │        │    │                 │
│      └───────────────┴───────────────┴────────┘    │                 │
│                                                     │                 │
│                                        ┌────────────┘                 │
│                                        │                              │
│                                        ▼                              │
│                                   ┌─────────┐                         │
│                                   │Complete │                         │
│                                   └────┬────┘                         │
│                                        │                              │
│                                        ▼                              │
│                                   ┌─────────┐                         │
│                                   │   END   │                         │
│                                   └─────────┘                         │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘
`;
}

// 导出流式调用方法
export async function* streamContentCreator(
  request: ContentRequest,
  threadId: string
) {
  const graph = createContentCreatorGraph();
  
  const config = {
    configurable: { thread_id: threadId },
    streamMode: "messages" as const,
  };

  const stream = await graph.stream(
    { 
      messages: [],
      request,
      currentPhase: "init",
    },
    config
  );

  for await (const event of stream) {
    yield event;
  }
}

五、后端项目结构

content-creator-backend/
├── prisma/
│   ├── schema.prisma              # 数据库模型定义
│   └── migrations/                # 数据库迁移
├── src/
│   ├── agent/                     # LangChain Multi-Agent 系统
│   │   ├── types.ts               # 类型定义
│   │   ├── orchestrator.agent.ts  # 编排器 Agent
│   │   ├── researcher.agent.ts    # 素材收集 Sub-Agent
│   │   ├── writer.agent.ts        # 内容撰写 Sub-Agent
│   │   ├── editor.agent.ts        # 编辑优化 Sub-Agent
│   │   ├── publisher.agent.ts     # 发布适配 Sub-Agent
│   │   ├── middleware/            # 中间件
│   │   │   ├── index.ts
│   │   │   ├── sensitive.middleware.ts
│   │   │   ├── seo.middleware.ts
│   │   │   ├── readability.middleware.ts
│   │   │   └── quality.middleware.ts
│   │   └── content-creator.graph.ts # 完整 Graph 组装
│   ├── config/                    # 配置
│   │   └── index.ts
│   ├── controllers/               # 控制器
│   │   ├── article.controller.ts
│   │   ├── generate.controller.ts
│   │   ├── material.controller.ts
│   │   └── publish.controller.ts
│   ├── middlewares/               # Express 中间件
│   │   ├── auth.middleware.ts
│   │   ├── error.middleware.ts
│   │   └── validate.middleware.ts
│   ├── routes/                    # 路由
│   │   ├── article.routes.ts
│   │   ├── generate.routes.ts
│   │   ├── material.routes.ts
│   │   ├── publish.routes.ts
│   │   └── index.ts
│   ├── services/                  # 服务层
│   │   ├── article.service.ts
│   │   ├── material.service.ts
│   │   ├── publish.service.ts
│   │   ├── search.service.ts      # 搜索服务
│   │   ├── trend.service.ts       # 热点服务
│   │   └── image.service.ts       # 图片服务
│   ├── schemas/                   # Zod Schema
│   │   ├── article.schema.ts
│   │   └── generate.schema.ts
│   ├── types/                     # TypeScript 类型
│   │   └── index.ts
│   ├── utils/                     # 工具函数
│   │   ├── jwt.ts
│   │   ├── logger.ts
│   │   └── response.ts
│   └── app.ts                     # 应用入口
├── .env
├── .env.example
├── package.json
├── tsconfig.json
└── README.md

六、总结

技术要点回顾

模块技术栈说明
架构模式SubagentsOrchestrator 调度多个专业 Sub-Agent
OrchestratorLangGraph StateGraph编排和路由决策
ResearchercreateReactAgent + Tools网络搜索、趋势分析、竞品研究
WriterwithStructuredOutput大纲生成 + 分章节内容撰写
EditorcreateReactAgent + Tools语法检查、事实核查、原创检测
PublishercreateReactAgent + ToolsSEO优化、格式转换、平台适配
Middleware流水线模式敏感词、SEO、可读性、质量评分
流式输出SSE实时展示创作进度

自动化内容创作系统7大架构亮点

架构亮点

┌─────────────────────────────────────────────────────────────────────────────┐
│                           项目架构亮点                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  1. Subagents 模式 - 完美匹配内容创作流水线                                  │
│     ┌───────────────────────────────────────────────────────────────────┐   │
│     │  Orchestrator → Researcher → Writer → Editor → Publisher          │   │
│     │       ↑              ↓          ↓         ↓          ↓            │   │
│     │       └──────────────┴──────────┴─────────┴──────────┘            │   │
│     │                     (每阶段完成后汇报给 Orchestrator)               │   │
│     └───────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  2. 中间件模式 - 横切关注点统一处理                                          │
│     ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐          │
│     │敏感词过滤│→│SEO优化  │→│可读性检查│→│质量评分  │→│最终输出  │          │
│     └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘          │
│                                                                              │
│  3. 分章节生成 - 保证长文质量                                                │
│     • 先生成大纲,确定结构                                                   │
│     • 逐章节撰写,融入相关素材                                               │
│     • 避免一次性生成导致的质量下降                                           │
│                                                                              │
│  4. 多平台适配 - 一次创作,多平台分发                                        │
│     • 知乎:深度长文 + 代码高亮                                              │
│     • 公众号:图文并茂 + 链接脚注                                            │
│     • 小红书:口语化 + emoji + 短文                                          │
│                                                                              │
│  5. 质量保障 - 多维度检查                                                    │
│     • 原创性检测:防止抄袭                                                   │
│     • 事实核查:确保准确性                                                   │
│     • 语法检查:保证表达规范                                                 │
│     • SEO 优化:提升搜索排名                                                 │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

项目亮点

  1. Subagents 架构:Orchestrator 编排 4 个专业 Sub-Agent,职责分离清晰
  2. 中间件流水线:统一处理敏感词、SEO、质量检查等横切关注点
  3. 分章节生成:避免一次性生成长文导致的质量下降
  4. 多平台适配:一次创作,自动适配知乎、公众号、小红书等平台
  5. 素材驱动:先收集素材再写作,内容有据可依
  6. 质量保障:原创检测 + 事实核查 + 语法检查 + SEO 优化
  7. 结构化输出:大纲、文章、质量报告都是结构化数据

扩展方向

  • 添加 Translator Sub-Agent:支持多语言翻译
  • 接入 AI 配图生成:自动生成文章配图
  • 支持 批量创作:基于关键词列表批量生成文章
  • 添加 A/B 标题测试:生成多个标题供选择
  • 接入 自动发布:通过平台 API 一键发布
  • 支持 用户反馈学习:根据阅读数据优化内容策略
  • 添加 模板系统:保存优秀文章结构作为模板复用

读文档、看源码、写代码,理解 AI Agent 本质 🤖