知更 Knower
文档

知更 Knower 文档

欢迎阅读知更 Knower 的完整技术文档。本文档涵盖系统架构、算法原理、数据结构和全部 API 接口。

知更是一个 开源免费 的桌面应用,采用 MIT 协议发布。你的数据永远留在本地。

知更 Knower 是面向个人视频创作者(B站/抖音/小红书)的本地 AI 桌面工作流客户端。帮助从选题到发布,生成多平台发布物料(脚本、标题、标签、封面文案、字幕稿等)。

核心特性

  • 多平台物料生成 — 粘贴脚本,自动生成 B站、YouTube、抖音、小红书的发布物料
  • 本地数据爬取 — 支持 B站、抖音、小红书、微博的数据采集
  • 数据 100% 本地 — SQLite 存储,数据从未离开你的电脑
  • 自带 API Key — 你自己的 AI 服务密钥,我们不接触
  • AI Agent 工作流 — ReAct 循环 + 有状态条件路由 + 流式输出
  • 双协议 LLM — 同时支持 Anthropic (Claude) 和 OpenAI 标准 API
  • 选题评价算法 — 5 维度 12 指标量化评估选题爆款潜力
  • 多账号隔离 — 支持多创作者账号切换,数据互不干扰

安装

环境要求

  • 操作系统:Windows 10+(macOS 版本开发中)
  • Node.js:18+(推荐 20 LTS)
  • Python:3.10+(仅爬虫模块需要)

从源码构建

克隆仓库
git clone https://github.com/user/knower.git
cd knower
安装依赖
npm install
启动开发
npm run dev

Vite HMR + Electron 热重载将自动启动。

构建发布版本

npm run build    # tsc 类型检查 + Vite 打包 + electron-builder 打包
npm run preview  # 预览前端产物

爬虫模块初始化(可选)

cd knower-agent/crawler
setup_env.bat    # 创建 venv + 安装依赖 + 安装 Playwright

快速上手

安装完成后,按以下步骤开始使用:

  1. 启动应用后,进入 设置 页面
  2. 选择 LLM 提供商(Anthropic 或 OpenAI-compatible),填入 API Key 和模型名
  3. 进入 创作台,输入你的创作想法
  4. AI Agent 会自动执行工具调用,生成多平台物料
支持 Anthropic 原生 API(Claude 系列)和 OpenAI-compatible API(GPT、DeepSeek、通义千问等)。

创作台

创作台是知更的核心界面,提供 AI 对话式创作体验。底层运行的是一个 ReAct (Reason + Act) Agent,最大迭代 10 轮,支持工具调用和流式输出。

Agent 执行流程

graph LR U[用户输入] --> A[LLM 推理] A -->|tool_use| T[执行工具] T -->|结果返回| A A -->|end_turn| R[输出回复] A -->|auto 路由| A T -->|错误| E[重试/降级] E --> A

使用方式

在聊天输入框中输入你的创作需求,Agent 会自动决定执行哪些工具:

// 示例:生成多平台物料
用户: 帮我根据这个脚本生成 B站和小红书的发布物料

Agent 执行流程:
1. 解析用户意图 → 确定需要 analyze_script + expand_script
2. 调用 analyze_script 分析脚本内容
3. 调用 expand_script 生成多平台物料
4. 调用 save_result 保存到数据库
5. 返回最终回复

输出物料类型

物料类型说明
B站标题优化后的视频标题(10-30 字,含数字/问句/情感词)
B站标签相关话题标签,支持热度排序
小红书标题小红书风格标题(emoji + 关键词优化)
封面文案封面图文字建议(大字报风格 / 信息卡片)
拍摄清单分镜拍摄建议(景别 + 时长 + 画面描述)
字幕稿带时间戳的口播字幕

灵感库

灵感库用于管理和浏览 AI 生成的选题建议。基于爬取的平台数据和你的历史表现,AI 会为你推荐个性化选题。选题经过病毒性评分算法量化评估(详见 选题评价算法)。

选题生成流程

graph LR D[爬取数据] --> A[分析爆款规律] A --> M[匹配创作者偏好] M --> S[生成选题建议] S --> V[病毒性评分] V --> R[返回灵感库]

数据分析

数据分析页面展示爬取到的各平台数据,帮助你了解爆款规律。

  • 概览卡片 — 各平台关键指标一览(总视频数、总播放量、平均互动率)
  • 趋势图表 — 内容表现趋势可视化(按日/周聚合)
  • 爆款分析 — AI 分析高互动内容的共性(标题模式、发布时间、分类分布)

爬虫模块

MediaCrawler 多平台爬虫已集成到 knower-agent/crawler/,支持 B站、抖音、小红书、微博四个平台。通过 Node.js 子进程桥接 Python 进程。

