news 2026/9/30 4:21:32

基于Next.js的个人IP内容矩阵系统实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Next.js的个人IP内容矩阵系统实战

做个人IP最痛苦的事情,不是写不出内容,而是内容生产全靠脑子记、流程全靠人肉盯。公众号写一篇,小红书要改一版,抖音要再拆成短视频脚本,知乎还得整理成问答体,这些改版、排期、素材存档、平台数据回收,以前全靠表格和个人备忘录硬撑。撑到内容量稍微上来一点,表格就开始失控,漏发、重复选题、数据找不到对应版本,各种事故反复出现。

所以我自己动手做了这套个人IP内容矩阵系统,技术栈上选了Next.js + PostgreSQL + Prisma + Tailwind这套全栈组合,后端逻辑全部写在API Routes里,没拆独立服务。这套系统的核心价值很简单:把选题、内容资产、多平台发布计划、效果数据全部串在一条流水线上,让内容从灵感到发布再到数据回收,全程有迹可循。这篇文章就是把我在这个全栈项目里的代码实践、踩坑记录和方案取舍完整写出来,适合正在做类似内容中台想法、或者想找一个真实业务练手全栈架构的朋友参考。

1. 方案设计:先把业务理顺,再谈技术

1.1 个人IP内容矩阵到底需要什么

在写第一行代码之前,我花了很长时间梳理自己真正的需求。个人IP的内容矩阵,表面看是“多平台发内容”,但实际上有几个很明确的痛点:

第一,选题管理。我经常在灵感爆发期攒出几十个选题,然后放到某个备忘录里吃灰。等想用的时候,要么找不到了,要么发现同一主题已经写过两遍。系统需要给每个选题一个唯一的状态,从“灵感的草稿”到“已经产出内容”再到“已经被某平台使用过”,每一步都要有记录。

第二,内容资产的版本管理。同一主题下,长文、短视频脚本、小红书图文文案,它们之间有关联,但又是不同格式的资产。过去我用文件夹按平台归类,结果是同一个主题的内容被拆散在好几个地方。系统里应该以“选题”为聚合根,下面挂不同平台的内容变体。

第三,发布计划与状态跟踪。内容写好了不代表完事,还要考虑不同平台的最佳发布时间。我之前因为漏看日期,出现过同一篇内容在公众号和小红书同日发出,直接导致数据分流。系统需要有计划排期,并且记录每个平台的实际发布状态。

第四,数据回收。发布之后的效果数据必须回填到内容资产上,否则写复盘的时候又是一顿乱翻。

基于这四点,产品形态就很清楚了:选题库、内容工作台、发布日历、数据看板。技术框架不需要太重,一个能跑前后端的全栈框架加一个关系型数据库就足够。所以Next.js成了最自然的选择,它的App Router能同时承载页面渲染和API接口,一套代码搞定整个应用。

1.2 技术选型:为什么是Next.js加PostgreSQL

选型这块我说一下自己试过之后的结论。最开始想过Vue + Flask这样的前后端分离方案,但很快就发现一个问题:这个项目的前端页面大多数是数据展示和表单操作,没有极端复杂的交互,把前后端拆成两个项目反而增加了部署成本,服务端和前端之间的类型还容易不同步。

Next.js的App Router模式,让页面可以直接在服务端取数,然后渲染出HTML。列表页、看板页这类场景根本不需要客户端发请求,数据直接在服务端拿完再传给组件,页面加载速度快,代码也简洁。API Routes用来处理需要写操作或者有CSRF风险的接口,比如创建选题、更新发布状态。这样形成了两级数据通道:读多用Server Component,写操作走API,这个模式在这个项目里实测下来非常顺。

数据库选了PostgreSQL,理由很简单:这个项目天然有实体关系。选题关联内容资产,内容资产关联发布计划,发布计划关联平台数据,这些数据如果拆到MongoDB里做文档嵌套,反而没有关系型数据库来得直接。尤其是我后面还要做“某平台某时间段内的数据汇总”这类查询,SQL的聚合能力比在业务代码里做内存计算高效得多。ORM选用Prisma,不选TypeORM的原因是我喜欢Prisma的schema即真理风格,数据库结构一眼就能看全,而且迁移工具好用,不用手写SQL迁移脚本。

