【问题汇总】常见问题解答
BettaFish 常见问题解答(持续更新)
[!NOTE] Agent 自动整理说明:本页由 Agent 根据当前代码、主线提交、Tag / Release、Issue 与 PR 中的公开讨论汇总,并由项目维护者审核后更新。请不要把 API Key、Cookie、数据库密码或完整
.env发到 Issue。
[!IMPORTANT] 适用基线:本次整理截至 2026-07-20,当前
main为40327d7。最新已发布 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 chromiumPDF 导出的系统依赖是可选的;只需 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_* 初始化数据库容器。详见 #332 和 MindSpider 文档。
6. Docker 里的 5432 和宿主机的 5444 有什么区别?
默认 Compose 网络中:
- BettaFish 容器连数据库:
DB_HOST=db、DB_PORT=5432。 - 宿主机直接连 PostgreSQL:
localhost:5444。 DB_*是 BettaFish 的应用连接参数;POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_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.log、logs/media.log、logs/query.log 和对应端口,不要只继续拉长超时来遮住子进程退出。
如果持续失败,请依次检查:
- 子进程是否还存活,8501 / 8502 / 8503 是否真正监听。
- 对应 Agent 日志中是否有依赖、配置或导入错误。
- Docker 端口映射、本机防火墙、远程访问主机名是否正确。
- 本地子应用连接问题与外部 LLM / 搜索 / 爬虫网络问题要分开排查;当前本地健康检查已显式绕过代理,但外部请求仍可能受代理 / VPN 影响。
三、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 --testBroad Topic 先把话题和关键词写入 daily_topics,Deep Sentiment 再读取这批关键词去各平台搜索和入库。--setup 仍存在于兼容 CLI,但当前 MindSpider 文档已将它标为废弃,常规流程优先使用自动初始化和 --status。
11. 没有弹出二维码,或小红书等平台爬取失败,是不是不支持?
当前代码支持 xhs 等 MediaCrawler 平台,旧 FAQ 中“不支持小红书”的结论已经过时。但“代码包含支持”不等于第三方平台永远可用:登录、验证码、风控、签名和页面结构都可能变化。
首次运行每个目标平台时:
- 确认子模块和 Playwright Chromium 已安装。
- 将 MediaCrawler 的
HEADLESS设为False,观察真实登录页面。 - 手动扫码或完成验证,再确认登录状态已保存。
- 只有在登录状态已损坏且你明白后果时,才重置对应
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.py 与 BroadTopicExtraction/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,怎么排查?
先用单平台、小规模参数复现,不要一开始就全平台大量爬取:
- 在 Broad Topic 日志和数据库中确认
daily_topics确实有该批次的关键词。 - 看 Deep Sentiment 日志最终选中的话题日期和关键词,避免误以为它正在用你指定的批次。
- 只跑一个平台的
--test,并打开浏览器,确认登录、验证码、页面访问和搜索结果。 - 确认相应平台的数据表有新增记录,并核对容器/宿主机数据库地址。
- 附上该平台完整日志和当前提交;顶层“返回码 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 清理/恢复和报告分章处理,但修复器不可能将任意一段截断、缺字段或不遵循协议的输出变成可靠结果。
持续出错时:
- 先更新到你要验证的明确提交,确保不是旧版 Report V1 问题。
- 替换为更强、更稳定的结构化输出模型,尤其是 Report Agent。
- 确认供应商没有截断输出,模型上下文和超时足够。
- 报 Issue 时附上去秘后的原始模型回复、失败阶段与完整日志。
参考 #681。
五、Report Agent 与最终报告
19. 三个 Agent 看起来都跑了,为什么 Report Agent 仍然锁定?
Web 流程不是只看页面上的进度文字。Report Agent 初始化时会记录三个目录当时的 .md 文件数:
insight_engine_streamlit_reportsmedia_engine_streamlit_reportsquery_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.py、regenerate_latest_md.py 或 regenerate_latest_pdf.py。
21. 最终报告太短、被截断、排版错乱或图表空白,怎么办?
当前 Report Engine V2 已经是分阶段的 Document IR 管线,支持分章生成、结构修复、HTML / PDF / Markdown 渲染,并优先使用本地 Chart.js / MathJax 等资产。因此旧 FAQ 中“打开 VPN 就能修图表”或“一次模型输出就是整份报告”的判断已经过时。
建议按以下顺序排查:
- 确认 Query / Media / Insight 三份上游输入都是本轮新生成且内容完整。
- 使用长上下文、结构化输出稳定的强 Report 模型;更换模型是重要排查项,但不是唯一原因。
- 检查供应商是否截断长输出、超时或返回不完整 JSON。
- 保留本次章节输出、IR JSON、HTML 和完整日志;图表问题要区分“IR 没有/无效数据”与“浏览器渲染失败”。
- 如需自定义样式,使用当前支持的
.md/.txt报告模板,不要沿用 Report V1 的假设。
已知边界:Markdown 不会保留完整交互式 Chart.js 图表,而是降级为表格/文本;超长表格在 PDF 中的分页仍可能不够自然。这些不应被描述为“所有格式都会逐像素完全一致”。
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.py 或 regenerate_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 将保持作为常见问题入口。如果某条答案与当前代码不一致,请附上可复现信息和当前提交,我们会持续更新。
Source: 666ghj/BettaFish