| 中文 | [English](./README_en.md) |
|
|
| # S1-deepresearch 推理框架 |
|
|
| ## 核心特性 |
|
|
| - **多 LLM 客户端**: 支持 vLLM、Azure OpenAI、AIHubMix 等多种 LLM 服务 |
| - **丰富的工具集**: 提供 9 种工具,涵盖搜索、网页访问、文件解析、代码执行、多模态问答、bash 等 |
| - **批量推理**: 支持并发批量推理,自动断点续传,定期保存结果 |
| - **单条推理**: 支持单条查询的详细调试和测试 |
| - **负载均衡**: 支持多 LLM 节点的负载均衡和一致性调度 |
| - **详细日志**: 为每个查询生成独立的日志文件,便于问题追踪和分析 |
|
|
| ## 项目结构(当前) |
|
|
| ```text |
| ./ |
| ├── run_batch_inference_demo.sh # 本地/vLLM 脚本模板 |
| ├── run_batch_inference_online_demo.sh # 在线平台脚本模板 |
| ├── inference/ |
| │ ├── run_batch_inference.py |
| │ └── run_single_inference.py |
| ├── server/ |
| ├── tool_kits/ |
| ├── utils/ |
| │ └── config/ |
| │ ├── config.example.json |
| │ └── README.md |
| ├── models/tokenizer/ |
| └── test_all_tools.py |
| ``` |
|
|
| ## 快速开始 |
|
|
| ### 1. 安装依赖 |
|
|
| ```bash |
| pip install -r requirements.txt |
| ``` |
|
|
| ### 2. 配置(推荐 JSON 或环境变量) |
|
|
| 配置优先级:`自定义 JSON > 环境变量 > utils/config.py 默认值`。 |
|
|
| 常用做法: |
|
|
| ```bash |
| cp utils/config/config.example.json utils/config/config.local.json |
| ``` |
|
|
| 然后按需修改 `config.local.json`,例如: |
|
|
| - `TOOLS_SERVER_BASE_ENDPOINT_URL` |
| - `AIHUBMIX_KEY` / `AZURE_KEY` / `VOLCANO_KEY` / `ALIYUN_KEY` |
| - `CLIENT_TIMEOUT` |
|
|
| 也可以通过环境变量覆盖,例如: |
|
|
| ```bash |
| export S1_DR_CONFIG_JSON="utils/config/config.local.json" |
| ``` |
|
|
| ### 3. 准备输入 JSONL |
|
|
| 输入文件每行一个 JSON。最少建议包含 `question`,通常同时包含 `id` 与 `file_path`。 |
|
|
| #### 3.1 jsonl 示例(涉及文件输入) |
|
|
| ```json |
| {"id":"query_001","question":"阿里巴巴成立时,18位创始团队成员中,姓马、姓蔡、姓张的创始人的平均年龄,保留一位小数","file_path":[]} |
| {"id":"query_002","question":"阅读当前说明书,大疆发布的起飞重量最大的AIR系列无人机飞完半程马拉松,电池还剩多少毫安时的电能?(注1:假设水平无风,最低耗能的情况为最大航速的60%飞行;注2:耗电可以按最长飞行时间换算)","file_path":["/path/to/file.pdf"]} |
| ``` |
|
|
| #### 3.2 jsonl 示例(涉及 Skill 使用) |
|
|
| ```json |
| {"id":"query_003","question":"Use pymatgen to build a simple TiO2 surface slab. Please generate a common low-index surface, report the Miller index, slab thickness, and vacuum size, and briefly describe the resulting surface structure.","skills":[{"name": "skill_name1", "description": "description1", "skill_path": "skill_path1"}, {"name": "skill_name2", "description": "description2", "skill_path": "skill_path2"}]} |
| ``` |
|
|
| ## 推荐启动方式:复制脚本后运行 |
|
|
| ### A. 本地 / vLLM(`run_batch_inference_demo.sh`) |
| |
| ```bash |
| cp run_batch_inference_demo.sh run_batch_local.sh |
| mkdir -p run_logs |
| # 编辑 run_batch_local.sh 中的参数 |
| bash run_batch_local.sh |
| ``` |
| |
| 说明: |
| |
| - 脚本内部已使用 `nohup ... &` 启动 Python,会打印后台 PID。 |
| - 常看日志:`tail -f run_logs/run.log` |
|
|
| ### B. 在线平台(`run_batch_inference_online_demo.sh`) |
|
|
| ```bash |
| cp run_batch_inference_online_demo.sh run_batch_online.sh |
| mkdir -p run_logs |
| # 编辑 run_batch_online.sh 中的参数 |
| bash run_batch_online.sh |
| ``` |
|
|
| 说明: |
|
|
| - 重点修改:`LLM_CLIENT_URLS`、`LLM_CLIENT_MODELS`、`SYSTEM_FORMAT` |
| - 常看日志:`tail -f run_logs/run_batch_*.log` |
|
|
| ## 脚本参数说明 |
|
|
| ### 基础参数 |
|
|
| - `LLM_CLIENT_URLS`:模型服务地址,多个地址用空格分隔(与模型列表一一对应) |
| - `LLM_CLIENT_MODELS`:模型名列表,多个模型用空格分隔 |
| - `TEST_DATA_FILE`:输入 JSONL 路径 |
| - `OUTPUT_FILE`:`ROLLOUT_NUM=1` 时的输出文件 |
| - `OUTPUT_DIR`:`ROLLOUT_NUM>1` 时输出目录(生成 `rollout_01.jsonl` 等) |
| - `ROLLOUT_NUM`:每条样本重复推理次数 |
| - `RESUME_FROM_FILE`:断点续跑文件(可空) |
| - `AVAILABLE_TOOLS`:启用工具列表(空格分隔) |
| - `TASK_TYPE`:是否按“输入仅文本”场景处理,默认 `input_only` |
|
|
| ### 推理控制参数 |
|
|
| - `MAX_ROUNDS`:单 query 最大轮次 |
| - `CONCURRENCY_WORKERS`:并发 worker 数 |
| - `SAVE_BATCH_SIZE`:每处理多少条就自动落盘一次 |
| - `TEMPERATURE`:采样温度 |
| - `TOP_P`:top-p(`run_batch_inference_demo.sh` 已包含) |
| - `EXTRA_PAYLOAD`:额外模型 payload(JSON 字符串,`run_batch_inference_demo.sh` 已包含) |
| - `TIMEOUT_FOR_ONE_QUERY`:单 query 超时时间(秒) |
| - `LLM_API_RETRY_TIMES`:LLM 请求失败后的重试次数(不含首次) |
| - `SYSTEM_PROMPT`:自定义 system prompt;留空时使用内置默认 prompt |
| - `SYSTEM_FORMAT`:平台格式(主要在 `run_batch_inference_online_demo.sh`) |
|
|
| ### 上下文截断相关参数 |
|
|
| - `DISCARD_ALL_MODE`:是否启用 discard-all(`true/false`) |
| - `MODEL_MAX_CONTEXT_TOKENS`:模型最大上下文长度 |
| - `DISCARD_RATIO`:触发 discard 的比例阈值 |
| - `TOKENIZER_PATH`:token 统计所用 tokenizer 路径 |
|
|
| ### 日志参数 |
|
|
| - `LOG_LABEL`:日志标签,目录形如 `logs/YYYY_MM_DD_<LOG_LABEL>/` |
| - `LOG_FILE`:脚本启动日志文件(`run_logs/*.log`) |
| - `LOGGING_ROOT`:日志根路径(`run_batch_inference_demo.sh` 已包含,可空) |
|
|
| ## `SYSTEM_FORMAT` 可选值 |
| |
| `SYSTEM_FORMAT` 将对应不同的平台处理逻辑,根据该关键词进入不同的处理分支。 |
|
|
| - `deep_research`:本地 deep research 格式(vLLM 部署) |
| - `azure`:Azure OpenAI |
| - `aihubmix`:AIHubMix(OpenAI 兼容) |
| - `aihubmix_claude`:AIHubMix Claude 格式 |
| - `aihubmix_glm`:AIHubMix GLM 格式 |
| - `volcano`:火山引擎 |
| - `aliyun`:阿里云百炼平台格式 |
|
|
| ## 当前默认可用工具(9 个) |
|
|
| - `wide_search`:基于 Serp 进行通用网页搜索,支持一轮提交多个 query |
| - `scholar_search`:基于 Google Scholar 进行学术检索 + web 结果) |
| - `image_search`:图片检索,支持多 query。 |
| - `wide_visit`:访问网页并按目标 `goal` 产出摘要 |
| - `file_wide_parse`:解析本地/在线文件(PDF、DOCX、MD、CSV等) |
| - `execute_code`:执行 Python 代码 |
| - `ask_question_about_image`:图像理解与问答 |
| - `ask_question_about_video`:视频理解与问答 |
| - `bash`:执行 shell 脚本 |
|
|
| 各工具对应的 schema 定义详见 utils/prompts.py 下的 `DEEPRESEARCH_SYSTEM_PROMPT` |
|
|
| ## 输出与日志 |
|
|
| ### 输出 JSONL(字段详解) |
|
|
| `run_batch_inference.py` 写出的每行字段如下: |
|
|
| - `time_stamp`:该行结果写入时的时间戳(`YYYY-MM-DD HH:MM:SS`)。 |
| - `query_id`:批处理层生成的 query 标识(基于 `question` 哈希)。 |
| - `query`:本条输入的 `question` 文本。 |
| - `result`:单个 segment 的详细结果对象(来自 `run_single_inference.py`)。 |
| - `status`:任务状态,`success` / `timeout` / `error`。 |
| - `discard_segments`:被 `discard-all` 截断并做 summary 的段数(不含最终段)。 |
| - `elapsed_sec`:该 query 本次 rollout 的总耗时(秒)。 |
| - `rollout_idx`:第几次 rollout(从 1 开始)。 |
| - `src`:原始输入行完整内容(通常含 `id`、`question`、`file_path`、skills 等)。 |
| - `segment_idx`:当前是第几个 segment(从 1 开始)。 |
| - `segment_total`:该 query 共拆成多少个 segment。若无有效 `result`,会写成 `0`。 |
|
|
| 其中 `result` 常见字段(`run_single_inference.py`): |
|
|
| - `query_id`:单次运行实例 ID(含时间后缀)。 |
| - `tools`:本次启用的 tools schema(字符串形式)。 |
| - `messages`:用于模型推理与工具交互的日志消息。 |
| - `final_answer`:当前 segment 的回答文本。 |
| - `transcript`:更完整的对话轨迹(含工具回填)。 |
| - `rounds`:该 segment 执行到的轮数。 |
| - `stopped_reason`:停止原因(如 `no_tool_calls`、`discard_all_01`、`discard_all_final`、`max_rounds_exceeded`)。 |
| - `error`:仅在异常时可能出现。 |
|
|
| ### 日志目录 |
|
|
| 默认日志结构如下(`LOGGING_ROOT` 为空时): |
|
|
| ```text |
| logs/ |
| └── YYYY_MM_DD_<LOG_LABEL>/ |
| ├── collect.log |
| └── <query_id>/ |
| ├── run.log |
| └── result.json |
| ``` |
|
|
| ## 工具测试 |
|
|
| 运行工具测试脚本: |
| ```bash |
| python test_all_tools.py |
| ``` |
| 该脚本会测试所有注册的工具,验证其基本功能是否正常。 |