项目状态:实验性 / 作品展示(portfolio project)。接口与行为可能随时调整,不建议直接用于生产环境。
一个基于 CrewAI + Streamlit + OpenAI-compatible API 的自动报告生成项目。用户输入主题、上传图片或上传文献后,系统会按「研究 → 写作 → 审核」流程生成高质量 Markdown 报告,并支持导出 PDF / Word。
这个项目适合作为 AI Agent / 多 Agent 协作 / 自动化研究写作方向的实习作品展示。
专业中文 AI 报告工作台,支持主题研究、图片理解、文献综述、Agent 执行过程展示,以及 Markdown / PDF / Word 多格式交付。截图使用演示配置,不包含可用 API 凭证。
- 多 Agent 工作流:研究员、写作者、审核员分工协作。
- 联网搜索:优先使用 Responses API 的
web_search工具,对旧版兼容商自动回退到web_search_preview。 - 主题报告生成:输入一个主题,自动搜索资料、整理观点、撰写报告并审核。
- 图片识别:上传截图、图表、论文页面或题目图片,先识别图片内容,再生成报告。
- 文献分析:上传 PDF / 文档,分阶段提取内容并生成文献综述或分析报告。
- 前端页面:使用 Streamlit 提供可视化输入、API 配置、任务运行过程和报告预览。
- 运行过程展示:页面展示任务阶段、工具调用和结果摘要,便于理解 Agent 工作流。
- 多格式导出:支持 Markdown、PDF、Word 下载。
- 缓存管理:对文献分阶段处理结果进行缓存,减少重复调用。
auto_report_agent/
├── app.py
├── src/
│ └── auto_report_agent/
│ ├── agent_events.py
│ ├── api_config.py
│ ├── cache_manager.py
│ ├── crew.py
│ ├── document_ingest.py
│ ├── docx_export.py
│ ├── frontend.py
│ ├── main.py
│ ├── openai_web_search_tool.py
│ ├── pdf_export.py
│ ├── run_manager.py
│ ├── settings.py
│ ├── staged_literature.py
│ ├── vision.py
│ ├── py.typed
│ └── config/
│ ├── agents.yaml
│ └── tasks.yaml
├── docs/
│ └── images/
│ └── workspace-preview.png
├── output/
├── tests/
├── .env.example
├── .gitignore
├── LICENSE
├── pyproject.toml
└── README.md
- Python
>=3.10,<3.14 - 支持任何遵循 OpenAI 协议的 API 服务,包括 OpenAI、Azure OpenAI、DeepSeek、Qwen、Kimi、智谱 GLM、Ollama、vLLM 等官方或自建服务,以及各类第三方聚合商
- 如需联网搜索,服务商需要支持 Responses API 的
web_search或兼容的web_search_preview工具 - 如需图片识别,模型需要支持视觉输入
git clone https://github.com/Z-jla/auto_report_agent.git
cd auto_report_agent
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
# source .venv/bin/activate
pip install -e .开发模式:
pip install -e ".[dev]"复制环境变量示例文件:
cp .env.example .envWindows PowerShell:
Copy-Item .env.example .env编辑 .env:
# 推荐:使用 LLM_* 命名(与 CrewAI / LiteLLM 保持一致)
LLM_API_KEY=你的 API Key
LLM_BASE_URL=https://你的兼容商地址/v1
LLM_MODEL=你的模型名
# 如果视觉模型和文本模型不同,可以单独配置
LLM_VISION_MODEL=
# chat:普通 Chat Completions
# responses:Responses API,适合 Web Search
LLM_API_MODE=chat
# 流式接收模型输出,默认开启;关掉容易被中转/反代按超时掐断
LLM_STREAM=true
# 是否启用兼容商 Web Search
ENABLE_WEB_SEARCH=false
# 公共部署安全模式;本机 Ollama/私网服务请改为 local
APP_DEPLOYMENT_MODE=public兼容性:旧的
OPENAI_API_KEY、OPENAI_API_BASE、OPENAI_MODEL_NAME、OPENAI_VISION_MODEL_NAME、OPENAI_API_MODE仍然可用(作为 fallback)。同时设置时,优先读取LLM_*。
注意:不要把
.env提交到 GitHub。项目已经在.gitignore中忽略.env。
APP_DEPLOYMENT_MODE=public(默认安全策略):页面不会预填服务器.env中的 Key,只允许 HTTPS 公网 API 地址,并禁用手动全局缓存清理。APP_DEPLOYMENT_MODE=local:适合本机单用户使用,允许http://localhost、Ollama、vLLM 等本地或私网接口。- CrewAI 的详细日志和任务回放 SQLite 可能包含提示词、上传内容与完整输出,因此公共模式默认关闭两者,本地模式默认开启。只有在明确接受相应数据暴露或落盘风险时,才用
CREWAI_VERBOSE、CREWAI_PERSIST_TASK_OUTPUTS覆盖默认值。 - 如需迁移输出、缓存、
.env和 CrewAI 状态,请在启动 Python 之前通过系统、容器或服务环境设置AUTO_REPORT_HOME;不要把它写进待迁移的.env,因为程序必须先知道应用目录才能找到该文件。旧版曾允许单独设置CREWAI_STORAGE_DIR;现在该值会被忽略并记录警告,请人工检查旧目录中是否遗留回放数据库。 - 公共模式允许页面内置服务商域名,并叠加
APP_ALLOWED_API_HOSTS中的自定义主机(支持*.example.com)。访问私网接口需要同时设置主机白名单和APP_ALLOW_PRIVATE_API_HOSTS=true,且只应在受信环境中开启。 - 白名单对所有模型调用生效,主题模式和文献模式一视同仁。用自建或小众中转时,公共模式下必须把它的主机名加进
APP_ALLOWED_API_HOSTS(本机开发直接用APP_DEPLOYMENT_MODE=local更省事),否则任务在组装阶段就会报「Base URL 安全校验未通过」。 - 默认限制为:图片 10 MB、最多 5 篇文献、单篇 25 MB、合计 50 MB、PDF 200 页。可通过
.env.example中的MAX_*变量调整,Streamlit 服务器还有 50 MB 的请求前置上限。
streamlit run app.py打开浏览器后可以:
- 在侧边栏填写 API Key、Base URL、模型名和是否启用联网搜索。
- 选择任务模式:
- 主题研究报告
- 图片识别 + 报告生成
- 文献分析 / 文献综述
- 点击「生成报告」。
- 在页面查看运行过程和最终报告。
- 下载 Markdown / PDF / Word。
python -m auto_report_agent.main或安装后运行:
auto-report-agent不带参数时会逐项询问。也可以直接用参数调用,便于脚本化:
# 主题研究报告
auto-report-agent --mode topic --topic "AI Agent 最新进展"
# 文献分析(给了 --file 就默认按文献模式)
auto-report-agent --file a.pdf --file b.pdf --instruction "对比方法与结论"
# 自动化场景:缺参数时直接报错,不阻塞等待输入
auto-report-agent --mode topic --topic "..." --no-input传入参数后不会再追问可选项;--no-input 时缺少必需参数会以退出码 2 结束。
每次运行使用独立目录:
output/runs/<run_id>/final_report.md
output/runs/<run_id>/run.json
前端支持下载:
final_report.mdfinal_report.pdffinal_report.docx
这些生成文件默认不会被 Git 提交。Streamlit 只展示当前浏览器会话生成的历史报告,不读取其他会话的运行目录。
文献模式的写作任务会先保存草稿。如果随后的流程失败,前端默认保留可用产物供下载:已有非空审核稿时优先保留审核稿且不删除写作草稿;审核稿缺失或空白时原子恢复写作草稿。可用 PAPER_KEEP_DRAFT_ON_FAILURE=false 关闭失败产物保留。
运行目录和按会话隔离的文献缓存都会持续累积,而公共模式禁用了侧边栏的手动清理入口,因此前端和 CLI 会周期性删除超过 OUTPUT_RETENTION_DAYS(默认 7 天)的 output/runs/<run_id>/ 和文献缓存命名空间;同一进程默认最多每小时扫描一次,可用 OUTPUT_RETENTION_SWEEP_INTERVAL_SECONDS 调整。活跃缓存通过心跳保护,疑似过期时还会复查其内部文件。这是磁盘占用的兜底,不是精确缓存策略:被删缓存会在下次请求时重新生成。
OUTPUT_RETENTION_DAYS=0 只关闭运行目录和文献缓存清理。公共模式默认不使用 CrewAI 的跨会话任务回放数据库,并会清除旧版本遗留的数据库;显式启用 CREWAI_PERSIST_TASK_OUTPUTS 后,数据库记录才会按相同保留期清理。
pip install -e ".[dev]"
ruff check .
ruff format --check .
python -m compileall -q app.py src tests
mypy
pytest -q- 不要提交
.env、API Key、日志、缓存和生成报告。 - 如果误把 API Key 提交到远程仓库,请立刻撤销并重新生成 Key。
- 公共模式不会把服务器 Key 下发到浏览器;页面填写的配置作为参数直接传给模型调用,不写入进程环境变量,因此不同浏览器会话之间不共享凭据,也不需要串行等待。
- 公共模式默认关闭 CrewAI verbose 输出和跨会话任务回放持久化,避免提示词、上传内容或报告进入共享日志/SQLite;这些开关若被显式开启,应按敏感数据管理对应存储。
- Base URL 会执行协议、主机、DNS 和私网地址校验;公共部署建议再设置主机白名单。
- 每次报告写入独立运行目录;文献缓存按浏览器会话、模型、Base URL、接口模式、提示词版本和生成参数隔离。
普通 Chat Completions 只负责文本生成,不等于具备联网搜索。项目优先使用 OpenAI Responses API 的 web_search 工具;对旧兼容商会回退到 web_search_preview。
只有在「后端直连接口 = responses」且「联网搜索已勾选」时,搜索工具才会挂到研究员身上;其余情况下工具会被直接摘掉,研究员改为基于自身知识作答,并在来源清单里说明无法提供实时链接。这样做是因为留着一个用不了的工具并非无害——研究员会反复调用它、反复读到同一条「已跳过」提示,白白耗掉迭代次数和 token。
网页由浏览器渲染 Markdown,PDF 由 reportlab 渲染。项目已经对标题(1-6 级)、段落、列表、表格、加粗、斜体和中文换行做了适配;行内标记不成对时会自动降级为纯文本,不会导致整份导出失败。复杂 Markdown 仍可能需要继续优化。
文献分析会分阶段读取、摘要和合并,长文档会产生多次模型调用。超过片段上限时会均匀选择首部、中部和尾部,并把覆盖比例写入综合材料;可以通过 .env 中的 PAPER_CHUNK_SIZE、PAPER_MAX_CHUNKS_PER_DOC 等参数控制成本和速度。
同一篇文献内的片段摘要互相独立,默认会并发 4 个同时分析(PAPER_STAGE_CONCURRENCY,可设 1-16)。10 个片段的文档实测约有 3 倍加速。如果你的兼容商配额较低、容易返回 429,把它调回 1 就是原来的串行行为。命中缓存的片段不占用并发额度。
片段、单篇合并、多篇合并、失败降级材料和最终 paper_context 都有字符预算,并另受程序内不可调高的硬上限约束,避免兼容接口返回异常长文本时把后续上下文撑爆。默认最终材料最多 60000 字符,可用 PAPER_CONTEXT_MAX_CHARS 调低;其余分层预算见 .env.example。发生裁剪时会公平保留各片段/文献的标签与首尾,并把覆盖说明单独保留在最终材料中。
多数情况是中转服务或反向代理把长请求掐断了。不少中转(尤其是 Cloudflare 前置的)会关闭约 120 秒内没有返回任何字节的连接,而一次报告写作经常要跑两三分钟——非流式请求在生成完成前一个字节都不发,于是连接先被关掉,客户端只看到 Connection error。SDK 默认还会重试两次,所以现象往往是「卡了六分多钟然后失败」。
项目默认已经开启流式(LLM_STREAM=true),字节持续流动就不会触发这类超时。如果你把它关掉又遇到这个报错,先把它设回 true。
需要注意:调小 max_tokens 之类的输出上限并不能绕开,模型思考期间同样不发送任何内容,超时照样触发。
若确认不是超时(例如很短的请求也失败),再检查 LLM_BASE_URL 是否可达、Key 是否有效。
MIT License
