Skip to content

Drug Procurement — a study whose run happens somewhere else

studies/drug_procurement/ · reference: true · external MARL pipeline (AgentProcure)

How do government, enterprise and hospital policies optimize centralized drug procurement (集采) strategy? The case is one procurement game cell of China's second national volume-based procurement batch: adefovir dipivoxil tablets (drug_68), round 2, three competing manufacturers. But the reason this page exists is not the pharmacology. It is the mechanism: a study whose actual run belongs to a heavy external pipeline, and which still plugs into the same artifacts, the same discovery fields and the same dashboard. Everything is materialized here except the training itself.

P / E / B

what it is where it comes from
P 5 agents — government, hospital, enterprise_1..3 — all with learnable: true and their own policy_group. Enterprise attributes are real (anonymized) workbook rows for the adefovir case: shared Pmax 1.08 yuan/tablet, Q0 2893.17, Qe 3471.804, but heterogeneous beta_i / omega (0.265/0.50, 0.470/2.00, 0.265/0.50). Interaction is explicit_network (government↔each enterprise, government↔hospital, hospital↔each enterprise). population/population.json
E Four layers, no scheduled events, no broadcasts — plus a case-specific game block. environment/environment.json
B RL policies, not LLM agents. Government Box(3) (Pmax scale, rho, omega); enterprise Box(1) (a normalized bid mapped into (cost_i, Pmax)); hospital Box(2) (report-next ratio, execution rate). the game block + model.py
layer modality scope dynamics content
policy_variables physical macro scheduled government-side Pmax, rho, x, omega
enterprise_market_state physical local endogenous cost, beta_i, bid, profit, selection status
hospital_execution_state physical local endogenous hospital execution / reporting variables
procurement_notice information macro scheduled evidence-bound case and run-mode notes

The game block is case-specific, not part of the common schema

Alongside the standard layers / scheduled_events / information_program, this study's environment.json carries a game object: game_type: general_sum, timing: simultaneous, observability: partially_observable, api_target: pettingzoo_parallel, gamma_default: 0.99, plus typed roles, observations, action spaces, rewards and a termination clause. Treat it as a case-specific extension — the environment schema every other study uses does not include it. It is what makes a Markov game expressible inside the same artifact.

Rewards are deliberately in three different units: social welfare (utility) for government, profit (yuan) for enterprises, execution utility for the hospital. They must be read per-role, never summed — that is what "general-sum, mixed-motive" means in practice.

The game structure the study materializes: 5 tracked agents, their action spaces and per-role rewards

One step, and the horizon

n_steps: 50 is one procurement episode, and the axis is a training episode, not calendar time. That is the sharpest departure from every other case on these pages: a step advances the game, and the whole 50-step episode is replayed thousands of times while the policies learn.

Training config (simulation/simulation.json): PPO on RLlib, ctde: true, gamma: 0.99, train_episodes: 10000, eval_episodes: 1000, one policy per role and one per enterprise. Winner selection uses soft_topk during training (differentiable, learnable) and hard_topk at evaluation (lowest bids win) — which is exactly why selection_accuracy exists as its own metric rather than being averaged into returns.

Results

There are none — and that is the point

reports/report.md is explicitly a pre-run, setup-only report: 0 training episodes, 0 evaluation episodes. There is no trajectory/ directory and no study.duckdb. The external AgentProcure checkout and its heavy dependencies (pettingzoo / ray[rllib] / gymnasium / torch) are not installed in this workspace.

What ships instead is a bilingual run_note on study.yaml, which the workflow surfaces to the reader:

This case runs through the external AgentProcure multi-agent RL pipeline (ray + torch, a heavy training job). The hosted service does not run the training — to produce a real run, clone the repo and run it locally (AgentProcure/run_training.py), then import the trajectory via studies/drug_procurement/adapter/socioverse_export.py.

So the workflow for this study is: materialize here → train there → import back. Everything a reader needs to judge the study — the game structure, the t=0 roster, the grounding ledger, the figures — is committed and reviewable before a single GPU-hour is spent. When the training does run, the exported trajectory lands in the same study.duckdb shape as every other study, and the same report and dashboard paths apply, with the four display_metrics (government_return, enterprise_return, hospital_return, selection_accuracy).

The setup report still carries findings, because structural findings do not need a trajectory: the population size is not arbitrary but pinned by the ≥3-manufacturer eligibility rule; enterprise_2 is the structural outlier on both beta_i and omega simultaneously, which predicts two separable strategy paths (high-quality/high-cost vs low-price/high-volume) to be confirmed or refuted by an actual run.

Grounding

Five sourced facts, one proxy fact, three assumptions, two implementation references — plus something no other study in the catalog has: an evidence[] array inside resources.json, carrying typed engineering evidence (PettingZoo parallel API contract, Gymnasium spaces, RLlib multi-agent policy mapping) with supports[], confidence and retrieved_at fields, referenced by evidence_ids from inside the game block.

entry basis role
≥3 manufacturers required for a variety to enter the batch (NHSA) sourced pins role_counts.enterprise = 3 and n_applicants = 3
average price cut of winning products: 53% sourced the empirical envelope for how aggressive a learned bid may plausibly be
maximum single-variety price cut: 93% sourced the upper edge of that envelope
32 varieties / 100 products won in the batch sourced scope context: this study is one cell of that batch
winning results took effect 2020-04 sourced anchors round 2 to the Jan-2020 bid / Apr-2020 execution cycle
adefovir being among the second-batch varieties proxy drug identity and qualitative price level come from an industry-press roundup; no official public bulletin for this specific winning bid was found
enterprise cost / elasticity / quality parameters from the anonymized workbook assumed real bid costs are not public; values are simulator inputs, not claims about real firms
a single illustrative drug_68 × round 2 cell assumed a readable whole game, not a batch-wide panorama
results are valid only as within-simulator paired differences assumed the strongest of the three: no real-world causal policy conclusion may be drawn

This is the catalog's clearest basis: proxy

sourced means an authoritative source states the value. assumed means nobody states it and the study declares its own choice. proxy is the middle case that people usually skip: the claim is supported, but only by a substitute of lower evidentiary standing — here, press coverage standing in for an official bulletin. Recording it as proxy rather than quietly promoting it to sourced is the whole discipline in one field. See Grounding & Provenance.

Note also how the third assumption constrains interpretation, not just inputs. A study can declare the limits of its own conclusions in the same ledger it declares its constants.

The single case sits inside a much larger research dataset — the AgentProcure project's NVBP corpus of several hundred drugs across procurement rounds, firm types and bidding outcomes — which is what drug_id / round_id / focus_drugs select from:

Characteristics of the AgentProcure research dataset: drug forms, ATC categories, rounds, competition and firm attributes

What you can fork

param the question it opens
drug_id the same game machinery on another variety — does enterprise heterogeneity look structurally similar across drugs?
round_id the same variety across procurement batches.
timestep where inside the 50-step episode you slice.
focus_drugs a multi-cell comparison rather than a single game.
data_path point the case resolver at a different workbook.
shock_id the counterfactual axis — see below.

--shock-id all runs 15 counterfactual scenarios: 6 enterprise-cost shocks (enterprise_cost_down__cost_scale_{1p5,1p2,1p1,0p9,0p8,0p5}), 6 hospital-demand shocks (hospital_demand_up__q0_scale_{…} with the same six factors), and 3 government single-winner scenarios (gov_single_winner__single_winner_x_{1,2,3}). The last group is the direct mechanism-design experiment: how do all three roles' returns move when the number of winners changes? Read every one of those as a paired difference inside the simulator — that limit is declared in the grounding ledger, not a footnote.