两年前我还在手动运营六个内容账号睡得最晚的一晚是因为一篇稿子要在三个平台各改一遍格式凌晨一点半才把封面、标签、摘要全部处理完。那时候我就意识到内容的“生产”已经被AI接管但“分发”和“品牌植入”仍然在靠人工死磕。后来我花了两三周时间把整个流程代码化做了一套开源的一站式AI运营源码系统把AI内容生成、多平台发布、品牌信息嵌入放进同一条流水线。到今天它已经稳定运行了八个多月每天自动输出十几篇图文我需要做的只是每周看一次效果报表。这套系统不是什么大厂平台就是个人也能部署起来的轻量方案。做自媒体矩阵的、做企业内容营销的、想给产品批量做种草内容的都可以参照这篇文章里的设计自己搭一套。下面我会从最底层的需求拆解讲到模块实现再到部署和真实踩坑代码片段可以直接拿回去改。1. 内容运营流水线的改造起点从“重复搬运”到“全自动分发”1.1 手动发布一个平台需要多少分钟先说一个最朴素的问题一篇图文手动发到五个平台到底要花多久很多人觉得复制粘贴很快其实完全不是。我实测过一篇2000字左右的文章发到第一个平台需要处理标题字数限制、首图尺寸、摘要字数、正文排版、话题标签大概10分钟。发到第二个平台又因为编辑器不支持某些Markdown语法需要重新调整代码块和列表再加8分钟。如果是第三个、第四个平台每家的规则都不一样平均下来一个平台至少6到8分钟。五个平台就是四十分钟而且纯粹是机械劳动中间还不能走神否则容易漏设原创声明、漏勾选“允许转载”之类的选项。这种工作最可怕的地方在于它会天天重复。每天写三篇内容分发就要两个多小时占掉一天有效工作时间的三分之一。更别提分发完还要回去检查哪些平台发布失败了、哪篇被系统判了重复、哪个账号的Token过期了。我见过不少团队用协作表格管理这些事但表格只能记录“有没有发”不能解决“为什么要手动发”。所以这套系统要做的第一件事是把“写完内容到内容上架”之间的所有重复步骤接管过来。人工只需要确认选题、审核最终稿剩下的标题微调、排版转换、标签组合、定时发布全部交给代码。1.2 品牌植入为什么是体力活如果你的内容里需要带上自家品牌或者客户品牌工作量还要再加一档。品牌植入不是简单地把品牌名塞进文章里而是要控制出现位置、出现次数、上下文语境还要避开违禁词。手动操作的时候我经常为了把品牌词“自然”地放进某一段反复调整前后句改着改着就把原来的行文节奏破坏了。更麻烦的是多平台发布时每个平台对“营销内容”的容忍度不一样。有些平台品牌词出现三次就可能被限流有些平台则需要你在文末明确标注广告信息。这些规则如果全由人来记很容易出错。我当时的想法是把品牌相关的约束做成结构化数据交给AI在生成阶段就处理好而不是生成完再人工去插。1.3 为什么现成的“内容中台”工具解决不了我也试用过几个号称“AI写稿多平台分发”的商业工具总结下来有几个痛点一是价格不便宜按账号数和生成次数收费账号一多成本直线上升二是“品牌植入”都做得很浅基本就是生成完把品牌词替换进去效果生硬而且容易被平台识别为营销三是数据不透明我看不到生成Prompt、发布日志和失败重试的具体细节出了问题只能找客服。开源项目里也有不少单点工具比如只做AI文章生成的、只做定时发布到单一平台的。但它们之间没有统一的数据结构任务状态、文章内容、发布结果各存各的串不起来。我要的是一个能覆盖“选题—生成—植入—审核—发布—数据回传”全链路的自托管系统这也是为什么最终决定自己写一套。2. 系统整体架构四个模块如何协作成一条完整的“产稿供应链”2.1 模块划分生成、植入、发布、调度这套系统的源码不是一个大而全的单体应用而是按职责拆成了四个模块外加一个调度中枢内容生成模块generator负责根据主题、大纲、语气等参数调用大模型接口产出标题、摘要、正文。品牌植入模块brand维护品牌库向生成模块提供结构化品牌约束并在生成后校验植入效果。多平台发布模块publisher封装各平台发布接口处理登录态、排版转换、频率控制、失败重试。任务调度中枢task把上面三个模块串起来负责创建任务、推进状态、记录日志。所有模块之间不直接互相调用而是通过一个简单的状态机来协作。每个任务都有pending → generating → auditing → publishing → done/failed这几个状态任何一个环节失败都会自动重试或者进入人工处理队列。2.2 任务数据流与运行机制具体跑一轮的流程是这样的调度中心每天按配置生成任务每个任务包含一个选题和一组目标平台。生成模块先从品牌库拉取约束信息组装成Prompt请求大模型得到文章草稿。草稿经过审核长度检查、品牌词计数、敏感词过滤、相似度检测之后交给发布模块。发布模块根据目标平台的不同分别做排版转换和封面处理然后调用对应平台的发布接口最后把返回的帖子ID、状态、失败原因写回任务日志。这里我踩过一个设计上的坑最初所有模块都是同步调用生成完立刻发布结果某个平台临时不可用会导致整条链路阻塞。后来改成了任务表驱动每个阶段独立记录状态失败的任务挂起等下一轮调度再处理。这样单个平台出问题不会影响其他平台的发布进度。2.3 技术选型为什么是PythonFastAPISQLite技术栈选得很轻Python 3.10 FastAPI做Web管理和API入口SQLite做本地存储APScheduler做定时调度。没有用PostgreSQL、Redis这些重型组件因为这套系统本质上是一个“单人或者小团队可维护的自动化管道”数据量一天也就几百条SQLite完全扛得住备份也简单直接复制文件就行。FastAPI的好处是自带API文档我可以直接在浏览器里调试任务接口不用单独搭一套管理后台。如果以后想把任务提交、文章审核做成多用户协作FastAPI也可以方便地加认证和权限。整个系统跑起来内存占用不到300MB放在一台2核2G的小机器上绰绰有余。2.4 源码目录结构开源出来的目录结构大致如下没有过度工程化基本一看就懂aiops/ ├── app/ │ ├── generator/ │ │ ├── client.py # 大模型接口封装 │ │ ├── prompt_builder.py # Prompt组装 │ │ └── post_cleaner.py # AI味清理 │ ├── brand/ │ │ ├── brand_lib.py # 品牌库读写 │ │ └── validator.py # 植入效果校验 │ ├── publisher/ │ │ ├── base.py # 发布基类 │ │ ├── platform_a.py # 某资讯平台实现 │ │ ├── platform_b.py # 某技术社区实现 │ │ └── platform_c.py # 某问答社区实现 │ ├── task/ │ │ ├── manager.py # 任务状态机 │ │ └── scheduler.py # 定时调度 │ └── config/ │ ├── settings.yaml # 全局配置 │ └── base.py # 配置加载 ├── storage/ │ ├── credentials/ # 各平台登录凭据 │ └── logs/ # 运行日志 ├── data/ │ └── app.db # SQLite数据库 ├── run.py # 启动入口 └── requirements.txt每个模块的入口都是一个CLI命令也可以直接通过HTTP API调用。这样设计的好处是我想单独跑一遍“只生成不发布”的流程时不需要把整个系统拉起来。3. 内容生成模块把“AI写稿”从抽奖变成可控输出3.1 模型接入与请求封装内容生成模块是整个系统的“发动机”。我在接入层做了一个非常薄的封装不绑定任何特定的大模型服务而是通过标准的HTTP接口调用远端大模型API。这样既可以在云端服务之间切换也可以换成自建的开源模型服务。核心请求逻辑很简单就是一个call_llm(prompt_messages, temperature, max_tokens)函数。但它支撑了系统里所有AI调用所以我重点控制了三件事超时时间、重试次数、输出长度上限。大模型接口偶尔会有网络抖动或者响应超时如果不做重试整个任务链就断了。我的策略是连续失败3次就把任务标记为“需人工”把错误信息写进日志而不是无限重试。3.2 Prompt模板设计把写作要求“结构化”AI写稿最容易出现的问题不是“写不出来”而是“乱写”。让它自由发挥的话十条里有七八条偏题品牌词出现的位置也不可控。所以我在Prompt设计上花了最多功夫核心思想是把写作要求结构化成JSON明确告诉模型“你要输出什么格式、包含什么信息、遵守什么规则”。下面是一段简化的Prompt构建代码import json def build_prompt(topic: str, brand_info: dict, outline: list, tone: str 专业): sys_prompt ( 你是一名资深内容运营编辑擅长撰写结构清晰、有观点的原创内容。 你会自然地在行文中提到指定品牌但不要生硬重复品牌名。 全文输出为JSON包含title、summary、outline、content四个字段。 ) user_prompt f 请围绕主题“{topic}”写一篇约1200字的图文内容。 要求 1. 语气风格{tone} 2. 章节结构至少覆盖以下大纲点{json.dumps(outline, ensure_asciiFalse)} 3. 品牌信息{json.dumps(brand_info, ensure_asciiFalse)} 4. 品牌出现规则全文出现3到5次第一次必须出现在前两段最后一次放在结尾总结句中。 5. 禁止出现“最好的”“第一品牌”“国家级”等广告违禁词用使用场景和用户体验描述替代。 请直接输出JSON不要包含markdown代码块。 return [ {role: system, content: sys_prompt}, {role: user, content: user_prompt}, ]几个关键设计点大纲由任务配置传入模型不需要自己定选题方向避免跑偏。品牌信息里面的“关键词”和“使用场景”会被拼进Prompt让模型知道该从哪些角度写而不是简单地把品牌词替换掉。强制输出JSON格式方便后续代码解析。模型偶尔会输出多余的文字说明所以我在解析的时候做了容错只截取第一个{到最后一个}之间的内容。3.3 输出解析与“AI味”清理大模型生成的原稿直接拿去发很快会被平台识别为低质内容。我在生成之后加了一道“后清理”流程主要做三件事首段改写很多模型喜欢用“在当今社会”“随着科技的发展”开头这些句子一眼就能看出来是AI写的。我会用一个“首段重写”的二次调用要求模型把开头改成具体的场景描写或者故事引入。这个技巧实测效果很好能让文章存活率提升不少。语气词替换把“值得注意的是”“总而言之”这类模板化连接词批量替换成更自然的过渡句比如“这里有个容易被忽略的点”“所以下次遇到类似情况时可以试试”。长度校准模型报的“1200字”经常不准。我会按字符数做一次软检查少于800字就追加一段超过2000字就截断到主要章节。这一步听起来很繁琐但对最终发布效果影响非常大。没有做清理之前我的文章在某个平台被系统标记为“疑似AI生成”的比例高达30%加了这个环节之后这个比例降到了5%左右。3.4 成本与速度的平衡策略大模型API是按次调用的每次都让最强的模型来写成本会有点吓人。我的方案是“草稿用轻量模型成稿用高质量模型”先用轻量模型按大纲生成一个粗糙草稿再让高质量模型在草稿基础上重写润色。这样做比直接让高质量模型从零开始写能省下不少token而且最终质量更稳定因为草稿已经把结构和素材定死了重写模型只需要专注表达。实际跑下来一篇1200字文章的总token成本大概在轻量模型的两倍多一点但这是值得的。内容质量直接影响平台推荐量质量差的内容发了也白发账号权重还会被拉低。4. 品牌信息嵌入从硬广告到“观点式自然出现”的实现路径4.1 品牌库的数据结构设计品牌植入不是简单地把“某品牌”三个字塞进文章里。我在系统里设计了一个品牌库每个品牌的信息以JSON形式存储{ id: 1, name: 某品牌, aliases: [某牌子, 某家], keywords: [耐用, 省电, 便携], scenes: [长途通勤, 户外露营, 办公桌面], forbidden_words: [第一, 最好, 国家级], max_count: 5, min_count: 3 }字段含义很直接name是标准品牌名aliases是备选叫法用来让文章不那么重复keywords是品牌卖点AI在写作时需要围绕这些词展开scenes是使用场景用来生成真实的用户描述forbidden_words用来规避广告法风险max_count和min_count控制品牌词出现次数。这个品牌库是整个植入功能的基石。它不只服务于Prompt构建还服务于生成后的校验。4.2 三种植入策略与适用场景根据内容类型和投放目的我实现了三种植入策略可以在任务配置时按需选择显式嵌入适合短平快的内容。在首段明确提一次品牌中间的小标题里带一次结尾再点一次。这个策略最简单可控但只适合用户已经对品牌有认知的场景比如公众号推文、新品发布公告。语义嵌入适合中长文。不直接说品牌名而是先描述某个使用场景比如“露营三天不充电”再引出品牌产品。模型在这个策略下会把品牌卖点和使用体验绑定在一起。这种方式在问答社区和测评类内容里非常自然。观点式嵌入适合深度内容。把品牌产品作为“作者观点”的一部分比如“经过对比测试我认为在千元价位里它是最均衡的选择”。这种植入最软但要求模型的判断和内容逻辑一致否则会显得突兀。三种策略在实现上差别不大都是通过Prompt里的“品牌出现规则”字段来控制但最终效果差异很明显。观点式嵌入的阅读体验最好平台识别营销的几率也最低显式嵌入胜在稳妥适合赶时间批量出内容。4.3 植入效果校验与密度控制生成完成之后不能直接信模型说“我植入好了”。我写了一个独立的校验函数做三件事统计品牌名和别名在全文的出现次数如果不在min_count和max_count之间就打回重写。检查品牌词第一次出现的位置要求必须在前两段以内避免读者读了一半才知道文章在讲什么。检查forbidden_words列表里的词是否出现一旦出现就标记为“需人工调整”。密度控制是品牌植入里最容易翻车的地方。我一开始把max_count设成8结果大批文章被平台判定为营销内容账号被限流。后来调到3到5次配合语义植入策略被系统误伤的情况明显减少了。现在我的默认配置是文章篇幅越长品牌出现次数可以稍高但单篇不超过5次。4.4 品牌信息如何在生成阶段与大纲绑定这里还要强调一个设计思路品牌植入是在生成阶段完成的不是生成之后再插入。因为文章一旦写完整再去插入品牌词前后语境很难圆回来读起来会有明显的割裂感。具体做法是在构建大纲的时候把品牌卖点和某个章节绑定。比如一篇露营装备推荐文章大纲里本来就有一个“电池续航实测”的部分品牌库里的“省电”这个关键词就会被安排进这个章节的要求里让模型在这一段自然提到品牌。这样一来品牌词出现在哪个章节、出现在什么上下文里都是可控的而不是碰运气。5. 多平台发布模块接口抽象、登录态维护与排版适配5.1 统一发布接口的设计多平台发布是这个系统里“脏活”最多的模块。不同平台的接口风格完全不一样有的接受Markdown有的要纯文本有的必须单独提交封面图和摘要。为了不让上层业务逻辑被某个平台的API绑死我抽象了一个发布基类class BasePublisher: def __init__(self, credentials: dict): self.credentials credentials def login(self): 获取并缓存登录态 raise NotImplementedError def publish_text(self, title: str, content: str, tags: list): 纯文本发布 raise NotImplementedError def publish_rich(self, title: str, content: str, cover: str, digest: str): 图文发布适用于需要封面图和摘要的平台 raise NotImplementedError每个平台的实现类只需要关注两件事如何登录、如何把文章数据翻译成该平台要求的参数。上层调度完全感知不到平台差异都是调用publish_text或者publish_rich。5.2 不同平台内容的差异化处理这里说的“排版适配”不是简单地把HTML转成Markdown而是每个平台的特殊处理规则。我整理了三个典型场景资讯类平台要求缩略图尺寸为16:9摘要控制在90字以内正文里不能有某些HTML标签。我在发布前会把封面图统一裁切成平台所需尺寸并重新生成摘要。技术社区类代码块转换是最麻烦的平台编辑器对缩进和空行的处理不一致必须把代码块转成平台自己的代码插件格式。我写了一个轻量转换函数把GitHub风格的 代码块替换成平台需要的标签。问答社区类这类平台对“营销嫌疑”最敏感。我的做法是跳过显式植入策略的文章优先用观点式嵌入的内容。发布时还要注意不能带外链。平台差异如果全部硬编码进发布模块会越写越乱。我的做法是写一个“平台能力表”用配置声明每个平台支持哪些能力、需要哪些必填项发布时根据这张表动态调整。5.3 登录态与Token刷新机制多平台发布绕不开登录态管理。有些平台用开放平台的Token有效期几个小时要刷新有些平台是类似浏览器的Cookie过期时间短且需要维护会话。我在storage/credentials/目录下按平台保存凭据文件发布模块启动时会先检查凭据是否有效如果过期就执行刷新逻辑。刷新失败时系统不会直接崩溃而是把任务标记为“等待人工登录”并通过日志和监控提醒我。这个模块比较费心因为各平台刷新Token的流程差别很大。我的建议是不要试图把所有平台都做到“免人工维护”先把两三个主要平台的刷新流程跑通其他平台预留手动更新凭据的入口。大多数个人运营者一个平台能自动跑就已经省下很多时间了。5.4 发布调度与频率控制批量发布不能在同一秒内一股脑把十几篇内容全发出去容易被平台风控。我在调度里加了频率控制默认每个平台间隔5到10分钟每天最多发布固定数量。时间点也会做随机化处理避免每天发布节奏完全一致比如8点、10点、14点各一篇而不是整点钉死。如果某个平台返回“频率过高”或者“内容重复”的错误调度中心会把该任务挂起延后半小时再重试。重试两次仍然失败就会进入人工处理队列不会无限循环下去。6. 部署上线流程从拉取源码到第一篇文章自动发出6.1 环境准备与依赖安装这套系统对运行环境的要求非常低。我用的是Python 3.10版本依赖都写在requirements.txt里主要包括FastAPI、APScheduler、requests、PyYAML、Pillow图片处理。安装命令就是标准的pip install -r requirements.txt首次建议在本地跑通流程再上服务器。我一开始直接在服务器上调试结果因为网络环境和本地不一样平台接口的连通性排查了好久。先在本地把生成、发布流程跑一遍能省掉很多冤枉时间。6.2 配置文件详解系统核心配置全部集中在app/config/settings.yaml里我贴一个经过简化的示例llm: endpoint: http://你的模型服务地址/v1/chat/completions api_key: 替换成你的key model: default temperature: 0.7 max_tokens: 3000 brands: - id: 1 name: 某品牌 aliases: [某牌子] keywords: [耐用, 省电] scenes: [户外露营, 办公] max_count: 5 min_count: 3 platforms: - name: 某资讯平台 type: rich credential_file: credentials/platform_a.json publish_interval_seconds: 300 - name: 某技术社区 type: markdown credential_file: credentials/platform_b.json publish_interval_seconds: 600 schedule: daily_count: 12 start_time: 08:00 end_time: 22:00 audit: min_content_length: 800 max_brand_count: 5 similarity_threshold: 0.75配置项里最容易忽略的是max_tokens。如果设得太小文章生成到一半会被截断导致品牌词没有出现校验阶段就会把文章打回重写。我最初设的是1500经常出现这种问题后来根据实际输出字节数调整到了3000才稳定。6.3 数据库设计与初始化系统一共三张核心表设计得非常简单CREATE TABLE tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, topic TEXT NOT NULL, brand_id INTEGER, target_platforms TEXT, status TEXT DEFAULT pending, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER, title TEXT, summary TEXT, content TEXT, status TEXT, generated_at DATETIME ); CREATE TABLE publish_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER, platform TEXT, platform_post_id TEXT, status TEXT, message TEXT, published_at DATETIME );数据库文件放在data/app.db首次运行时会自动创建表结构不需要手动执行SQL。日常使用中我每三天备份一次这个文件因为里面存了所有发布历史换服务器或者出问题恢复都靠它。6.4 任务创建与结果验证部署完成后可以手动创建一个测试任务来验证全流程python run.py create-task --topic 露营灯怎么选 --brand-id 1 python run.py process-tasks第一条命令创建任务第二条命令处理所有待处理任务。如果只想生成不发布可以用--dry-run参数这是我最常用的调试方式。验证通过后再把定时调度打开系统就会按schedule配置自动创建任务并执行。再提一个细节正式用之前先用一个临时测试账号跑几次发布确认平台返回的帖子ID是正常的。千万别拿主力账号直接试有些平台在凭据失效后可能触发安全验证处理起来很麻烦。7. 实际运行中的问题与调优记录7.1 生成内容超长导致品牌词丢失系统上线头两周最频繁的问题不是发布失败而是校验阶段打回率接近两成。查日志发现大部分打回原因是“品牌词出现次数不达标”。但奇怪的是查看Prompt品牌约束明明写得很清楚。后来定位到根因文章超过模型输出上限尾部内容被截断被截掉的部分恰好包含品牌词的收尾出现。解决方式有两个一是把max_tokens提高二是把“品牌词最后一次出现”从文章末尾改到倒数第二部分。现在我用的是后者因为即使长度还是超了结尾被截断也不太影响品牌词出现次数。7.2 平台检测到内容相似怎么办发布一段时间后某技术社区平台开始提示“内容疑似重复”但我的文章确实是每篇不同主题。仔细排查发现问题出在开头的“AI味清理”没有完全生效——清理之后每篇文章的第一段都是同一个“故事引入”模板只是具体名词换了一下。平台可能提取的是段落哈希导致相似度被误判。解决办法是在清理流程里加入“首段重写”和“句法变体”两步首段重写确保引入方式不同句法变体则把开头第一句的主语、语序做随机调整。加了这两步之后平台重复提示基本消失了。7.3 品牌植入过度的账号被限流第三个坑是关于限流的。某资讯平台一开始给了不错的推荐量但连续发了一周带品牌词密度较高的文章之后账号的推荐权重明显下降后台看到“低质内容”的提示。我把植入密度参数从5次降到了3次并且把文章重点转向“使用体验描述”而不是“产品参数堆砌”。一周后账号推荐恢复。经验是品牌词密度宁可少一点也不要让平台觉得你在发广告。好内容是给用户看的不是给爬虫识别的。7.4 运行数据与后续设想到现在为止这套系统每天的运行情况大致是创建并生成12到15篇内容其中大约有2篇会因为审核不通过或者平台错误进入人工处理。真正需要人工干预的比例不到15%剩余85%的内容从生成到发布全自动完成。内容推荐数据比起纯人工时期不仅没有下降反而整体提升了大概20%。后续我想做三件事一是给生成模块加入“历史效果反馈”机制阅读量高的文章风格会反向影响Prompt权重二是做一个多账号矩阵支持目前只用了一个主账号很多平台的流量红利吃不满三是在发布模块里接入更多内容类型比如短视频脚本和图文卡片。如果你也在搭类似的东西我的建议是先跑通最小闭环——一个选题、一个品牌、一个平台稳定以后再横向扩展。把链路拉长之前先把每一环的容错做扎实比增加功能点重要得多。