使用 Motia 构建 AI 社交媒体内容自动化工作流从文章 URL 一键生成 Twitter 线程与 LinkedIn 帖子【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub本文基于仓库motia-content-creation目录下的 README.md 及其完整源码深入讲解如何用 Motia 编排一个“文章 → 社交内容”的 AI 自动化流水线通过 Firecrawl 抓取文章正文由 LLM 生成 Twitter 线程与 LinkedIn 帖子再调用 Typefully 保存为待审核草稿。读完本文你将掌握 Motia 事件驱动工作流的四步编排模式、Python/TypeScript 混合 Step 的写法、提示词模板与结构化输出对接方法以及本地与云端推理模型的接入方式。项目概览与技术选型该项目的核心定位是精简的内容生成 Agent用户只提交一个文章 URL系统自动完成抓取、改写与排期三件事最终产出两条平台内容Twitter 线程、LinkedIn 帖子供人工在 Typefully 草稿箱中审核发布。按 README.md 声明技术栈由三部分组成组件职责Motia统一后端编排框架负责事件路由、Step 执行与可视化调试Firecrawl抓取网页正文输出结构化 MarkdownOllamaDeepseek-R1本地模型推理用于生成社交内容需要特别说明的一个现状差异README 声明的生成模型是 Ollama 本地推理 Deepseek-R1requirements.txt中也确实保留了ollama0.5.0依赖但从当前仓库源码看两个生成 Step 实际通过AsyncOpenAI客户端以gpt-4o模型执行推理详见下文 generate-twitter.step.py 与 generate-linkedin.step.py。由于 OpenAI 客户端兼容 Ollama 提供的 OpenAI 兼容端点http://localhost:11434/v1只需修改base_url与模型名即可切回 README 所描述的本地 Deepseek-R1 方案后续章节会给出具体改造说明。工作流总览API → Scrape → Generate → Schedule整个工作流由 4 个主要步骤串联而成API → Scrape → Generate → ScheduleAPI通过 POST 请求接收文章 URLScrape使用 Firecrawl 将网页正文提取为 MarkdownGenerate基于提示词模板用 LLM 生成 Twitter 线程与 LinkedIn 帖子Schedule将生成内容作为草稿保存到 Typefully等待人工审核。从源码角度这 4 个步骤本质上是事件驱动拓扑。各 Step 的config块中声明了subscribes订阅的事件与emits发出的事件事件流如下api.step.py收到 HTTP 请求 → 发出scrape-articlescrape.step.py订阅scrape-article→ 抓取成功后发出generate-contentgenerate-twitter.step.py与generate-linkedin.step.py同时订阅generate-content并行分支→ 分别发出twitter-schedule与linkedin-scheduleschedule-twitter.step.ts订阅twitter-schedule、schedule-linkedin.step.ts订阅linkedin-schedule→ 写入 Typefully 草稿值得注意的是该项目刻意采用 Python 与 TypeScript 混合抓取与生成环节*.step.py使用 Python依赖 pydantic 做数据模型校验排期环节*.step.ts使用 TypeScript依赖 zod 校验这正是 Motia 多语言 Step 编排能力的直接体现。工程目录结构motia-content-creation/ ├── steps/ │ ├── api.step.py # API 端点处理器接收 URL │ ├── scrape.step.py # Firecrawl 抓取集成 │ ├── generate-twitter.step.py # Twitter 内容生成 │ ├── generate-linkedin.step.py # LinkedIn 内容生成 │ ├── schedule-twitter.step.ts # Twitter Typefully 排期 │ └── schedule-linkedin.step.ts # LinkedIn Typefully 排期 ├── prompts/ │ ├── twitter-prompt.txt # Twitter 生成提示词 │ └── linkedin-prompt.txt # LinkedIn 生成提示词 ├── config/ │ └── index.js # 配置管理含环境变量校验 ├── package.json # npm 脚本与依赖声明 ├── motia-workbench.json # Workbench 画布布局 ├── requirements.txt # Python 依赖 └── README.md环境准备与安装前置条件Node.js 18Python 3.xAPI KeyFirecrawl抓取文章Typefully保存草稿另外根据源码 generate-twitter.step.py 与 generate-linkedin.step.py生成步骤还会读取OPENAI_API_KEY因此实际运行时也应一并配置若按 README 走 Ollama 本地推理则此 Key 可留空但需将客户端base_url指向本地端点。安装步骤安装 Ollama 并拉取 Deepseek-R1按 README 的本地推理方案# Linux 下安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 拉取 Deepseek-R1 模型 ollama pull deepseek-r1安装项目依赖npm install # 或使用 pnpm pnpm install配置环境变量。复制示例文件或直接创建.envcp .env.example .env # 编辑 .env 填入 API Key.env核心变量FIRECRAWL_API_KEYyour_firecrawl_api_key TYPEFULLY_API_KEYyour_typefully_api_key环境变量的加载与校验由 config/index.js 统一完成模块顶部require(dotenv).config()加载.env随后validate()方法检查FIRECRAWL_API_KEY与TYPEFULLY_API_KEY是否存在任一缺失都会抛出Missing required environment variables: ...错误从启动阶段就避免了“跑到一半才发现 Key 没配”的问题。启动开发服务器npm run dev值得说明的是npm run dev并非直接执行 node而是走 package.json 中声明的prepare→dev两级脚本链prepare: python3 -m venv python_modules source python_modules/bin/activate pip install -r requirements.txt, dev: source python_modules/bin/activate motia dev即npm install触发prepare自动创建python_modules虚拟环境并安装 Python 依赖pydantic、firecrawl、python-dotenv、requests、ollama随后motia dev在激活该虚拟环境的同一 shell 中启动。其余脚本还包括dev:debugmotia dev --debug调试模式、buildmotia build构建与generate:configmotia get-config导出配置。源码级剖析四个步骤的实现细节第一步API 入口api.step.pyapi.step.py 定义了一个type: api的 Step路由POST /generate-content请求体{ url: HttpUrl }由 pydantic 的HttpUrl校验非法 URL 会直接返回 400响应体200对应SuccessResponsemessage/requestId/url/status400对应ErrorResponse其config块声明了emits: [scrape-article]handler 中通过context.trace_id生成请求追踪 ID随await context.emit({...})把requestId、url、timestamp广播给下游并立即返回{message: Content generation started, ...}。也就是说API 层是异步触发语义请求发出即返回“处理中”真正的生成发生在事件链路上。第二步Scrapescrape.step.pyscrape.step.py 订阅scrape-article事件使用 Firecrawl Python SDK 抓取正文app FirecrawlApp(api_keyFIRECRAWL_API_KEY) scrapeResult app.scrape_url(input[url]) if not scrapeResult.success: raise Exception(fFirecrawl scraping failed: {scrapeResult.error}) content scrapeResult.markdown title scrapeResult.metadata.get(title, Untitled Article)源码展示了三个关键处理细节失败即抛错success为假时直接raise异常会沿事件链路向上冒泡便于在 Workbench 中定位只取 MarkdownscrapeResult.markdown是后续所有 LLM 提示词的输入原料标题缺失时回退为Untitled Article日志透出信息量成功日志会输出标题与抓取字符数len(content)方便判断内容是否完整。抓取成功后发出generate-content事件携带requestId、url、title、content与时间戳。第三步Generategenerate-twitter / generate-linkedin两个生成 Step 结构对称均为type: event、订阅generate-content构成并行分支。以 generate-twitter.step.py 为例核心逻辑分四段读取并填充提示词模板with open(prompts/twitter-prompt.txt, r, encodingutf-8) as f: twitterPromptTemplate f.read() twitterPrompt twitterPromptTemplate.replace({{title}}, input[title]).replace({{content}}, input[content])调用 LLMtwitter_content await openai_client.chat.completions.create( modelgpt-4o, messages[{role: user, content: twitterPrompt}], temperature0.7, max_tokens2000, response_format{type: json_object} )参数含义temperature0.7在创造性与稳定性间取平衡max_tokens2000为长线程/长帖预留空间response_format{type: json_object}强制结构化 JSON 输出与提示词中的 JSON Schema 约定保持一致。JSON 解析兜底优先json.loads解析失败时退化为{text: 原始内容}避免单条坏输出中断整个工作流。发出排期事件emits: [twitter-schedule]携带requestId、url、title、content解析后的结构化内容、generatedAtISO 时间与originalUrl。LinkedIn 分支逻辑一致仅事件名linkedin-schedule与模板路径prompts/linkedin-prompt.txt不同。第四步Scheduleschedule-twitter / schedule-linkedin排期环节改用 TypeScript 实现。以 schedule-twitter.step.ts 为例它订阅twitter-schedule通过 axios 调用 Typefully 草稿 APIconst typefullyApiUrl https://api.typefully.com/v1/drafts/ const headers { X-API-KEY: Bearer ${appConfig.typefully.apiKey}, Content-Type: application/json }两个值得注意的对接细节线程拼接input.content.thread.map((tweet) tweet.content).join(\n\n\n\n)—— 生成阶段返回的 JSON 是{ thread: [{tweetNumber, content}] }数组排期时按四个换行符Typefully 识别多推文线程的分隔约定拼成完整草稿内容草稿模式请求体schedule_date: null表示不指定发布时间、仅保存为草稿供人工在 Typefully 草稿箱中审阅后手动发布。LinkedIn 分支schedule-linkedin.step.ts则直接取input.content.post作为整篇帖子内容同样以schedule_date: null写入草稿。提示词工程两种平台内容的生成规范提示词模板是该工作流“写得好不好”的核心变量值得单独展开。Twitter 线程提示词prompts/twitter-prompt.txt模板采用少样本few-shot风格先给出一整篇完整的 Bayes 定理科普线程作为范例逐条展示开篇钩子、(1/n)编号、段落分隔---、插图占位、互动表情与结尾关注引导的写法随后要求模型聚焦 6 个维度Opening Hook以清晰、抓眼球的语句开篇Thread Structure把复杂概念拆解成可消化的短推Engagement恰当使用 emoji、提问与行动号召Pacing保持推文间的过渡节奏Value每条推文都要承载增量信息Closing以有力的总结或行动号召收尾。并明确规定输出规模3-7 条推文与 JSON 格式{ thread: [ { tweetNumber: 1, content: ... }, { tweetNumber: 2, content: ... } ], totalTweets: 7 }这个 Schema 与调度端input.content.thread的消费方式严格对应形成“提示词定义结构 → 模型输出结构 → Step 消费结构”的闭环。LinkedIn 帖子提示词prompts/linkedin-prompt.txt同样采用少样本范式以一篇 Taipy 的推广帖为范例突出 7 个要求强开场、价值主张、可操作信息、专业语气、要点列表便于移动端扫读、行动号召、真实感。输出 JSON 为{ post: 完整帖子内容, characterCount: 1250 }调度端通过input.content.post直接取用characterCount字段便于做长度合规检查。启动、调用与结果查看触发内容生成curl -X POST http://localhost:3000/generate-content \ -H Content-Type: application/json \ -d {url: https://example.com/article}响应示例{ message: Content generation started, requestId: req_123456, url: https://example.com/article, status: processing }其中requestId即源码中的context.trace_id可用于在 Workbench 中追踪该次请求在整条事件链上的流转。查看结果处理完成后打开 Typefully 草稿箱审阅生成的 Twitter 线程与 LinkedIn 帖子按需编辑后手动发布。由于schedule_date恒为null内容始终以草稿形式落库不会未经确认就对外发布——这是该工作流“人机协同”安全边界的关键设计。可视化监控Motia WorkbenchMotia 自带 Workbench 交互式 UI随npm run dev自动启动。它把工作流渲染为可交互的流程图便于实时观察每个 Step 的输入输出、事件广播与异常位置。画布布局由 motia-workbench.json 持久化{ id: content-generation, config: { steps/api.step.py: { x: 1, y: 0 }, steps/scrape.step.py: { x: 1, y: 190 }, steps/generate-twitter.step.py: { x: -206, y: 366 }, steps/generate-linkedin.step.py: { x: 220, y: 366 }, steps/schedule-twitter.step.ts: { x: -218, y: 483 }, steps/schedule-linkedin.step.ts: { x: 213, y: 483 } } }坐标分布直观复现了拓扑结构api在最上scrape紧随其后向下分裂为 Twitter / LinkedIn 两条并行分支最终汇聚到两个排期端点。调试模式下npm run dev:debug可更细致地观察事件数据。常见问题与扩展方向提示Missing required environment variables说明.env未创建或缺失FIRECRAWL_API_KEY/TYPEFULLY_API_KEYconfig/index.js 会在启动阶段直接拦截。生成阶段报鉴权错误当前源码的生成步骤读取OPENAI_API_KEY见 generate-twitter.step.py请确认已配置README 的环境变量清单未列出该项属于“文档与源码现状不一致”的一个坑。切换回 Ollama 本地 Deepseek-R1README 声明的本地推理方案可通过 OpenAI 兼容客户端实现——将AsyncOpenAI的base_url指向http://localhost:11434/v1、模型名改为deepseek-r1或deepseek-r1:7b等已拉取的标签即可requirements.txt中的ollama依赖也可用于ollama list/ollama pull的本地管理。从草稿升级为定时发布将排期请求体中的schedule_date: null改为 ISO 时间字符串Typefully 即按计划时间发布。扩展新平台参照现有结构新增“生成 Step订阅generate-content 排期 Step订阅新事件”即可Motia 的事件订阅机制使分支扩展无需改动既有 Step。小结motia-content-creation是一个麻雀虽小、五脏俱全的 Motia 实战示例它以API → Scrape → Generate → Schedule四步事件拓扑完整演示了“外部请求接入 → 网页内容抓取 → LLM 结构化生成 → 第三方 API 落库”的 Agent 流水线范式。其多语言 Step 混合、事件驱动解耦、少样本提示词 JSON Schema 契约、Workbench 可视化调试等设计都是构建真实 AI 内容自动化系统的可复用模板。结合源码steps/ 目录与提示词prompts/ 目录阅读你可以快速将其改造为适配公众号、Newsletter、博客等更多内容渠道的自动化引擎。【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
