agent_urban_planning.LLMDecisionEngine¶
- class LLMDecisionEngine(params, llm_client, *, response_format='score_all', rebalance_instruction=False, stage2_top_k_residences=None, prompt_builder=None, response_validator=None, **kwargs)[source]¶
Bases:
objectFull LLM-as-decision-maker hierarchical engine (V5).
The LLM is queried per agent cluster per market iteration to make discrete location decisions directly: stage 1 selects a residence, stage 2 selects a workplace conditional on residence. This is the paper’s headline contribution and the
auplibrary’s core extensibility point.Configure via constructor kwargs to reproduce V5 from the paper:
response_format="score_all"+rebalance_instruction=True+stage2_top_k_residences=10keeps stage-2 fan-out tractable when the LLM scores all 96 zones in stage 1.- Parameters:
params (
Any) –AhlfeldtParamsinstance carrying structural elasticities.llm_client (
Any) – Anagent_urban_planning.llm.LLMClientinstance (or any object with a.complete(user, system="")method).response_format (
Literal['top5','score_all']) –"score_all"(paper headline) asks the LLM to score every zone;"top5"is a legacy ablation where the LLM ranks only its top 5. Default"score_all".rebalance_instruction (
bool) – IfTrue, the stage-1 prompt includes an explicit “weight affordability ≥ amenity” instruction. DefaultFalse(the V5 paper run sets this toTrue).stage2_top_k_residences (
Optional[int]) – When set to an int, stage-2 fan-out is capped at the top-K residences per cluster (by stage-1 score), preventing the cost blowup from score-all stage-1 producing 96 residences per cluster.Nonedisables the cap. DefaultNone; the V5 paper run uses10.prompt_builder (
Optional[Callable]) – Optional override for the stage-1 prompt builder callable. When provided, takes precedence over theresponse_formatselection.response_validator (
Optional[Callable]) – Optional override for the response validator callable. When provided, takes precedence over the format selection.**kwargs (
Any) – Forwarded toAhlfeldtHierarchicalLLMEngine. Common kwargs:cluster_k(default 50),clustering_algo,zone_name_map,cache_dir,softmax_T,num_agents,batch_size,seed,llm_concurrency,progress_callback,max_retries.
- Raises:
ValueError – If
response_formatis not one of{"top5", "score_all"}, or ifllm_clientis None.
Examples
V5 reproduction (paper’s headline LLM-ABM):
>>> import agent_urban_planning as aup >>> engine = aup.LLMDecisionEngine( ... params=scenario.ahlfeldt_params, ... llm_client=aup.llm.CodexCliClient(), ... response_format="score_all", ... rebalance_instruction=True, ... stage2_top_k_residences=10, ... cluster_k=50, ... num_agents=1_000_000, ... seed=42, ... )
Custom prompt builder (research extensibility):
>>> def my_prompt(persona, zones_info, *, prompt_version): ... return ("system", f"persona: {persona}; rank top 3.") >>> engine = aup.LLMDecisionEngine( ... params=scenario.ahlfeldt_params, ... llm_client=aup.llm.CodexCliClient(), ... prompt_builder=my_prompt, ... response_validator=my_validator, ... )
Notes
The V5 score-all configuration produces 96-zone stage-1 distributions, which would cause stage-2 fan-out to explode (50 clusters × 96 residences = 4800 stage-2 LLM calls per market iteration). The
stage2_top_k_residenceskwarg caps this at top-K residences (default for V5 production: 10); residences outside the top-K fall back to the sampler’s uniform-workplace default inAhlfeldtHierarchicalLLMEngine.See also
agent_urban_planning.UtilityEngine— closed-form V1/V2/V3 baselines.agent_urban_planning.HybridDecisionEngine— V4 (LLM elicits preferences, closed-form choice).References
Ahlfeldt, G. M., Redding, S. J., Sturm, D. M., Wolf, N. (2015). The economics of density: Evidence from the Berlin Wall. Econometrica, 83(6), 2127-2189.
- property rebalance_instruction: bool¶
Whether the stage-1 prompt includes the affordability rebalance instruction.
- decide_batch(*args, **kwargs)[source]¶
Forward to the underlying implementation’s
decide_batch.Transparently forwards to
AhlfeldtHierarchicalLLMEngine.decide_batch(). Each call issues one stage-1 LLM call per agent cluster (residence) plus up tostage2_top_k_residencesstage-2 calls per cluster (workplace conditional on residence), with caching on price buckets to amortize costs across market iterations.- Parameters:
- Return type:
- Returns:
List of
agent_urban_planning.LocationChoice, one per input agent and in the same order.
Examples
>>> import agent_urban_planning as aup >>> # engine = aup.LLMDecisionEngine(params, llm_client=client) >>> # choices = engine.decide_batch(agents, env, zones, prices)