Skip to content

【问题汇总】常见问题解答 #700

Description

@666ghj

BettaFish 常见问题解答(持续更新)

Note

Agent 自动整理说明:本页由 Agent 根据当前代码、主线提交、Tag / Release、Issue 与 PR 中的公开讨论汇总,并由项目维护者审核后更新。请不要把 API Key、Cookie、数据库密码或完整 .env 发到 Issue。

Important

适用基线:本次整理截至 2026-07-20,当前 main40327d7。最新已发布 Release 仍是 v3.0.0,但当前 main 比它多 44 个提交,两者不能等同。以后如果代码继续变化,请以当时的 README.env.example 和源码为准。

一、版本、安装与配置

1. “最新版”到底是哪个?当前还有 GraphRAG 吗?

  • 最新已发布版本是 v3.0.0;最新代码是 main,两者之间还有 44 个主线提交。
  • 如果你要可重复地使用某个发布版,请记录 Tag;如果你在验证最新修复,请在干净分支上使用当前 main
  • 报告问题时不要只写“最新版”,请附上 git rev-parse HEAD 的输出。
  • GraphRAG 曾经合入,但后续已回退;当前 main 不包含 GraphRAG 模块。不要根据旧的 v3 介绍推断当前行为。参考 PR #503回退提交PR #592

2. 源码安装推荐哪个 Python 版本?为什么 MediaCrawler 目录是空的?

README 声明支持 Python 3.9+,但 Docker 镜像和当前主要示例都使用 Python 3.11,因此建议把 3.11 作为首选可复现基线。Python 3.14 目前会遇到锁定的 Pillow 9.5.0 安装失败,见 #337

MediaCrawler 现在是 Git 子模块,克隆时应当带上子模块:

git clone --recurse-submodules https://github.com/666ghj/BettaFish.git
cd BettaFish

如果已经克隆,但 MindSpider/DeepSentimentCrawling/MediaCrawler 为空,请在仓库根目录执行:

git submodule update --init --recursive

使用 uv 的常见安装流程:

uv venv --python 3.11
uv pip install -r requirements.txt
uv run playwright install chromium

PDF 导出的系统依赖是可选的;只需 HTML / Markdown 时可以先不安装。PDF 请按 PDF 依赖文档 配置。

3. .env 应该放在哪里?每个 Agent 可以共用一个模型吗?

  • 当前统一使用仓库根目录.env;旧文档中各子 Agent 独立配置的方式已过时。
  • 加载器会先检查当前工作目录,再检查项目根目录;因此建议始终从仓库根目录启动,避免误读子目录中的另一份 .env
  • Insight、Media、Query、Report、MindSpider、Forum Host 和 Keyword Optimizer 都有独立的 Key / Base URL / Model 配置。技术上可以填同一个模型,但不代表质量和能力都足够。Report 需要长上下文、稳定结构化输出与较强指令遵循;Media 的部分流程还需要模型具备相应的多模态能力。
  • 模型和供应商会变化,具体推荐以当前 .env.example 为准;Report Agent 优先使用强模型。

Caution

不要上传完整 .env。只需提供去秘后的变量名、供应商、Base URL 格式和模型 ID,Key 只能显示为 ***

4. 项目可以直接部署到公网吗?

不可以把默认 Web 应用直接暴露到公网。

当前配置接口没有完整的应用级认证边界,默认公网暴露可能泄露数据库凭据和 API Key,也可能导致配置被修改。请仅在本机或可信局域网内使用;如果确实需要远程访问,必须在前面增加真实的身份认证、TLS、访问控制和秘密管理。只修改 HOST、防火墙或端口映射并不等于安全。参考 #238

二、数据库、Docker 与启动

5. app.py 已经启动,为什么数据库还是空的?

python app.py 启动的是多 Agent 分析系统。它会检查/创建缺失的表,但不会自动爬取社交平台业务数据

  • MindSpider 负责将话题和平台数据写入共享数据库。
  • Query / Media / Insight 等分析 Agent 从数据库或其他数据源读取数据。
  • “表初始化成功”只代表结构就绪,不代表已经有业务数据。

源码模式下,需要先准备好可连接的 PostgreSQL / MySQL 实例、数据库和有建表权限的用户;Docker Compose 会根据 POSTGRES_* 初始化数据库容器。详见 #332MindSpider 文档

6. Docker 里的 5432 和宿主机的 5444 有什么区别?