1.3 目录结构:按业务域划分,不是按文件类型划分

目录结构这块我踩过一次坑,第一版按传统习惯分了components、lib、pages这样的目录,结果业务逻辑散得到处都是。后来完全重构了一版,改为按业务域划分。

app/ (auth)/ (dashboard)/ topics/ assets/ planner/ analytics/ api/ topics/ assets/ planner/ analytics/ lib/ schema.prisma services/ topics.ts assets.ts planner.ts analytics.ts utils/ date.ts ai.ts platform.ts

括号这种路由组是Next.js的约定,(auth)和(dashboard)本身不生成URL路径,只是用来组织布局。api路由也按业务域分开放,这样每个域的页面、接口、服务逻辑都聚在一起,改一个功能时只需要进同一个目录,不用在几个大目录之间来回跳。这个结构坚持下来,后面加新功能时确实轻松很多。

2. 数据建模:内容资产的主数据设计

2.1 核心表结构:选题、内容资产、发布计划

数据模型是这套系统的地基,也是最需要想清楚的部分。直接看Prisma schema,我精简一下核心的表结构:

model Persona { id String @id @default(cuid()) name String description String platforms Json // 绑定的平台,如 ["xiaohongshu", "wechat", "douyin"] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Topic { id String @id @default(cuid()) personaId String title String description String? status String @default("idea") // idea -> active -> produced -> archived source String @default("manual") // manual | ai keyword String? targetAudience String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt assets ContentAsset[] } model ContentAsset { id String @id @default(cuid()) topicId String type String // longform | shortform | image | script platform String // wechat | xiaohongshu | douyin | zhihu title String body String // 正文内容,Markdown格式 mediaUrls Json? status String @default("draft") // draft -> reviewing -> approved -> published wordCount Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PublishPlan { id String @id @default(cuid()) assetId String platform String plannedAt DateTime publishedAt DateTime? status String @default("scheduled") // scheduled -> published | failed externalUrl String? platformPostId String? errorMessage String? version Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PlatformMetric { id String @id @default(cuid()) planId String platform String metrics Json collectedAt DateTime @default(now()) }

这个建模思路的关键在于:ContentAsset挂在Topic下,PublishPlan挂在ContentAsset下,形成一条从灵感到发布到数据回收的完整链路。你不能凭空建一个ContentAsset,必须先有Topic。同理,你不能凭空建一个PublishPlan,必须先有ContentAsset。这个约束保证了系统的数据是干净的。

PlatformMetric单独建表而不是在PublishPlan里加几个字段,是因为同一个发布计划在不同日期会被多次抓取数据,今天是阅读量,过几天又是新的阅读量,历史轨迹要保留下来。

2.2 内容状态机设计:流转要可控

状态管理是这个系统里容易被忽略但实际上决定体验的部分。我设计了两个状态机:

Topic的状态:idea(灵感阶段)到active(被采纳进排期)到produced(已经有内容产出)再到archived(归档)。这里不能出现跳过,比如一个topic直接到produced而没有active,说明流程上有漏操作。

type TopicStatus = "idea" | "active" | "produced" | "archived"; const TOPIC_TRANSITIONS: Record<TopicStatus, TopicStatus[]> = { idea: ["active", "archived"], active: ["produced", "archived"], produced: ["archived", "active"], archived: ["active"], }; export function canTransitionTopic(from: TopicStatus, to: TopicStatus): boolean { return TOPIC_TRANSITIONS[from]?.includes(to) ?? false; }

ContentAsset的状态:draft到reviewing到approved再到published,以及从approved回到draft的返工路径。发布计划PublishPlan的状态:scheduled到published或者failed。这套约束看起来多余,但真正用起来之后,我发现它能强制使用者(也就是我自己)保持操作的规范性,不会出现内容还没定稿就标记了已发布这种混乱。

2.3 时间字段和软删除的实践心得

关于时间字段,所有时间戳都统一用UTC存储,这是一个非常关键的决定。因为内容发布涉及排期,如果直接用本地时间存,换一台服务器或者换了时区,排期就全乱了。我在所有涉及时间的字段都用了DateTime类型,并且在前端展示的时候统一用dayjs配合本地时区做格式化转换。

软删除方面,这个系统的数据都是长期价值资产,我不会物理删除任何记录,只在需要隐藏的地方用状态字段控制显示。比如选题归档了我就不展示在待办列表里,但数据还在库里,随时可以恢复。这个决策让我避免了“误删了又找不回来”的尴尬。

另外所有表都加了createdAt和updatedAt,这两个字段的语义很简单:createdAt记录资产进入系统的时间,updatedAt记录最近一次修改,这在看板按时间段汇总的时候非常好用,可以直接按createdAt分组统计每周的选题产出量。

3. 后端API与业务逻辑落地

3.1 统一响应格式与错误处理

Next.js的API Routes本质上是函数,每个route handler接收Request对象,返回Response对象。一开始我写接口的时候,每个接口自己处理错误,结果前端拿到错误时的格式五花八门。后来统一做了一个响应包装器:

export function ok<T>(data: T, message = "success") { return Response.json( { code: 0, message, data }, { status: 200 } ); } export function fail(message: string, status = 400, code = -1) { return Response.json( { code, message, data: null }, { status } ); } export function handleError(error: unknown) { console.error("[api error]", error); if (error instanceof ZodError) { return fail("参数校验失败: " + error.message, 422); } if (error instanceof Prisma.PrismaClientKnownRequestError) { return fail("数据库操作失败", 500); } return fail("服务器内部错误", 500); }

统一的响应格式是{ code, message, data },前端只要判断code是否为0就能知道成功还是失败,错误信息通过message字段展示给用户。这个包装看起来简单,但它让调用方不需要关心HTTP状态码的各种边界情况,遇到参数错误、数据库错误、未知错误都能拿到结构化的错误信息。

3.2 服务端Session管理与权限控制

这个系统虽然是个人用,但在设计上我还是加了简单的登录机制,因为后期可能开放给团队协作。会话管理直接用了JWT,放在HTTP Only的Cookie里,服务端通过middleware统一校验:

// middleware.ts import { NextResponse } from "next/server"; import { jwtVerify } from "jose"; const SECRET = new TextEncoder().encode(process.env.JWT_SECRET); export async function middleware(request: NextRequest) { const token = request.cookies.get("token")?.value; if (!token) { return NextResponse.redirect(new URL("/login", request.url)); } try { await jwtVerify(token, SECRET); return NextResponse.next(); } catch { return NextResponse.redirect(new URL("/login", request.url)); } } export const config = { matcher: ["/((?!login|_next/static|favicon.ico).*)"], };

jose这个库是我推荐的,因为Edge Runtime和middleware默认运行在Vercel Edge上,Node.js的jsonwebtoken库在Edge环境不兼容。jose完全兼容,而且API简洁。这里有个小细节:matcher要排除登录页和静态资源,否则用户还没登录就被重定向循环了。

3.3 服务层业务逻辑:选题推荐怎么实现

API route不该堆逻辑,我把可复用的业务逻辑抽到了lib/services目录里。举一个比较有代表性的例子——选题推荐功能。

我的选题库里可能躺着几百个历史选题,每次想新选题时都容易撞车。我写了一个服务,用关键词相似度来排除重复选题:

import { PrismaClient } from "@prisma/client"; import { normalizeText, calculateSimilarity } from "@/lib/utils/text"; const prisma = new PrismaClient(); export async function suggestTopics(keyword: string, limit: number = 5) { const normalizedKeyword = normalizeText(keyword); const existingTopics = await prisma.topic.findMany({ where: { status: { in: ["idea", "active"] } }, select: { id: true, title: true, keyword: true }, }); const suggestions = existingTopics .map((topic) => { const topicKeyword = normalizeText(topic.keyword ?? ""); const similarity = calculateSimilarity(normalizedKeyword, topicKeyword); return { ...topic, similarity }; }) .filter((t) => t.similarity > 0.6) .sort((a, b) => b.similarity - a.similarity) .slice(0, limit); return suggestions; }

calculateSimilarity我实现的是简单的Jaccard相似度,基于bigram(二字切分)集合的交并比,对中文短文本来说效果够用,而且零依赖。这个逻辑完全没必要上向量数据库,几百条数据量级,内存算一下绰绰有余。

4. AI能力集成:让内容矩阵系统半自动运转

4.1 LLM接口封装:统一调用入口

这套系统的核心价值之一,就是把AI从玩具变成生产力工具。我在系统里集成了几个AI能力:选题生成、标题改写、内容摘要提取、平台风格改写。但AI集成有一个容易被低估的工程问题:LLM的输出是不稳定的,而业务系统需要稳定。所以我做了一个统一的AI调用封装:

import OpenAI from "openai"; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); export async function generateTopics(persona: string, count: number = 5) { const completion = await openai.chat.completions.create({ model: "gpt-4o-mini", messages: [ { role: "system", content: `你是一位资深内容策划,深度了解${persona}的受众。请为这位个人IP生成${count}个高质量选题。`, }, { role: "user", content: `请输出严格的JSON数组,每个元素包含title和description字段。不要输出任何多余文字。`, }, ], response_format: { type: "json_object" }, }); return parseJsonOutput(completion.choices[0].message.content ?? ""); }

