Views
No views yet
matbee/lfm2.5-audio-tool-aware-v2, converted to the weight layout used by mlx-community/LFM2.5-Audio-1.5B-bf16. Weights are bfloat16 — no quantization. Drop-in replacement for any code that loads the upstream MLX base model.conformer.* → audio_encoder.* (NeMo → MLX subkey aliases: feed_forward1→ff1, norm_X→X_norm, batch_norm→norm).depthformer.* → audio_head.depthformer.blocks.*; the fused operator.qkv_proj (1536×1024) split into separate attn.{q,k,v}_proj of shape 1024/256/256.audio_adapter.model.N → audio_adapter.layers.N.(O, 1, k) → (O, k, 1); pointwise (O, I, 1) → (O, I) Linear; 4D pre-encode conv (O, I, H, W) → (O, H, W, I).to_logits cloned from embedding (safetensors cannot store aliased tensors).num_batches_tracked (BatchNorm counters), audio_loss_weights, codebook_offsets.mlx_lm.models.lfm2 and runs a forward pass.LiquidAI/LFM2.5-Audio-1.5B that handles both turns of a tool-augmented voice flow:| Turn | Trigger | Behavior |
|---|---|---|
| 1 — acknowledge | user audio + Tools available: … system prompt | Short ack ("setting your alarm now.") then stop |
| 2 — narrate | same audio + Known facts you must use… block injected via set_context() | Speaks the result naturally ("your alarm is set for 7am.") |
| Other classes | (any) | Refusal on missing tool, normal answer on general knowledge, chitchat reply |
matbee/lfm2.5-audio-tool-aware-v1, which mastered turn 1 but regressed to always-ack on turn 2 (0/20 narration on injected context). v2 adds the tool_result_speak class to the training mix and lifts narration from 0/20 → 20/20 while improving ack accuracy from 93.3% → 100%.1# turn 1 — model emits "let me check the weather for you" and stops
2# coordinator runs the weather tool, gets "Weather in Tokyo: 72°F, sunny."
3await ctrl.audio_node.set_context("Weather in Tokyo: 72°F, sunny.")
4# (no reset_history — same session continues)
5# turn 2 — model says "it's 72 and sunny in tokyo"set_context() appends a Known facts you must use when relevant:\n{result} block to the system prompt before turn 2 generation. v2 is trained to read that block and produce a natural narration without regenerating an ack.Respond with interleaved text and audio.
Tools available:
- weather: get current weather and forecasts for a location
- alarm: set or cancel alarms
- music: play, pause, or skip music
…
If a request needs one of these tools, acknowledge briefly and stop.
If known facts are provided below, use them to answer the user directly
without acknowledging again. Otherwise answer normally.
Known facts you must use when relevant:
Weather in Tokyo: 72°F, sunny.Known facts block is optional — present it for turn-2 narration, omit it for turn-1 ack.matbee/lfm2-tool-aware-dataset-v2 eval split (149 parsed rows across 5 classes):| Class | v1 | v2 | Notes |
|---|---|---|---|
tool_match (ack) | 93.3% | 100.0% | v1 state-query failures fixed (e.g., "what's the thermostat set to") |
tool_result_speak (narrate) | n/a (0/20 strict) | 89.7% | New behavior unlocked. Failures are all call scenario fact-vs-query overrides |
tool_miss (refuse) | 93.1% | 96.7% | |
general (answer normally) | 100.0% | 100.0% | No baseline regression |
chitchat (chat) | 100.0% | 100.0% | (after correcting scorer false-positives on "doing well, thanks") |
call scenario fact-vs-query override: "call mom" + injected fact "Calling your office" → narration says "connecting you to your office". The model trusts the fact verbatim — correct general behavior but for call the contact name shouldn't be overridden. In production the dispatcher provides query-aligned facts; this only manifests when synthesis mismatches them."recipe for miso soup" with search listed but not recipe → "searching for miso soup recipe". Arguably correct — search can find recipes.1from pathlib import Path
2import torch
3import torchaudio
4from liquid_audio import LFM2AudioModel, LFM2AudioProcessor, ChatState
5
6# Pass a Path (not str) so liquid-audio takes the local-checkpoint branch
7local = Path("./lfm2.5-audio-tool-aware-v2")
8processor = LFM2AudioProcessor.from_pretrained(local, device="cuda").eval()
9model = LFM2AudioModel.from_pretrained(
10 local, device="cuda", dtype=torch.bfloat16
11).eval()
12
13def respond(system_prompt: str, wav_path: str) -> str:
14 chat = ChatState(processor)
15 chat.new_turn("system"); chat.add_text(system_prompt); chat.end_turn()
16 wav, sr = torchaudio.load(wav_path)
17 if wav.shape[0] > 1: wav = wav.mean(0, keepdim=True)
18 chat.new_turn("user"); chat.add_audio(wav, sr); chat.end_turn()
19 chat.new_turn("assistant")
20 pieces = []
21 for token in model.generate_interleaved(
22 **chat, max_new_tokens=120, audio_temperature=1.0, audio_top_k=4
23 ):
24 if token.numel() == 1:
25 pieces.append(processor.text.decode(token))
26 return "".join(pieces).strip()
27
28# Turn 1 — ack
29TOOLS = (
30 "Respond with interleaved text and audio.\n\n"
31 "Tools available:\n- weather: get current weather...\n\n"
32 "If a request needs one of these tools, acknowledge briefly and stop. "
33 "If known facts are provided below, use them to answer the user "
34 "directly without acknowledging again. Otherwise answer normally."
35)
36print(respond(TOOLS, "user_says_whats_the_weather.wav"))
37# → "let me check the weather in tokyo."
38
39# Turn 2 — narrate (after dispatcher returned the result)
40WITH_FACTS = TOOLS + "\n\nKnown facts you must use when relevant:\n" \
41 "Weather in Tokyo: 72°F, sunny."
42print(respond(WITH_FACTS, "user_says_whats_the_weather.wav"))
43# → "it's 72 and sunny in tokyo."LiquidAI/LFM2.5-Audio-1.5B (1.45B params, bf16)matbee/lfm2-tool-aware-dataset-v2. v2 mix: 28% tool_match / 29% tool_result_speak / 14% tool_miss / 18% general / 11% chitchatCUDA_LAUNCH_BLOCKING=1, NCCL_P2P_DISABLE=1 for the no-NVLink 4090 pair)liquid_audio.trainer.Trainer — full fine-tune, bf16 mixed precisiontool_result_speak class. Per-class accuracy is the fairer comparison and shows uniform improvement.call scenario fact-vs-query alignment — see Known failure modes above.tool_result_speak training data: synthetic facts are randomly drawn per scenario, not query-aligned. This trains the model to trust the injected fact over the user's query when they conflict. Correct in production (where dispatcher provides aligned facts), occasionally surfaces during eval.am_adam (Kokoro male, American English).process() calls).LICENSE.@misc{liquidai2025lfm25audio,
title={LFM2.5-Audio: Speech-to-Speech Foundation Model},
author={Liquid AI},
year={2025},
publisher={Hugging Face},
url={https://huggingface.co/LiquidAI/LFM2.5-Audio-1.5B}
}matbee/lfm2-tool-aware-dataset-v2.