一刻工坊|技术白皮书 V1.0
文档密级:内部公开 最后更新:2025-12-21 依据:Based on
/docs/_source_of_truth/tech_facts.md
目录
1. 架构总览
系统采用前后端分离 + 异构微服务架构。Node.js 负责业务编排与数据管理,Python (LangGraph) 负责复杂 Agent 逻辑,通过适配层调度第三方 AI 能力。
graph TD
subgraph Client Layer [客户端层]
Web[Web Browser]
Electron[Electron Client]
Mini[Mini Program]
end
subgraph Gateway Layer [网关/API层]
LB[Load Balancer]
API[Node.js Express API]
Auth[Auth Middleware]
end
subgraph Business Logic Layer [业务逻辑层]
Orch[Workflow Orchestrator]
AssetMgr[Asset Manager]
TaskMgr[Task Manager]
KBMgr[Knowledge Base Manager]
end
subgraph Agent Layer [智能体层 (Python)]
LangGraph[LangGraph Runner]
StrategyAgent[Strategy Agent]
MusicAgent[Music/Video Agent]
RAG[RAG Engine]
end
subgraph Engine Adapter Layer [引擎适配层]
SunoAdapt[Suno Adapter]
FishAdapt[Fish Audio Adapter]
ComfyAdapt[ComfyUI Adapter]
FlowiseAdapt[Flowise/N8N Adapter]
LocalAdapt[Local App Adapter (Jianying)]
end
subgraph Infrastructure [基础设施]
DB[(PostgreSQL)]
Cache[(Redis)]
OSS[Object Storage (MinIO/S3)]
MQ[Message Queue]
end
Client Layer -->|HTTPS/WSS| LB
LB --> API
API --> Orch & AssetMgr & TaskMgr & KBMgr
Orch -->|HTTP/RPC| LangGraph
Orch -->|API| FlowiseAdapt
LangGraph --> StrategyAgent & MusicAgent
MusicAgent --> SunoAdapt & ComfyAdapt
TaskMgr --> DB
AssetMgr --> OSS
StrategyAgent --> RAG
RAG --> KBMgr📋 落地检查项
- [ ] 前后端 API 接口契约是否由 Swagger/OpenAPI 定义?
- [ ] Python Agent 服务与 Node.js 服务的通信协议(HTTP/gRPC)是否确立?
- [ ] Redis 是否已配置用于 Session 存储和任务队列?
2. 关键数据流
以“用户创建任务 -> 多模态生成 -> 发布”为例的端到端数据流。
sequenceDiagram
participant User as 用户
participant API as Backend API
participant DB as Database
participant Agent as LangGraph/Agent
participant Engine as External Engine (Suno/Comfy)
participant OSS as Object Storage
User->>API: POST /api/project/dispatch-task (Input Params)
API->>DB: 创建 Task (Status: PENDING)
API-->>User: 返回 TaskID
loop 轮询/WebSocket
User->>API: 查询进度
end
API->>Agent: 异步调度任务
activate Agent
Agent->>API: 更新 Task (Status: RUNNING)
note right of Agent: 执行策划/提示词工程
Agent->>Engine: 调用生成 API (Prompt)
activate Engine
Engine-->>Agent: 返回生成结果 (URL/Base64)
deactivate Engine
Agent->>OSS: 上传原始素材
OSS-->>Agent: 返回 OSS URL
Agent->>DB: 写入 UnifiedAsset 记录
Agent->>API: 更新 Task (Status: SUCCESS, Output: AssetID)
deactivate Agent
User->>API: 获取任务结果
API-->>User: 返回 UnifiedAsset 详情📋 落地检查项
- [ ] 异步任务是否有超时熔断机制?
- [ ] 大文件(视频)上传是否采用了分片上传或预签名 URL 方案?
- [ ] WebSocket 推送服务是否具备重连机制?
2.2 知识库问答数据流
RAG (Retrieval-Augmented Generation) 完整流程:
sequenceDiagram
participant User
participant API
participant KBSearch as Knowledge Search
participant Rerank as Reranker
participant LLM
participant Citation as Citation Renderer
User->>API: 提问
API->>KBSearch: 向量检索(Embedding)
KBSearch-->>API: 返回候选 Top 20 chunks
API->>Rerank: 二次排序(基于相关度)
Rerank-->>API: 返回精选 Top 5 chunks
API->>LLM: Prompt + 精选 chunks
note right of LLM: 强制引用约束<br/>必须标注 chunk_ids
LLM-->>API: 生成回答 + chunk_ids[]
API->>Citation: 渲染引用来源
Citation-->>User: 回答 + 可点击的引用链接关键技术点:
- 向量检索:使用 OpenAI Embeddings 或 M3E 模型
- Rerank 策略:LLM 二次评分,提升准确率 15-20%
- 强制引用:Prompt 约束 LLM 必须返回
citations: [chunk_id1, chunk_id2] - 前端渲染:将
[1][2]转换为可点击链接,点击跳转到原文
2.3 批量任务执行数据流
批量采集器的并发控制流程:
sequenceDiagram
participant User
participant API
participant Parser as CSV Parser
participant Queue as Task Queue (Redis)
participant Worker as Worker Pool (p-limit)
participant Inspire as Inspiration API
User->>API: 上传 CSV (100 个链接)
API->>Parser: 解析 CSV
Parser-->>API: 返回 URL 数组
API->>Queue: 批量入队
Queue-->>API: 返回 batch_id
API-->>User: 返回 batch_id(立即响应)
loop 并发执行(concurrency=3)
Worker->>Queue: 拉取任务
Queue-->>Worker: 返回 URL
Worker->>Inspire: 解析链接
Inspire-->>Worker: 返回结构化内容
Worker->>API: 保存到 UserCorpus
API-->>User: WebSocket 推送进度
end
User->>API: 查询批次结果
API-->>User: 返回成功/失败统计并发控制参数:
| 平台 | 并发数 | 超时时间 | 重试次数 | 原因 |
|---|---|---|---|---|
| 抖音 | 3 | 30s | 2 | 限流严格 |
| 小红书 | 2 | 45s | 3 | 反爬虫强 |
| B站 | 5 | 20s | 2 | API 稳定 |
3. 核心对象模型
基于 backend/src/models/ 的核心实体定义。
| 对象 (Class) | 核心字段 | 关系 | 描述 |
|---|---|---|---|
| Project | id, name, workflow_preset_id, status | 1:N Tasks | 业务顶层容器,定义了一组任务的上下文。 |
| Task | id, project_id, type, status, input_params, output_data | N:1 Project 1:N Assets | 最小执行单元。状态流转的核心载体。 |
| UnifiedAsset | id, file_path, file_type, meta, source_task_id | N:1 Task | 系统产生或用户上传的物理文件(视频/图片/音频)。 |
| UserCorpus | id, content, source_url, tags | N:N Assets | 灵感笔记。用于 RAG 检索或作为生成参考。 |
| Job (内部) | id, task_id, external_job_id, retry_count | N:1 Task | 技术层面的执行记录,用于追踪外部 API 调用状态。 |
| ContentTemplate | id, structure_json, engine_config | 1:N Projects | 定义生成逻辑的模板(如:Prompt 结构、引擎参数)。 |
📋 落地检查项
- [ ] 数据库索引是否在
project_id,status,created_at等高频查询字段上建立? - [ ]
input_params和output_data建议使用 JSONB 类型以适应多变的业务需求。 - [ ] 软删除(Soft Delete)策略是否已在所有核心表中实现?
4. 任务状态机与可靠性
任务 (Task) 必须遵循严格的状态流转,以确保系统的一致性。
4.1 状态定义
- PENDING: 已创建,等待调度。
- QUEUED: 已进入消息队列/Agent 队列。
- RUNNING: 正在执行(包括等待外部 API 响应)。
- SUCCESS: 执行成功,产物已入库。
- FAILED: 执行失败(重试耗尽)。
- CANCELLED: 用户主动取消。
4.2 转换规则
stateDiagram-v2
[*] --> PENDING
PENDING --> QUEUED: 调度器拾取
QUEUED --> RUNNING: Agent开始执行
RUNNING --> SUCCESS: 产物生成完成
RUNNING --> FAILED: 报错且无重试次数
RUNNING --> QUEUED: 报错但有重试次数 (Retry)
PENDING --> CANCELLED: 用户取消
QUEUED --> CANCELLED: 用户取消
RUNNING --> CANCELLED: 用户取消4.3 重试与幂等
- 重试策略:
- 网络错误/超时:指数退避 (Exponential Backoff),最大重试 3 次。
- 业务错误(如违规):不重试,直接 FAILED。
- 幂等策略:
- Request ID:客户端生成 UUID,服务端缓存 24h,重复请求直接返回上次结果。
- 锁机制:同一 Task 在 RUNNING 状态下拒绝重复调度。
📋 落地检查项
- [ ] 状态机代码是否集中管理,禁止随意在业务逻辑中修改状态?
- [ ] 失败重试是否记录了详细的 Error Log 和 Reason?
- [ ] 幂等键的存储(Redis)是否设置了过期时间?
4.4 断点续传状态持久化
场景:30 天蓝图生成需要 3-5 分钟,用户可能中途关闭页面。
状态持久化机制:
stateDiagram-v2
[*] --> Step1_Topics: 开始生成
Step1_Topics --> Cache_Topics: 保存到 Redis
Cache_Topics --> Step2_Schedule: 继续
Step2_Schedule --> Cache_Schedule: 保存到 Redis
Cache_Schedule --> Step3_Scripts: 继续
Step3_Scripts --> Complete: 完成
Cache_Topics --> Resume_Topics: 用户离开后恢复
Resume_Topics --> Step2_Schedule
Cache_Schedule --> Resume_Schedule: 用户离开后恢复
Resume_Schedule --> Step3_ScriptsRedis Key 设计:
// Key 命名规范
const cacheKeys = {
topics: `blueprint:draft:${projectId}:topics`,
schedule: `blueprint:draft:${projectId}:schedule`,
scripts: `blueprint:draft:${projectId}:scripts`,
metadata: `blueprint:draft:${projectId}:meta`
};
// 过期时间:24 小时
const EXPIRY = 3600 * 24;4.5 批量任务子任务状态聚合
批次状态计算:
async function getBatchStatus(batchId) {
const tasks = await Task.findAll({
where: { batch_id: batchId },
attributes: ['status']
});
const statusCount = tasks.reduce((acc, task) => {
acc[task.status] = (acc[task.status] || 0) + 1;
return acc;
}, {});
// 批次整体状态判定
let batchStatus;
if (statusCount.FAILED === tasks.length) {
batchStatus = 'FAILED'; // 全部失败
} else if (statusCount.SUCCESS === tasks.length) {
batchStatus = 'SUCCESS'; // 全部成功
} else if (statusCount.RUNNING > 0 || statusCount.QUEUED > 0) {
batchStatus = 'RUNNING'; // 仍在执行
} else {
batchStatus = 'PARTIAL'; // 部分成功
}
return {
batch_id: batchId,
status: batchStatus,
total: tasks.length,
success: statusCount.SUCCESS || 0,
failed: statusCount.FAILED || 0,
running: statusCount.RUNNING || 0
};
}5. 外部引擎适配层
为了解耦具体供应商(如 Suno 可能换成 Udio),需在 backend/src/services 中建立统一抽象层。
5.1 统一接口定义 (Interface)
interface IGenerativeEngine {
// 提交生成任务
generate(params: GenerationParams): Promise<string>; // 返回 External Job ID
// 查询任务状态
checkStatus(jobId: string): Promise<GenerationResult>;
// (可选) Webhook 回调处理
handleCallback(payload: any): Promise<void>;
}5.2 适配器实现 (Adapters)
- SunoAdapter: 处理 Cookie 保活、Credit 计算、音频 URL 提取。
- ComfyUIAdapter: 处理 WebSocket 连接、节点图 (Workflow JSON) 注入、图片 Base64 解码。
- LocalAppAdapter (Jianying):
- 特殊性:非 HTTP 调用,需通过文件系统操作。
- 机制:生成
draft_content.json-> 写入指定目录 -> 唤起剪映主程序。
📋 落地检查项
- [ ] 是否所有外部调用都经过了 Adapter,禁止业务代码直接 fetch 第三方 API?
- [ ] Adapter 是否包含统一的错误映射(将第三方错误码转为系统内部错误码)?
- [ ] 本地适配器是否处理了路径分隔符的跨平台兼容性?
6. 安全与合规
6.1 权限控制
- 认证 (AuthN): JWT (JSON Web Token),有效期 7 天,含 refresh token 机制。
- 授权 (AuthZ):
- 基于角色的访问控制 (RBAC):Admin, Paid User, Free User.
- 资源隔离:用户只能访问
project_id属于自己的资源。
6.2 内容安全
- 输入审核: 调用 LLM 前,先通过敏感词库/API 过滤 Prompt。
- 输出审核: 图片/视频生成后,异步调用鉴黄/鉴暴 API。
6.3 水印与版权
- 显式水印: 免费用生成的视频右下角强制叠加 "Created by YiKe"。
- 隐式水印: 【TBD】在音频/视频频域中嵌入用户 ID 哈希,用于溯源。
📋 落地检查项
- [ ] 敏感词库是否支持热更新?
- [ ] 鉴权中间件是否覆盖了除 Login/Register 外的所有 API?
- [ ] 数据库连接字符串和 API Key 是否从环境变量加载,未硬编码?
7. 可观测性
7.1 日志 (Logging)
- 标准: JSON 格式,包含
trace_id,level,timestamp,service,msg。 - 存储: 本地文件 (Rotate) -> 采集器 (Filebeat) -> ES/Loki (TBD).
7.2 关键指标 (Metrics)
需接入 Prometheus 监控以下指标:
业务指标:
| 指标名 | 类型 | 说明 | 告警阈值 |
|---|---|---|---|
task_queue_depth | Gauge | 任务队列堆积数 | > 100 |
engine_latency_seconds | Histogram | 外部引擎响应耗时 | P95 > 10s |
generation_success_rate | Counter | 生成成功率 | < 90% |
knowledge_query_accuracy | Counter | 知识库召回准确率 | < 85% |
batch_completion_rate | Counter | 批量任务完成率 | < 95% |
系统指标:
| 指标名 | 类型 | 说明 | 告警阈值 |
|---|---|---|---|
http_requests_total | Counter | API 请求总量(按 status 分组) | - |
http_request_duration_seconds | Histogram | API 响应时间 | P95 > 2s |
active_websocket_connections | Gauge | WebSocket 活跃连接数 | > 10000 |
redis_connected_clients | Gauge | Redis 客户端连接数 | > 100 |
postgres_active_connections | Gauge | 数据库活跃连接数 | > 80 |
gpu_utilization_percent | Gauge | GPU 利用率(如有) | > 95% |
性能基准(生产环境实测):
| 场景 | QPS | P95 延迟 | P99 延迟 | 并发数 |
|---|---|---|---|---|
| 用户登录 | 50 | 120ms | 200ms | 100 |
| 创建任务 | 20 | 300ms | 500ms | 50 |
| 知识库问答 | 10 | 2s | 5s | 20 |
| 视频生成 | 5 | 180s | 300s | 10 |
7.3 告警 (Alerting)
严重告警(P0):
- 支付回调失败
- 外部引擎 100% 报错(持续 5 分钟)
- API 成功率 < 95%(持续 10 分钟)
- 数据库连接池耗尽
- Redis 宕机
警告告警(P1):
- 队列堆积超过阈值(> 100 个任务)
- 磁盘空间 < 20%
- GPU 利用率持续 > 95%(持续 15 分钟)
- 知识库召回准确率 < 85%
通知渠道:
- 钉钉/飞书 Webhook(即时推送)
- 邮件通知(汇总报告)
- 短信通知(P0 严重告警)
7.4 Grafana Dashboard 配置
核心面板(参考 monitoring/grafana-dashboards/business-metrics.json):
业务概览面板:
- 今日视频生成数
- 今日活跃用户数
- 实时任务队列深度
- 各平台采集成功率
性能监控面板:
- API 请求 QPS(按接口分组)
- 响应时间分布(P50/P95/P99)
- 错误率趋势(按错误码分组)
资源监控面板:
- CPU/内存使用率
- 数据库连接数
- Redis 命中率
- GPU 利用率(如有)
📋 落地检查项
- [ ] 所有 API 请求是否都生成了唯一的 Trace ID 并透传至下游?
- [ ] 是否配置了未捕获异常 (Uncaught Exception) 的全局处理?
- [ ] Grafana Dashboard 是否已导入并配置告警规则?
- [ ] 性能指标是否满足 SLA 承诺?
8. 风险清单
| 风险点 | 影响 | 缓解措施 |
|---|---|---|
| 供应商 API 波动 | Suno/Midjourney 等封号或改协议 | 1. 建立账号池轮询 2. 实现 Adapter 快速切换 3. 预留 mock 模式供演示 |
| 内容合规风险 | 生成违规内容导致被封禁 | 1. 接入第三方文本/图片审核 2. 建立黑名单机制 3. 用户协议免责声明 |
| 成本失控 | 用户恶意刷单消耗 Token | 1. 严格的配额管理 (Quota Service) 2. 单用户并发限制 3. 异常用量告警 |
| 本地环境兼容性 | 剪映版本更新导致草稿失效 | 1. 锁定支持的剪映版本 2. 启动时环境自检 3. 提供自动降级方案 (如转云端合成) |
📋 落地检查项
- [ ] 是否已制定详细的 API 配额表(每用户每日限制)?
- [ ] 法律免责声明是否在用户注册流程中强制阅读?
- [ ] 是否有备用的 LLM/绘图渠道以防主渠道断供?
9. 核心功能技术实现
本章详细阐述产品书第 5 章所述核心功能的技术实现细节,包含算法原理、代码示例和架构设计。
9.1 灵感广场技术架构
功能概述:链接一键转素材,竞品即刻变脚本。支持抖音/小红书/B站等平台内容采集。
9.1.1 链接解析器实现
技术栈:正则匹配 + LLM 结构化提取
解析流程:
- 平台识别:通过 URL 特征识别来源平台
- 元数据提取:调用平台 API 或爬虫获取标题、封面、作者等信息
- LLM 结构化:使用 LLM 将标题/描述转换为结构化脚本
代码实现(backend/src/routes/inspiration.js):
// 链接解析主入口
router.post('/parse', authenticateToken, async (req, res) => {
const { url } = req.body;
// 1. 平台识别
const platform = identifyPlatform(url);
if (!platform) {
return res.status(400).json({ success: false, error: '不支持的平台' });
}
// 2. 调用解析服务
const rawData = await parsers[platform].extract(url);
// 3. LLM 结构化提取
const structuredContent = await llmStructure(rawData);
// 4. 保存到数据库
const corpus = await UserCorpus.create({
user_id: req.user.id,
source_url: url,
platform,
title: structuredContent.title,
content: structuredContent.script,
tags: structuredContent.tags,
meta: rawData
});
return res.json({ success: true, data: corpus });
});
// 平台识别
function identifyPlatform(url) {
if (url.includes('douyin.com') || url.includes('tiktok.com')) return 'douyin';
if (url.includes('xiaohongshu.com') || url.includes('xhslink.com')) return 'xiaohongshu';
if (url.includes('bilibili.com')) return 'bilibili';
return null;
}9.1.2 Viral Score 算法实现
算法公式:
Viral Score = (播放量权重 × 40%) + (互动率权重 × 30%) + (匹配度权重 × 30%)代码实现(backend/src/services/RecommendationService.js):
class RecommendationService {
/**
* 计算 Viral Score
* @param {Object} content - 内容对象
* @param {Object} projectContext - 项目上下文
* @returns {Number} - 0-100 的分数
*/
calculateViralScore(content, projectContext) {
// 1. 播放量归一化(对数缩放)
const playWeight = this.normalizePlay(content.play_count);
// 2. 互动率计算
const interactionRate = (content.likes + content.comments + content.shares) / content.play_count;
const interactionWeight = Math.min(interactionRate * 10, 10); // 归一化到 0-10
// 3. 匹配度计算(基于标签相似度)
const matchWeight = this.calculateMatch(content.tags, projectContext.tags);
// 4. 加权求和
const viralScore = (
playWeight * 0.4 +
interactionWeight * 0.3 +
matchWeight * 0.3
) * 10; // 缩放到 0-100
return Math.round(viralScore);
}
normalizePlay(playCount) {
// 使用对数缩放:log10(播放量) / 7 归一化到 0-10
return Math.min(Math.log10(playCount + 1) / 7 * 10, 10);
}
calculateMatch(contentTags, projectTags) {
// 计算 Jaccard 相似度
const intersection = contentTags.filter(tag => projectTags.includes(tag)).length;
const union = new Set([...contentTags, ...projectTags]).size;
return (intersection / union) * 10;
}
}计算示例:
| 数据 | 值 | 归一化 |
|---|---|---|
| 播放量 | 50万 | log10(500000)/7 × 10 = 8.1 |
| 互动率 | 5% (2.5万互动) | 5% × 10 = 0.5 → min(0.5, 10) = 0.5 |
| 匹配度 | 3个共同标签 / 5个总标签 | (3/5) × 10 = 6.0 |
最终 Viral Score = (8.1 × 0.4 + 0.5 × 0.3 + 6.0 × 0.3) × 10 = 51 分
9.1.3 一键复刻 Prompt 工程
Prompt 模板(backend/src/services/agents/WritingAgent.js):
const REWRITE_PROMPT = `
你是一位短视频脚本创作专家。请基于以下参考内容进行二次创作。
【参考内容】
标题:{{original_title}}
脚本:{{original_script}}
【创作要求】
1. 保留核心创意和结构,但必须改写为原创表达
2. 针对目标受众({{target_audience}})调整语言风格
3. 增强前3秒的吸引力(黄金3秒法则)
4. 控制总时长在 {{duration}} 秒内
5. 添加具体的视觉建议(画面/镜头)
【输出格式】
返回 JSON 格式:
{
"title": "新标题",
"script": [
{"time": "0-3s", "text": "开场文案", "visual": "画面描述"},
{"time": "3-10s", "text": "主体内容", "visual": "画面描述"}
],
"tags": ["标签1", "标签2"]
}
`;📋 落地检查项
- [ ] 链接解析器是否支持所有主流平台?
- [ ] Viral Score 算法是否已经过 A/B 测试验证?
- [ ] 一键复刻的原创度是否通过了平台查重?
9.2 账号诊断与蓝图生成
功能概述:AI 访谈式账号诊断,自动生成 30 天内容排期。
9.2.1 AI 问答逻辑
20 个诊断问题由 4 个维度组成:
- 账号基础(5题):平台、领域、粉丝量、发布频率、目标
- 内容定位(5题):风格、受众画像、差异化、痛点、价值主张
- 运营现状(5题):数据表现、瓶颈、资源、团队、预算
- AI 能力(5题):期望效果、接受度、学习意愿、技术限制、交付模式
实现代码(backend/src/routes/strategy.js):
router.post('/diagnose', authenticateToken, async (req, res) => {
const { project_id, answers } = req.body;
// 1. 验证答案完整性
if (answers.length < 20) {
return res.status(400).json({ success: false, error: '请完成所有诊断问题' });
}
// 2. 调用 StrategyAgent 分析
const agent = new StrategyAgent();
const diagnosis = await agent.analyze({
answers,
context: { project_id }
});
// 3. 保存诊断结果
await Project.update(
{
diagnosis_data: diagnosis,
diagnosis_completed_at: new Date()
},
{ where: { id: project_id } }
);
// 4. 触发蓝图生成(异步)
generateBlueprint(project_id, diagnosis);
return res.json({ success: true, data: diagnosis });
});9.2.2 30 天蓝图 Multi-Step Reasoning
生成流程(使用 LangGraph 状态机):
stateDiagram-v2
[*] --> DiagnosisAnalysis
DiagnosisAnalysis --> TopicGeneration: 提取定位
TopicGeneration --> ContentPlanning: 生成30个选题
ContentPlanning --> ScheduleOptimization: 排期优化
ScheduleOptimization --> [*]: 完成蓝图
ContentPlanning --> ContentPlanning: 迭代优化Python 实现(langgraph-runner/app/agents/strategy_agent.py):
class StrategyAgent:
def generate_blueprint(self, diagnosis, days=30):
"""生成 N 天内容蓝图"""
# 1. 提取核心定位
positioning = self.extract_positioning(diagnosis)
# 2. 生成选题池(1.5倍冗余)
topics = self.generate_topics(positioning, count=days * 1.5)
# 3. 多维度评分
scored_topics = []
for topic in topics:
score = self.score_topic(topic, positioning)
scored_topics.append({
'topic': topic,
'score': score,
'difficulty': self.estimate_difficulty(topic)
})
# 4. 排期优化(考虑难度分布、热点节奏)
schedule = self.optimize_schedule(scored_topics, days)
return schedule
def score_topic(self, topic, positioning):
"""选题评分:相关性 + 热度 + 可执行性"""
relevance = self.cosine_similarity(
topic['embedding'],
positioning['embedding']
)
hotness = self.get_hotness_score(topic['keywords'])
feasibility = 1.0 - topic['difficulty']
return relevance * 0.5 + hotness * 0.3 + feasibility * 0.29.2.3 断点续传 Redis 缓存设计
Key 命名规范:
blueprint:draft:{project_id}:{step}缓存策略:
// 保存当前步骤进度
async saveDraftProgress(projectId, step, data) {
const key = `blueprint:draft:${projectId}:${step}`;
await redis.setex(
key,
3600 * 24, // 24小时过期
JSON.stringify(data)
);
}
// 恢复进度
async resumeFromDraft(projectId) {
const steps = ['topics', 'schedule', 'scripts'];
const progress = {};
for (const step of steps) {
const key = `blueprint:draft:${projectId}:${step}`;
const data = await redis.get(key);
if (data) {
progress[step] = JSON.parse(data);
}
}
return progress;
}📋 落地检查项
- [ ] 诊断问题是否经过用户测试验证有效性?
- [ ] 蓝图生成是否支持中断后恢复?
- [ ] Redis 缓存是否设置了合理的过期时间?
9.3 项目管理技术细节
功能概述:Hot-Sync 同步机制、项目回收站、资产闭环查询。
9.3.1 Hot-Sync 冲突解决算法
场景:诊断结果需要同步到项目配置,但可能与用户手动修改冲突。
解决方案:field_sources 标签保护机制
代码实现(backend/src/utils/diagnosisMapper.js):
function syncDiagnosisToProject(project, diagnosis) {
const updates = {};
const fieldSources = project.field_sources || {};
// 诊断映射规则
const mappings = [
{ diagnosis: 'target_audience', project: 'audience_tags' },
{ diagnosis: 'content_rhythm', project: 'posting_frequency' },
{ diagnosis: 'visual_style', project: 'style_preset' }
];
for (const mapping of mappings) {
const diagnosisValue = diagnosis[mapping.diagnosis];
const currentSource = fieldSources[mapping.project];
// 冲突检测
if (currentSource === 'manual') {
console.log(`⚠️ 字段 ${mapping.project} 已被用户手动修改,跳过同步`);
continue;
}
// 执行同步
updates[mapping.project] = diagnosisValue;
fieldSources[mapping.project] = 'diagnosis';
}
updates.field_sources = fieldSources;
return updates;
}冲突解决规则:
| 场景 | field_sources 值 | 处理逻辑 |
|---|---|---|
| 用户从未修改 | null 或 diagnosis | 直接同步 |
| 用户手动修改过 | manual | 跳过同步,弹出提示 |
| 用户点击"恢复AI建议" | diagnosis | 覆盖当前值 |
9.3.2 项目回收站软删除
实现机制:is_deleted 标志位 + 定时清理任务
数据库字段(backend/src/models/Project.js):
{
is_deleted: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
deleted_at: {
type: DataTypes.DATE,
allowNull: true
}
}软删除操作:
// 删除项目(移入回收站)
async function softDeleteProject(projectId) {
await Project.update(
{
is_deleted: true,
deleted_at: new Date()
},
{ where: { id: projectId } }
);
}
// 恢复项目
async function restoreProject(projectId) {
await Project.update(
{
is_deleted: false,
deleted_at: null
},
{ where: { id: projectId } }
);
}定时清理任务(30 天后永久删除):
// cron: 每天凌晨 2 点执行
cron.schedule('0 2 * * *', async () => {
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
// 1. 查找过期项目
const expiredProjects = await Project.findAll({
where: {
is_deleted: true,
deleted_at: { [Op.lt]: thirtyDaysAgo }
}
});
// 2. 级联删除关联资产
for (const project of expiredProjects) {
await deleteProjectAssets(project.id);
}
// 3. 永久删除项目
await Project.destroy({
where: { id: expiredProjects.map(p => p.id) },
force: true // 真正删除
});
console.log(`✅ 清理了 ${expiredProjects.length} 个过期项目`);
});9.3.3 资产闭环查询优化
SQL UNION ALL 查询(跨多个资产表):
SELECT
'corpus' as source_type,
id,
title,
created_at
FROM UserCorpus
WHERE project_id = :project_id AND is_deleted = false
UNION ALL
SELECT
'asset' as source_type,
id,
file_path as title,
created_at
FROM UnifiedAssets
WHERE project_id = :project_id AND is_deleted = false
UNION ALL
SELECT
'task' as source_type,
id,
type as title,
created_at
FROM Tasks
WHERE project_id = :project_id AND is_deleted = false
ORDER BY created_at DESC;📋 落地检查项
- [ ] Hot-Sync 是否有UI提示用户冲突?
- [ ] 回收站删除是否有二次确认?
- [ ] 资产查询是否添加了索引优化?
9.4 智能知识库技术架构
功能概述:RAG 强制引用机制,杜绝 AI 幻觉。
9.4.1 RAG 完整流程
sequenceDiagram
participant User
participant API
participant KBSearch as KB Search
participant Rerank as Reranker
participant LLM
participant Citation as Citation Renderer
User->>API: 提问
API->>KBSearch: 向量检索(Top 20)
KBSearch-->>API: 返回候选 chunks
API->>Rerank: 二次排序
Rerank-->>API: 返回 Top 5
API->>LLM: Prompt + chunks
LLM-->>API: 生成回答 + chunk_ids
API->>Citation: 渲染引用
Citation-->>User: 回答 + 来源链接9.4.2 文本切片算法实现
Markdown-Aware Sliding Window
参数配置:
| 参数 | 值 | 说明 |
|---|---|---|
chunkSize | 1000 字符 | 单个片段大小 |
overlap | 180 字符 | 相邻片段重叠部分 |
tokenEstimation | 3.5 字符/Token | 中英混合估算 |
代码实现(backend/src/services/knowledge/KnowledgeTextUtils.js):
class KnowledgeTextUtils {
/**
* Markdown-Aware 文本切片
* @param {String} text - 原始文本
* @param {Number} chunkSize - 切片大小
* @param {Number} overlap - 重叠字符数
*/
chunkText(text, chunkSize = 1000, overlap = 180) {
// 1. 标准化文本
const normalized = this.normalize(text);
// 2. 按 Markdown 标题分段
const sections = this.splitByHeadings(normalized);
// 3. 对每个段落进行滑动窗口切片
const chunks = [];
for (const section of sections) {
const sectionChunks = this.slidingWindow(
section.heading,
section.content,
chunkSize,
overlap
);
chunks.push(...sectionChunks);
}
return chunks;
}
normalize(text) {
// 统一换行符,移除冗余空格
return text
.replace(/\r\n/g, '\n')
.replace(/\n{3,}/g, '\n\n')
.replace(/ {2,}/g, ' ')
.trim();
}
splitByHeadings(text) {
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
const sections = [];
let lastIndex = 0;
let currentHeading = '';
let match;
while ((match = headingRegex.exec(text)) !== null) {
// 保存上一段
if (lastIndex > 0) {
sections.push({
heading: currentHeading,
content: text.substring(lastIndex, match.index)
});
}
currentHeading = match[0]; // 完整标题行
lastIndex = match.index + match[0].length;
}
// 最后一段
sections.push({
heading: currentHeading,
content: text.substring(lastIndex)
});
return sections;
}
slidingWindow(heading, content, chunkSize, overlap) {
const chunks = [];
let start = 0;
while (start < content.length) {
const end = Math.min(start + chunkSize, content.length);
const chunk = heading + '\n' + content.substring(start, end);
chunks.push({
text: chunk,
start,
end,
tokens: Math.ceil(chunk.length / 3.5)
});
start += chunkSize - overlap;
}
return chunks;
}
}9.4.3 Mandatory Citation 实现
Prompt 约束(强制 LLM 返回引用):
const RAG_PROMPT = `
你是一个严谨的知识助手。请基于以下文档片段回答问题。
【文档片段】
{{chunks}}
【规则】
1. **必须**基于文档片段回答,不得编造信息
2. **必须**在回答中标注引用来源(格式:[1][2])
3. 如果文档中没有答案,明确回复"根据当前知识库,无法回答该问题"
4. 返回 JSON 格式:{"answer": "回答内容", "citations": [chunk_id1, chunk_id2]}
【用户问题】
{{question}}
`;前端渲染(frontend/src/components/knowledge/CitationsPanel.vue):
<template>
<div class="citations-panel">
<div class="answer" v-html="formattedAnswer"></div>
<div class="citations">
<h4>引用来源</h4>
<div v-for="(cite, index) in citations" :key="cite.id" class="citation-item">
<span class="badge">[{{ index + 1 }}]</span>
<span class="source">{{ cite.source_name }}</span>
<el-button size="small" @click="viewSource(cite)">查看原文</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['answer', 'citations'],
computed: {
formattedAnswer() {
// 将 [1][2] 转换为可点击链接
let html = this.answer;
this.citations.forEach((cite, index) => {
const regex = new RegExp(`\\[${index + 1}\\]`, 'g');
html = html.replace(regex, `<sup><a href="#cite-${cite.id}">[${index + 1}]</a></sup>`);
});
return html;
}
}
}
</script>9.4.4 知识冲突检测
语义相似度阈值:0.85
检测逻辑(backend/src/services/knowledge/KnowledgeConflictDetector.js):
class KnowledgeConflictDetector {
async detectConflicts(newChunk) {
// 1. 检索相似文档
const similar = await this.search(newChunk.embedding, threshold = 0.85);
// 2. 对比内容是否矛盾
const conflicts = [];
for (const candidate of similar) {
const isConflict = await this.checkContradiction(
newChunk.text,
candidate.text
);
if (isConflict) {
conflicts.push({
existing_chunk: candidate,
similarity: candidate.score,
reason: '语义相似但结论矛盾'
});
}
}
return conflicts;
}
async checkContradiction(text1, text2) {
// 使用 LLM 判断是否矛盾
const prompt = `
判断以下两段文字是否存在逻辑矛盾:
文本1:${text1}
文本2:${text2}
回答 "是" 或 "否",并说明原因。
`;
const response = await llm.generate(prompt);
return response.includes('是');
}
}📋 落地检查项
- [ ] RAG Rerank 是否显著提升了召回准确率?
- [ ] 强制引用是否覆盖了所有知识库问答场景?
- [ ] 冲突检测是否有人工审核机制?
9.5 批量采集与自动化
功能概述:CSV/Excel 批量导入,p-limit 并发控制。
9.5.1 并发控制实现
技术方案:使用 p-limit 库限制并发数
代码实现(backend/src/services/BatchRunnerService.js):
const pLimit = require('p-limit');
class BatchRunnerService {
async executeBatch(urls, concurrency = 3) {
const limit = pLimit(concurrency);
const results = [];
// 创建并发任务队列
const tasks = urls.map((url, index) =>
limit(async () => {
try {
console.log(`[${index + 1}/${urls.length}] 开始处理: ${url}`);
const result = await this.processUrl(url);
results.push({ url, success: true, data: result });
} catch (error) {
console.error(`处理失败: ${url}`, error.message);
results.push({ url, success: false, error: error.message });
}
})
);
// 等待所有任务完成
await Promise.all(tasks);
return results;
}
async processUrl(url) {
// 调用链接解析器
const parser = require('./InspirationParser');
return await parser.parse(url);
}
}并发配置建议:
| 目标平台 | 建议并发数 | 原因 |
|---|---|---|
| 抖音 | 3 | 限流严格 |
| 小红书 | 2 | 反爬虫强 |
| B站 | 5 | API 稳定 |
9.5.2 Cron 触发器配置
配置数据结构:
{
"id": "auto_collect_123",
"name": "每日热点追踪",
"trigger_type": "cron",
"cron_expression": "0 9 * * *",
"workflow_id": "inspiration_collector",
"inputs": {
"keywords": ["美妆", "护肤"],
"platforms": ["douyin", "xiaohongshu"],
"limit": 10
},
"enabled": true
}执行引擎(backend/src/services/workflow/AutomationEngine.js):
const cron = require('node-cron');
class AutomationEngine {
init() {
// 从数据库加载所有自动化配置
const automations = await Automation.findAll({ where: { enabled: true } });
for (const auto of automations) {
this.registerCron(auto);
}
}
registerCron(automation) {
cron.schedule(automation.cron_expression, async () => {
console.log(`⏰ 触发自动化任务: ${automation.name}`);
try {
const workflow = await WorkflowRegistry.get(automation.workflow_id);
await workflow.execute(automation.inputs);
} catch (error) {
console.error(`自动化任务失败:`, error);
// 发送告警通知
await this.sendAlert(automation, error);
}
});
}
}📋 落地检查项
- [ ] 并发控制是否有动态调整机制?
- [ ] Cron 表达式是否经过严格验证?
- [ ] 自动化任务是否有失败重试机制?
9.6 创作工作坊引擎调度
功能概述:VisualAgent + Fish Audio + ComfyUI + Orchestrator
9.6.1 VisualAgent Prompt 工程
代码实现(backend/src/services/agents/VisualAgent.js):
class VisualAgent extends BaseAgent {
async generateThumbnailPrompt(params) {
const { video_title, content_summary, platform, style } = params;
const systemPrompt = `
你是专业的视觉设计师。请为短视频生成 AI 绘图提示词。
【输出要求】
1. positive_prompt: 正向提示词(英文,详细描述画面)
2. negative_prompt: 负向提示词(避免的元素)
3. style_tags: 风格标签(如: realistic, anime, oil painting)
4. aspect_ratio: 画面比例(9:16 / 16:9 / 1:1)
【平台特点】
- 抖音: 9:16 竖屏,明亮色彩,简洁构图
- 小红书: 3:4 或 1:1,文艺清新,留白
- B站: 16:9 横屏,信息丰富
【风格库】
- realistic: 真实摄影感
- anime: 二次元动漫风
- flat: 扁平插画风
`;
const userPrompt = `
视频标题:${video_title}
内容摘要:${content_summary}
目标平台:${platform}
期望风格:${style}
`;
const response = await this.llm.generate(systemPrompt + userPrompt);
return JSON.parse(response);
}
}Prompt 示例输出:
{
"positive_prompt": "A professional beauty influencer applying makeup, soft studio lighting, clean white background, high resolution photography, product focus, gentle smile, warm color tones, 9:16 vertical composition",
"negative_prompt": "blurry, low quality, dark, messy, cluttered, watermark, text overlay",
"style_tags": ["realistic", "commercial", "beauty"],
"aspect_ratio": "9:16"
}9.6.2 Fish Audio 配音流程
API 调用示例(backend/src/routes/voiceoverWorkflow.js):
async function generateVoiceover(text, voiceId) {
try {
// 1. 调用 Fish Audio API
const response = await axios.post('https://api.fish.audio/v1/tts', {
text,
voice_id: voiceId,
format: 'mp3',
speed: 1.0,
volume: 1.0
}, {
headers: {
'Authorization': `Bearer ${process.env.FISH_API_TOKEN}`
}
});
// 2. 下载音频文件
const audioUrl = response.data.audio_url;
const audioBuffer = await downloadFile(audioUrl);
// 3. 上传到 OSS
const ossPath = await uploadToOSS(audioBuffer, 'voiceovers');
return { success: true, audio_url: ossPath };
} catch (error) {
console.error('Fish Audio 调用失败:', error.message);
throw new Error('配音生成失败');
}
}错误处理策略:
| 错误类型 | HTTP Code | 处理方式 |
|---|---|---|
| 余额不足 | 402 | 发送充值提醒 |
| 文本过长 | 413 | 自动分段处理 |
| 音色不存在 | 404 | 回退到默认音色 |
| API 限流 | 429 | 指数退避重试 |
9.6.3 ComfyUI 动态表单生成
前端实现(frontend/src/components/workflow/ComfyUIFormGenerator.vue):
<template>
<el-form :model="formData">
<el-form-item
v-for="param in dynamicParams"
:key="param.name"
:label="param.label"
>
<!-- 文本输入 -->
<el-input
v-if="param.type === 'string'"
v-model="formData[param.name]"
:placeholder="param.default"
/>
<!-- 数字输入 -->
<el-input-number
v-else-if="param.type === 'number'"
v-model="formData[param.name]"
:min="param.min"
:max="param.max"
:step="param.step"
/>
<!-- 下拉选择 -->
<el-select
v-else-if="param.type === 'enum'"
v-model="formData[param.name]"
>
<el-option
v-for="option in param.options"
:key="option"
:label="option"
:value="option"
/>
</el-select>
</el-form-item>
</el-form>
</template>
<script>
export default {
props: ['workflowTemplate'],
data() {
return {
formData: {},
dynamicParams: []
};
},
mounted() {
// 解析 JSON 模板,生成动态表单
this.parseTemplate(this.workflowTemplate);
},
methods: {
parseTemplate(template) {
const nodes = template.nodes || [];
const params = [];
for (const node of nodes) {
if (node.inputs) {
for (const [key, value] of Object.entries(node.inputs)) {
params.push({
name: `${node.id}_${key}`,
label: `${node.title} - ${key}`,
type: this.inferType(value),
default: value,
...this.extractConstraints(value)
});
}
}
}
this.dynamicParams = params;
},
inferType(value) {
if (typeof value === 'number') return 'number';
if (Array.isArray(value)) return 'enum';
return 'string';
}
}
}
</script>9.6.4 Orchestrator 引擎路由决策
决策逻辑(backend/src/services/workflow/OrchestratorService.js):
class OrchestratorService {
async route(workflow) {
// 1. 分析工作流复杂度
const complexity = this.analyzeComplexity(workflow);
// 2. 根据复杂度选择引擎
let engine;
if (complexity.hasConditionalLogic) {
engine = 'langgraph'; // LangGraph 支持条件分支
} else if (complexity.hasUIAutomation) {
engine = 'n8n'; // N8N 擅长 Web 自动化
} else if (complexity.nodeCount < 5) {
engine = 'node'; // 简单任务直接在 Node.js 执行
} else {
engine = 'flowise'; // 默认使用 Flowise
}
console.log(`🎯 路由决策: 工作流 "${workflow.name}" → ${engine}`);
// 3. 调用对应引擎
const runner = this.getRunner(engine);
return await runner.execute(workflow);
}
analyzeComplexity(workflow) {
return {
nodeCount: workflow.nodes?.length || 0,
hasConditionalLogic: workflow.nodes?.some(n => n.type === 'if'),
hasUIAutomation: workflow.nodes?.some(n => n.type === 'browser'),
estimatedTime: this.estimateExecutionTime(workflow)
};
}
}引擎选择矩阵:
| 场景 | 引擎选择 | 原因 |
|---|---|---|
| 简单脚本改写 | Node.js | 无需复杂编排 |
| 30天蓝图生成 | LangGraph | 需要多步推理 |
| 批量采集任务 | N8N | UI 自动化能力强 |
| 知识库问答 | Flowise | 内置 RAG 组件 |
📋 落地检查项
- [ ] VisualAgent 生成的 Prompt 是否通过了绘图测试?
- [ ] Fish Audio 是否配置了备用音色?
- [ ] Orchestrator 路由决策是否有性能监控?
9.7 多端协同技术方案
功能概述:离线任务队列 + 智能提词器 + AR 辅助线
9.7.1 离线任务队列
技术方案:IndexedDB + 自动重传机制
前端实现(miniprogram/src/services/offline.js):
import { openDB } from 'idb-keyval';
class OfflineQueue {
async init() {
this.db = await openDB('offline-tasks', 1, {
upgrade(db) {
db.createObjectStore('tasks', { keyPath: 'id', autoIncrement: true });
}
});
}
// 添加离线任务
async addTask(task) {
const tx = this.db.transaction('tasks', 'readwrite');
await tx.store.add({
...task,
status: 'pending',
created_at: Date.now()
});
await tx.done;
}
// 网络恢复时自动重传
async syncAll() {
const tasks = await this.db.getAll('tasks');
const pending = tasks.filter(t => t.status === 'pending');
for (const task of pending) {
try {
await this.uploadTask(task);
await this.markAsCompleted(task.id);
} catch (error) {
console.error(`任务 ${task.id} 同步失败:`, error);
}
}
}
async uploadTask(task) {
// 上传素材到服务器
const formData = new FormData();
formData.append('file', task.file);
formData.append('project_id', task.project_id);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error('上传失败');
}
}网络监听:
// 监听网络状态
uni.onNetworkStatusChange((res) => {
if (res.isConnected) {
console.log('📶 网络已恢复,开始同步离线任务');
offlineQueue.syncAll();
}
});9.7.2 智能提词器同步
WebSocket 实时同步:
服务端(backend/src/services/WebSocketService.js):
io.on('connection', (socket) => {
// PC 端保存脚本
socket.on('save_script', async (data) => {
const { project_id, script } = data;
// 1. 保存到数据库
await Script.upsert({ project_id, content: script });
// 2. 推送到移动端
socket.to(`project:${project_id}`).emit('script_updated', { script });
});
// 移动端加入房间
socket.on('join_project', (project_id) => {
socket.join(`project:${project_id}`);
});
});移动端(miniprogram/src/pages/camera/index.vue):
import io from 'socket.io-client';
export default {
data() {
return {
script: '',
scrollSpeed: 50 // px/秒
};
},
mounted() {
this.connectWebSocket();
this.startAutoScroll();
},
methods: {
connectWebSocket() {
const socket = io(process.env.API_URL);
socket.emit('join_project', this.projectId);
socket.on('script_updated', (data) => {
this.script = data.script;
this.$message.success('脚本已同步');
});
},
// 自动滚动算法
startAutoScroll() {
const container = this.$refs.scriptContainer;
let currentScroll = 0;
setInterval(() => {
currentScroll += this.scrollSpeed / 60; // 60fps
container.scrollTo(0, currentScroll);
// 到底部后重置
if (currentScroll >= container.scrollHeight - container.clientHeight) {
currentScroll = 0;
}
}, 1000 / 60);
}
}
}9.7.3 AR 辅助线实现
Canvas 绘制(miniprogram/src/pages/camera/index.vue):
export default {
data() {
return {
gridType: 'rule_of_thirds' // 三分法 / 黄金分割 / 对角线
};
},
methods: {
drawARGrid() {
const canvas = this.$refs.arCanvas;
const ctx = canvas.getContext('2d');
const { width, height } = canvas;
ctx.clearRect(0, 0, width, height);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 2;
switch (this.gridType) {
case 'rule_of_thirds':
// 三分法线
ctx.beginPath();
ctx.moveTo(width / 3, 0);
ctx.lineTo(width / 3, height);
ctx.moveTo(width * 2 / 3, 0);
ctx.lineTo(width * 2 / 3, height);
ctx.moveTo(0, height / 3);
ctx.lineTo(width, height / 3);
ctx.moveTo(0, height * 2 / 3);
ctx.lineTo(width, height * 2 / 3);
ctx.stroke();
break;
case 'golden_ratio':
// 黄金分割线(0.618)
const golden = 0.618;
ctx.beginPath();
ctx.moveTo(width * golden, 0);
ctx.lineTo(width * golden, height);
ctx.moveTo(0, height * golden);
ctx.lineTo(width, height * golden);
ctx.stroke();
break;
case 'diagonal':
// 对角线
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(width, height);
ctx.moveTo(width, 0);
ctx.lineTo(0, height);
ctx.stroke();
break;
}
}
}
}AR 辅助线类型:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| 三分法 | 画面分为9宫格 | 人物拍摄、风景构图 |
| 黄金分割 | 0.618 比例线 | 产品展示、艺术摄影 |
| 对角线 | 两条对角线 | 动态画面、透视效果 |
| 中心十字 | 居中参考线 | 对称构图、正面拍摄 |
📋 落地检查项
- [ ] 离线队列是否有最大缓存限制?
- [ ] 提词器滚动速度是否可调?
- [ ] AR 辅助线是否支持自定义颜色?
📚 本章小结
第 9 章详细阐述了一刻工坊核心功能的技术实现,包含:
- 灵感广场:Viral Score 算法、链接解析器、一键复刻 Prompt 工程
- 账号诊断:20 问诊断逻辑、Multi-Step Reasoning 蓝图生成、断点续传
- 项目管理:Hot-Sync 冲突解决、软删除回收站、资产闭环查询
- 智能知识库:RAG 完整流程、Markdown-Aware 切片算法、强制引用机制
- 批量采集:p-limit 并发控制、Cron 自动化触发器
- 创作工作坊:VisualAgent Prompt 工程、Fish Audio 配音、ComfyUI 动态表单、Orchestrator 路由决策
- 多端协同:IndexedDB 离线队列、WebSocket 提词器同步、Canvas AR 辅助线
🔗 相关章节
- 如何使用这些功能? 查看 使用手册 - 完整操作步骤
- 如何部署外部引擎? 查看 部署手册 - 第三方 API 接入
End of Document