关键点在于response_format设置为json_object,这让模型强行输出结构化JSON,而不是一段带解释的文字。这个API参数是OpenAI在后期版本加的,不设置的话,模型经常会在JSON外面包一层markdown代码块或解释性文字,解析的时候非常痛苦。

4.2 结构化输出容错:AI代码里最重要的一环

模型即使设置了json_object模式,也还是有可能输出格式异常,比如用了单引号、尾逗号、或者是空字符串。所以我在parseJsonOutput里做了三层容错:

export function parseJsonOutput(content: string): unknown { if (!content || content.trim() === "") { throw new Error("AI返回内容为空"); } const cleaned = content .trim() .replace(/^```(?:json)?/gm, "") .replace(/```$/gm, "") .trim(); try { return JSON.parse(cleaned); } catch { // 某些情况下AI会输出带有解释前缀的JSON,尝试截取第一个{到最后一个}之间的内容 const match = cleaned.match(/\{[\s\S]*\}/); if (match) { try { return JSON.parse(match[0]); } catch { throw new Error("AI输出无法解析为JSON"); } } throw new Error("AI输出中未找到JSON结构"); } }

这个函数我建议直接复制走,因为几乎每个接入LLM的项目都会遇到这个问题。先清理markdown代码块标记,再尝试直接解析,解析失败就尝试用正则截取JSON对象区域,最后才抛错。这样即使模型输出不规范,也能尽最大努力把数据提取出来。

4.3 定时任务:每天自动生成一批新选题

集成AI的另一个落地场景是定时任务。我在系统里接了一个每日定时任务,每天早上自动生成一批新选题,存放在idea状态,等我来筛选:

// app/api/cron/generate-topics/route.ts import { NextRequest } from "next/server"; import { generateTopics } from "@/lib/services/ai"; import { prisma } from "@/lib/prisma"; export async function GET(request: NextRequest) { const authHeader = request.headers.get("authorization"); if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) { return Response.json({ error: "Unauthorized" }, { status: 401 }); } const personas = await prisma.persona.findMany(); for (const persona of personas) { const topics = await generateTopics(persona.name, 3); await prisma.topic.createMany({ data: topics.map((t: any) => ({ personaId: persona.id, title: t.title, description: t.description, status: "idea", source: "ai", })), }); } return Response.json({ message: "topics generated" }); }

定时任务接口必须校验请求来源,这里用了一个CRON_SECRET做Bearer鉴权。Vercel的Cron配置则是定期向这个接口发请求,避免接口被任何人调用后产生大量无意义的AI请求,浪费额度。

5. 前端实现细节:交互与体验的打磨

5.1 Server Component与API的明确分工

前端我做了很明确的分层。列表页、统计页这类以读操作为主的页面,用Server Component在服务端直接取数,然后渲染出静态HTML,这种方式的性能非常好,也不需要前端load状态。难点在于Server Component里不能直接用useState和onClick,需要交互的地方就切给客户端组件。

具体的做法是一个页面里外层是Server Component,负责数据获取和骨架,内层组件标注“use client”,接收服务端传下来的数据,再负责交互。比如选题列表页:

// app/dashboard/topics/page.tsx import { prisma } from "@/lib/prisma"; import { TopicTable } from "./TopicTable"; export default async function TopicsPage() { const topics = await prisma.topic.findMany({ where: { status: { not: "archived" } }, orderBy: { updatedAt: "desc" }, include: { assets: { select: { id: true } } }, }); return <TopicTable initialTopics={topics} />; }

TopicTable内部是一个客户端组件,管理筛选、排序、分页这些交互状态,但数据的初始值来自服务端,不再多一次请求。

5.2 编辑器与拖拽排序的选型

内容编辑是这个系统使用频次最高的页面,我一开始考虑上了富文本编辑器,但后来决定用Markdown文本域加实时预览的方案。理由很简单:富文本编辑器在内容迁移时容易产生脏HTML,而Markdown是纯文本,以后做平台分发时,转成小红书格式、知乎格式都很方便,不会出现样式错乱。

发布日历的拖拽排序我用的是dnd-kit,相比react-dnd,dnd-kit的API更现代,对触摸设备和键盘操作的支持也更好。拖拽的目的是手动调整计划的发布时间,这个功能在产品上很简单,但代码上要注意能拖拽的只有处于scheduled状态、还没发布的计划,已经发布的不允许拖。

5.3 看板图表:别一上来就堆“酷炫”

数据看板这块我用了Recharts,这是React生态里我用的最顺手的图表库,对时间序列图、柱状图、饼图都有比较友好的封装。看板的最核心指标是:近30天各平台的发布数量、互动总数、阅读量趋势、选题到发布的平均耗时。这些指标拆到图表上,就是三个柱状图加一个折线图。

Recharts的用法很直白,比如平台发布数量对比图:

"use client"; import { ResponsiveContainer, BarChart, Bar, XAxis, YAxis, Tooltip, CartesianGrid, } from "recharts"; export function PlatformPublishChart({ data }: { data: { platform: string; count: number }[] }) { return ( <ResponsiveContainer width="100%" height={260}> <BarChart data={data}> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="platform" /> <YAxis /> <Tooltip /> <Bar dataKey="count" fill="#1677ff" radius={[4, 4, 0, 0]} /> </BarChart> </ResponsiveContainer> ); }

ResponsiveContainer会自动根据父容器宽度调整图表尺寸,这比固定宽度要稳定得多,尤其在移动端预览时表现明显。

6. 数据看板与统计聚合

6.1 跨平台指标采集的实现思路

数据回收是内容矩阵闭环的最后一环,也是最容易偷懒的一环。我设计了一个PlatformMetric采集表,每条记录包含planId、platform、metrics和collectedAt。metrics是一个JSON字段,结构是动态的,因为不同平台的指标不一样:

{ "views": 1200, "likes": 86, "comments": 12, "shares": 5, "saves": 23 }

采集方式目前半自动化:一部分平台开放了官方API,我写了一个采集脚本,通过它们的API拉取数据后写入PlatformMetric表;没有API的平台就手动在后台填。采集脚本通过一个管理员接口手动触发,避免被Cron调用时因为接口限流导致封号风险。

6.2 聚合查询与性能优化

看板页需要的不是明细数据,而是聚合后的统计。我第一次用Prisma直接分组查询,发现在数据量超过几万条后会明显变慢。后来换了思路,用SQL直接聚合,Prisma允许使用$queryRaw执行原生SQL,这个查询性能非常好:

SELECT DATE_TRUNC('day', collected_at) AS day, platform, COUNT(DISTINCT plan_id) AS publish_count, SUM(metrics->>'views')::int AS total_views, SUM(metrics->>'likes')::int AS total_likes, SUM(metrics->>'comments')::int AS total_comments, SUM(metrics->>'shares')::int AS total_shares FROM platform_metric WHERE collected_at >= NOW() - INTERVAL '30 days' GROUP BY 1, 2 ORDER BY 1 ASC;

PostgreSQL的JSON字段可以直接用->>操作符取出文本值并做类型转换,这个能力在处理动态指标时特别实用。SQL聚合在数据库端执行,只返回已经汇总好的结果,大幅降低了网络传输量和JS内存占用。

6.3 看板加载速度优化的两个技巧

看板页最初每次打开都要现算聚合,数据量大时能感觉到明显延迟。后来做了两个优化:第一个是给platform_metric表加了(tplatform, collected_at)的复合索引,让范围查询走索引而不是全表扫描;第二个是每天凌晨跑一个定时任务生成前一天的聚合数据存入单独一张summary表,看板页默认直接读summary表,只有需要看当天实时数据时才查明细表。这两个优化做完,看板加载速度从原来的平均3秒降到了500毫秒以内。

7. 部署、监控与迭代

7.1 Vercel部署与Cron配置

这个系统我部署在Vercel上,全程没有自己的服务器,这对个人项目来说是最省心的方案。Vercel部署Next.js是零配置体验,推代码自动构建。数据库用Neon的PostgreSQL免费套餐,它的serverless特性就是按需启动连接,适合偶尔访问的小项目。

定时任务直接在vercel.json里配置:

{ "crons": [ { "path": "/api/cron/generate-topics", "schedule": "0 0 * * *" }, { "path": "/api/cron/collect-metrics", "schedule": "0 9 * * *" } ] }

注意Vercel的Cron用UTC时间,0点等于北京时间早上8点,这个时间点生成选题正好是大多数人的晨间创作时段。

7.2 环境变量与密钥管理的坑

个人项目很容易把密钥直接写在代码里,这个习惯我强烈建议改掉。所有敏感信息走环境变量,本地用.env.local,生产环境在Vercel面板里配置。尤其是OpenAI的API密钥和数据库连接字符串,一旦泄露就非常被动,AI密钥被刷的代价可能是一夜之间几百美金的账单。

环境变量命名我有一套自己的规范:前缀固定是OPENAI_、DATABASE_、CRON_、JWT_,这样一看变量名就知道它属于哪个模块。服务器端的变量必须在变量名前加NEXT_PUBLIC前缀才能暴露给浏览器端代码,这本身就是一个安全的屏障。默认情况下,服务端变量对浏览器端是完全不可见的。

7.3 日志、错误监控与迭代节奏

这个系统虽然小,但日志和错误监控不能省。API Routes里所有接口都被handleError包装,任何未捕获的异常都会先走console.error,再调用一个统一的错误上报函数。Vercel自带日志查看功能,在控制台可以直接看到每个函数的输出,配合Vercel Analytics能观察到页面的访问情况。

迭代方面我有一个很务实的建议:不要想着一次性把所有功能做完。这个系统我分了三个阶段上线,第一阶段只有选题库和内容资产录入,第二阶段加了发布计划和日历,第三阶段才上的数据看板。每个阶段我都能正常地日常使用,而不是一直在等“功能齐全了才用起来”的那个永远不会到来的日子。

8. 踩过的坑与排查技巧实录

8.1 Next.js Server Component中直接用Prisma导致的连接数问题

这是我这个项目踩过最大的坑。第一版我直接在Server Component里new PrismaClient(),结果本地一次页面刷新就报了数据库连接数上限错误。原因很简单:Next.js在开发模式下,每次热更新都会重新执行模块,而PrismaClient如果被反复实例化,连接池就会不断增长。

解决方法是把PrismaClient定义为全局单例:

import { PrismaClient } from "@prisma/client"; const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined; }; export const prisma = globalForPrisma.prisma ?? new PrismaClient(); if (process.env.NODE_ENV !== "production") { globalForPrisma.prisma = prisma; }

globalThis上挂一个prisma实例,开发模式下热更新不会反复创建新连接,生产环境则每次实例化都能在请求之间复用。

8.2 内容发布失败后的状态处理

发布计划中常遇到的问题是:平台登录态过期,或者内容素材不完整导致发布失败。最初我只记录了一个failed状态,但failed之后怎么办没有设计好。后来我在PublishPlan上加了errorMessage字段,失败时写入具体原因,而且只允许从failed状态重新回到scheduled,不允许从failed直接改到published,防止出现“平台实际没发出去,但系统标记了已发布”的假数据。

8.3 LLM生成内容的质量把控

AI生成选题这件事,最大的风险不是技术,而是内容质量。系统确实能自动生成几十个选题,但其中真正符合我IP调性的大概只有三分之一。所以我对AI生成内容加了一个“人工审核”的前置环节:AI生成的所有选题都标记source为ai,并且状态落在idea,不会直接进入active排期。我必须手动点一下“采纳”按钮,它才会进入正式选题池。

这个设计本质上是在效率和可控之间做了一个取舍。纯粹的自动化会让系统变得省事,但代价是内容失去个人风格。对于个人IP这种靠人味吃饭的场景,我宁愿多花30秒筛选,也不让系统替我做了所有决定。

最后再分享一点我做这个项目最大的体会:全栈项目真正难的不是某个技术点,而是把业务逻辑想明白之后,让所有技术环节都围绕业务去落地。这个内容矩阵系统写下来,代码量不大,但每个表、每个接口、每个页面的设计都直接服务于“从灵感到数据回收”这条业务链路。如果你也要做类似的系统,我建议你把四成精力花在业务梳理和数据建模上,三成花在整合AI这类智能能力上,剩下三成才是编码和调试。这套比例如果反了,先写代码再补业务,大概率要返工。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 4:20:55

CentOS防火墙实战:firewalld与iptables全解析,端口开放与排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 4:20:42

MBA论文写作实战:8个AI平台全流程拆解与避坑指南

MBA论文这座大山&#xff0c;我太熟了。白天公司开会、晚上赶作业、周末还要带娃&#xff0c;却要在一年内交出一篇一两万字的毕业论文&#xff0c;这种被论文追着跑的感觉&#xff0c;写过的人都会懂。我自己在读完MBA后帮不少师弟师妹改过论文&#xff0c;也实测过市面上几乎…

作者头像 李华
网站建设 2026/9/30 4:17:43

从零构建AI服务:HTTP协议级AI工程化实践

1. 这不是“搭积木”&#xff0c;而是重建AI系统的底层认知框架“AI Engineering from Scratch”——这个标题乍看像一句技术圈的时髦口号&#xff0c;实则藏着一个被严重低估的真相&#xff1a;当前90%标榜“AI工程化”的团队&#xff0c;其实只是在已有模型、已有平台、已有S…

作者头像 李华
网站建设 2026/9/30 4:17:06

人工智能导论期中复习全攻略:概念、搜索算法与知识表示一次理清

“人工智能导论”这门课&#xff0c;我在湖南科技大学大三下学期选的时候&#xff0c;本以为就是一门背概念的“通识选修”&#xff0c;结果期中考前一周翻开教材和老师的PPT才发现&#xff0c;里面既有大量需要辨析记忆的定义和流派&#xff0c;又有必须老老实实动手算的搜索题…

作者头像 李华
网站建设 2026/9/30 4:16:57

AI辅助嵌入式开发:从寄存器配置到智能体工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 4:16:12

电网规划核心技术:直流潮流模型与三类规划方法实战解析

简介&#xff1a;这份PPT课件面向电力系统及其自动化专业的本科生、研究生与电力规划从业者&#xff0c;系统讲解电网规划的核心理论与工程方法&#xff0c;帮助读者建立从负荷预测、电源规划到网架方案决策的完整知识框架。资源为单个pptx文件&#xff0c;压缩包约3.15MB&…

作者头像 李华