架构

graph TB subgraph "Node.js 进程" C[crawler.js] -->|"spawn python"| SP[Python 子进程] end subgraph "Python 进程" SP --> MC[MediaCrawler] MC --> BILI[B站 API] MC --> DY[抖音 API] MC --> XHS[小红书 API] MC --> WB[微博 API] end C -->|"JSON stdout"| R[解析结果] R --> DB[(SQLite)]

Node.js 封装

// lib/crawler.js — 子进程调用
const { spawn } = require('child_process')

async function runCrawler(platform, keyword, options = {}) {
  const args = [
    'main.py',
    '--platform', platform,
    '--keyword', keyword,
    '--max-notes', String(options.maxNotes || 10),
  ]

  return new Promise((resolve, reject) => {
    const proc = spawn('python', args, {
      cwd: path.join(__dirname, '..', 'crawler'),
    })

    let stdout = ''
    proc.stdout.on('data', d => { stdout += d })
    proc.on('close', code => {
      if (code !== 0) return reject(new Error(`Exit ${code}`))
      try {
        resolve(JSON.parse(stdout))
      } catch {
        reject(new Error('Failed to parse crawler output'))
      }
    })
  })
}

Electron IPC 调用

// 渲染进程调用
const result = await window.electronAPI.runCrawler('bili', '关键词', {
  maxNotes: 10,
  specifiedId: '可选:指定UP主ID',
})

注意事项

  • 首次运行需扫码登录,登录状态保存在 mediasrc/login_state/
  • 建议 ENABLE_CDP_MODE = False(除非有远程调试 Chrome)
  • .gitignore 已排除 .venv/data/、登录状态等

选题评价算法(病毒性评分)

病毒性评分(Virality Score)是一个基于 5 个维度、12 个原始指标的量化评估系统,用于预测选题的爆款潜力。评分范围 0-100,支持 4 种预设权重方案。

算法架构

