DeepResearch Eval

May 23, 2026 · View on GitHub

A simplified implementation of Vision DeepResearch.

Files

FilePurpose
eval_runner.pyEntry point: loads parquet, runs agents in parallel, judges answers, writes outputs
deepresearch_agent.pyMultiTurnReactAgent — multi-turn ReAct loop with tool calling
tools.pyTool implementations (search, visit, PythonInterpreter, crop_and_search)
unpack_parquet.pyExtract images from a packed parquet → local files + rewritten parquet
run_eval.shEnv-var wrapper around eval_runner.py (single file or whole directory)
deploy/run_inference_server.shvLLM launcher for the inference role (port 8001 by default)
deploy/run_extract_judge_server.shvLLM launcher for the shared extract + judge role (port 8002 by default)
deploy/run_all_in_one_server.shOne-process vLLM launcher serving all roles (smoke-test convenience)

Step 1 — Install dependencies

pip install pandas pyarrow openai Pillow requests oss2 numpy json5

Step 2 — Download and unpack the dataset

The packed parquets are hosted on HuggingFace: https://huggingface.co/datasets/Osilly/Vision-DeepResearch-Eval (files live under data/ in the repo root).

pip install huggingface_hub

huggingface-cli download Osilly/Vision-DeepResearch-Eval \
    --repo-type dataset \
    --local-dir ./hf_data

Then unpack — this extracts embedded images to local files and rewrites images to absolute local paths, dropping the image_packed column:

cd Vision-DeepResearch/rllm/eval

python unpack_parquet.py \
    --output_dir ./data/ready \
    --images_dir ./data/images \
    ../../../hf_data/data/*.parquet

./data/ready/ will contain one inference-ready parquet per dataset; ./data/images/ will hold the extracted image files referenced by them.


Step 3 — Deploy the vLLM servers

The pipeline consumes three logical OpenAI-compatible roles:

RoleUsed byRequired env vars
InferenceMultiTurnReactAgent — produces tool calls and final answersTONGYI_BASE_URL, TONGYI_MODEL_NAME
Extract / summaryVisitTool and crop_and_search — summarises raw webpage / visual-search HTML into structured JSONVLLM_EXTRACT_URL, EXTRACT_MODEL
Judge / rewardeval_runner.py — LLM-as-judge for accuracy scoringJUDGE_BASE_URL, JUDGE_MODEL, JUDGE_API_KEY

The extract (summary) and judge (reward) roles can share a single server — both are stateless OpenAI calls and a single VL-capable instruct model (e.g. Qwen3-VL-30B-A3B-Instruct) covers both. The default deploy below uses two processes total: one for inference, one shared by extract + judge.

Ready-to-run launchers ship under deploy/:

ScriptRoleDefault port
deploy/run_inference_server.shinference8001
deploy/run_extract_judge_server.shextract + judge (shared)8002
deploy/run_all_in_one_server.shall roles, single process8001

Each script accepts overrides via env vars: MODEL_PATH, MODEL_NAME, PORT, GPUS, TP_SIZE, GPU_MEM_UTIL, MAX_MODEL_LEN. Typical two-process deploy:

For a smoke test, run deploy/run_all_in_one_server.sh and point all three URLs at the same port — slow at scale because traffic serialises through one process.


Step 4 — Configure environment variables

# --- Required: inference endpoint (port 8001) ---
export TONGYI_BASE_URL="http://localhost:8001/v1"
export TONGYI_MODEL_NAME="Qwen3-VL-30B-A3B-Instruct"
export TONGYI_API_KEY="EMPTY"             # vLLM does not check the key

# --- Extract / summary AND judge / reward (shared, port 8002) ---
export VLLM_EXTRACT_URL="http://localhost:8002"
export EXTRACT_MODEL="Qwen3-VL-30B-A3B-Instruct"

export JUDGE_BASE_URL="http://localhost:8002/v1"
export JUDGE_MODEL="Qwen3-VL-30B-A3B-Instruct"
export JUDGE_API_KEY="EMPTY"

# --- Required for crop_and_search tool ---
export ZHIPU_API_KEY="your_zhipu_key"        # Zhipu web/image search API
export OSS_ACCESS_KEY_ID="your_oss_ak"       # Aliyun OSS (stores cropped images)
export OSS_ACCESS_KEY_SECRET="your_oss_sk"
export OSS_BUCKET_NAME="your_oss_bucket"
export IMAGE_CROP_CACHE="/tmp/crop_cache"    # local temp dir for crops

Step 5 — Run evaluation

PARQUET accepts either a single file or a directory — pointing it at the directory will evaluate every *.parquet inside, writing one sub-folder per dataset.

cd Vision-DeepResearch/rllm/eval

# Run all datasets at once
export PARQUET=./data/ready
export OUTPUT_DIR=./outputs/Qwen3-VL-30B-A3B-Instruct
bash run_eval.sh

# …or a single dataset
export PARQUET=./data/ready/bcvl_level1_199.parquet
bash run_eval.sh

Optional env vars for run_eval.sh:

VariableDefaultDescription
PARALLEL_TASKS10Concurrent tasks
MAX_SAMPLES(all)Cap number of samples
TEMPERATURE0.6Sampling temperature
TOP_P0.95Top-p
MAX_TOKENS(unset)Max completion tokens
OUTPUT_DIR./outputsOutput root
JUDGE_BASE_URLsame as TONGYI_BASE_URLJudge endpoint
JUDGE_MODELsame as TONGYI_MODEL_NAMEJudge model
JUDGE_API_KEYsame as TONGYI_API_KEYJudge API key

Datasets

FileSamples
bcvl_level1_199.parquet199
bcvl_level2_200.parquet200
fvqa_300.parquet300
infoseek_300.parquet300
livevqa_webwatcher_subset_300.parquet300
mmsearch_vision_171.parquet171
simplevqa_300.parquet300
MMSearch-Plus_221.parquet221
worldvqa_sampled_300.parquet300
testmini500_v1.parquet (VDR Bench)500

Thanks for their contributions.