From 5b8f5bc55432d32a777915abc31a35118a323433 Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Tue, 10 Mar 2026 18:01:20 +0000 Subject: [PATCH] fix: improve advisor prompts for more reliable column role assignment - Pass 1: clearer definition of "conversational" vs non-conversational, constrained dataset_type to specific enum values - Pass 2: much more explicit worked examples with step-by-step reasoning, added "skip" role for metadata columns, stronger reminder at end that all-user is wrong - Pass 3: returns raw text instead of JSON for cleaner system prompts, removed system message to give model more freedom --- studio/backend/utils/datasets/llm_assist.py | 170 +++++++++++--------- 1 file changed, 97 insertions(+), 73 deletions(-) diff --git a/studio/backend/utils/datasets/llm_assist.py b/studio/backend/utils/datasets/llm_assist.py index 1dc4ca387b..2481a63ba5 100644 --- a/studio/backend/utils/datasets/llm_assist.py +++ b/studio/backend/utils/datasets/llm_assist.py @@ -487,15 +487,20 @@ def _run_multi_pass_advisor( { "role": "system", "content": ( - "You are a dataset analyst specializing in HuggingFace datasets for LLM fine-tuning. " - "You classify datasets and determine if they can be used directly for conversational " - "fine-tuning or if they need conversion. Respond with ONLY valid JSON, no explanation." + "You are a dataset analyst. Your job is to look at a HuggingFace dataset " + "and figure out what kind of data it contains and whether it is already in " + "a conversational format suitable for LLM fine-tuning. A dataset is " + '"conversational" if it already has columns like "messages", "conversations", ' + 'or multiturn "user"/"assistant" pairs. Some datasets are NOT conversational ' + "— they are things like summarization, question answering, translation, " + "classification, etc. Those need conversion. You must respond with ONLY a " + "valid JSON object. Do not write any explanation before or after the JSON." ), }, { "role": "user", "content": textwrap.dedent(f"""\ - Analyze this HuggingFace dataset and classify it. + Look at this HuggingFace dataset and classify it. DATASET CARD (excerpt): {card_excerpt} @@ -505,17 +510,19 @@ def _run_multi_pass_advisor( COLUMNS: {columns} - SAMPLE DATA: + SAMPLE DATA (first 3 rows): {samples_text} - Respond with a JSON object: + Based on the above, respond with this exact JSON structure: {{ - "dataset_type": "", - "is_conversational": , - "needs_conversion": , - "description": "<1-2 sentence description of what this dataset is for>", - "task_description": "" - }}"""), + "dataset_type": "", + "is_conversational": , + "needs_conversion": , + "description": "", + "task_description": "" + }} + + Respond with ONLY the JSON object. No markdown, no explanation."""), }, ] raw1 = _generate_with_backend(backend, messages1, max_tokens=256) @@ -545,49 +552,76 @@ def _run_multi_pass_advisor( { "role": "system", "content": ( - "You map dataset columns to conversation roles for LLM fine-tuning. " - "Each column becomes either 'user' (the INPUT the model receives) or " - "'assistant' (the OUTPUT the model should generate). " - "There MUST be at least one user column AND at least one assistant column. " - "Respond with ONLY valid JSON." + "You are a data preparation assistant. Your job is to assign each column " + "in a dataset to a conversation role for LLM fine-tuning. There are exactly " + "two roles:\n" + '- "user" = This column contains INPUT that the model will receive as a prompt.\n' + '- "assistant" = This column contains OUTPUT that the model should learn to generate.\n\n' + "CRITICAL RULES:\n" + "1. There MUST be at least one column assigned to \"user\" AND at least one " + "column assigned to \"assistant\". Never assign all columns to the same role.\n" + "2. The column that contains the TARGET or OUTPUT or ANSWER or LABEL must " + "ALWAYS be assigned to \"assistant\". This is the thing the model should learn " + "to produce.\n" + "3. The columns that contain the SOURCE or INPUT or CONTEXT or QUESTION must " + "be assigned to \"user\". This is what the model receives.\n" + '4. Metadata columns like "id", "index", "source", "url", "date" should be ' + 'set to "skip".\n\n' + "You must respond with ONLY a valid JSON object." ), }, { "role": "user", "content": textwrap.dedent(f"""\ - Dataset classification: + Here is a dataset that has been classified: + + CLASSIFICATION: {json.dumps(pass1, indent=2)} - COLUMNS: {columns} + COLUMNS AVAILABLE: {columns} - SAMPLE DATA: + SAMPLE DATA (first 3 rows): {samples_text} - Assign each column to a role: "user" (INPUT) or "assistant" (OUTPUT). + Your task: assign each column to either "user", "assistant", or "skip". - EXAMPLES: - - Summarization (columns: document, summary): - column_roles: {{"document": "user", "summary": "assistant"}} - - NLI (columns: premise, hypothesis, label): - column_roles: {{"premise": "user", "hypothesis": "user", "label": "assistant"}} - label_mapping: {{"label": {{"0": "entailment", "1": "neutral", "2": "contradiction"}}}} - - Translation (columns: en, fr): - column_roles: {{"en": "user", "fr": "assistant"}} - - QA (columns: question, context, answer): - column_roles: {{"context": "user", "question": "user", "answer": "assistant"}} + Here are worked examples to guide you: - RULES: - - There MUST be at least one "user" AND at least one "assistant" column. - - The output/target column MUST be "assistant", never "user". - - If a column has integer labels (0, 1, 2...), provide label_mapping with ALL values. - - Ignore ID or metadata columns (do not include them). + Example 1 — Summarization dataset with columns ["document", "summary"]: + "document" is the input text → "user" + "summary" is the output the model should generate → "assistant" + Result: {{"document": "user", "summary": "assistant"}} - Respond with JSON: + Example 2 — Question answering dataset with columns ["context", "question", "answer"]: + "context" is input → "user" + "question" is input → "user" + "answer" is what the model should generate → "assistant" + Result: {{"context": "user", "question": "user", "answer": "assistant"}} + + Example 3 — Classification dataset with columns ["text", "label"]: + "text" is input → "user" + "label" is the output the model should predict → "assistant" + Result: {{"text": "user", "label": "assistant"}} + + Example 4 — Translation dataset with columns ["en", "fr"]: + "en" is the source language (input) → "user" + "fr" is the target language (output) → "assistant" + Result: {{"en": "user", "fr": "assistant"}} + + Now apply this logic to the actual dataset columns listed above. + + Respond with this exact JSON structure: {{ - "column_roles": {{"": "user or assistant"}}, - "label_mapping": {{"": {{"0": "