graph TB RAW["原始数据
play_count, like_count, ..."] --> IND["指标计算
computeRawIndicators"] IND --> NORM["归一化
fit-transform"] NORM --> DIM["维度融合
加权平均"] DIM --> TOTAL["总分计算
加权求和"] TOTAL --> CONF["置信度评估"] CONF --> INTERP["解读生成"] NORM -.->|"反数据泄露
fit只看训练集"| NORM

5 个评估维度

维度Key权重包含指标
互动速率velocity0.30播放速率、互动速率、互动率
话题趋势trend0.25趋势加速度、话题密度、新鲜度衰减
创作者亲和度affinity0.20分类匹配、标题相似度、风格一致性
内容模式pattern0.15标题结构、时长适配、时间适配
平台适配platformFit0.10话题密度、新鲜度衰减(跨维度复用)

12 个原始指标公式

维度 1:互动速率(velocity)

指标公式说明
play_velocityplay_count / hours_since_publish每小时播放量,衡量传播速度
engagement_velocity(like + comment + share) / hours_since_publish每小时互动量
engagement_rate(like + comment + share) / play_count互动率,play 为 0 时取 0

维度 2:话题趋势(trend)

指标公式说明
trend_accelerationavg_play_7d / avg_play_30d近 7 天 vs 近 30 天均播放量比值,>1 表示上升趋势
topic_densitycount_7d / total_recent_7d该分类在近 7 天的视频占比
freshness_decaymax(0, 1 - avg_age_days / 30)分类内 top 视频平均年龄的衰减,越新越高

维度 3:创作者亲和度(affinity)

指标公式说明
category_matchcreator_top_in_cat / creator_history.length创作者在该分类的历史 top 内容占比
title_similarity|intersection(title_words, history_words)| / |title_words|标题关键词与历史高互动标题的重叠度
style_consistencymatching_memories / total_memories标题词汇与 Agent 记忆(风格偏好)的匹配度

维度 4:内容模式(pattern)

指标公式说明
title_structure(命中数 / 5 + pattern_bonus) * 100检查数字、问句、情感词、列表体、最佳长度(10-30字)
duration_fit0.5(MVP 占位值)视频时长适配(MVP 阶段暂无视频时长数据)
timing_fitbestHours.includes(hour) ? 80 : 40发布是否在历史最优时段(top 25% 发布小时)

维度 5:平台适配(platformFit)

复用 topic_densityfreshness_decay,权重分别为 0.60 和 0.40。

归一化方法

不同量纲的指标需要归一化到 [0, 100]。系统采用 fit-transform 模式防止数据泄露:fit() 只看训练集分布,transform() 用训练集的统计量映射新值。

方法指标算法
Percentile play_velocity, engagement_velocity 计算值在训练集中的百分位排名:(count_below / n) * 100
Z-Score engagement_rate z = (x - mean) / std,映射到 [0, 100]:clamp((z + 3) / 6 * 100)
LogMinMax trend_acceleration 先取 log(x + 1) 压缩长尾,再 MinMax 映射到 [0, 100]
MinMax 其余 9 个指标 (x - min) / (max - min) * 100

维度内融合

每个维度内,指标按子权重加权平均:

// 以 velocity 维度为例
dim_score = (play_velocity * 0.30 + engagement_velocity * 0.40 + engagement_rate * 0.30)
          / (0.30 + 0.40 + 0.30)

维度间融合(总分)

total_score = sum(dim_score[i] * dim_weight[i]) / sum(dim_weight[i])

预设权重方案

预设velocitytrendaffinitypatternplatformFit适用场景
default0.300.250.200.150.10通用平衡
newCreator0.250.350.050.200.15新创作者(重趋势、轻亲和度)
mature0.300.200.300.150.05成熟创作者(重亲和度)
trendHunter0.200.450.100.150.10追热点型(重趋势)

置信度评估

根据可用维度数量评估评分可信度:

等级条件含义
high≥5 个维度有数据评分高度可信
medium3-4 个维度有数据部分维度缺失,有一定偏差
low1-2 个维度有数据数据不足,仅供参考
none0 个维度有数据无法评分

标题结构评分算法

// computeTitleStructure — 检查 5 个维度
let score = 0, total = 5
if (/\d/.test(title)) score++                    // 包含数字
if (/[??为什么怎么如何]/.test(title)) score++   // 问句
if (/震撼|太绝|惊艳|离谱|炸裂|绝了|必看|宝藏/.test(title)) score++  // 情感词
if (/盘点|合集|推荐|分享|总结|个方法|个技巧/.test(title)) score++    // 列表体
if (title.length >= 10 && title.length <= 30) score++  // 最佳长度

// 如果有历史 pattern 数据,加权 bonus
const patternBonus = min(matchCount / topPatterns.length, 0.3)
return min((score / total + patternBonus) * 100, 100)

Agent 引擎概述

知更的 AI Agent 是一个基于 ReAct (Reason + Act) 范式的有状态工作流引擎。核心组件位于 knower-agent/agent/

组件架构

graph TB subgraph "Agent 引擎" CORE["core.js
ReAct 主循环"] STATE["state.js
状态机"] ROUTER["router.js
条件路由"] PROC["processor.js
结果处理"] TOOLS["tools/
8 个工具"] CACHE["cache.js
提示词缓存"] end subgraph "LLM 层" ANTH["anthropic.js
Anthropic SDK"] OAI["openai-compat.js
OpenAI 兼容"] end subgraph "数据层" DB["db/index.js
SQLite WASM"] MEM["memories
Agent 记忆"] end CORE --> STATE CORE --> ROUTER CORE --> PROC CORE --> TOOLS CORE --> CACHE CORE --> ANTH CORE --> OAI TOOLS --> DB PROC --> MEM

核心配置常量

const MAX_ITERATIONS = 10  // 最大 ReAct 循环次数
const TOOL_TIMEOUT = {
  default: 30000,          // 一般工具 30s 超时
  crawl_data: 120000,      // 爬虫工具 120s 超时
  crawl_data_batch: 120000,
}
const MAX_RETRIES = 2      // 工具执行最大重试次数

ReAct 循环(深入)

ReAct 循环是 Agent 的核心执行逻辑,位于 agent/core.js

flowchart TD START([开始]) --> INIT[初始化 AgentState] INIT --> PROMPT[构建系统提示词
+ 上下文] PROMPT --> LLM[调用 LLM
chat / stream] LLM --> STOP{stopReason?} STOP -->|"tool_use"| ROUTE{Router 判断} ROUTE -->|"工具兼容"| EXEC[执行工具
executeToolWithRetry] ROUTE -->|"工具不兼容"| WARN[记录警告
继续执行] WARN --> EXEC EXEC --> RESULT{执行成功?} RESULT -->|"成功"| PROC[processToolResult
更新 State] RESULT -->|"可重试错误"| RETRY[指数退避重试
1s, 2s, ...] RETRY --> EXEC RESULT -->|"不可重试"| ERR[记录错误
更新 State] PROC --> ITER{迭代次数未达上限?} ERR --> ITER ITER -->|"是"| PROMPT ITER -->|"否"| FORCED[强制结束
返回当前结果] STOP -->|"end_turn"| CHECK{State 检查} CHECK -->|"需要自动操作"| AUTO[auto_analyze /
auto_generate / auto_save] AUTO --> PROMPT CHECK -->|"任务完成"| DONE([返回回复]) CHECK -->|"idle 无操作"| DONE FORCED --> DONE

executeToolWithRetry 算法

async function executeToolWithRetry(tool, input, maxRetries = 2) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const result = await tool.execute(input)
      if (result.error && isRetryableError(result.error)) {
        await sleep(1000 * (attempt + 1))  // 指数退避
        continue
      }
      return result
    } catch (err) {
      if (isRetryableError(err.message) && attempt < maxRetries) {
        await sleep(1000 * (attempt + 1))
        continue
      }
    }
  }
  return { error: '工具执行失败', retryable: false }
}

