Архитектура
Интеллектуальная лестница — ключевая черта Needle 3. Каждый слой модели представляет собой подсеть с монотонно растущей ёмкостью. Разработчики могут выбрать подходящий размер: от 2-слойной (2L) до 20-слойной (20L) подсети. Каждая подсеть поддерживает тонкую настройку, так что 4L после обучения на конкретных задачах на одной эпохе может соответствовать DeepSeek V4 Flash. Интеллектуальная лестница обеспечивает создание бинарных файлов размером 9–29 МБ с квантизацией CQ2 и поддерживает широкий диапазон миниатюрных устройств.
- Входные данные
- Текстовые подсказки плюс определения инструментов или схема извлечения
- Выходные данные
- Структурированный JSON с вызовами инструментов или извлечениями
- Модель
- 29–121M Laddered Simple Attention Networks, квантизация CQ2
- Обучение
- 360B токенов на собственном структурированном наборе данных
- Скорость
- 400–4000 токенов/с при декодировании и 1–10000 токенов/с при предварительном заполнении на Raspberry Pi 5
Архитектура Laddered Simple Attention Networks требует более чем в 2 раза меньше MFLOPs на токен по сравнению с трансформером той же конфигурации.
Возможности
- Вызовы инструментов
- При наличии определений функций Needle выбирает нужные и заполняет все параметры из текста пользователя. Попросишь две вещи — получишь два вызова по порядку; попросишь чего-то, что не покрыто инструментами, — получишь пустой список, а не примерный ответ.
- Структурированное извлечение
- Описываешь формат данных, передаёшь неструктурированный текст — получаешь типизированные поля: счёт-фактуру, бронирование, уведомление, заполненную форму. Грамматика декодирования гарантирует корректность выходных данных. Извлечение хорошо обобщается и на задачи классификации.
- Текстовые эмбеддинги
- Та же модель возвращает вектор для предложения, что позволяет приложению искать, сопоставлять и маршрутизировать локально: найти нужную заметку, выбрать инструмент, ближайший к запросу, или объединить дублирующиеся алерты.
Примеры применения
- Умный дом
- От нажатия кнопок к общению с домом. «Приглуши спальню и закройся» превращается в два вызова, выполняемых офлайн, без обращения к хабу.
- Роботы
- Давай роботу-пылесосу или маленькому роботу нюансированные команды: «почисти кухню, но не трогай спальню», «вернись на станцию, когда закончишь». Каждая команда становится последовательностью перемещений, которые робот может выполнить.
- Смартфоны
- Ассистент, который действует на устройстве вместо ответа: создаёт альбом из фотографий прошлых выходных, открывает сайт, приглушает экран, находит договор в файлах.
- Носимые устройства
- Преобразует уведомление в структурированные данные прямо на запястье: платёж по карте в торговца, сумму и дату; сообщение в ответ; жалобу в флаг тональности.
- AR-очки
- Навигация и поиск поблизости по короткому запросу без участия телефона и сети.
- Автомобили
- Климат-контроль, медиа, навигация и вызовы по голосовым командам в салоне, при этом набор инструментов закреплён и сохраняется на протяжении долгого путешествия.
- Компьютеры
- Управление устройством на обычном языке: составление письма, запуск таймера, копирование адреса, открытие вкладки.
- Поиск и сопоставление
- Эмбеддинги, которые не покидают устройство: семантический поиск по заметкам, сообщениям и документам; сопоставление запроса с ближайшим из сотен инструментов; объединение почти дубликатов алертов на смарт-часах.
Начало работы
Установи Python пакет. Механизм вывода загружается один раз с Hugging Face и кэшируется — больше ничего не нужно собирать.
Needle читает описания инструментов, чтобы решить, какие вызывать и как заполнять параметры. Хорошее описание — всё что нужно.
Просто: декоратор функции. Сигнатура даёт типы параметров, docstring — описание инструмента, а run() замыкает цикл: модель выбирает вызов, Needle выполняет функцию, передаёт результат назад и возвращает финальный ответ с выполненными вызовами инструментов в results.
import needle
@needle.tool
def get_weather(city: str):
"Get the current weather for a city."
return {"city": city, "temp_c": 27, "sky": "clear"}
agent = needle.Needle(tools=[get_weather])
print(agent.run("what's it like in Lagos right now?")["results"])
# [{'city': 'Lagos', 'temp_c': 27, 'sky': 'clear'}]
Маршрутизация по паттерну: когда описание не может охватить все варианты формулировки, задай инструменту triggers — регулярные выражения, сопоставляемые с каждым запросом. Совпадение ограничивает декодирование до указанных инструментов и требует вызова, так что запрос достигает нужного инструмента вместо отказа или неправильной маршрутизации. Совпадение распространяется на весь ход общения, поэтому catch-all должен исключать существительные, которыми владеют другие инструменты, например ^(?![\s\S]*\b(lights?|doors?)\b)[\s\S]*\b(turn|switch)\b[\s\S]*\b(on|off)\b; тогда «switch the fan on and dim the kitchen lights» всё равно достигнет обоих инструментов.
from typing import Literal
@needle.tool(triggers=[r"\b(turn|switch|power|flip)\b.*\b(on|off)\b", r"\btoggle\b"])
def control_device(device: str, action: Literal["on", "off", "toggle"]):
"Switch or toggle any named smart-home device."
return {"device": device, "action": action}
agent = needle.Needle(tools=[control_device, get_weather])
agent.complete("toggle the garage door")
# function_calls [{"name": "control_device", "arguments": {"device": "garage door", "action": "toggle"}}]
Извлечение: чтобы вытащить структурированные данные из текста, опиши формат и вызови extract(). Передай модель Pydantic — получи типизированный объект.
from pydantic import BaseModel
class Invoice(BaseModel):
vendor: str
total: float
due_date: str
invoice = needle.extract("Invoice from Acme Corp, $1,200.00, due 2026-09-01", Invoice)
print(invoice.vendor, invoice.total) # -> Acme Corp 1200.0
Каждый ход возвращает один JSON объект:
{
"type": "call",
"success": true,
"error": null,
"error_code": null,
"function_calls": [ { "name": "set_lights", "arguments": { "room": "living room", "on": true, "brightness": 30 } } ],
"reasoning": "'living room' -> room; 'dim' -> on true, brightness 30",
"confidence": 0.94,
"prefill_tps": 4300.0,
"decode_tps": 850.0,
"peak_ram_mb": 28.5
}
Уровень доверия и маршрутизация: каждый ответ содержит оценку confidence из калибровочной головы, и механизм уже применяет нижний предел 0.1. Ниже него вызов удерживается в suppressed_calls, а function_calls пуста. Выше него — оценка на твой выбор: действуй сразу при высокой, показывай вызов и спрашивай при средней, а пустой результат рассматривай как отказ. Инструмент с triggers всегда создаёт вызов для совпадающего запроса, поэтому оценка подскажет, запустить его или запросить подтверждение.
r = agent.complete(user_text)
calls = r["function_calls"]
held = r["suppressed_calls"]
if calls and r["confidence"] >= 0.7:
execute(calls) # sure: act
elif calls or held:
confirm(calls or held, r["reasoning"]) # unsure: show the call, ask
else:
say("I can't do that here") # nothing to do: refuse
Написание инструментов: модель читает схему буквально, поэтому узкий инструмент с ясным описанием лучше широкого. Один инструмент на действие, описанный через действия, которые он выполняет («Включить или выключить свет в комнате»), а не через категорию. Называй варианты enum так, как их говорит пользователь (action: ["increase", "decrease"]), и держи синонимы в описании. Дай обязательному параметру default, если запрос может его опустить; обязательный параметр без default и без признака в запросе удерживается, а не угадывается. Помещай форматы значений в описания ("City, ST", "e.g. T-1042"). Добавляй triggers к намерениям, которые должны всегда достичь инструмента, и держи набор инструментов за ход маленьким — каждый дополнительный инструмент это шанс неправильно маршрутизировать.
Тонкая настройка: Python пакет — быстрый путь. LoRA на замороженной основе при полных 20 слоях, потом 4-битный .cact любой подсети, работающей на том же механизме.
needle finetune data.jsonl --epochs 10 --out adapter.safetensors
needle build --lora adapter.safetensors --out tuned.cact
needle build --lora adapter.safetensors --platform linux-arm64 --layers 2 --out ./device
Подробнее в руководствах: проектирование инструментов, доверие, структурированное извлечение, тонкая настройка, справочник Python, поддерживаемые устройства, формат .cact и портирование Needle. Исходный код на GitHub.
Платформа Cactus
Needle разработан для кастомизации. Его ёмкость — это лестница, и подсеть размером всего 2 слоя, обученная на инструментах одного продукта, оптимально работает на устройствах гораздо меньше, чем нужно полной модели. Ограничение ёмкости узкой, хорошо определённой задачей позволяет достичь там граничного уровня точности: тонкая настройка на DroidCall поднимает каждую подсеть на 18–36 пункта, и со слоя 4 и выше обученная подсеть превосходит DeepSeek V4 Flash, начиная с 29M параметров.
Платформа Cactus — полный путь: наборы данных Cactus, 2-битная квантизация за обученной моделью, проектирование и отслеживание оценок, полнослойные тонкие настройки и управление наборами данных, всё на инфраструктуре и конвейере обучения Cactus, без нужды собирать свой.
Развёртывание
Каждая цель развёртывания поставляется с предсобранным механизмом размером менее 1 МБ, загружающим веса needle3.cact при старте. needle build загружает механизм для платформы и помещает веса рядом, при полных 20 слоях или любой меньшей подсети:
| Цель | Папка платформы | Поставляется |
|---|---|---|
| macOS | macos-arm64 | needle CLI, libneedle.a, needle.h |
| Linux | linux-x86_64, linux-arm64, linux-armv7, linux-riscv64, linux-mipsel | needle CLI, libneedle.a, needle.h |
| Windows | windows-x86_64, windows-arm64 | needle.exe, libneedle.a, needle.h |
| Android | android-arm64, android-armv7, android-riscv64 | needle CLI, libneedle.a, needle.h |
| iOS | ios-arm64, ios-sim-arm64 | libneedle.a, needle.h |
| tvOS, watchOS | tvos-arm64, watchos-arm64 | libneedle.a, needle.h |
| Браузер | wasm | needle.js, needle.wasm, needle.h |
| WASI component | wasm-component | needle.component.wasm, needle.wit |
Одна папка на платформу; needle build --platform загружает её и помещает needle3.cact рядом с механизмом.
# engine, header and weights for this Mac
needle build --platform macos-arm64
# an 8-layer subnetwork for a Pi
needle build --platform linux-arm64 --layers 8 --out ./pi
# a tuned archive
needle build --lora adapter.safetensors --out tuned.cact