Generate, validate, and check your items for quality and redundancy using AI-GENIE (Generative Psychometrics via AI-GENIE: Automatic Item Generation and Validation via Network-Integrated Evaluation). AI-GENIE is a methodology that combines the latest open-source LLMs and generative artificial intelligence with advances in network psychometrics to facilitate scale generation, selection, and validation. The pipeline eliminates the need to generate hundreds of items by content experts, recruit diverse and experienced researchers, administer items to thousands of participants, and employ modern psychometric methods in the collected data.
Usage
AIGENIE(
item.attributes,
openai.API = NULL,
hf.token = NULL,
main.prompts = NULL,
groq.API = NULL,
anthropic.API = NULL,
jina.API = NULL,
model = "gpt4o",
temperature = 1,
top.p = 1,
embedding.model = "text-embedding-3-small",
target.N = NULL,
domain = NULL,
scale.title = NULL,
item.examples = NULL,
audience = NULL,
item.type.definitions = NULL,
response.options = NULL,
prompt.notes = NULL,
system.role = NULL,
EGA.model = NULL,
EGA.algorithm = NULL,
EGA.uni.method = NULL,
uva.cut.off = 0.2,
boot.iter = 500,
ncores = NULL,
keep.org = FALSE,
items.only = FALSE,
embeddings.only = FALSE,
adaptive = TRUE,
run.overall = FALSE,
all.together = FALSE,
plot = TRUE,
silently = FALSE
)Arguments
- item.attributes
A named list of atomic character vectors (required). Describes the attributes or characteristics that each item type should encompass. These are not necessarily lower-order dimensions, but can be if the item types represent appropriate hierarchical constructs. Each nested list must have at least two unique attributes. Repeated attributes within the same nested list are not allowed, but attributes can be repeated across nested lists. Each name of the list must be unique, and all elements within sublists must be strings. For example, attributes of the personality trait "neuroticism" might include "anxious", "depressed", "insecure", or "emotional" since these characteristics encompass aspects of neuroticism that the item pool should address.
- openai.API
A character string or NULL (optional, default: NULL). The OpenAI API key for authentication with OpenAI's services. Required when using OpenAI's platform for either item generation or embedding. If NULL, users must provide either
groq.APIfor item generation via Groq orhf.tokenfor embeddings via Hugging Face.- hf.token
A character string or NULL (optional, default: NULL). The Hugging Face API token for authentication with Hugging Face services. Required when using Hugging Face models for embeddings. If NULL, an
openai.APIkey must be provided since the user will need to embed via OpenAI.- main.prompts
A named list of character strings or NULL (optional, default: NULL). Custom prompts for item generation. If provided, this must be a named list where
names(main.prompts)equalsnames(item.attributes). Each prompt must explicitly mention all attributes found in the associated element ofitem.attributes. Users should not include instructions regarding layout/formatting of LLM response, as this is handled automatically for proper parsing. If NULL, AIGENIE builds appropriate prompts automatically based on other prompt-building parameters.- groq.API
A character string or NULL (optional, default: NULL). The Groq API key for authentication with Groq's LLM services. Required when users want to generate items via Groq's API platform using open-source models. Commonly used in combination with
openai.APIsince Groq does not provide embedding services.- anthropic.API
A character string or NULL (optional, default: NULL). The Anthropic API key for authentication with Anthropic's Claude models. Required when using Claude models (e.g., "sonnet", "opus", "haiku") for item generation. Get a key at https://platform.claude.com/docs/en/manage-claude/authentication.
- jina.API
A character string or NULL (optional, default: NULL). The Jina AI API key for authentication with Jina's embedding services. Required when using Jina embedding models (e.g., "jina-embeddings-v3", "jina-embeddings-v4"). Free tier available at https://jina.ai/.
- model
A character string (optional, default: "gpt4o"). Specifies which large language model to use for item generation. Supports models from multiple providers:
OpenAI:
"gpt-4o","gpt-4","gpt-3.5-turbo","o1","o1-mini"Anthropic:
"sonnet","opus","haiku", or full names like"claude-sonnet-4-5-20250929"Groq:
"llama-3.3-70b-versatile","mixtral-8x7b-32768","gemma2-9b-it","deepseek-r1-distill-llama-70b","qwen-2.5-72b"
Aliases like
"llama","mixtral","gemma","deepseek","claude"are also accepted. The function automatically determines which API service to use based on the model name and available API keys.- temperature
A numeric value (optional, default: 1). Controls the randomness and creativity of the LLM's item generation. Must be between 0-2, where lower values produce more deterministic outputs and higher values increase creativity and variability.
- top.p
A numeric value (optional, default: 1). Controls nucleus sampling for the LLM's text generation. Must be between 0-1, where lower values make the model more focused and higher values allow more diverse outputs. Can be used in conjunction with
temperature.- embedding.model
A character string (optional, default: "text-embedding-3-small"). Specifies which model to use for generating embeddings of items. Supports multiple providers:
OpenAI:
"text-embedding-3-small","text-embedding-3-large","text-embedding-ada-002"Jina AI:
"jina-embeddings-v3","jina-embeddings-v4","jina-embeddings-v2-base-en"(requiresjina.API)HuggingFace:
"BAAI/bge-small-en-v1.5","BAAI/bge-base-en-v1.5","thenlper/gte-base","sentence-transformers/all-MiniLM-L6-v2"
The provider is automatically detected based on the model name. Jina models support task adapters and Matryoshka dimension truncation for optimized embeddings.
- target.N
An integer, named list of integers, or NULL (optional, default: NULL). Specifies the number of items to generate for each item type. Can be a single integer (applies to all item types) or a named list of integers where
names(target.N)equalsnames(item.attributes)for different numbers per item type. If NULL, 60 items per item type will be generated. A rule of thumb is about 60 items or more per item type for meaningful reduction analysis.- domain
A character string or NULL (optional, default: NULL). Specifies the psychological or research domain for context in item generation. Should be specific (e.g., "personality", "child development") rather than general. If supplied, it will be used to construct appropriate prompts and system roles unless
system.roleis provided.- scale.title
A character string or NULL (optional, default: NULL). Specifies the name or title of the scale being developed. Can be formal or descriptive, but more specific titles generally produce better results. If supplied, it will be used to construct appropriate prompts and system roles unless
system.roleis provided.- item.examples
A data frame or NULL (optional, default: NULL). Provides example items to guide the LLM's generation style and format. Must be a data frame with columns:
statement(the actual item),attribute(the item's attribute), andtype(the item's type). All values must be non-empty strings, and theattributeandtypemust align with theitem.attributesobject. Items should be extremely high quality and validated if possible, as they serve as style templates.- audience
A character string or NULL (optional, default: NULL). Specifies the target population for the scale being developed. Should be as specific as possible (e.g., "educated adults in rural America", "children with ASD in second grade") rather than general demographic categories. If supplied, it will be used to construct appropriate prompts and system roles unless
system.roleis provided.- item.type.definitions
A named list of character strings or NULL (optional, default: NULL). Provides definitions or descriptions of each item type for the LLM. Must be a named list where
names(item.type.definitions)equalsnames(item.attributes). Useful when constructs or item types are obscure or potentially ambiguous, helping the LLM understand the item type or construct in your specific context. If supplied, it will be used to construct appropriate prompts and system roles unlesssystem.roleis provided.- response.options
A character vector or NULL (optional, default: NULL). Specifies the response scale labels for the generated items (e.g., c("agree", "neither agree nor disagree", "disagree")). These labels provide context for item writing but do not appear in the actual items themselves. If supplied, it will be used to construct appropriate system roles unless
system.roleis provided.- prompt.notes
A named list of character strings, character string, or NULL (optional, default: NULL). Allows users to add custom instructions or context to the prompts. Can be a named list where
names(prompt.notes)equalsnames(item.attributes)for different notes per item type, or a single string applied to all item types. These notes are appended at the end of constructed prompts, allowing users to add brief additional requirements (e.g., "All items MUST begin with the stem 'I am someone who...'") without creating entirely custom prompts. Should be brief; otherwise, users should consider usingmain.prompts.- system.role
A character string or NULL (optional, default: NULL). Defines the system role/persona for the LLM during item generation. If not provided, one is built automatically based on prompt-building parameters. Should be as specific as possible (e.g., "You are an expert scale developer and psychometrician with extensive expertise in drafting Likert-type items for children with ASD. Today, you will focus on developing robust, single-statement items that assess linguistic ability."). Applies to all LLM interactions.
- EGA.model
A character string or NULL (optional, default: NULL). Specifies which model to use for Exploratory Graph Analysis network construction. Valid options are "tmfg" or "glasso". If NULL, AIGENIE will test both "tmfg" and "glasso" models and automatically return the model that maximizes NMI (normalized mutual information). TMFG is a greedy but speedy network-building algorithm that works well for many applications, especially text. EBICglasso is slower but non-greedy and may capture more nuanced relationships.
- EGA.algorithm
A character string (optional, default is "walktrap" when there is a single trait and "louvain" when there is more than one trait). Specifies which community detection algorithm to use within the EGA framework. Valid options are "louvain", "walktrap", or "leiden". The algorithm operates separately from the network building specified by
EGA.model.- EGA.uni.method
A character string (optional, default: "louvain"). Specifies the method for handling unidimensional structures in EGA. Valid options are: "expand" (expands correlation matrix with four variables correlated 0.50; if dimensions \(\le\) 2, data are unidimensional), "LE" (applies Leading Eigenvector algorithm; if dimensions = 1, uses LE solution), or "louvain" (applies Louvain algorithm; if dimensions = 1, uses Louvain solution). This parameter is rarely modified by users.
- uva.cut.off
A numeric value in
[0, 1)(optional, default:0.20). The weighted topological overlap threshold passed toEGAnet::UVAduring the redundancy-reduction step. Items with pairwise wTO at or above this value are flagged as redundant. Lower values are more aggressive (remove more items); higher values are more conservative.- boot.iter
A positive integer (optional, default: 500). Number of bootstrap iterations used by
EGAnet::bootEGAduring item-stability analyses and iterative stability filtering.- ncores
A positive integer or
NULL(optional, default:NULL). Number of processing cores passed toEGAnet::bootEGA. WhenNULL, AIGENIE does not pass anncoresargument, preserving the current default behavior ofEGAnet::bootEGA.- keep.org
A logical value (optional, default: FALSE). Controls whether the pre-reduced items generated by the model are returned to the user. If TRUE, returns the full item pool before psychometric reduction. Does not affect the reduction process.
- items.only
A logical value (optional, default: FALSE). Controls whether the function only generates items without running the full psychometric pipeline. If TRUE, skips embedding, EGA, and reduction steps, returning only a data frame with columns
ID,statement,type, andattribute. Useful when users want to generate items with AIGENIE, embed them elsewhere, and use theGENIEfunction for reduction.- embeddings.only
A logical value (optional, default: FALSE). Controls whether the function generates items and embeddings but skips psychometric reduction. If TRUE, returns a named list with
embeddings(the embedding matrix) anditems(the items data frame). If bothitems.onlyandembeddings.onlyare TRUE, defaults toembeddings.onlybehavior.- adaptive
A logical value (optional, default: TRUE). Controls whether previously generated items are incorporated into subsequent prompts to reduce redundancy. Items are generated in batches to avoid context window limitations, potentially requiring multiple API calls. When TRUE, appends previously generated items so the model knows what has been generated to avoid repetition. Should always be enabled unless context limitations are a concern.
- run.overall
A logical value (optional, default: FALSE). Controls whether a fit analysis on the complete item pool is run post-reduction. By default, only type-level reduction analyses are run (i.e., items of like-type go through the pipeline independent of the other items in the pool). When this flag is
TRUE, an additional analysis is run on the overall sample, but no further reductions at the overall level are made. If only one item type is present, this argument will be ignored.- all.together
A logical value (optional, default: FALSE). Controls whether the reduction analysis on the complete item pool is run. By default, only type-level reduction analyses are run (i.e., items of like-type go through the pipeline independent of the other items in the pool). When this flag is
TRUE, reductions are made at the overall level (i.e., all items go through the reduction pipeline together, agnostic of item type). If only one item type is present, this argument will be ignored.- plot
A logical value (optional, default: TRUE). Controls whether visualizations are generated and displayed. When TRUE, generates EGA network comparison plots (before vs after reduction) for each item type and the sample overall. Plots are always saved and returned in the output object but can be suppressed from display for cleaner output.
- silently
A logical value (optional, default: FALSE). Controls console output and messaging during function execution. When TRUE, suppresses progress statements about item generation, embedding, and pipeline reduction. Does not affect warnings or errors, only informational messages. Operates independently of the
plotparameter.
Value
The structure of the return value depends on the function flags.
Defaults: items.only = FALSE, embeddings.only = FALSE,
run.overall = FALSE, keep.org = FALSE, all.together = FALSE.
When items.only = TRUE:
Returns a data.frame of generated items with columns:
ID, statement, type, and attribute.
When embeddings.only = TRUE:
Returns a named list with two elements:
embeddings— an embedding matrix/list (columns or rownames correspond to item IDs).items— the itemsdata.framedescribed above.
Default behaviour (items.only = FALSE, embeddings.only = FALSE,
run.overall = FALSE, keep.org = FALSE, all.together = FALSE):
Returns a named list with two top-level elements:
item_type_levelA named list where each name is an item type and each element is a per-type named list containing:
final_NMINumeric: final normalized mutual information after reduction.
initial_NMINumeric: initial NMI of the pre-reduced item pool.
embeddingsList or matrix of embeddings for this item type (see 'Notes on
embeddings' below).UVAList from Unique Variable Analysis (contains at least
n_removed,n_sweeps,redundant_pairsdata.frame).bootEGAList with bootEGA results (e.g.
initial_boot,final_boot,n_removed,items_removed,initial_boot_with_redundancies).EGA.model_selectedCharacter: chosen EGA model (e.g.
"TMFG"or"Glasso").final_itemsdata.frame: final items after reduction (columns includeID,statement,attribute,type,EGA_com).final_EGAEGA object (from EGAnet) after reduction.
initial_EGAInitial EGA object computed on the pre-reduced item set.
start_NInteger: initial number of items in this type.
final_NInteger: final number of items in this type.
network_plotggplot/patchworkobject comparing networks before vs after reduction.stability_plotggplot/patchworkobject showing item stability before vs after reduction.
overallNamed list with aggregated results across all item types. Under the default this contains:
final_itemsdata.frameof final items across all types (columns as above).embeddingsEmbeddings for the full reduced item set (see 'Notes on
embeddings' below). Note:overall$embeddingsdoes not includeselected.
When keep.org = TRUE (in addition to defaults above):
The top-level shape remains (item_type_level and overall) but includes original (pre-reduction) information:
item_type_levelEach per-type sublist contains:
final_NMI,initial_NMI,embeddings,UVA,bootEGA,EGA.model_selected,final_items,initial_items,final_EGA,initial_EGA,start_N,final_N,network_plot,stability_plot.overallContains
final_items,initial_items, andembeddingsfor the full item pool.
For keep.org = TRUE, per-type embeddings contains at least: full_org, sparse_org, selected, full, and sparse. (overall$embeddings contains the same subcomponents except selected is omitted.)
When run.overall = TRUE (items.only = FALSE, embeddings.only = FALSE):
item_type_levelSame per-type structure as the default (see above).
overallA named list with aggregated results (not limited to
final_itemsandembeddings) containing:final_NMI,initial_NMI,embeddings,EGA.model_selected,final_items,final_EGA,initial_EGA,start_N,final_N, andnetwork_plot.
When all.together = TRUE (regardless of run.overall):
Results are not split into item_type_level and overall. Instead the function returns a single named list (applies to the full — possibly keep.org modified — result set) containing:
final_NMI, initial_NMI, embeddings, UVA, bootEGA, EGA.model_selected, final_items, final_EGA, initial_EGA, start_N, final_N, network_plot, and stability_plot.
References
Golino, H. F., & Epskamp, S. (2017). Exploratory graph analysis: A new approach for estimating the number of dimensions in psychological research. PLOS ONE, 12(6), e0174035. doi:10.1371/journal.pone.0174035
Christensen, A. P., Garrido, L. E., & Golino, H. (2023). Unique variable analysis: A network psychometrics method to detect local dependence. Multivariate Behavioral Research, 58(6), 1165–1182. doi:10.1080/00273171.2023.2194606
Christensen, A. P., & Golino, H. (2021). Estimating the stability of psychological dimensions via bootstrap exploratory graph analysis: A Monte Carlo simulation and tutorial. Psych, 3(3), 479–500. doi:10.3390/psych3030032
Danon, L., Díaz-Guilera, A., Duch, J., & Arenas, A. (2005). Comparing community structure identification. Journal of Statistical Mechanics: Theory and Experiment, 2005(9), P09008. doi:10.1088/1742-5468/2005/09/P09008
Russell-Lasalandra, L. L., Christensen, A. P., & Golino, H. F. (2026). Generative psychometrics via AI-GENIE: Automatic item generation and validation with network-integrated evaluation. Behavior Research Methods, 58(8), 217. doi:10.3758/s13428-026-03082-1
Examples
if (FALSE) { # \dontrun{
########################################################
#### Example 1: Using AI-GENIE with Default Prompts ####
########################################################
# Add an OpenAI API key
key <- "INSERT YOUR KEY HERE"
# Item type definitions
trait.definitions <- list(
neuroticism = paste0(
"Neuroticism is a personality trait that describes one's ",
"tendency to experience negative emotions like anxiety, ",
"depression, irritability, anger, and self-consciousness."
),
openness = paste0(
"Openness is a personality trait that describes how ",
"open-minded, creative, and imaginative a person is."
),
extraversion = paste0(
"Extraversion is a personality trait that describes people ",
"who are more focused on the external world than their ",
"internal experience."
)
)
# Item attributes
aspects.of.personality.traits <- list(
neuroticism = c("anxious", "depressed", "insecure", "emotional"),
openness = c("creative", "perceptual", "curious", "philosophical"),
extraversion = c("friendly", "positive", "assertive", "energetic")
)
# Name the field or specialty
domain <- "Personality Measurement"
# Name the Inventory being created
scale.title <- "Three of 'Big Five:' A Streamlined Personality Inventory"
# Run AI-GENIE to generate, validate, and redundancy-check an item pool for your new scale.
personality.inventory.results <- AIGENIE(
item.attributes = aspects.of.personality.traits,
openai.API = key,
domain = domain,
scale.title = scale.title,
item.type.definitions = trait.definitions
)
# View the final item pool
View(personality.inventory.results)
#######################################################
#### Example 2: Using AI-GENIE with Custom Prompts ####
#######################################################
# Define a custom system role
system.role <- paste0(
"You are an expert methodologist who specializes in scale ",
"development for personality measurement. You are especially ",
"equipped to create novel personality items that mimic the ",
"style of popular 'Big Five' assessments."
)
# Define custom prompts for each personality trait
custom.personality.prompts <- list(
# Prompt for generating neuroticism traits
neuroticism = paste0(
"Generate unique, psychometrically robust single-statement items designed to assess ",
"the Big Five personality trait neuroticism.",
paste0(
"Neuroticism has the following characteristics: anxious, ",
"depressed, insecure, and emotional. "
)
),
# Prompt for generating openness traits
openness = paste0(
"Generate unique, psychometrically robust single-statement items designed to assess ",
"the Big Five personality trait openness.",
paste0(
"Openness has the following characteristics: creative, ",
"perceptual, curious, and philosophical"
)
),
# Prompt for generating extraversion traits
extraversion = paste0(
"Generate unique, psychometrically robust single-statement items designed to assess ",
"the Big Five personality trait extraversion.",
paste0(
"Extraversion has the following characteristics: friendly, ",
"positive, assertive, and energetic."
)
)
)
# Run AI-GENIE to generate, validate, and redundancy-check an item pool for your new scale.
personality.inventory.results.custom <- AIGENIE(
item.attributes = aspects.of.personality.traits, # created in example 1
main.prompts = custom.personality.prompts,
system.role = system.role,
openai.API = key, # created in example 1
scale.title = scale.title # created in example 1
)
# View the final item pool
View(personality.inventory.results.custom)
################################################################
###### Or, Run AIGENIE with an Open Source Model via Groq ######
################################################################
# Add your API Key from Groq
groq.key <- "INSERT YOUR KEY HERE"
# Chose an open-source model like 'DeepSeek' or 'GPT oss'
open.source.model <- "GPT oss 120b"
# Use AIGENIE with an open source model via Groq
personality.inventory.results.gptoss <- AIGENIE(
item.attributes = aspects.of.personality.traits, # created in example 1
openai.API = key, # Created in example 1
domain = domain, # Created in example 1
scale.title = scale.title, # Created in example 1
model = open.source.model, # Select a model available on Groq's API
groq.API = groq.key
)
# View the final item pool
View(personality.inventory.results.gptoss)
################################################################
###### Or, Run AIGENIE with a Hugging Face Embedding Model #####
################################################################
# Chose a BAAI/bge series OR thenlper/gte series model
hf.embedding.model <- "BAAI/bge-large-en-v1.5"
# Create a HF Token to access the best models. Moderate useage will still be FREE
hf.token <- "INSERT YOUR KEY HERE"
# Use AIGENIE with an open source model via Groq
personality.inventory.results.hf <- AIGENIE(
item.attributes = aspects.of.personality.traits, # created in example 1
# OpenAI API key is not needed for this example #
domain = domain, # Created in example 1
scale.title = scale.title, # Created in example 1
model = open.source.model, # Select a model available on Groq's API
groq.API = groq.key,
embedding.model = hf.embedding.model,
hf.token = hf.token
)
# View the final item pool
View(personality.inventory.results.hf)
################################################################
#### Example 4: Using Anthropic Claude for Item Generation ####
################################################################
# Add your Anthropic API key
anthropic.key <- "INSERT YOUR KEY HERE"
# Use Claude Sonnet (or "opus", "haiku", or full model names)
personality.inventory.claude <- AIGENIE(
item.attributes = aspects.of.personality.traits,
anthropic.API = anthropic.key,
openai.API = key, # Still needed for embeddings
model = "sonnet", # Alias for claude-sonnet-4-5-20250929
domain = domain,
scale.title = scale.title,
item.type.definitions = trait.definitions
)
# View the final item pool
View(personality.inventory.claude)
################################################################
#### Example 5: Using Jina AI Embeddings ####
################################################################
# Add your Jina API key (free tier available)
jina.key <- "INSERT YOUR KEY HERE"
# Use Jina embeddings with Groq for generation
personality.inventory.jina <- AIGENIE(
item.attributes = aspects.of.personality.traits,
groq.API = groq.key,
jina.API = jina.key,
model = "llama-3.3-70b-versatile",
embedding.model = "jina-embeddings-v3",
domain = domain,
scale.title = scale.title,
item.type.definitions = trait.definitions
)
# View the final item pool
View(personality.inventory.jina)
################################################################
#### Example 6: Anthropic + Jina (No OpenAI Required) ####
################################################################
# Full pipeline without OpenAI
personality.inventory.no.openai <- AIGENIE(
item.attributes = aspects.of.personality.traits,
anthropic.API = anthropic.key,
jina.API = jina.key,
model = "sonnet",
embedding.model = "jina-embeddings-v3",
domain = domain,
scale.title = scale.title,
item.type.definitions = trait.definitions
)
# View the final item pool
View(personality.inventory.no.openai)
} # }