// 可重试错误模式
const retryablePatterns = [
  'timeout', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED',
  'rate limit', '429', '503', '502',
  'network', 'fetch failed',
]

有限状态机

Agent 使用有限状态机(FSM)管理工作流状态,位于 agent/state.js。状态转换遵循严格的合法转换表。

stateDiagram-v2 [*] --> idle idle --> crawling: crawl_data idle --> analyzing: analyze_script idle --> querying: query_data idle --> suggesting: suggest_topics crawling --> analyzing: 数据就绪 crawling --> idle: 取消 crawling --> done: 完成 analyzing --> generating: 分析完成 analyzing --> idle: 取消 analyzing --> done: 完成 generating --> saving: 生成完成 generating --> idle: 取消 generating --> done: 完成 saving --> idle: 保存完成 saving --> done: 完成 querying --> idle: 查询完成 querying --> done: 完成 suggesting --> idle: 建议完成 suggesting --> done: 完成 done --> idle: 重置

合法转换表(VALID_TRANSITIONS)

const transitions = {
  idle:      ['crawling', 'analyzing', 'querying', 'suggesting'],
  crawling:  ['analyzing', 'idle', 'done'],
  analyzing: ['generating', 'idle', 'done'],
  generating:['saving', 'idle', 'done'],
  saving:    ['idle', 'done'],
  querying:  ['idle', 'done'],
  suggesting:['idle', 'done'],
  done:      ['idle'],
}

State 数据结构

class AgentState {
  phase: 'idle' | 'crawling' | 'analyzing' | 'generating' | 'saving' | 'querying' | 'suggesting' | 'done'
  script: string | null          // 用户输入的脚本
  analysis: object | null        // 分析结果
  materials: object | null       // 生成的物料
  crawlData: array | null        // 爬取结果
  crawlStats: object | null      // 爬取统计
  topicSuggestions: array | null // 选题建议
  errors: string[]               // 错误列表
  warnings: string[]             // 警告列表
  userPreferences: object        // 用户偏好(来自 memories)
  toolHistory: array             // 已执行工具历史
  metadata: {
    startTime: number,           // 开始时间戳
    toolCallCount: number,       // 工具调用次数
    iterationCount: number,      // ReAct 迭代次数
    platforms: string[],         // 相关平台
    targetPlatforms: string[],   // 目标平台
  }
}

getNextAction 决策逻辑

当 LLM 返回 end_turn(无工具调用)时,Router 根据当前 State 决定下一步:

  • idle + 有 script 但无 analysis → 自动触发 auto_analyze
  • analyzing + analysis 已就绪 → 自动触发 auto_generate
  • generating + materials 已就绪 → 自动触发 auto_save
  • 其他情况 → 返回 continue,等待下一轮

工具系统

Agent 可调用 8 个工具,每个工具有独立的输入模式(input_schema)、执行逻辑和超时设置。工具定义位于 agent/tools/

工具清单

工具名文件超时功能
analyze_scriptanalyze_script.js30s分析用户输入的脚本/想法,提取关键信息
expand_scriptexpand_script.js30s基于分析结果生成多平台发布物料
crawl_datacrawl_data.js120s调用 MediaCrawler 爬取单平台数据
crawl_data_batchcrawl_data_batch.js120s批量爬取多平台数据
query_dataquery_data.js30s查询本地数据库中的历史数据
save_resultsave_result.js30s将生成结果保存到数据库
request_user_inputrequest_user_input.js30s向用户请求额外信息
suggest_topicssuggest_topics.js30s基于数据生成选题建议

工具-阶段兼容矩阵

Router 在执行工具前会检查工具与当前 State 阶段的兼容性:

阶段可用工具
idlecrawl_data, crawl_data_batch, query_data, suggest_topics, request_user_input, analyze_script
crawlingcrawl_data, crawl_data_batch, query_data
analyzinganalyze_script, request_user_input
generatingexpand_script
savingsave_result
queryingquery_data
suggestingsuggest_topics
done(无可用工具)

工具调用序列图