默认 Compose 网络中:

  • BettaFish 容器连数据库:DB_HOST=dbDB_PORT=5432
  • 宿主机直接连 PostgreSQL:localhost:5444
  • DB_* 是 BettaFish 的应用连接参数;POSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_DB 是 PostgreSQL 容器初始化参数。自定义时必须保持两组参数一致。

最常见的错误是:应用运行在容器中却填 localhost:5444,或应用运行在宿主机却填 db:5432。请先确认“连接是从哪里发起的”。

修改 .env 后容器仍然使用旧配置时,请先核对根 .env 的文件挂载,再执行 docker compose up -d --force-recreate。如果拉镜像出现 content size of zero,常见原因是 Docker 29 / containerd 与镜像加速器的兼容性,应先排查 Docker 和镜像源,而不是修改 BettaFish 业务代码。参考 #533

7. 旧数据库升级后报字段类型错误,自动初始化为什么没修好?

SQLAlchemy create_all() 会创建缺失表,但不会把已有列自动迁移到新类型。例如旧库的 daily_topics.topic_id 是整数,而当前模型需要字符串,单纯更新 Python 代码不会修改旧表。

处理前先备份,然后按当前数据库方言做明确迁移;如果是可丢弃的空测试库,也可以重建后让当前代码创建结构。不要在未备份时删除生产数据库。

8. 主界面和三个 Agent 分别用哪些端口?端口占用怎么办?

  • 完整主系统:默认 5000
  • Insight Agent:8501
  • Media Agent:8502
  • Query Agent:8503

源码启动时,主服务的 HOST / PORT 由根 .env 控制。macOS 上 5000 被系统服务占用时,可把主服务改为其他端口。Docker 对外端口需要改 Compose 映射,例如 5001:5000;只改 .env PORT 不会自动修改宿主机端口映射。

当前正常退出已有优雅清理;只有异常中断后才可能留下旧进程。此时应先查明端口对应的 PID 和命令,确认是旧的 BettaFish 子进程后再结束;不要盲目清理系统中的其他进程。

9. 启动时出现健康检查连接失败,或子应用启动了但主页连不上?

健康检查会访问本机 127.0.0.1 上对应 Streamlit 端口的 /_stcore/health,启动后有 15 秒宽限期,最多等待约 90 秒。启动初期一次 connection refused 或短时 starting 不一定代表任务失败;如果程序后续能正常打开和运行,通常可以忽略这条瞬时告警。超过等待上限仍未就绪时,应查看 logs/insight.loglogs/media.loglogs/query.log 和对应端口,不要只继续拉长超时来遮住子进程退出。

如果持续失败,请依次检查:

  1. 子进程是否还存活,8501 / 8502 / 8503 是否真正监听。
  2. 对应 Agent 日志中是否有依赖、配置或导入错误。
  3. Docker 端口映射、本机防火墙、远程访问主机名是否正确。
  4. 本地子应用连接问题与外部 LLM / 搜索 / 爬虫网络问题要分开排查;当前本地健康检查已显式绕过代理,但外部请求仍可能受代理 / VPN 影响。

参考 #568#693

三、MindSpider 与爬取流程

10. 第一次跑 MindSpider 的正确顺序是什么?

数据爬取和多 Agent 分析是两个步骤。请先按 MindSpider 文档 用小规模参数打通爬取:

cd MindSpider

# 检查环境、配置和数据库
uv run main.py --status

# 方式 A:分步跑,最容易定位问题
uv run main.py --broad-topic
uv run main.py --deep-sentiment --platforms xhs dy wb --test

# 方式 B:小规模完整流程
uv run main.py --complete --test

Broad Topic 先把话题和关键词写入 daily_topics,Deep Sentiment 再读取这批关键词去各平台搜索和入库。--setup 仍存在于兼容 CLI,但当前 MindSpider 文档已将它标为废弃,常规流程优先使用自动初始化和 --status

11. 没有弹出二维码,或小红书等平台爬取失败,是不是不支持?

当前代码支持 xhs 等 MediaCrawler 平台,旧 FAQ 中“不支持小红书”的结论已经过时。但“代码包含支持”不等于第三方平台永远可用:登录、验证码、风控、签名和页面结构都可能变化。

首次运行每个目标平台时:

  1. 确认子模块和 Playwright Chromium 已安装。
  2. 将 MediaCrawler 的 HEADLESS 设为 False,观察真实登录页面。
  3. 手动扫码或完成验证,再确认登录状态已保存。
  4. 只有在登录状态已损坏且你明白后果时,才重置对应 browser_data;此操作会丢失已保存的会话,不要一上来就删。

