数据截至 (上游 commit 0b54741848df)
DeepAnalyze — 架构与原理
30 秒导读: DeepAnalyze 是中国人民大学 / 清华团队做的、号称「第一个面向自治数据科学的 agentic LLM」。一个 8B 的开源模型,你丢给它一堆数据文件(CSV / Excel / JSON / 数据库 / 文本)和一句话指令,它会自己反复「想一步 → 写一段 Python → 真的执行 → 读执行结果 → 再想」,最后产出一份分析师水准的研究报告。整个 agent 循环不靠外部 workflow 框架,而是训进了模型权重。
1. 这是什么(零基础也能懂)
一句话定义: DeepAnalyze 是一个会自己写代码、自己跑代码、自己看结果再决定下一步的数据分析模型。
解决什么问题 / 给谁用。 假设你是一个分析师,手上有十个零散的 Excel/CSV(学生贷款数据、人口数据、就业状态……),老板说「给我出一份数据科学报告」。平时你要:打开每个文件看字段、清洗、关联、建模、画图、写结论——好几个小时。DeepAnalyze 想做的事是:你把文件丢进一个目录,写一句 Generate a data science report.,它自己把上面这一整套干完,最后吐一份带数据、带图、带结论的 Markdown 报告。
它能做什么(功能):
- 覆盖整条数据科学流水线:数据准备、清洗、分析、建模、可视化、报告生成。
- 开放式数据深度研究:对结构化(数据库 / CSV / Excel)、半结构化(JSON / XML / YAML)、非结构化(TXT / Markdown)数据都能自己探索。
- 全开源:模型权重(DeepAnalyze-8B)、推理代码、50 万条训练数据、四种 UI(Web / Web v2 / Jupyter / CLI)全公开。
用起来什么样。 最小的真实调用就是 run.py 里这段——给个 prompt(指令 + 文件清单)、给个工作目录、指向模型,然后读返回的 reasoning:
# 示意,基于 run.py 真实用法
from deepanalyze import DeepAnalyzeVLLM
prompt = """# Instruction
Generate a data science report.
# Data
File 1: {"name": "person.csv", "size": "10.6KB"}
File 2: {"name": "enrolled.csv", "size": "20.4KB"}
..."""
da = DeepAnalyzeVLLM("/path/to/deepanalyze-8b/") # 连到本地 vLLM
answer = da.generate(prompt, workspace="/path/to/data/") # 在数据目录里跑
print(answer["reasoning"]) # 一长串 <Analyze>...<Code>...<Execute>...<Answer> 的过程 + 报告
注意 prompt 里只给了文件名和大小,没给文件内容——模型得自己写代码去 read_csv 看里面有什么。这是关键直觉。
一句话直觉/类比。 把它想成一个住在 Jupyter Notebook 里的实习分析师:它不能凭空知道数据长什么样,只能像人一样「写一个 cell、运行、看输出、再写下一个 cell」。区别是这套「写-跑-看-再写」的节奏不是外面的程序框架硬编排的,而是模型自己学会的本能——它知道什么时候该停下来写代码、什么时候该收尾给答案。
2. 顶层全景(它大概怎么转)
怎么读这张图
从上到下是一次任务的生命周期。左边那个循环是核心:模型每生成一段输出,外层代码就检查里面有没有 <Code>,有就执行、把结果塞回去,让模型继续;直到模型吐出 <Answer> 才停。
用户指令 + 数据文件清单(# Instruction / # Data)
│
▼
┌─────────────────────────────────────────────┐
│ 外层 Driver(deepanalyze.py / API / env) │
│ 维护 messages、检查标签、执行代码、回灌结果 │
└─────────────────────────────────────────────┘
│ 把 messages 发给 vLLM(stop="</Code>")
▼
┌──────────────────┐ 生成一段带标签的文本
│ DeepAnalyze-8B │ ───────────────────────────┐
│ (vLLM 服务) │ │
└──────────────────┘ ▼
▲ ┌─────────────────────────────┐
│ 把 <Execute> 结果 │ 这段里有什么标签? │
│ 当新一轮上下文回灌 │ │
│ │ <Analyze>/<Understand> → 继续│
│ │ <Code> → 抽代码、执行 ──┐ │
│ │ <Answer> → 收尾退出 │ │
│ └──────────────────────────┼────┘
│ ▼
│ ┌──────────────────────────┐
└──────────────────────────────────────│ 执行 Python(exec/沙箱) │
│ 捕获 stdout/stderr/报错 │
└──────────────────────────┘
│
▼(出现 <Answer> 后)
最终研究报告(Markdown,可导出 PDF)
部件一句话职责
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
DeepAnalyzeVLLM | 最小推理驱动:多轮循环、抽代码、exec 执行、回灌 | deepanalyze.py |
| 五个特殊标签 | 模型与驱动之间的「协议」:<Analyze> <Understand> <Code> <Execute> <Answer> | deepanalyze/add_vocab.py |
| prompt 模板 | 把用户输入包成 # Instruction + # Data(只放文件名+大小) | API/utils.py:prepare_vllm_messages |
| 课程训练脚本 | 三阶段把 agent 能力训进权重(单能力→多能力→RL) | scripts/single.sh、multi_coldstart.sh、multi_rl.sh |
| RL 环境 | GRPO 训练时的 rollout + 多分量奖励 | deepanalyze/SkyRL/skyrl-train/examples/deepanalyze/ |
| OpenAI 兼容 API | 生产版驱动:文件上传、流式、产物追踪、报告导出 | API/chat_api.py、API/utils.py |
| Docker 沙箱(v2) | 把代码执行隔离进每会话一个容器 | demo/chat_v2/backend_app/services/docker_executor.py |
主线走一遍(高层)
- 输入:用户给一句指令 + 一个装着数据文件的工作目录。驱动把它拼成
# Instruction\n...\n# Data\nFile 1: {...}—— 只有文件名和大小,没有内容。 - 模型起手:模型先
<Analyze>想该怎么办,然后<Code>写一段pandas去读文件、看字段。 - 执行回灌:驱动一看到
</Code>就停止生成,抽出代码exec,把 stdout/报错包进<Execute>...</Execute>拼回 messages。 - 滚动迭代:模型读到执行结果,
<Understand>总结观察,再<Analyze>+<Code>做下一步(清洗 / 关联 / 建模 / 画图)。如此往复,最多 30 轮。 - 收尾:模型认为够了,输出
<Answer>...</Answer>(一份完整报告)。驱动检测到<Answer>就退出循环,返回整段推理过程。
这套循环的代码非常薄(deepanalyze.py 全文不到 150 行)——重活在模型里,驱动只是个忠实的「执行+回灌」搬运工。下一章就拆这薄薄一层是怎么转的。
阅读地图(建议顺序)
- 01-agentic-loop.md —— 先看核心循环。读完你能讲清 DeepAnalyze 一次任务从请求到报告是怎么转的。
- 02-protocol-and-template.md —— 协议为什么在权重里、prompt 模板为什么这么薄、
execute这个非标准角色是怎么回事。 - 03-training-curriculum.md —— 这套本能怎么训出来的:三段式课程 + 数据分桶。
- 04-rl-env-and-reward.md —— RL 那一段最有料:多分量奖励怎么设计(精确匹配 + LLM 裁判 + 代码通过率 + 轮数)。
- 05-serving-and-sandbox.md —— 从「研究脚本」到「能上线的服务」:文件、流式、产物、Docker 沙箱。
如果你只想要一句话精华:DeepAnalyze 把数据科学的「写代码-执行-观察」循环当成一种语言协议(五个标签),用三阶段课程把这套协议焊进一个 8B 模型,推理时外层只负责执行代码、回灌结果。
横向对比(同 shelf 兄弟项目)
DeepAnalyze 属于 data-agents 区。和 shelf 里别的 agent 取舍不同:
- 协议在权重 vs 协议在 prompt:多数编码 / 通用 agent 把工具协议写在 system prompt 或 function-calling schema 里(模型可换);DeepAnalyze 把协议做成特殊 token 训进权重——绑死了模型,但换来极薄的外层和稳定的标签输出(见 02 章)。
- 解释器风格的执行:它和「代码解释器」类 agent 一样靠真执行 Python 拿 ground truth,但它执行的 不是「补丁打到文件」,而是「在工作目录里跑分析脚本」,产物是数据/图/报告(见 05 章)。
- RL 奖励设计:相比纯结果对错的 RL,它的奖励是过程 + 结果混合(代码通过率、分析质量 LLM 评分、开放研究还加轮数奖励),专门适配「报告没有唯一正确答案」的开放任务(见 04 章)。
代码地图(导航索引)
| 主题 | 文件 | 符号 / 锚点 |
|---|---|---|
| 最小推理循环 | deepanalyze.py | DeepAnalyzeVLLM.generate、DeepAnalyzeVLLM.execute_code |
| 标签解析与执行 | deepanalyze.py | 正则 <Code>(.*?)</Code>、stop=["</Code>"] |
| 特殊 token 注入 | deepanalyze/add_vocab.py | load_and_extend_model、new_tokens 列表 |
| prompt 模板 | API/utils.py | prepare_vllm_messages、collect_file_info |
| 单能力 SFT | scripts/single.sh | swift sft、reasoning/*.json 数据 |
| 多能力冷启动 SFT | scripts/multi_coldstart.sh | interation/*.json 数据 |
| RL(GRPO) | scripts/multi_rl.sh | main_deepanalyze、advantage_estimator=grpo |
| RL 环境 | deepanalyze/SkyRL/skyrl-train/examples/deepanalyze/deepanalyze_env.py | DeepAnalyzeEnv._get_reward、DeepAnalyzeEnv.step |
| 奖励函数 | deepanalyze/SkyRL/skyrl-train/examples/deepanalyze/utils.py | compute_tableqa_score_single、llm_as_judgement_*、check_valid_code_block |
| 生产 API 循环 | API/chat_api.py | chat_completions |
| Docker 沙箱 | demo/chat_v2/backend_app/services/docker_executor.py | execute_python_in_docker、ensure_execution_backend_ready |