sequenceDiagram participant U as 用户 participant A as Agent Core participant L as LLM participant T as Tool U->>A: 发送消息 A->>L: 构建 prompt + messages L-->>A: tool_use: analyze_script A->>T: execute(input) T-->>A: { script: {...} } A->>A: processToolResult 更新 State A->>L: 发送工具结果 L-->>A: tool_use: expand_script A->>T: execute(input) T-->>A: { materials: {...} } A->>A: processToolResult 更新 State A->>L: 发送工具结果 L-->>A: end_turn: 文本回复 A->>A: auto_save save_result A->>U: 返回最终回复

LLM 客户端(双协议架构)

系统同时支持 Anthropic 原生 API 和 OpenAI-compatible API,两个客户端实现统一接口。

统一接口规范

// 两个客户端都实现相同接口
interface LLMClient {
  chat({ system, messages, tools, maxTokens, temperature }): Promise<{
    content: ContentBlock[],    // Anthropic-style content blocks
    stopReason: 'tool_use' | 'end_turn',
    usage: { input_tokens, output_tokens }
  }>

  async *stream({ system, messages, tools, maxTokens, temperature, signal }): AsyncGenerator<
    | { type: 'text', text: string }
    | { type: 'final', content: ContentBlock[], stopReason, toolUseInputs, hasToolUse, usage }
  >
}

Anthropic 客户端

配置项说明示例
provider固定为 anthropicanthropic
apiKeyAnthropic API Keysk-ant-api03-xxx
baseUrlAPI 端点(可选)https://api.anthropic.com
modelClaude 模型名claude-sonnet-4-20250514

API 端点: POST /v1/messages

认证头: x-api-key: {apiKey}

流式协议: Server-Sent Events (SSE),事件类型包括 content_block_startcontent_block_deltacontent_block_stop

OpenAI-Compatible 客户端

配置项说明示例
provideranthropic 的任意值openai / deepseek / qwen
apiKey对应服务的 API Keysk-xxx
baseUrlAPI 端点https://api.openai.com/v1
model模型名gpt-4o / deepseek-chat

API 端点: POST /v1/chat/completions

认证头: Authorization: Bearer {apiKey}