12. --date 能爬取指定历史日期的平台内容吗?

不能把 --date 理解成第三方平台的“历史快照 API”。

  • --deep-sentiment --date YYYY-MM-DD 会优先选择数据库中该日期已有的 daily_topics 关键词批次,然后搜索当前平台能返回的内容。
  • 截至本文基线,--broad-topic --date 的日期没有传递到 Broad Topic 子程序,子程序仍按当天写入。
  • 因此 --complete --date 在历史日期上可能出现“Broad Topic 写今天,Deep Sentiment 查历史批次”的错位。

这是当前实现限制,请不要将它宣传为任意历史日期回溯功能。源码依据:MindSpider/main.pyBroadTopicExtraction/main.py

13. 如何指定自己的爬取关键词?

当前 BettaFish 的 MindSpider 高层 CLI 没有稳定的 --keywords 参数。标准流程是 Broad Topic 生成 daily_topics.keywords,Deep Sentiment 从数据库读取后再配置底层 MediaCrawler。

旧回复中提到的 MindSpider/data/daily_keywords.txt 现在会被 Broad Topic 写入,但 Deep Sentiment 不会把它当作当前关键词输入,因此手动改这个文件不是可靠方案。

如果必须使用自定义词,请把它作为高级操作:明确维护相应的 daily_topics 数据,或独立运行底层 MediaCrawler 并自行负责它的配置、数据表和登录状态。操作数据库前先备份。

14. 话题生成了,但爬取仍然是 0 条或返回码 1,怎么排查?

先用单平台、小规模参数复现,不要一开始就全平台大量爬取:

  1. 在 Broad Topic 日志和数据库中确认 daily_topics 确实有该批次的关键词。
  2. 看 Deep Sentiment 日志最终选中的话题日期和关键词,避免误以为它正在用你指定的批次。
  3. 只跑一个平台的 --test,并打开浏览器,确认登录、验证码、页面访问和搜索结果。
  4. 确认相应平台的数据表有新增记录,并核对容器/宿主机数据库地址。
  5. 附上该平台完整日志和当前提交;顶层“返回码 1”本身不足以定位原因。

四、LLM、搜索与 API 报错

15. 我没用 OpenAI 模型,为什么日志里仍然有 openai?本地模型能用吗?

openai 在这里主要是兼容客户端/请求协议,不代表你必须使用 OpenAI 官方模型。云端或本地服务只要实现项目需要的 OpenAI-compatible Chat Completions 接口,就可以尝试接入。

但“接口兼容”不等于“模型能力足够”。还要确认:

  • Base URL 是供应商实际的 Chat Completions 路由;
  • 模型 ID 完全匹配(包括大小写);
  • 上下文、结构化输出、指令遵循和超时限额能支撑相应 Agent;
  • Media 相关流程如果用到图像,模型和供应商路由也必须真正支持。

参考 #300

16. Tavily、Anspire 和 Bocha 怎么配?

  • Query / Web 搜索中的 Tavily Key 是独立配置。
  • Media 搜索工具通过 SEARCH_TOOL_TYPE 选择:使用 AnspireAPI 时,就填对应的 Anspire Key / Base URL;使用 BochaAPI 时,就填 Bocha AI Search 对应的 Key / Base URL。
  • 旧 FAQ 中“改成 Bocha Web Search 地址”的说法已不适用于当前代码。变量名中即使仍含 WEB_SEARCH,也要使用当前代码要求的 AI Search 凭据。
  • Base URL 必须包含 http://https://,并且以当前 .env.example 的域名/路由为准;自动补协议的改动尚未合入当前主线。

这三类配置不要混用。选择器、Key 和 Base URL 必须作为一组保持一致。参考 #462

17. 400 / 404 / 429 / 503 / JSON 解析错误分别怎么处理?

