Agent Personalization¶
The BAF generator can produce a personalized agent whose behaviour, presentation
and modality are adapted to an end-user’s profile. Personalization is opt-in — a
plain BAFGenerator with no config runs the normal pipeline and this page does
not apply.
Personalization has three distinct pieces, which can be combined:
Structured configuration — a JSON document organised into
presentation/modality/behavior/content/systemsections that controls agent language, style, readability, voice, platform, etc.Recommendation — given a user profile described in the BESSER User Modeling Language (personal information, accessibility, competences, preferences, culture…), produce a structured configuration automatically. Two backends are available: a deterministic rule-based mapping, and an LLM-based recommender.
Variants — a single agent model can be generated as several parallel variants (e.g. one per language, one per configuration, one per mapped user profile) which are bundled into the same ZIP output.
Tip
If you are using the Web Modeling Editor, the three pieces above are exposed through the Agent Configuration panel and the Generate / Deploy dialogs. The rest of this page describes the underlying API so you can also use the pieces programmatically.
Structured Configuration¶
The configuration is a dictionary with up to five sections. Every field is
optional — unspecified fields fall back to the defaults defined in
agent_config_recommendation_utils.load_default_agent_recommendation_config().
agent_config = {
"presentation": {
"agentLanguage": "english", # see allowed values below
"agentStyle": "formal",
"languageComplexity": "simple",
"sentenceLength": "concise",
"interfaceStyle": {
"size": 20,
"font": "sans",
"lineSpacing": 1.8,
"alignment": "left",
"color": "var(--apollon-primary-contrast)",
"contrast": "high",
},
"voiceStyle": {"gender": "female", "speed": 1.0},
"avatar": None,
"useAbbreviations": False,
},
"modality": {
"inputModalities": ["text", "speech"],
"outputModalities": ["text"],
},
"behavior": {
"responseTiming": "instant", # or "delayed"
},
"content": {
"adaptContentToUserProfile": True,
},
"system": {
"agentPlatform": "streamlit",
"intentRecognitionTechnology": "llm-based",
"llm": {"provider": "openai", "model": "gpt-5-mini"},
},
}
The full list of allowed values is defined in
RECOMMENDATION_ALLOWED_VALUES and includes:
agentLanguage:original,english,french,german,spanish,luxembourgish,portugueseagentStyle:original,formal,informallanguageComplexity:original,simple,medium,complexsentenceLength:original,concise,verbosefont:sans,serif,monospace,neutral,grotesque,condensedalignment:left,center,justifycontrast:low,medium,highvoiceGender:male,female,ambiguousresponseTiming:instant,delayedagentPlatform:websocket,streamlit,telegramintentRecognitionTechnology:classical,llm-basedllmProvider:openai,huggingface,huggingfaceapi,replicateopenaiModels:gpt-5,gpt-5-mini,gpt-5-nano
Note
The generator accepts both the sectioned shape above and the legacy
flat shape (all fields at the top level). A call to
flatten_agent_config_structure normalises any sectioned input into the
flat shape before templates are rendered, so both are equivalent.
Personalized Code Generation¶
Pass the configuration to the BAF Generator via the config
parameter. Provide an OpenAI key either via openai_api_key or the
OPENAI_API_KEY environment variable when agentLanguage,
agentStyle, languageComplexity, sentenceLength or
useAbbreviations differ from original — those fields are applied by
re-writing message content through an LLM call.
from besser.generators.agents.baf_generator import BAFGenerator, GenerationMode
generator = BAFGenerator(
model=agent,
config=agent_config,
openai_api_key="sk-...", # or set OPENAI_API_KEY env var
generation_mode=GenerationMode.FULL,
)
generator.generate()
In FULL mode the generator produces, in addition to the usual
<agent>.py / config.yaml / readme.txt:
personalized_agent_model.py— the B-UML agent model after personalization has been applied, suitable for re-importing or further transformation.personalized_agent_model.json— the same model serialised as JSON for frontend preview / round-tripping.
PERSONALIZED_ONLY skips the templated code and only emits the two
personalization artefacts. CODE_ONLY skips personalization entirely. See
BESSER Agentic Framework (BAF) Generator for the full mode reference.
Recommendation Backends¶
The personalization pipeline can be fed by a manual recommendation — but the backend also exposes two endpoints that recommend a configuration from a user profile.
Rule-based manual mapping¶
The manual mapping lives in
besser/utilities/web_modeling_editor/backend/services/utils/agent_config_manual_mapping_utils.py.
It is a literature-synthesised rule table with:
Conditions that match characteristics from the user profile document (
age_gte,profile_text_contains_any, language codes, disabilities, education level…).Priority — when multiple rules match, lower numbers take precedence. The output configuration is the merged result of every matched rule.
Evidence — each rule cites the papers the recommendation is drawn from.
Match mode —
any(any condition matches) orall.
Examples of shipped rules: older_adults_readability,
adolescents_relatable_style, low_vision_contrast_boost,
hearing_impairment_speech_support.
Rules produce partial configurations (only the fields they affect), which are
merged onto the defaults via merge_dicts. This backend is deterministic
and does not require an OpenAI key.
LLM-based recommendation¶
The LLM backend sends the normalised user-profile document, the allowed values,
the default configuration, and an optional currentConfig to an OpenAI model
and asks it to return a valid configuration JSON. The output is parsed by
extract_json_object (robust to light markdown wrapping) and validated by
normalize_recommended_agent_config before being returned to the caller.
The LLM backend requires an OpenAI API key. The model name is caller-selectable
(gpt-5, gpt-5-mini, gpt-5-nano).
Variants¶
A single generator invocation can produce multiple variants bundled into the same ZIP. Three orthogonal mechanisms are supported; they are looked up in this order and the first one that matches wins:
Multi-language —
config["languages"]is a dict mapping language name to a per-language override. Each language becomes a sub-directory and every message string is translated.Variations —
config["baseModel"]+config["variations"]— each variation produces a separate variant starting from the base agent model.Configuration variants —
config["configurations"]is a list of{name, config}objects. Each entry generates an agent with that specific configuration.
If none of the three match but the config contains a personalizationMapping
list, a per-user-profile variant is emitted for each mapping entry. See
the section below.
The bundling and helper dispatch is handled by
besser/utilities/web_modeling_editor/backend/services/utils/agent_generation_utils.py
(handle_multi_language_generation, handle_variation_generation,
handle_configuration_variants, handle_personalized_agent).
Personalization Mapping¶
A personalizationMapping is a list linking user profiles to
configurations:
config["personalizationMapping"] = [
{
"name": "senior-user-1",
"user_profile": {...}, # serialised UserDiagram (see user_diagram.rst)
"agent_config": {...}, # structured agent configuration (sectioned or flat)
},
...
]
Each entry produces its own agent variant inside the output ZIP plus a
user_profiles.json file at the root bundling every profile. At runtime the
generated agent can select the right variant for an incoming user based on
their mapped profile.
The backend normalises the mapping in-place before invoking the generator:
the raw UML JSON present in each user_profile is converted to the
normalised user-profile document (see
User Diagram) so the generator never sees
editor-internal shapes.
OpenAI API Key¶
Personalization features that call an LLM (language/style rewriting,
agentLanguage translation, LLM-based recommendation) need an OpenAI API
key. The key is looked up in this order:
openai_api_keyconstructor argument onBAFGenerator.openai_api_key/openaiApiKey/OPENAI_API_KEY/apiKeyinside theconfigdict (top-level or undersystem).OPENAI_API_KEYenvironment variable.
If no key is found and a pipeline stage needs one, configure_agent raises
RuntimeError with the failing stage. The BAF generator then continues with
any non-LLM fields already applied. For deployments to external hosting
(GitHub + Render), the generated render.yaml declares OPENAI_API_KEY
as a secret env var the user is expected to set on Render’s side.
See Also¶
BESSER Agentic Framework (BAF) Generator — the BAF generator and its
GenerationModeparameter.User Diagram — the
UserDiagrammodel type that feeds the recommendation backends.Web Editor Backend API — HTTP endpoints for recommendation (
/recommend-agent-config-llm,/recommend-agent-config-mapping,/agent-config-manual-mapping).