SDialog: Synthetic Dialogue Generation and Analysis

repository·main·Indexed 40 days ago

https://github.com/idiap/sdialog

An open-source toolkit for the end-to-end lifecycle of LLM-based conversational agents. SDialog supports construction, user simulation, dialog generation, and evaluation. Key features include persona definition, orchestrator attachment, mechanistic interpretability via Inspectors, and a comprehensive audio pipeline for TTS and acoustic room simulation.

Tokens
71.4K
Snippets
203
Records
237
Agent score
99%

What's inside SDialog

  1. Overview of SDialog

    main

    SDialog is a modular Python toolkit designed for generating, steering, evaluating, and analyzing synthetic dialogues using instruction-tuned Large Language Models (LLMs). It provides standardized abstractions for multi-agent role-play, dynamic orchestration, and reproducible experiment pipelines.

    Key capabilities include:

    • Persona-driven multi-agent simulations.
    • Dynamic orchestration (rule-based, probabilistic, or semantic).
    • Attribute and dialogue generation.
    • Evaluation (linguistic, coherence, embedding similarity, and LLM judges).
    • Mechanistic interpretability and activation steering.
  2. Audio Generation and Acoustic Simulation Tutorials

    main

    The sdialog library provides a comprehensive audio pipeline for generating and simulating dialogue. The tutorials in this directory cover the following capabilities:

    Core Audio Generation

    • Text-to-Speech (TTS): Setting up engines and using voice databases to assign specific voices to speakers.
    • Audio Pipelines: Synthesizing speech from textual dialogue, resampling output to specific sampling rates, and switching between MP3, WAV, and FLAC formats.
    • Voice Management: Loading voice databases from Hugging Face, local storage, or on-the-fly using the VoiceDatabase class, and selecting voices based on attributes like age and gender.

    Acoustic Simulation

    • Environment Simulation: Making audio sound as if it were recorded in specific rooms using ray tracing technology, including background and foreground effects.
    • Room Generation: Using MedicalRoomGenerator, BasicRoomGenerator, or extending the RoomGenerator class to create custom environments. You can customize dimensions, wall materials, furniture placement, and the positioning of speakers and microphones using absolute or relative coordinates.
    • Acoustic Variations: Comparing how different room configurations and acoustic properties impact speech.
    • Impulse Response Simulation: Simulating specific recording devices (e.g., phones vs. high-quality microphones) by applying microphone impulse responses to the audio.
  3. Define and use Personas

    main

    A Persona is a structured attribute bundle (role, style, goals, etc.) used to condition LLM prompts. SDialog provides many built-in personas across domains like Healthcare, Finance, and Technical Support.

    Custom Personas

    To create a custom persona, inherit from sdialog.personas.BasePersona. All personas support .clone(overrides) for creating variants with lineage tracking, and serialization via .json() or .to_file().

    Automated Persona Generation

    You can use PersonaGenerator to automatically generate persona instances based on a class definition. If you use Pydantic Field descriptions in your class, the generator uses those descriptions as instructions for the LLM.

    from sdialog.generators import PersonaGenerator
    from sdialog.personas import BasePersona
    from pydantic import Field
    
    # Define a custom persona with field descriptions for the LLM
    class TravelAgentPersona(BasePersona):
        role: str = Field("", description="The role of the persona, e.g., 'Travel Agent'")
        expertise: str = Field("", description="The area of expertise")
        tone: str = Field("", description="The tone of the persona")
        goals: str = Field("", description="A short description of the goals")
        constraints: str = Field("", description="Operational constraints")
    
    # Use PersonaGenerator to create an instance via an LLM
    generator = PersonaGenerator(TravelAgentPersona, model="openai:gpt-4")
    generated_persona = generator.generate()
    generated_persona.print()
  4. Reproduce generations using seeds

    main

    SDialog supports deterministic generation by providing a seed argument to generation-based components (Agents, DialogGenerator, and PersonaGenerator). This is effective as long as the underlying LLM backend supports seeding. The seed is typically saved in the metadata (e.g., dialog.seed) for reproducibility.

    # Agent-based dialogue reproducibility
    dialog_a = alice.dialog_with(mentor, max_turns=6, seed=12345)
    dialog_b = alice.dialog_with(mentor, max_turns=6, seed=12345)
    assert [t.text for t in dialog_a.turns] == [t.text for t in dialog_b.turns]
    
    # DialogGenerator seeding
    from sdialog.generators import DialogGenerator
    gen = DialogGenerator("Short friendly greeting")
    d1 = gen.generate(seed=42)
    d2 = gen.generate(seed=42)
    
    # PersonaGenerator seeding
    from sdialog.personas import Doctor
    from sdialog.generators import PersonaGenerator
    pg = PersonaGenerator(Doctor(specialty="Cardiology"))
    pg.set(years_of_experience="{5-10}")
    p1 = pg.generate(seed=99)
  5. Extend SDialog by subclassing core components

    main

    SDDialog is designed to be extended by subclassing its base classes. Common extension points include:

    • Persona variants: Subclass sdialog.personas.BasePersona.
    • Orchestrators: Implement the instruct(dialog, utterance) method.
    • Persistent Orchestrators: Subclass sdialog.orchestrators.base.BasePersistentOrchestrator.
    • Dialog Scores: Subclass sdialog.evaluation.base.BaseDialogScore and implement score(dialog).
    • Dataset Score Evaluators: Implement __eval__ (and optionally __plot__) in sdialog.evaluation.base.BaseDatasetScoreEvaluator.
    • Embedding Evaluators: Implement __eval__ (and optionally __plot__) in sdialog.evaluation.base.BaseDatasetEmbeddingEvaluator.
    • LLM Judges: Subclass sdialog.evaluation.base.BaseLLMJudge and implement judge(dialogs).
  6. Use the Agent class for LLM-backed actors

    main

    The sdialog.agents.Agent class encapsulates an LLM-backed conversational actor. It manages persona, context, memory (role-tagged messages), and optional tools. It supports orchestrator pipelines, 'thinking' (reasoning) extraction, and lookahead capabilities without mutating memory.

    # Example of invoking an agent
    resp = agent("Hello!")
  7. Simulate telecommunications environments

    main

    Use the TelecommunicationsBackend to simulate telephone calls. This allows you to place speakers in different Room environments and apply codec compression and bandpass filtering.

    Configure the environment via a dictionary specifying:

    • speaker_rooms: A mapping of speaker IDs to Room objects.
    • codec: Global codec (e.g., 'g.711', 'g.729', 'amr', 'amr-wb', or 'default').
    • speaker_codecs: (Optional) Per-speaker codec overrides.
    • mixing_strategy: 'mono' or 'stereo'.

    When calling audio_pipeline.inference(), set room_acoustics_backend="telecommunications" and perform_room_acoustics=True.

    from sdialog.audio.room_acoustics_backends.telecommunications import TelecommunicationsBackend
    from sdialog.audio.pipeline import AudioPipeline
    from sdialog.audio.room import Room
    
    # Create different rooms for each speaker
    caller_room = Room(name="Office", ...)
    receiver_room = Room(name="Street", ...)
    
    # Configure the telecommunications environment
    telecom_env = {
        "speaker_rooms": {
            "speaker_1": caller_room,
            "speaker_2": receiver_room
        },
        "codec": "g.711",
        "mixing_strategy": "stereo"
    }
    
    # Run the pipeline
    audio_dialog = audio_pipeline.inference(
        dialog,
        environment=telecom_env,
        perform_room_acoustics=True,
        room_acoustics_backend="telecommunications"
    )
  8. Handle thinking segments and reasoning tokens

    main

    If an Agent is initialized with think=True and the backend supports surrogate reasoning tokens, SDialog can preserve or strip these segments.

    If the backend does not natively support them, you can use the thinking_pattern parameter (accepting a regex capturing group) to allow SDialog to recognize and handle thinking segments manually. This is useful for analyzing chain-of-thought reasoning without leaking it to the final output.

  9. Guide dialogues using Few-Shot Learning (Exemplars)

    main

    You can steer the style, structure, or format of a conversation by providing example_dialogs. These exemplars are injected into the system prompt. You can use Dialog.from_file() to load dialogues from a folder and optionally filter by file type using the type argument.

    # 1. Agent Role-Play with Exemplars
    from sdialog.personas import Persona
    from sdialog.agents import Agent
    my_example_dialogs = [...] # List of Dialog objects
    student = Agent(persona=Persona(name="Learner", role="math student"))
    tutor = Agent(persona=Persona(name="Guide", role="math tutor"))
    fewshot_dialog = student.dialog_with(tutor, example_dialogs=my_example_dialogs)
    
    # 2. DialogGenerator with Exemplars
    from sdialog.generators import DialogGenerator
    from sdialog.dialog import Dialog
    my_example_dialogs = Dialog.from_file("path/to/reference_dialogs/")
    gen = DialogGenerator("Provide a short educational exchange.", example_dialogs=my_example_dialogs)
    
    # 3. PersonaDialogGenerator with specific file types
    from sdialog.personas import Persona
    from sdialog.generators import PersonaDialogGenerator
    my_example_dialogs = Dialog.from_file("path/to/reference_dialogs/", type="csv")
    p1 = Persona(name="Coach", role="productivity mentor")
    p2 = Persona(name="Client", role="knowledge worker")
    pd_gen = PersonaDialogGenerator(p1, p2, dialogue_details="Exchange 3 tips.", example_dialogs=my_example_dialogs)
  10. How Orchestrators work and how to compose them

    main

    Orchestrators are lightweight controllers that examine the current Dialog state and the last utterance from the other agent to optionally return an instruction.

    They are composed using the pipe operator (|). Orchestrators can be ephemeral (one-time instructions) or persistent (instructions that stay in the agent's system messages across multiple turns).

    Built-in Orchestrators:

    • SimpleReflexOrchestrator: Triggers a fixed instruction if a condition is met in the input utterance.
    • LengthOrchestrator: Enforces minimum length or encourages wrapping at a maximum length.
    • ChangeMindOrchestrator: Injects probabilistic revisions (limited number of times).
    • SimpleResponseOrchestrator: Suggests responses based on semantic similarity to canned responses or an action graph.
    • InstructionListOrchestrator: Follows a deterministic scripted sequence of steps.
    # Compose orchestrators using the pipe operator
    length_orch = LengthOrchestrator(min=8, max=12)
    reflex_orch = SimpleReflexOrchestrator(
        condition=lambda utt: "confused" in utt.lower() or "don't understand" in utt.lower(),
        instruction="Slow down and explain with a concrete example to clarify."
    )
    agent = agent | length_orch | reflex_orch
  11. Core components of the SDialog audio module

    main

    The audio module enables transforming text dialogues into immersive audio experiences. Its main abstractions are:

    • AudioDialog: An extension of Dialog that supports audio turns and contains metadata for audio generation.
    • AudioTurn: Represents an individual turn with associated audio files, durations, and voice info.
    • BaseTTS: Abstract interface for TTS engines. Implementations include KokoroTTS, IndexTTS, and HuggingFaceTTS.
    • BaseVoiceDatabase: Manages speaker metadata (gender, age, etc.). Implementations include HuggingfaceVoiceDatabase and LocalVoiceDatabase.
    • AcousticsSimulator: Simulates 3D environments using Room specifications and RoomGenerator (e.g., MedicalRoomGenerator).
    • AudioProcessor: Applies effects like microphone simulation via impulse responses.
  12. Core Concepts: Dialog, Turn, and Event

    main

    The fundamental building blocks of SDialog are:

    • sdialog.Dialog: An ordered collection of Turn instances and optional Event objects. It includes metadata (version, timestamp, ID, parentId, seed, model) and utility methods for text transformation, filtering, and serialization.
    • sdialog.Turn: Represents a single utterance in a dialogue, containing speaker and text fields.
    • sdialog.Event: A generic record for actions such as utterances, instructions, or tool invocations.

    Dialog objects support various operations including:

    • Text Transforms: .lower(), .upper(), .replace(), .re_sub().
    • Utilities: .prompt(), .rename_speaker(), .filter(), .get_speakers(), .length() (for words, turns, or minutes).
    • I/O: .to_file(), .from_file(), .clone() (with lineage tracking).