从0搭建一个能赚钱的AI自动化工具:我用Python做了个"自动写爆款"系统,月入过万的技术复盘

3 阅读16分钟

作者按:这不是一篇"教你暴富"的爽文。我会从一个真实的付费项目出发,把技术选型、架构设计、核心代码、商业变现的完整链路拆开讲清楚。读完这篇文章,你至少能复现一个可上线的产品。


一、项目背景:为什么做这个工具?

2024年下半年,我接了一个需求:一个做跨境电商的团队,每天需要在多个平台(Shopify独立站、亚马逊、小红书)发布产品描述和营销文案。他们有3个运营,每人每天花2小时"洗稿改写",月人力成本接近4万。

我的方案很简单:用AI自动化替代80%的重复工作

最终交付的系统叫  "ContentPilot" ——一个AI内容自动化生产平台。它做了这几件事:

  1. 自动采集竞品数据:爬取指定类目的爆款产品信息、评价关键词、价格趋势
  2. AI智能生成内容:基于采集数据,用GPT生成多语言、多平台适配的产品文案
  3. 定时自动发布:通过各平台API,按预设时间表自动发布内容
  4. 数据反馈闭环:追踪发布内容的数据表现,反哺AI生成策略

上线3个月后,这个工具从内部工具变成了SaaS产品,按月收费,目前有20+付费用户。


二、技术选型:为什么选这套技术栈?

很多开发者一上来就问"该用什么框架",我换个方式——先看需求,再看技术。

需求维度技术选择选择理由
Web API服务FastAPI异步高性能,自带OpenAPI文档,开发效率是Flask的2倍
定时任务/异步队列Celery + Redis成熟的分布式任务队列,支持定时调度、重试、任务链
AI内容生成OpenAI API (GPT-4o)效果最稳定,多语言能力强,API生态完善
数据采集Playwright + httpxPlaywright处理动态渲染页面,httpx做高性能API请求
数据存储PostgreSQL + SQLAlchemy关系型数据适合结构化的任务和内容管理
部署Docker + Docker Compose一键部署,环境一致,扩展方便

整体架构如下:

┌─────────────────────────────────────────────────┐
│                   Nginx (反向代理)                │
├─────────────────────────────────────────────────┤
│              FastAPI (Web服务层)                   │
│  ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │ 用户管理  │ │ 任务管理  │ │ 内容管理/模板    │ │
│  └──────────┘ └──────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────┤
│           Celery Worker (任务执行层)              │
│  ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │ 数据采集  │ │ AI生成   │ │ 自动发布         │ │
│  │ Worker   │ │ Worker   │ │ Worker           │ │
│  └──────────┘ └──────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────┤
│    Redis (消息队列 + 缓存)  │  PostgreSQL (持久化) │
└─────────────────────────────────────────────────┘

核心设计思路:Web层只负责接收请求和返回结果,所有耗时操作都丢给Celery异步处理。用户提交任务后立即拿到task_id,通过轮询或WebSocket获取结果。


三、核心模块实现

3.1 项目结构

content-pilot/
├── app/
│   ├── api/              # FastAPI路由
│   │   ├── tasks.py      # 任务相关接口
│   │   ├── content.py    # 内容管理接口
│   │   └── auth.py       # 认证接口
│   ├── core/             # 核心配置
│   │   ├── config.py     # 环境配置
│   │   └── security.py   # JWT认证
│   ├── models/           # 数据库模型
│   │   ├── task.py
│   │   └── content.py
│   ├── services/         # 业务逻辑
│   │   ├── crawler.py    # 数据采集服务
│   │   ├── ai_writer.py  # AI内容生成服务
│   │   └── publisher.py  # 自动发布服务
│   ├── workers/          # Celery任务
│   │   ├── crawl_tasks.py
│   │   ├── generate_tasks.py
│   │   └── publish_tasks.py
│   └── main.py           # FastAPI入口
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── .env

3.2 FastAPI 服务入口

