作者按:这不是一篇"教你暴富"的爽文。我会从一个真实的付费项目出发,把技术选型、架构设计、核心代码、商业变现的完整链路拆开讲清楚。读完这篇文章,你至少能复现一个可上线的产品。
一、项目背景:为什么做这个工具?
2024年下半年,我接了一个需求:一个做跨境电商的团队,每天需要在多个平台(Shopify独立站、亚马逊、小红书)发布产品描述和营销文案。他们有3个运营,每人每天花2小时"洗稿改写",月人力成本接近4万。
我的方案很简单:用AI自动化替代80%的重复工作。
最终交付的系统叫 "ContentPilot" ——一个AI内容自动化生产平台。它做了这几件事:
- 自动采集竞品数据:爬取指定类目的爆款产品信息、评价关键词、价格趋势
- AI智能生成内容:基于采集数据,用GPT生成多语言、多平台适配的产品文案
- 定时自动发布:通过各平台API,按预设时间表自动发布内容
- 数据反馈闭环:追踪发布内容的数据表现,反哺AI生成策略
上线3个月后,这个工具从内部工具变成了SaaS产品,按月收费,目前有20+付费用户。
二、技术选型:为什么选这套技术栈?
很多开发者一上来就问"该用什么框架",我换个方式——先看需求,再看技术。
| 需求维度 | 技术选择 | 选择理由 |
|---|---|---|
| Web API服务 | FastAPI | 异步高性能,自带OpenAPI文档,开发效率是Flask的2倍 |
| 定时任务/异步队列 | Celery + Redis | 成熟的分布式任务队列,支持定时调度、重试、任务链 |
| AI内容生成 | OpenAI API (GPT-4o) | 效果最稳定,多语言能力强,API生态完善 |
| 数据采集 | Playwright + httpx | Playwright处理动态渲染页面,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排序):
- 技术博客 + GitHub开源核心模块:写3-5篇深度技术文章(就像这篇),在文末附上产品链接。我的第一篇"用Python自动化跨境电商文案"在掘金获得了2万+阅读,直接转化了8个付费用户。
- 跨境电商社群:在相关的知识星球、微信群做分享。不需要硬广,分享自动化提效的思路,自然有人来问"这个工具能买吗"。
- 产品 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。
如果你也想做类似的项目,我的建议是:
- 先找到付费用户,再开始开发——哪怕是口头承诺也行
- MVP只做一个平台、一种内容类型——先验证需求
- 把核心逻辑做成可配置的——Prompt模板、采集规则都要支持热更新
- 重视日志和监控——线上出问题时,日志是唯一的救命稻草
完整代码(脱敏后)已开源在 GitHub,欢迎 Star 和 PR。如果觉得这篇文章对你有帮助,或者有合作意向,欢迎联系。
本文首发于个人技术博客,转载请注明出处。 项目持续迭代中,最新功能进度和定价信息请查看官网。