企业做内容营销时经常卡在两段之间:通用 AI 写作工具不了解你的企业,写出来的东西「像 AI、不像你」;矩阵分发工具只负责发,不负责写。中间那段把素材喂给 AI、改格式、逐个平台登录的体力活,没人愿意天天干。BullFlow(推量牛)的思路是把这三段串成一条闭环——先把企业的公司、品牌、产品、客户、案例和文档沉淀成专属知识库,再由 Agent 基于这些资产创作文章、图文、图片、视频,最后一键分发到 17 个社媒平台,发布结果再回流分析。

零调用费的 RAG 链路

这个项目最值得先说的一个判断是:整条 RAG 链路不碰付费模型。文档 OCR、语义分句、向量化、重排、以文搜图、语音转录,全部用开源模型本地部署——OCR 是 PaddleOCR PP-StructureV3,分句是 wtpsplit SaT,向量是 BGE-M3(1024 维),重排是 BGE-Reranker-v2-m3,搜图是 OpenCLIP ViT-L-14,转录是 WhisperX。这意味着知识库建得再大、检索得再频繁,也没有一分钱调用费,企业资料也不出内网。只有最后「写文章、出图、出视频」这一步才调用大模型,而且走 OpenAI 兼容接口,供应商随你换。

文档入库的四级降级链

把企业文档吃进去,是整条链路的起点。它支持 12 种格式(PDF / Word / Excel / PPT / Markdown / HTML / EPUB 等),解析走一条四级降级链:每一级失败都会记日志再自动降级。这个设计可以抽象成一段逻辑,自己写出来也不复杂:

# 文档解析降级链:按优先级逐级尝试,失败记录原因再降级
def parse_document(path):
    chain = [
        ("ocr", parse_with_paddleocr),    # PaddleOCR:PDF/图片版面+表格结构化
        ("pandoc", parse_with_pandoc),    # Pandoc 转 GFM Markdown:docx/html/epub 等
        ("native", parse_native),         # PyMuPDF / python-docx / openpyxl 原生解析
        ("binary", store_binary_only),    # 兜底:识别文件头,无法提文本则仅存储
    ]
    for name, fn in chain:
        try:
            return name, fn(path)
        except Exception as e:
            log(f"[{name}] 解析失败,降级:{e}")
    return "binary", store_binary_only(path)

四级链的意义在于:扫描版 PDF 走 OCR,普通 Word 走 Pandoc,PPTX 内嵌图片并发 OCR,实在提不出文本的旧版二进制格式(doc/xls/ppt)就「仅存储」不入库,而不是让整个入库任务失败。

混合检索与 RRF 融合

检索这一层做的是「三库同步入库」:MySQL 存分块原文,Milvus 存 BGE-M3 向量,Elasticsearch 存 IK 分词全文索引。查询时向量召回和全文召回并行各取 top_k×3,再用 RRF 融合,可选重排。RRF(Reciprocal Rank Fusion)本身是公开算法,写出来能直接跑:

# RRF 融合:给向量召回与全文召回各自排序,按倒数排名加权合并
def rrf_fusion(vector_rank, fulltext_rank, k=60):
    score = {}
    for doc_id, rank in vector_rank.items():
        score[doc_id] = score.get(doc_id, 0) + 1.0 / (k + rank)
    for doc_id, rank in fulltext_rank.items():
        score[doc_id] = score.get(doc_id, 0) + 1.0 / (k + rank)
    return sorted(score.items(), key=lambda x: -x[1])

# 示例:向量召回排第 1 的文档,全文召回排第 3,融合后靠前
print(rrf_fusion({"a": 1, "b": 2}, {"a": 3, "c": 1}))

关键配置在 backend/.env 里,几个值直接决定检索行为:

# 混合检索关键配置(backend/.env)
HYBRID_MERGE_MODE=rrf            # 融合方式:rrf / weighted
HYBRID_VECTOR_WEIGHT=0.6         # weighted 模式下的向量权重
HYBRID_FULLTEXT_WEIGHT=0.4       # weighted 模式下的全文权重
RERANKER_ENABLED=false           # 是否开启 BGE-Reranker 重排
CHUNK_SIZE=2048                  # 普通块最大字符数

融合默认用 RRF(k=60),也可切换成归一化加权(默认向量 0.6 / 全文 0.4);向量分低于阈值(默认 0.40)直接丢弃,命中块再自动拼上前后相邻块给模型更完整的上下文。这套「并行召回 + 融合 + 阈值过滤 + 相邻扩展」的组合,比把 PDF 直接丢给模型要工程化得多。

分发网关与账号安全

分发由独立的推量发网关提供,国内 11 个平台(抖音、小红书、视频号、公众号、知乎等)走灵径,海外 6 个(LinkedIn、YouTube、X 等)走 Composio OAuth。防关联是矩阵账号的命门:代理 IP 按区域粘性分配,同一 IP 同一平台最多 15 个账号,每 20 分钟健康巡检并自动迁移,14 天未用的账号自动回收停止计费。发布结果通过 Webhook 回流,HMAC-SHA256 签名加时间戳防重放。

几个工程约定

读这份 README 能挖出几条通用约定,值得抄:多租户是所有业务表带 user_id,MySQL、Milvus、ES 三处检索强制按用户过滤,漏了任何一处就是跨租户泄露;时间统一 UTC,写库用 utcnow;上传/生成立即返回、后台任务独立会话处理,ML 推理走 asyncio.to_thread 不阻塞事件循环。计费上它做了「后付费防透支」——生成前按预估校验余额、生成后按实际用量扣,余额不足扣到 0,杜绝少量余额无限使用。

适用边界

最需要泼冷水的两点:一是分发要真正登录各平台,依赖灵径和 Composio 两个第三方服务,得自行开通账号;不配置的话,知识库、AI 创作、内容生成这些能力不受影响,但分发用不了。二是 OCR(PaddleOCR)建议用 NVIDIA GPU,纯 CPU 跑扫描版 PDF 会慢。另外它是 MIT 协议可商用,但商用前各组件(FFmpeg、Milvus、BGE 等)的许可证要自己确认。

一句话,BullFlow 的价值不在「又一个 AI 写作工具」,而在它把「懂企业、写内容、发全网、回流数据」这条最容易被拆成三四个 SaaS 拼在一起的链路,收进了一个能私有化部署的工程里。想复用的话,最值得抄的是 RRF 混合检索和四级解析降级链这两处。