这是整个系统的"门面"。FastAPI的好处是代码即文档,请求参数自动校验。

# app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from app.api import tasks, content, auth
from app.core.config import settings
from app.models.base import init_db


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期:启动时初始化数据库连接池"""
    await init_db()
    yield
    # 清理资源(如果有)


app = FastAPI(
    title="ContentPilot API",
    description="AI内容自动化生产平台",
    version="1.0.0",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(auth.router, prefix="/api/v1/auth", tags=["认证"])
app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["任务"])
app.include_router(content.router, prefix="/api/v1/content", tags=["内容"])


@app.get("/health")
async def health_check():
    return {"status": "healthy", "version": "1.0.0"}

关键代码块二:创建内容生成任务接口

# app/api/tasks.py
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from pydantic import BaseModel, Field
from typing import Optional, List
from enum import Enum
from datetime import datetime

router = APIRouter()


class ContentType(str, Enum):
    PRODUCT_DESC = "product_desc"      # 产品描述
    MARKETING_COPY = "marketing_copy"   # 营销文案
    SOCIAL_POST = "social_post"         # 社交媒体帖文
    EMAIL_SUBJECT = "email_subject"     # 邮件标题


class Platform(str, Enum):
    SHOPIFY = "shopify"
    AMAZON = "amazon"
    XIAOHONGSHU = "xiaohongshu"
    WECHAT = "wechat"


class CreateTaskRequest(BaseModel):
    """创建内容生成任务的请求体"""
    product_name: str = Field(..., min_length=1, max_length=200,
                               description="产品名称")
    product_keywords: List[str] = Field(..., min_items=1, max_items=20,
                                         description="产品关键词")
    content_type: ContentType = Field(..., description="内容类型")
    target_platform: Platform = Field(..., description="目标平台")
    target_language: str = Field(default="zh-CN", description="目标语言")
    reference_urls: Optional[List[str]] = Field(default=None,
                                                 description="参考竞品URL")
    tone: str = Field(default="专业", description="文案风格:专业/轻松/幽默")
    scheduled_at: Optional[datetime] = Field(default=None,
                                              description="定时发布时间")

    class Config:
        json_schema_extra = {
            "example": {
                "product_name": "智能温控保温杯 Pro Max",
                "product_keywords": ["保温杯", "智能温控", "钛合金", "商务礼品"],
                "content_type": "product_desc",
                "target_platform": "amazon",
                "target_language": "en-US",
                "tone": "专业"
            }
        }


class TaskResponse(BaseModel):
    task_id: str
    status: str
    message: str


@router.post("/generate", response_model=TaskResponse)
async def create_generate_task(request: CreateTaskRequest):
    """
    创建AI内容生成任务
    
    提交后返回task_id,通过GET /tasks/{task_id}查询进度和结果。
    如果设置了scheduled_at,内容将在指定时间自动发布。
    """
    from app.workers.generate_tasks import generate_content_task
    from app.workers.crawl_tasks import crawl_competitor_data

    # Step 1: 如果有参考URL,先启动数据采集任务
    if request.reference_urls:
        crawl_result = crawl_competitor_data.delay(
            urls=request.reference_urls,
            keywords=request.product_keywords
        )
        # 将采集任务ID传递给生成任务,形成任务链
        chain = crawl_result | generate_content_task.s(
            product_name=request.product_name,
            keywords=request.product_keywords,
            content_type=request.content_type.value,
            platform=request.target_platform.value,
            language=request.target_language,
            tone=request.tone,
            scheduled_at=request.scheduled_at.isoformat() if request.scheduled_at else None,
        )
        chain()
        return TaskResponse(
            task_id=crawl_result.id,
            status="queued",
            message="数据采集+内容生成任务已提交"
        )

    # Step 2: 无需采集,直接生成
    result = generate_content_task.delay(
        product_name=request.product_name,
        keywords=request.product_keywords,
        content_type=request.content_type.value,
        platform=request.target_platform.value,
        language=request.target_language,
        tone=request.tone,
        scheduled_at=request.scheduled_at.isoformat() if request.scheduled_at else None,
        crawl_data=None,
    )
    return TaskResponse(
        task_id=result.id,
        status="queued",
        message="内容生成任务已提交"
    )


@router.get("/{task_id}")
async def get_task_status(task_id: str):
    """查询任务执行状态和结果"""
    from app.core.celery_app import celery_app
    task_result = celery_app.AsyncResult(task_id)

    response = {
        "task_id": task_id,
        "status": task_result.state,
    }

    if task_result.ready():
        if task_result.successful():
            response["result"] = task_result.result
        else:
            response["error"] = str(task_result.result)

    return response

3.3 Celery 异步任务调度

这是系统的"发动机"。所有耗时操作——数据采集、AI生成、自动发布——都在这里执行。

# app/workers/__init__.py
from celery import Celery
from app.core.config import settings

celery_app = Celery(
    "content_pilot",
    broker=settings.REDIS_URL,
    backend=settings.REDIS_URL,
)

celery_app.conf.update(
    task_serializer="json",
    result_serializer="json",
    accept_content=["json"],
    timezone="Asia/Shanghai",
    enable_utc=True,
    task_track_started=True,
    task_acks_late=True,           # 任务执行完才确认,防止丢失
    worker_prefetch_multiplier=1,  # 一次只取一个任务,避免阻塞
    task_soft_time_limit=300,      # 软超时5分钟
    task_time_limit=360,           # 硬超时6分钟
    # 定时任务配置
    beat_schedule={
        "daily-report-generation": {
            "task": "app.workers.generate_tasks.daily_content_report",
            "schedule": 60 * 60 * 9,  # 每9小时执行一次
            "args": (),
        },
        "content-analytics-sync": {
            "task": "app.workers.publish_tasks.sync_content_analytics",
            "schedule": 60 * 30,  # 每30分钟同步一次数据
            "args": (),
        },
    },
)
# app/workers/generate_tasks.py
import json
import logging
from app.workers import celery_app
from app.services.crawler import CompetitorCrawler
from app.services.ai_writer import AIContentWriter

logger = logging.getLogger(__name__)


@celery_app.task(bind=True, max_retries=3, default_retry_delay=60)
def generate_content_task(self, product_name, keywords, content_type,
                          platform, language, tone, scheduled_at,
                          crawl_data=None):
    """
    AI内容生成任务
    
    支持重试机制:失败后最多重试3次,每次间隔60秒。
    使用bind=True可以通过self.update_state()上报进度。
    """
    try:
        # 上报进度:开始生成
        self.update_state(state="PROGRESS", meta={"step": "init", "progress": 10})

        writer = AIContentWriter()

        # 上报进度:准备Prompt
        self.update_state(state="PROGRESS", meta={"step": "preparing", "progress": 30})

        # 构建生成参数
        params = {
            "product_name": product_name,
            "keywords": keywords,
            "content_type": content_type,
            "platform": platform,
            "language": language,
            "tone": tone,
            "crawl_data": crawl_data,  # 来自上游采集任务的数据
        }

        # 上报进度:调用AI生成
        self.update_state(state="PROGRESS", meta={"step": "generating", "progress": 60})

        result = writer.generate(params)

        # 上报进度:保存结果
        self.update_state(state="PROGRESS", meta={"step": "saving", "progress": 90})

        # 保存到数据库
        from app.models.content import Content
        from app.core.database import get_sync_session

        with get_sync_session() as session:
            content = Content(
                product_name=product_name,
                content_type=content_type,
                platform=platform,
                language=language,
                generated_text=result["content"],
                title=result.get("title", ""),
                metadata_=json.dumps(params, ensure_ascii=False),
                scheduled_at=scheduled_at,
            )
            session.add(content)
            session.commit()

        logger.info(f"内容生成完成: {product_name} -> {platform}")

        # 如果设置了定时发布,投递发布任务
        if scheduled_at:
            from app.workers.publish_tasks import schedule_publish
            schedule_publish.apply_async(
                args=[content.id],
                eta=scheduled_at,  # Celery原生支持定时执行
            )

        return {
            "content_id": content.id,
            "content": result["content"],
            "title": result.get("title", ""),
            "word_count": len(result["content"]),
            "platform": platform,
        }

    except Exception as exc:
        logger.error(f"内容生成失败: {exc}, 重试中...")
        # 重试,exponential_backoff让间隔越来越长
        raise self.retry(exc=exc, countdown=60 * (self.request.retries + 1))

3.4 AI内容生成核心

这是整个系统的"大脑"。关键在于Prompt工程——不是简单地把关键词丢给GPT,而是构建结构化的、平台适配的提示词。

# app/services/ai_writer.py
import openai
from typing import Optional, Dict, Any
from app.core.config import settings


class AIContentWriter:
    """AI内容生成服务:封装OpenAI API调用 + Prompt管理"""

    # 不同平台的Prompt模板
    PLATFORM_TEMPLATES = {
        "amazon": {
            "system": (
                "你是一个专业的亚马逊产品文案撰写专家。"
                "你需要根据产品信息生成符合亚马逊A+内容标准的产品描述。"
                "要求:包含5点Bullet Points、详细的产品描述、SEO关键词自然融入。"
                "语言风格:{tone},字数:800-1200字。"
            ),
            "format": (
                "## 产品名称\n{title}\n\n"
                "## 五大亮点\n{bullets}\n\n"
                "## 产品描述\n{description}\n\n"
                "## SEO关键词\n{seo_keywords}"
            ),
        },
        "shopify": {
            "system": (
                "你是一个高端独立站的产品文案撰写专家。"
                "文案需要有品牌调性,注重情感共鸣和购买转化。"
                "要求:吸引眼球的标题、情感化的产品故事、清晰的功能卖点。"
                "语言风格:{tone},字数:600-1000字。"
            ),
            "format": (
                "## {title}\n\n"
                "{story}\n\n"
                "### 为什么选择{product_name}?\n"
                "{selling_points}\n\n"
                "### 产品参数\n{specs}"
            ),
        },
        "xiaohongshu": {
            "system": (
                "你是一个小红书爆款文案创作者。"
                "文案需要网感强,善用Emoji,有吸引力的标题,引发互动的结尾。"
                "要求:标题含关键词,正文分段清晰,带3-5个相关Tag。"
                "语言风格:{tone},字数:300-600字。"
            ),
            "format": "{title}\n\n{body}\n\n{tags}",
        },
    }

    def __init__(self):
        self.client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)
        self.model = "gpt-4o"

    def generate(self, params: Dict[str, Any]) -> Dict[str, str]:
        """
        生成内容主方法
        
        Args:
            params: 包含product_name, keywords, content_type,
                   platform, language, tone, crawl_data
        
        Returns:
            {"title": str, "content": str}
        """
        platform = params["platform"]
        template = self.PLATFORM_TEMPLATES.get(platform, self.PLATFORM_TEMPLATES["amazon"])

        # 构建系统提示词
        system_prompt = template["system"].format(tone=params.get("tone", "专业"))

        # 构建用户消息
        user_message = self._build_user_message(params, template)

        # 如果有竞品采集数据,加入上下文
        messages = [
            {"role": "system", "content": system_prompt},
        ]

        if params.get("crawl_data"):
            crawl_context = self._format_crawl_data(params["crawl_data"])
            messages.append({
                "role": "system",
                "content": f"以下是竞品分析数据,请参考但不要抄袭:\n{crawl_context}"
            })

        messages.append({"role": "user", "content": user_message})

        # 调用OpenAI API
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            temperature=0.7,       # 创造性适中
            max_tokens=2000,
            presence_penalty=0.3,  # 鼓励话题多样性
            frequency_penalty=0.5, # 减少重复用词
        )

        raw_content = response.choices[0].message.content

        # 解析结果
        return self._parse_response(raw_content, params["content_type"])

    def _build_user_message(self, params: Dict[str, Any], template: Dict) -> str:
        """根据平台模板构建用户输入"""
        return (
            f"请为以下产品生成{params['content_type']}:\n\n"
            f"产品名称:{params['product_name']}\n"
            f"核心关键词:{'、'.join(params['keywords'])}\n"
            f"目标语言:{params['language']}\n\n"
            f"请严格按照以下格式输出:\n{template['format']}"
        )

    def _format_crawl_data(self, crawl_data: Any) -> str:
        """将采集的竞品数据格式化为AI可读的上下文"""
        if isinstance(crawl_data, str):
            try:
                crawl_data = json.loads(crawl_data)
            except json.JSONDecodeError:
                return crawl_data

        sections = []
        for item in crawl_data.get("items", [])[:5]:  # 最多参考5个竞品
            sections.append(
                f"- {item.get('title', 'N/A')}: "
                f"评分{item.get('rating', 'N/A')}, "
                f"热词: {', '.join(item.get('top_keywords', []))}"
            )

        return "\n".join(sections) if sections else "暂无有效竞品数据"

    def _parse_response(self, raw: str, content_type: str) -> Dict[str, str]:
        """解析AI返回的内容,提取标题和正文"""
        lines = raw.strip().split("\n")
        title = ""
        content_lines = []

        for i, line in enumerate(lines):
            if line.startswith("## ") and not title:
                title = line.replace("## ", "").strip()
            else:
                content_lines.append(line)

        return {
            "title": title or lines[0].strip(),
            "content": "\n".join(content_lines).strip(),
        }

3.5 数据采集模块

爬虫是系统的"眼睛"。采集竞品数据为AI生成提供参考上下文。

# app/services/crawler.py
import asyncio
import logging
from typing import List, Dict, Optional
from playwright.async_api import async_playwright
import httpx

logger = logging.getLogger(__name__)


class CompetitorCrawler:
    """竞品数据采集器:支持动态页面渲染和API直采"""

    def __init__(self):
        self.headers = {
            "User-Agent": (
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
        }

    async def crawl_product_page(self, url: str) -> Dict:
        """
        使用Playwright采集产品页面(处理JS渲染)
        
        返回:标题、价格、评分、评价摘要、关键词
        """
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
            page = await browser.new_page()

            try:
                await page.goto(url, wait_until="networkidle", timeout=30000)

                # 提取产品信息(选择器需根据目标网站调整)
                title = await page.text_content("h1.product-title") or ""
                price = await page.text_content(".price") or ""
                rating = await page.text_content(".rating-score") or ""

                # 提取评价关键词
                review_keywords = await page.eval_on_selector_all(
                    ".review-text",
                    "elements => elements.slice(0, 20).map(e => e.textContent)"
                )

                return {
                    "url": url,
                    "title": title.strip(),
                    "price": price.strip(),
                    "rating": rating.strip(),
                    "review_snippets": [r.strip() for r in (review_keywords or [])],
                    "top_keywords": self._extract_keywords(
                        [r.strip() for r in (review_keywords or [])]
                    ),
                }

            except Exception as e:
                logger.error(f"采集失败 {url}: {e}")
                return {"url": url, "error": str(e)}
            finally:
                await browser.close()

    async def crawl_multiple(self, urls: List[str]) -> List[Dict]:
        """并发采集多个页面,限制并发数为3"""
        semaphore = asyncio.Semaphore(3)

        async def limited_crawl(url):
            async with semaphore:
                return await self.crawl_product_page(url)

        tasks = [limited_crawl(url) for url in urls]
        results = await asyncio.gather(*tasks, return_exceptions=True)

        # 过滤掉异常结果
        return [r for r in results if isinstance(r, dict) and "error" not in r]

    def _extract_keywords(self, texts: List[str]) -> List[str]:
        """简易关键词提取:基于词频统计(生产环境建议用jieba或TF-IDF)"""
        from collections import Counter
        import re

        all_words = []
        for text in texts:
            # 中文按字切分(简化版),英文按空格切分
            words = re.findall(r'[\u4e00-\u9fff]{2,}|[a-zA-Z]{3,}', text)
            all_words.extend(words)

        # 返回出现频率最高的10个词
        counter = Counter(all_words)
        return [word for word, count in counter.most_common(10)]

3.6 自动发布模块

通过平台API实现自动发布,这里以通用的发布接口为例:

# app/services/publisher.py
import httpx
import logging
from typing import Dict, Optional

logger = logging.getLogger(__name__)


class ContentPublisher:
    """多平台内容发布器"""

    def __init__(self):
        # 各平台API配置(实际应从数据库/环境变量读取)
        self.platform_configs = {
            "shopify": {
                "api_base": "https://{store}.myshopify.com/admin/api/2024-01",
                "auth_header": "X-Shopify-Access-Token",
            },
            "xiaohongshu": {
                "api_base": "https://edith.xiaohongshu.com/api",
            },
        }

    async def publish_to_shopify(self, store: str, access_token: str,
                                  title: str, body_html: str,
                                  product_type: str = "") -> Dict:
        """发布内容到Shopify"""
        config = self.platform_configs["shopify"]
        url = f"{config['api_base'].format(store=store)}/products.json"

        payload = {
            "product": {
                "title": title,
                "body_html": body_html,
                "product_type": product_type,
                "status": "active",
                "variants": [{"price": "0.00"}],  # 价格后续手动设置
            }
        }

        async with httpx.AsyncClient(timeout=30) as client:
            response = await client.post(
                url,
                json=payload,
                headers={
                    config["auth_header"]: access_token,
                    "Content-Type": "application/json",
                },
            )

            if response.status_code in (200, 201):
                data = response.json()
                logger.info(f"Shopify发布成功: product_id={data['product']['id']}")
                return {"success": True, "product_id": data["product"]["id"]}
            else:
                logger.error(f"Shopify发布失败: {response.status_code} {response.text}")
                return {"success": False, "error": response.text}

    async def publish(self, platform: str, content_id: int,
                      title: str, body: str, **kwargs) -> Dict:
        """统一发布入口"""
        publishers = {
            "shopify": self.publish_to_shopify,
        }

        publisher = publishers.get(platform)
        if not publisher:
            return {"success": False, "error": f"不支持的平台: {platform}"}

        return await publisher(title=title, body_html=body, **kwargs)

四、部署方案:Docker一键上云

整个系统用Docker Compose编排,一行命令启动:

# docker-compose.yml
version: "3.8"

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql+asyncpg://user:pass@db:5432/content_pilot
      - REDIS_URL=redis://redis:6379/0
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    depends_on:
      - db
      - redis
    restart: unless-stopped

  worker:
    build: .
    command: celery -A app.workers worker -l info -c 4
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/content_pilot
      - REDIS_URL=redis://redis:6379/0
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    depends_on:
      - db
      - redis
    restart: unless-stopped

  beat:
    build: .
    command: celery -A app.workers beat -l info
    environment:
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - redis
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: content_pilot
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - api

volumes:
  pgdata:
  redisdata:

部署流程:

# 1. 克隆代码
git clone https://github.com/yourname/content-pilot.git
cd content-pilot

# 2. 配置环境变量
cp .env.example .env
# 编辑 .env,填入 OPENAI_API_KEY、数据库密码等

# 3. 一键启动
docker compose up -d

# 4. 查看日志
docker compose logs -f worker

服务器推荐配置:2核4G起步(阿里云/腾讯云轻量约100元/月),月流量按需购买。OpenAI API费用根据使用量,一般每月几十到几百美元。


五、商业化:怎么把工具变成付费产品?

技术做完了,怎么赚钱?这是我踩过坑的地方——先别急着写代码,先想清楚商业模式

5.1 定价策略

我采用了三层定价模型

套餐月费包含功能目标用户
入门版¥299/月50次AI生成/月,1个平台,手动发布个人卖家
专业版¥799/月300次AI生成/月,3个平台,自动发布+定时中小团队
企业版¥2999/月无限生成,全部平台,定制Prompt,API接入品牌方/代理

核心逻辑:入门版用低价获客,专业版贡献主要收入,企业版拉高客单价

5.2 获客渠道

实际有效的获客方式(按ROI排序):

  1. 技术博客 + GitHub开源核心模块:写3-5篇深度技术文章(就像这篇),在文末附上产品链接。我的第一篇"用Python自动化跨境电商文案"在掘金获得了2万+阅读,直接转化了8个付费用户。
  2. 跨境电商社群:在相关的知识星球、微信群做分享。不需要硬广,分享自动化提效的思路,自然有人来问"这个工具能买吗"。
  3. 产品 Hunt / 即刻等社区:发布Product Hunt可以带来一波初始流量。

5.3 技术护城河

很多人担心"这个门槛不高,别人也能做"。我的经验是:

  • 数据壁垒:采集的竞品数据越多,AI生成质量越高,这是飞轮效应
  • Prompt积累:针对不同品类、不同平台,我们积累了200+经过验证的Prompt模板
  • 平台适配:各平台API对接、反爬策略、格式适配,这些"脏活"是壁垒
  • 客户关系:一旦客户的数据和模板都在你的系统里,迁移成本很高

5.4 成本控制

成本项月费用优化方案
服务器¥100-300用按量计费,初期1台2核4G够用
OpenAI API¥500-3000用GPT-4o-mini处理简单任务,GPT-4o只用于复杂生成
域名+SSL¥100/年几乎可忽略
数据库¥0自建PostgreSQL,量大了再上云RDS
总计¥700-3500/月5个专业版用户即可覆盖成本

六、踩坑总结

做这个项目,我踩了几个值得分享的坑:

1. OpenAI API的rate limit不是开玩笑的 初期没做请求限流,高峰期直接触发429错误。解决方案:在Celery Worker层面做令牌桶限流,GPT-4o请求间隔不低于2秒。

2. 爬虫反爬是个持久战 不要指望一套爬虫方案能一直用。建议:采集频率控制在合理范围(每天每站不超过100次请求),关键数据做本地缓存,减少重复请求。

3. Celery任务积压会导致内存爆炸 高峰期任务积压了2000+,Worker内存直接飙升到16G。解决方案:设置worker_prefetch_multiplier=1,配合task_acks_late=True,让Worker逐条处理。

4. 用户不会用API,需要一个简单的Web界面 交付后客户说"你给我个API我该怎么用?"——所以后来用Streamlit快速搭了一个管理后台,虽然丑但够用。如果是正式产品,建议用React/Vue做一个Dashboard。


七、总结

这个项目的核心价值不在于某个单一的技术点,而在于把多个技术组件串联成一个完整的产品

  • FastAPI 提供高性能API服务
  • Celery 处理异步任务和定时调度
  • OpenAI API 实现智能内容生成
  • Playwright 完成数据采集
  • Docker 保证部署一致性

整套系统的代码量大约5000行(不含前端),一个有经验的Python开发者2-3周可以完成MVP。

如果你也想做类似的项目,我的建议是:

  1. 先找到付费用户,再开始开发——哪怕是口头承诺也行
  2. MVP只做一个平台、一种内容类型——先验证需求
  3. 把核心逻辑做成可配置的——Prompt模板、采集规则都要支持热更新
  4. 重视日志和监控——线上出问题时,日志是唯一的救命稻草

完整代码(脱敏后)已开源在 GitHub,欢迎 Star 和 PR。如果觉得这篇文章对你有帮助,或者有合作意向,欢迎联系。


本文首发于个人技术博客,转载请注明出处。  项目持续迭代中,最新功能进度和定价信息请查看官网。