现象 常见含义 首先处理
400 Content Exists Risk 上游供应商的内容审核/风控拒绝 检查输入是否合规,更换合适的合规输入或可用供应商;不是 BettaFish 业务代码的 400
401 / 鉴权类 403 Key、权限、账户或路由问题 检查去秘后的 Key 所属产品、Base URL、账户权限和余额
402 账户余额或付费配额不足 在供应商端检查余额、计费状态和模型权限
404 model_not_found 模型 ID 或 Base URL 路由不存在 从供应商控制台复制精确模型 ID,核对大小写与路由
429 限流、并发或配额限制 降低并发,查配额/账户状态,按供应商重试策略稍后再试
503 no available channel 分销渠道或上游服务当前无可用通道 查供应商状态,更换可用渠道/官方端点,持续失败不要只等待代码重试
连接失败 / 超时 / 5xx 网络、代理、供应商负载或服务异常 区分偶发与持续失败,检查代理、服务状态、配额与端点
JSON 解析失败 模型未遵循结构、输出被截断或接口兼容不完整 使用更强的模型,检查上下文/超时,保留去秘后原始模型输出与完整日志

当前代码有应用级退避重试,但它也会重试部分永久性 400 / 404。如果每次都是完全相同的 400 / 404,继续等待通常不会自愈;应停止本次任务,修正内容、模型 ID 或端点后再运行。详见 #691#695#696

18. 明明有 JSON 修复和重试,为什么还会失败?

当前已有多层 JSON 清理/恢复和报告分章处理,但修复器不可能将任意一段截断、缺字段或不遵循协议的输出变成可靠结果。

持续出错时:

  1. 先更新到你要验证的明确提交,确保不是旧版 Report V1 问题。
  2. 替换为更强、更稳定的结构化输出模型,尤其是 Report Agent。
  3. 确认供应商没有截断输出,模型上下文和超时足够。
  4. 报 Issue 时附上去秘后的原始模型回复、失败阶段与完整日志。

参考 #681

五、Report Agent 与最终报告

19. 三个 Agent 看起来都跑了,为什么 Report Agent 仍然锁定?

Web 流程不是只看页面上的进度文字。Report Agent 初始化时会记录三个目录当时的 .md 文件数:

  • insight_engine_streamlit_reports
  • media_engine_streamlit_reports
  • query_engine_streamlit_reports

正常 Web 流程要求三个目录相对该基线都有新文件,并且 logs/forum.log 就绪。如果最后只保存了一份上游报告,就说明另外两个 Agent 没有完成这一轮的新输出,Report Agent 不会开始正常 Web 汇总。

请检查 /api/report/status 返回的 missing_files / 计数信息,以及三个 Agent 各自的日志。健康检查启动期的瞬时失败只要后续能正常运行,一般不是这里的根因。参考 #693#470

20. 三份上游报告已经生成,只想重跑最终报告,怎么做?

不需要再跑三个 Agent,在仓库根目录使用独立命令行工具:

python report_engine_only.py

# 可选:指定主题
python report_engine_only.py --query "你的报告主题"

# 可选:跳过 PDF
python report_engine_only.py --skip-pdf

该工具会从三个上游目录选择现有的最新 Markdown,显示文件后等待确认,并刻意跳过 Web 的“文件必须比启动时新增”检查。代码至少需要一份上游报告才能运行,但三份都齐全时信息更完整。

默认输出:

  • HTML:final_reports/
  • PDF:final_reports/pdf/
  • Markdown:final_reports/md/
  • Document IR:final_reports/ir/

如果只需要用已保存的章节 / IR 重新渲染,请使用 regenerate_latest_html.pyregenerate_latest_md.pyregenerate_latest_pdf.py

21. 最终报告太短、被截断、排版错乱或图表空白,怎么办?

当前 Report Engine V2 已经是分阶段的 Document IR 管线,支持分章生成、结构修复、HTML / PDF / Markdown 渲染,并优先使用本地 Chart.js / MathJax 等资产。因此旧 FAQ 中“打开 VPN 就能修图表”或“一次模型输出就是整份报告”的判断已经过时。

建议按以下顺序排查:

  1. 确认 Query / Media / Insight 三份上游输入都是本轮新生成且内容完整。
  2. 使用长上下文、结构化输出稳定的强 Report 模型;更换模型是重要排查项,但不是唯一原因。
  3. 检查供应商是否截断长输出、超时或返回不完整 JSON。
  4. 保留本次章节输出、IR JSON、HTML 和完整日志;图表问题要区分“IR 没有/无效数据”与“浏览器渲染失败”。
  5. 如需自定义样式,使用当前支持的 .md / .txt 报告模板,不要沿用 Report V1 的假设。

已知边界:Markdown 不会保留完整交互式 Chart.js 图表,而是降级为表格/文本;超长表格在 PDF 中的分页仍可能不够自然。这些不应被描述为“所有格式都会逐像素完全一致”。

参考 #600#681

22. PDF 生成失败会导致整个报告不能用吗?