流式协议: SSE,标准 OpenAI 格式(data: {choices: [{delta: {...}}]}

格式转换层

OpenAI 客户端内部进行 Anthropic ↔ OpenAI 格式转换:

  • 工具定义: Anthropic input_schema → OpenAI function.parameters
  • 消息格式: Anthropic tool_result blocks → OpenAI role: 'tool' messages
  • 工具调用: Anthropic tool_use blocks → OpenAI tool_calls 数组
  • 输出归一化: OpenAI tool_calls → Anthropic-style tool_use content blocks

LLM 流式状态机

stateDiagram-v2 [*] --> Waiting: 发起请求 Waiting --> ReceivingText: 收到 text_delta Waiting --> ReceivingTool: 收到 tool_call delta ReceivingText --> ReceivingText: 继续 text_delta ReceivingText --> ReceivingTool: 收到 tool_call delta ReceivingTool --> ReceivingTool: 继续 tool_call fragment ReceivingText --> Final: 收到 DONE final ReceivingTool --> Final: 收到 DONE final Final --> [*]: yield final event

API 配置

在设置页面配置 LLM 服务。支持 Anthropic (Claude) 和 OpenAI-compatible 两种协议。

配置项说明

配置项说明Anthropic 示例OpenAI 示例
providerLLM 提供商anthropicopenai / deepseek
apiKeyAPI Keysk-ant-api03-xxxsk-xxx
baseUrlAPI 端点https://api.anthropic.comhttps://api.openai.com/v1
model模型名claude-sonnet-4-20250514gpt-4o
Anthropic 使用 x-api-key 认证头,OpenAI 使用 Bearer token。系统根据 provider 字段自动选择正确的客户端和认证方式。
API Key 仅存储在本地 electron-store 中,不经过任何第三方服务器。

平台参数

平台platform 值说明特殊参数
B站biliBilibili 视频平台specifiedId(指定视频ID), creatorId(指定UP主ID)
抖音dy需要 Node.js(JS 签名)-
小红书xhs图文/视频笔记-
微博wb微博内容-

数据库

使用 sql.js(WebAssembly 版 SQLite)本地数据库 knower.db。支持防抖写入(2s 延迟)和进程退出时强制刷盘。

写入策略

// 防抖写入:2s 内多次修改只写一次
let _dirty = false
let _saveTimer = null

function saveDb() {
  _dirty = true
  if (_saveTimer) return
  _saveTimer = setTimeout(() => {
    if (!_dirty || !db) return
    _dirty = false
    const data = db.export()      // 导出为 Uint8Array
    const buffer = Buffer.from(data)
    fs.writeFileSync(DB_PATH, buffer)
  }, 2000)
}

// 进程退出时强制刷盘
process.on('exit', flushDb)
process.on('SIGINT', () => { flushDb(); process.exit() })
process.on('SIGTERM', () => { flushDb(); process.exit() })

数据库模块导出 42+ 个函数,覆盖所有表的 CRUD 操作。


数据库 Schema

完整 Schema 包含 10 张表,支持多账号数据隔离。

erDiagram accounts ||--o{ scripts : has accounts ||--o{ conversations : has accounts ||--o{ memories : has accounts ||--o{ crawl_tasks : has conversations ||--o{ messages : has crawl_tasks ||--o{ crawl_content : has accounts ||--o{ topic_suggestions : has

accounts — 多创作者账号管理

CREATE TABLE IF NOT EXISTS accounts (
  id          TEXT PRIMARY KEY,
  name        TEXT NOT NULL,
  platform    TEXT NOT NULL,
  uid         TEXT DEFAULT '',
  avatar_url  TEXT DEFAULT '',
  description TEXT DEFAULT '',
  is_active   INTEGER DEFAULT 0,
  user_id     TEXT NOT NULL DEFAULT 'default',
  created_at  DATETIME DEFAULT (datetime('now','localtime')),
  updated_at  DATETIME DEFAULT (datetime('now','localtime'))
)

scripts — 脚本存储

CREATE TABLE IF NOT EXISTS scripts (
  id         INTEGER PRIMARY KEY AUTOINCREMENT,
  content    TEXT NOT NULL,
  analysis   TEXT,
  result     TEXT,
  account_id TEXT NOT NULL DEFAULT 'default',
  created_at DATETIME DEFAULT (datetime('now','localtime'))
)

conversations — 对话记录

CREATE TABLE IF NOT EXISTS conversations (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  title       TEXT NOT NULL DEFAULT '新对话',
  is_pinned   INTEGER DEFAULT 0,
  account_id  TEXT NOT NULL DEFAULT 'default',
  created_at  DATETIME DEFAULT (datetime('now','localtime')),
  updated_at  DATETIME DEFAULT (datetime('now','localtime'))
)

messages — 消息

CREATE TABLE IF NOT EXISTS messages (
  id              INTEGER PRIMARY KEY AUTOINCREMENT,
  conversation_id INTEGER NOT NULL,
  role            TEXT NOT NULL,          -- 'user' | 'assistant' | 'system'
  content         TEXT NOT NULL,
  created_at      DATETIME DEFAULT (datetime('now','localtime')),
  FOREIGN KEY (conversation_id) REFERENCES conversations(id)
)

memories — Agent 记忆

CREATE TABLE IF NOT EXISTS memories (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  account_id  TEXT NOT NULL DEFAULT 'default',
  type        TEXT NOT NULL,          -- 'style' | 'preference' | 'topic'
  key         TEXT NOT NULL,
  value       TEXT NOT NULL,
  evidence    TEXT,
  weight      REAL NOT NULL DEFAULT 0.5,
  created_at  TEXT NOT NULL,
  updated_at  TEXT NOT NULL
)

crawl_tasks — 爬取任务

CREATE TABLE IF NOT EXISTS crawl_tasks (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  platform      TEXT NOT NULL,
  keywords      TEXT,
  crawler_type  TEXT DEFAULT 'search',
  status        TEXT DEFAULT 'pending',  -- 'pending' | 'running' | 'done' | 'error'
  result_json   TEXT,
  account_id    TEXT NOT NULL DEFAULT 'default',
  created_at    DATETIME DEFAULT (datetime('now','localtime')),
  completed_at  DATETIME
)

crawl_content — 爬取内容数据

CREATE TABLE IF NOT EXISTS crawl_content (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  task_id       INTEGER,
  platform      TEXT NOT NULL,
  content_type  TEXT,
  content_id    TEXT,
  title         TEXT,
  "desc"        TEXT,
  author_name   TEXT,
  author_id     TEXT,
  like_count    INTEGER DEFAULT 0,
  comment_count INTEGER DEFAULT 0,
  share_count   INTEGER DEFAULT 0,
  play_count    INTEGER DEFAULT 0,
  created_at    TEXT,
  raw_json      TEXT,
  category      TEXT DEFAULT '未分类',
  source_uid    TEXT DEFAULT '',
  source_name   TEXT DEFAULT '',
  fetched_at    DATETIME DEFAULT (datetime('now','localtime')),
  FOREIGN KEY (task_id) REFERENCES crawl_tasks(id),
  UNIQUE(platform, content_id)
)

topic_suggestions — 选题建议

CREATE TABLE IF NOT EXISTS topic_suggestions (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  account_id  TEXT NOT NULL DEFAULT 'default',
  title       TEXT NOT NULL,
  description TEXT,
  score       REAL DEFAULT 0,
  reasoning   TEXT,
  source      TEXT DEFAULT 'ai',
  status      TEXT DEFAULT 'pending',  -- 'pending' | 'approved' | 'rejected'
  created_at  DATETIME DEFAULT (datetime('now','localtime'))
)

content_notes — 创作者笔记

CREATE TABLE IF NOT EXISTS content_notes (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  account_id  TEXT NOT NULL DEFAULT 'default',
  title       TEXT,
  content     TEXT NOT NULL,
  tags        TEXT,
  created_at  DATETIME DEFAULT (datetime('now','localtime')),
  updated_at  DATETIME DEFAULT (datetime('now','localtime'))
)

content_library — 内容素材库

CREATE TABLE IF NOT EXISTS content_library (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  account_id  TEXT NOT NULL DEFAULT 'default',
  type        TEXT NOT NULL,          -- 'reference' | 'template' | 'asset'
  title       TEXT,
  content     TEXT NOT NULL,
  metadata    TEXT,
  created_at  DATETIME DEFAULT (datetime('now','localtime'))
)

IPC 通道全表

渲染进程通过 contextBridge 与主进程通信,安全配置:contextIsolation: truenodeIntegration: false。所有 handler 使用 ipcMain.handle / ipcRenderer.invoke 模式。

设置存储

通道方向参数返回说明
store:getR→Mkey: stringany读取 electron-store
store:setR→Mkey: string, value: anyvoid写入 electron-store

对话管理

通道方向参数返回
conversation:listR→MaccountId?: stringConversation[]
conversation:createR→Mtitle: string, accountId{ id: number }
conversation:renameR→Mid: number, title: stringvoid
conversation:deleteR→Mid: numbervoid
conversation:togglePinR→Mid: numbervoid

消息管理

通道方向参数返回
messages:getR→MconversationId: numberMessage[]
messages:addR→MconversationId, role, content{ id: number }

脚本管理

通道方向参数返回
script:saveR→Mcontent, analysis, result, accountId{ id: number }
script:listR→MaccountId?: stringScript[]

爬虫

通道方向参数返回
crawler:runR→Mplatform, keyword, optionsCrawlResult

账号管理

通道方向参数返回
account:listR→M-Account[]
account:createR→Mname, platform, uid?Account
account:switchR→MaccountId: stringvoid
account:deleteR→MaccountId: stringvoid

数据查询

通道方向参数返回
data:crawlContentR→MaccountId?CrawlContent[]
data:crawlTasksR→MaccountId?CrawlTask[]
data:statsR→MaccountId?Stats

选题管理

通道方向参数返回
topic:listR→MaccountId?TopicSuggestion[]
topic:createR→Mtitle, description, score, accountIdTopicSuggestion
topic:updateStatusR→Mid, statusvoid
topic:deleteR→Midvoid

笔记与素材

通道方向参数返回
note:listR→MaccountId?Note[]
note:createR→Mtitle, content, tags, accountIdNote
note:updateR→Mid, title?, content?, tags?void
note:deleteR→Midvoid
library:listR→MaccountId?LibraryItem[]
library:createR→Mtype, title, content, metadata?, accountIdLibraryItem
library:deleteR→Midvoid

记忆系统

通道方向参数返回
memory:listR→MaccountId?, type?Memory[]
memory:upsertR→Mtype, key, value, evidence?, weight?, accountIdMemory
memory:deleteR→Midvoid

窗口控制

通道方向说明
window:minimizeR→M最小化窗口
window:maximizeR→M最大化/还原窗口
window:closeR→M关闭窗口

事件流(M→R)

事件方向说明
agent:progressM→RAgent 执行进度(阶段、工具名、进度百分比)
agent:streamM→RLLM 流式输出文本块
agent:tool-callM→R工具调用开始/完成/错误
topic:toChatM→R从灵感库发送选题到创作台

技术栈

技术版本用途
Electron33桌面应用框架
React18UI 渲染(Hooks API)
TypeScript5.6类型安全(strict mode)
Vite6构建工具 + HMR
vite-plugin-electron-Electron 主进程/preload 分离构建
Tailwind CSS3.4样式系统(暗色主题)
sql.js-WASM 版 SQLite(本地数据库)
@anthropic-ai/sdk-Anthropic Claude API 客户端
gsap-动画库(页面过渡、折叠动画)
@phosphor-icons/react-图标库
MediaCrawler-多平台数据爬取(Python)

项目结构

knower/
├── electron/
│   ├── main.ts              # 主进程:窗口创建(~48个IPC handler)
│   └── preload.ts           # contextBridge暴露~50个方法
├── src/
│   ├── App.tsx              # 页面路由 (useState<Page>)
│   ├── components/
│   │   ├── ChatView.tsx     # 创作台(Agent流式输出)
│   │   ├── Sidebar.tsx      # 侧边栏(导航+对话历史)
│   │   ├── AccountSwitcher.tsx  # 多账号切换
│   │   ├── MaterialCards.tsx # 物料卡片展示
│   │   ├── SettingsView.tsx # API配置页
│   │   ├── TopicsView.tsx   # 灵感库
│   │   └── DataView.tsx     # 数据分析
│   ├── contexts/
│   │   ├── ToastContext.tsx  # 全局Toast
│   │   ├── PlatformContext.tsx # 平台信息
│   │   └── AccountContext.tsx  # 账号状态
│   ├── lib/
│   │   └── gsap.ts          # 页面过渡动画
│   ├── types/
│   │   └── electron.ts      # IPC类型定义
│   └── index.css            # Tailwind组件样式
├── knower-agent/
│   ├── agent/
│   │   ├── core.js          # ReAct主循环(MAX_ITERATIONS=10)
│   │   ├── state.js         # 有限状态机(8状态)
│   │   ├── router.js        # 条件路由+工具兼容检查
│   │   ├── processor.js     # 工具结果处理+上下文构建
│   │   ├── cache.js         # 系统提示词缓存
│   │   └── tools/           # 8个工具实现
│   │       ├── analyze_script.js
│   │       ├── expand_script.js
│   │       ├── crawl_data.js
│   │       ├── crawl_data_batch.js
│   │       ├── query_data.js
│   │       ├── save_result.js
│   │       ├── request_user_input.js
│   │       └── suggest_topics.js
│   ├── llm/
│   │   ├── index.js         # LLM客户端工厂
│   │   ├── anthropic.js     # Anthropic SDK封装
│   │   └── openai-compat.js # OpenAI兼容(格式转换层)
│   ├── virality-score/
│   │   ├── index.js         # 统一入口
│   │   ├── metrics.js       # 12个指标计算
│   │   ├── normalizer.js    # 4种归一化器(fit-transform)
│   │   └── scorer.js        # 维度融合+置信度+解读
│   ├── db/
│   │   └── index.js         # SQLite WASM(10表,42+函数)
│   ├── lib/
│   │   └── crawler.js       # Python子进程桥接
│   └── crawler/             # MediaCrawler Python模块
├── tailwind.config.js       # 颜色和字体定义
├── vite.config.ts           # Vite + electron构建配置
└── tsconfig.json

系统架构图

graph TB subgraph "Electron 渲染进程" UI["React UI"] IPC["electronAPI
(contextBridge)"] end subgraph "Electron 主进程" MT["main.ts"] HANDLERS["~48 IPC Handlers"] WIN["BrowserWindow
frame:false, vibrancy"] end subgraph "Agent Core (Node.js)" REACT["ReAct 循环
core.js"] STATE["状态机
state.js"] ROUTER["路由器
router.js"] TOOLS["8 个工具
tools/"] end subgraph "LLM 层" ANTH["Anthropic
Claude API"] OAI["OpenAI-compat
GPT/DeepSeek/..."] end subgraph "数据层" DB["SQLite WASM
knower.db
10表, 42+函数"] MEM["Agent 记忆
memories表"] end subgraph "外部服务" CRAWL["MediaCrawler
Python 子进程"] BILI["B站 API"] DY["抖音 API"] XHS["小红书 API"] WB["微博 API"] end UI <-->|"IPC"| IPC IPC <-->|"ipcMain.handle"| HANDLERS MT --> WIN HANDLERS --> REACT REACT --> STATE REACT --> ROUTER REACT --> TOOLS REACT --> ANTH REACT --> OAI TOOLS --> DB TOOLS --> CRAWL CRAWL --> BILI CRAWL --> DY CRAWL --> XHS CRAWL --> WB ROUTER --> MEM

分支约定

分支用途
main稳定版本
dev开发分支
feat/xxx功能分支

提交规范

提交格式:type(scope): 描述

type说明示例
feat新功能feat(chat): 接入 streaming API
fix修复fix(settings): 修复 API key 保存
refactor重构refactor(agent): 有状态条件路由替代 while 循环
style样式style: 调整侧边栏间距
docs文档docs: 更新 API 配置说明
chore杂项chore: 升级 Electron 版本

贡献指南

欢迎贡献代码!请遵循以下步骤:

  1. Fork 仓库并创建功能分支 feat/your-feature
  2. 按照提交规范进行开发
  3. 确保 npm run build 通过
  4. 提交 Pull Request 到 dev 分支
每个功能模块独立,互不耦合。代码全部开源(MIT 协议)。

许可证

知更 Knower 采用 MIT License 开源协议发布。

你可以自由地使用、修改和分发本软件,但需保留原始版权声明和许可证。