Faithful Persona Steering under Incongruity via Dual-Stream Refinement
QuirkyMind addresses a critical failure mode in persona-based LLMs: persona incongruity, where stable traits coexist with atypical, context-specific stances (e.g., a climate activist who supports nuclear energy). Existing methods either succumb to context drift (prompt-based) or suppress idiosyncratic "quirks" in favour of generic distributional patterns (fine-tuning).
Our framework disentangles identity definition from its expression via three stages:
- Traits Anchoring — constructs a dual-stream latent state
z⁽⁰⁾by fusing a sentence-level SBERT summary (semantic stability) with a token-level embedding stream (generative control). - In-Context Narrative Refinement — iteratively stabilises the state over simulated multi-turn dialogue using an alternating objective: InfoNCE (discriminative alignment) + Cross-Entropy (generative refinement).
- Persona-Steered Generalization — transfers
z⁽*⁾to downstream PQA / PNI tasks via frozen-backbone LoRA adapters.
Evaluated on Persona-Steered QA (PQA) and Narrative Inference (PNI) across 7 ATP domains and PersonaChat, QuirkyMind uniquely resolves the Accuracy–Individuation–Diversity Trilemma that monolithic baselines cannot.
Figure 3: Three-stage architecture — Traits Anchoring (dual-stream latent state), In-Context Narrative Refinement (alternating InfoNCE + CE), and Persona-Steered Generalization (LoRA adapters for PQA / PNI).
Code accompanying:
"Faithful Persona Steering under Incongruity via Dual-Stream Refinement"
Yu-An Chu, Jen-Ren Pong, Chia-Yao Yeh, Meng-Fen Chiang
Findings of ACL 2026, National Yang Ming Chiao Tung University
quirkymind/
├── src/quirkymind/
│ ├── quirkymind.py # Main pipeline (Stage 1: InfoNCE · Stage 2: CE+KL+Contrastive)
│ │ # training_mode: full | lora_only | simple_peft
│ │ # inference_mode: BASELINE | SINGLE | MULTI
│ ├── personachat_eval.py # PersonaChat evaluation (Section 4.4) + shared metrics
│ │ # exports: eval_pni_extended, Liu et al. (2024) IND/EXAG
│ │ # (imported by quirkymind.py and baselines)
│ ├── convert.py # Dataset conversion: MCQ/ATP CSV → QuirkyMind JSON
│ ├── demo.py # Gradio interactive persona-chat demo (PQA + PNI)
│ └── baselines/
│ ├── psp.py # PSP baseline (Tan et al., EMNLP 2024)
│ └── prefix.py # Prefix-Tuning + SBERT baseline
├── scripts/
│ ├── run_quirkymind.sh # SLURM: train + evaluate full QuirkyMind pipeline
│ ├── run_baselines.sh # SLURM: multi-seed (42/123/2024) PSP + Prefix baselines
│ └── run_personachat.sh # SLURM: PersonaChat cross-domain generalization (Section 4.4)
├── dataset/ # (gitignored) place ATP CSVs and PersonaChat here
├── results/ # (gitignored) experiment outputs
├── requirements.txt
├── LICENSE # MIT
└── README.md
git clone https://github.com/Chu1004/QuirkyMind.git
cd QuirkyMind
conda create -n quirkymind python=3.10 -y
conda activate quirkymind
pip install -r requirements.txtAll commands below run from the repository root. The launch scripts set PYTHONPATH automatically; for direct module calls:
export PYTHONPATH="$PYTHONPATH:$(pwd)/src"QuirkyMind is evaluated on two benchmarks:
| Dataset | Role | Domains / Size |
|---|---|---|
| American Trends Panel (ATP) | Primary — naturally incongruous personas from real-world surveys | 7 domains, 2,200 personas, 9,106 instances (Table 1 in paper) |
| PersonaChat (Zhang et al., 2018) | Cross-domain generalization (Section 4.4) | 400 sampled personas, 800 items |
ATP domain mapping (Table 1):
| Domain | ATP Wave | N personas | Q per persona |
|---|---|---|---|
| SOCIAL (SO) | Wave 131 | 400 | 12 |
| SCIENCE (SC) | Wave 123 | 200 | 12 |
| RELIGION (RL) | Wave 143 | 200 | 12 |
| POLITICS (PL) | Wave 92 | 200 | 12 |
| METHODOLOGY (MT) | Wave 98 | 400 | 12 |
| JOURNALISM (JN) | Wave 141 | 400 | 12 |
| GLOBAL (GL) | Wave 105 | 400 | 12 |
Place prepared CSVs under dataset/. Convert raw ATP MCQ data:
python -m quirkymind.convert --input dataset/raw_atp.csv --output_dir dataset/Download and prepare PersonaChat automatically:
python -m quirkymind.personachat_eval --download_dataSplit policy: all splits are persona-disjoint (70 / 10 / 20 train/val/test) with zero persona overlap across partitions, preventing the row-level leakage that within-persona splits introduce. See Section 4.1.
python -m quirkymind.quirkymind \
--csv dataset/MT_test.csv \
--model_name meta-llama/Llama-3.1-8B-Instruct \
--training_mode full \
--s1_epochs 10 \
--s2_epochs 5 \
--seed 42 \
--out_dir results/quirkymind--training_mode options (Section 4.5 Ablation):
| Mode | Description |
|---|---|
full |
QuirkyMind: Stage 1 InfoNCE + Stage 2 multi-objective FT |
lora_only |
LoRA-only ablation — no persona modules (PEFT-only baseline in Table 4) |
simple_peft |
Stage 2 only with randomly initialised persona modules |
Inference modes (BASELINE / SINGLE / MULTI) are evaluated automatically at the end of training.
bash scripts/run_baselines.sh # local
sbatch scripts/run_baselines.sh # NCHC / SLURMRuns PSP (Tan et al., 2024) and Prefix+SBERT over seeds {42, 123, 2024}.
python -m quirkymind.personachat_eval \
--csv dataset/personachat_converted.csv \
--test_liu_metrics \
--output_dir results/personachatEvaluates Accuracy, D2, SDIVsem, IND, and EXAG following Liu et al. (2024).
python -m quirkymind.demo # Gradio UI at http://0.0.0.0:7860Supports PQA (option scoring) and PNI (multi-round generation with latent blending).
From Table 8 (Appendix G.1):
| Group | Parameter | Value |
|---|---|---|
| Architecture | Soft Prompt Tokens S | 32 |
| Soft Prompt Scale α | 0.5 | |
| LoRA Rank r | 4 | |
| LoRA Alpha | 8 | |
| LoRA Dropout | 0.1 | |
| Optimization | Batch Size | 8 |
| Weight Decay | 1e-3 | |
| LR Stage 1 (η_θ) | 3e-5 | |
| LR Stage 2 (η_ϕ) | 1e-5 | |
| Epochs Stage 1 | 10 | |
| Epochs Stage 2 | 5 | |
| Stage 2 Loss λ | Cross-Entropy | 1.0 |
| Label Smoothing | 0.1 | |
| KL Divergence | 0.05 | |
| Contrastive (InfoNCE) | 0.1 | |
| Anchor Regularization | 0.1 | |
| Soft Prompt Reg. | 5e-4 | |
| Inference | Temperature | 0.7 |
| Top-p | 0.9 | |
| Repetition Penalty | 1.1 | |
| Max New Tokens | 16 |
- LLM backbones:
meta-llama/Llama-3.1-8B-Instruct,Qwen/Qwen2.5-7B-Instruct,mistralai/Mistral-7B-Instruct-v0.3 - Sentence encoder:
sentence-transformers/all-MiniLM-L6-v2(frozen SBERT) - PEFT: LoRA via 🤗
peft - Hardware: single NVIDIA RTX 5090 (32 GB)
- See
requirements.txtfor the full dependency list.
All scripts in scripts/ carry #SBATCH headers (1 GPU, 40 GB RAM, 8 CPUs):
sbatch scripts/run_quirkymind.sh # full pipeline
sbatch scripts/run_baselines.sh # PSP + Prefix baselines
sbatch scripts/run_personachat.sh # PersonaChat cross-domain evalLogs are written to logs/.
If you use this code or build on our work, please cite:
@inproceedings{chu-etal-2026-quirkymind,
title = {Faithful Persona Steering under Incongruity via Dual-Stream Refinement},
author = {Chu, Yu-An and
Pong, Jen-Ren and
Yeh, Chia-Yao and
Chiang, Meng-Fen},
booktitle = {Findings of the Association for Computational Linguistics: ACL 2026},
year = {2026},
address = {San Diego, California, USA},
publisher = {Association for Computational Linguistics}
}TODO before public release: add pages, url, and doi fields once the ACL Anthology entry is live.
This work is supported by the National Science and Technology Council (NSTC), Taiwan (grant nos. 114-2222-E-A49-004 and 114-2639-E-A49-001-ASP).
Released under the MIT License.
