agent_urban_planning.AhlfeldtHierarchicalLLMEngine¶
- class AhlfeldtHierarchicalLLMEngine(params, llm_client, *, cluster_k=50, clustering_algo='kmeans', zone_name_map=None, cache_dir='.cache/llm_v5_hierarchical', softmax_T=1.0, max_retries=3, prompt_version='v5-hierarchical-v2', llm_concurrency=15, progress_callback=None, seed=None, prompt_builder_stage1=None, response_validator_stage1=None, stage2_top_k_residences=None, **parent_kwargs)[source]¶
Bases:
AhlfeldtABMEngineLLM-as-decision-maker engine with clustering and two-stage prompts.
The full V5 / V5 engine. Replaces
V[i, j]entirely with an LLM call made per cluster per market iteration. Stage 1 selects a residence; stage 2 selects a workplace conditional on residence. Returned scores become sampling probabilities (via_scores_to_probs) and are sampledM = num_agentstimes to build the empiricallast_choice_probabilitiesmatrix consumed byAhlfeldtMarket.Cache namespace:
.cache/llm_v5_hierarchical/. Most users should configure this throughLLMDecisionEngine.- Parameters:
params (
AhlfeldtParams) – Structural Ahlfeldt parameters.llm_client – An LLM client object (
.complete(user, system="")returning a string).cluster_k (
int) – Number of clusters used in stage-1 prompt grouping.clustering_algo (
str) – Clustering algorithm; only"kmeans"is currently supported.zone_name_map (
Optional[dict[str,str]]) – Optionalsynthetic_id -> real_namemapping for prompt-side zone naming.cache_dir (
str|Path) – Directory where stage-1 / stage-2 LLM call results are persisted.softmax_T (
float) – Temperature applied to LLM-returned scores.max_retries (
int) – Retry budget on parse errors per LLM call.prompt_version (
str) – String identifier baked into cache keys.llm_concurrency (
int) – Max parallel LLM calls.progress_callback (
Optional[Callable[[str,int,int,int],None]]) – Optional(stage, done, total, retries)callback for progress reporting.prompt_builder_stage1 (
Optional[Callable[...,tuple[str,str]]]) – Optional override for the stage-1 prompt builder.response_validator_stage1 (
Optional[Callable[...,list[tuple[str,float]]]]) – Optional override for the stage-1 response validator.stage2_top_k_residences (
Optional[int]) – Optional cap on stage-2 fan-out (used in V5 score-all mode).**parent_kwargs – Forwarded to
AhlfeldtABMEngine.
Examples
>>> import agent_urban_planning as aup >>> # Prefer the public wrapper: >>> # engine = aup.LLMDecisionEngine(params, llm_client=client, >>> # response_format="score_all")
- ensure_clustering(agents)[source]¶
Build (or reuse) the cluster assignments for the given agent set.
Idempotent: re-calling with the same agent set is a no-op. On first call the agents are one-hot encoded and clustered with the configured algorithm (currently only
kmeans);self._cluster_labels,self._cluster_personas, andself._cluster_weightsare populated.- Parameters:
- Return type:
- Returns:
None.
- Raises:
ValueError – If
self.clustering_algois not supported.RuntimeError – If the cluster weights sum to zero.
Examples
>>> import agent_urban_planning as aup >>> # engine = aup.LLMDecisionEngine(params, llm_client=client) >>> # engine.ensure_clustering(list(population))
- decide_batch(agents, environment, zone_options, prices)[source]¶
Issue stage-1 + stage-2 LLM calls and sample per-agent (R, W) choices.
For each cluster, issues one stage-1 LLM call (residence ranking / scoring) plus up to
stage2_top_k_residencesstage-2 calls (workplace conditional on residence). Cached results are reused across iterations via the in-memory and on-disk caches keyed by(cluster, stage, residence, prompt_version, price_bucket, wage_bucket). Returned scores are converted to sampling probabilities and samplednum_agentstimes to populateself.last_choice_probabilities.- Parameters:
- Return type:
- Returns:
List of
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)
- cluster_personas()[source]¶
Return a copy of the per-cluster persona strings.
Each persona is a one-line
persona_summary()of the highest-weight agent in the cluster, used as the persona block in stage-1 prompts. Useful for diagnostic logging.Examples
>>> import agent_urban_planning as aup >>> # engine.cluster_personas() # one persona per cluster