不会。PDF 是可选输出,HTML 和 Markdown 仍可以正常生成。先运行:

python -m ReportEngine.utils.dependency_check

再根据 PDF 依赖文档 安装对应操作系统的 Pango / Cairo / GTK 等组件。Docker 镜像已包含相关系统依赖。如果暂时不需要 PDF,可以用 python report_engine_only.py --skip-pdf

请优先使用 report_engine_only.pyregenerate_latest_pdf.py。当前旧 export_pdf.py 还包含开发机器的绝对路径,不适合作为通用跨机器命令。

六、结果质量与 Agent 协作

23. 报告出现幻觉、引用不可靠或计算不对,怎么减少?

BettaFish 的结构校验和报告管线可以改善输出格式,但不能保证 LLM 生成的每个事实、引用和计算都真实。特别是 Insight 需要依赖真实的私域数据;新建空库或上游 Agent 没有产出数据时,模型更容易用看似合理的内容补空。

建议:

  • 先确认数据库真的有与任务相关的业务数据;
  • 确认三个上游 Agent 都提供了本轮输入;
  • 使用能力更强的模型,但不把“换模型”当成事实校验的替代品;
  • 对重要结论、数字、引用链接和决策依据做人工复核。

请把报告当作研究辅助材料,不要当作未经验证的事实源。参考 #277

24. Insight、Query 和 Media 的数据源有什么区别?

  • Insight Agent:主要读取共享/私域数据库中的舆情数据;当前会对命中结果做聚类和代表性抽样,不保证把数据库所有记录逐条放入上下文。
  • Query Agent:主要使用 Tavily 做外部网络/新闻搜索,并对 URL 和相关性做基本规范化/过滤。
  • Media Agent:使用当前选定的 Anspire 或 Bocha 搜索服务。

因此,“报告没有引用”不一定只是 Report Agent 的问题;应先确认对应上游 Agent 是否真的取得了有效来源。参考 #532

25. Forum Host 为什么允许各 Agent 持续通报自己的调研进展?

这是效率、信息共享与相互影响之间的权衡:

  • 各分析 Agent 应尽量独立推进,避免因为强同步而降低整体效率。
  • Host 的主要作用是共享必要信息、让其他 Agent 知道当前进展,同时避免彼此直接改写对方状态。
  • Agent 通报自己的调研进度符合这个设计目标,不等于它已经完成所有任务。

如果要评估 Host 是否真正带来了纠偏效果,建议基于具体案例做对照和消融实验,比较“无 Host”、“仅进度共享”与“允许纠偏信息”等策略,不要只凭一次运行下结论。参考 #687

26. 为什么我的结果和项目示例不一样?运行很久就是死锁吗?

示例报告取决于当时的数据库、时间、搜索结果、模型和供应商,不是确定性快照。官方武汉大学示例使用的是百万级数据库;少量本地样本不应被期待逐字复制相同内容和图表。参考 #174

多 Agent 搜索、反思、Forum 交流和分章 Report 本身会消耗大量 Token 和时间,运行很久本身不能证明死锁。应同时观察子进程是否存活、日志是否继续更新、供应商请求是否在重试,以及输出文件是否增长。如果日志长时间停在相同的永久性 4xx,应先修配置而不是继续等。

七、提 Issue 前请附上这些信息

仓库目前没有独立的 Issue 模板。为了避免反复追问,新 Issue 请尽量一次提供:

  • 使用的 Tag 或 git rev-parse HEAD 完整 SHA;
  • Docker / 源码安装方式,操作系统,Python 版本;
  • git submodule status 输出(如涉及 MindSpider / MediaCrawler);
  • 精确执行的命令和最小可复现步骤;
  • 期望结果与实际结果;
  • 完整 traceback,以及对应 Agent / MindSpider / Report 阶段的日志;
  • 去秘后的供应商、Base URL 格式、模型 ID 和搜索工具类型;
  • UI 问题的截图,以及浏览器/端口信息。

Caution

请必须删除 API Key、Cookie、Authorization Header、数据库密码、个人数据和完整 .env。如果秘密已经误发到公开 Issue,请立即在对应平台吊销并更换,仅编辑删除文字并不能保证密密未被记录。


本 Issue 将保持作为常见问题入口。如果某条答案与当前代码不一致,请附上可复现信息和当前提交,我们会持续更新。

Metadata

Metadata

Assignees

Labels

Q&AGeneral Q&A, communication with developersvaluable feedbackGood for newcomers

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions