La Interfaz del Controlador de Inteligencia Artificial (AICI) le permite construir controladores que limitan y la salida directa de un modelo de lenguaje grande (LLM) en tiempo real. Los controladores son programas flexibles capaces de implementar decodificación restringida, edición dinámica de indicaciones y texto generado, y coordinar la ejecución en múltiples generaciones paralelas. Los controladores incorporan una lógica personalizada durante la decodificación del token-by-token y mantienen el estado durante una solicitud de LLM. Esto permite diversas estrategias del controlador, desde la decodificación programática o basada en consultas hasta conversaciones de múltiples agentes para ejecutar eficientemente en una integración estrecha con la propia LLM.
El propósito de AICI es facilitar la construcción y experimentar con estrategias de controlador existentes y completamente nuevas para mejorar las generaciones de LLM. Al abstraer los detalles de implementación de la inferencia y el motor de servicio LLM subyacente, AICI tiene como objetivo simplificar el desarrollo de controladores, facilitar la redacción de controladores rápidos y facilitar la compatibilidad en los motores de inferencia y servicio de LLM.
AICI está diseñado para la ejecución local y en la nube, incluidas (eventualmente) implementaciones de LLM múltiples. Los controladores se implementan como módulos WebAsmbly (WASM) de peso ligero que se ejecutan en la misma máquina que el motor de inferencia LLM, utilizando la CPU mientras la GPU está ocupada con la generación de tokens. AICI es una capa en la pila de inferencias, y está diseñada para permitir bibliotecas de control como la guía, LMQL y otros ejecutarse además y obtener mejoras de eficiencia y rendimiento, así como la portabilidad en la inferencia y los motores de servicio LLM.
AICI actualmente se integra con Llama.CPP, Huggingface Transformers y RLLM (motor de inferencia LLM basado en TCH personalizado), con VLLM en las obras.
Aici es:
AICI es un prototipo, diseñado y construido en Microsoft Research.
En este rápido arranque, lo guiaremos a través de los siguientes pasos:
Para compilar componentes AICI, debe configurar su entorno de desarrollo para el óxido. Para este rápido arranque, también necesita Python 3.11 o posterior para crear un controlador.
Nota
Usuarios de Windows : use WSL2 o el DevContainer incluido. Agregar soporte nativo de Windows se rastrea aquí.
Usuarios de MacOS : asegúrese de tener herramientas de línea de comandos Xcode instaladas ejecutando xcode-select -p y, si no está instalado, ejecute xcode-select --install .
CUDA : La construcción CUDA se basa en una instalación específica de Libtorch. Es muy recomendable que use el DevContainer incluido.
Si está usando DevContainer, puede omitir a la siguiente sección.
Utilizando el administrador de paquetes del sistema, instale las herramientas necesarias para la construcción del código en el repositorio, incluidos git , cmake y ccache .
Por ejemplo, en WSL / Ubuntu usando apt :
sudo apt-get install --assume-yes --no-install-recommends
build-essential cmake ccache pkg-config libssl-dev libclang-dev clang llvm-dev git-lfs
o usar HomeBrew en macOS:
brew install git cmake ccache
Luego instale Rust, Rustup y Cargo , siguiendo las instrucciones proporcionadas aquí y aquí:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Después de la instalación, verifique que el comando rustup --version sea accesible ejecutándolo desde el terminal. Si no se reconoce el comando, intente abrir una nueva sesión de terminal.
Siguiente instalación componente WASM32-Wasi Rust:
rustup target add wasm32-wasi
Si ya tenía el óxido instalado o recibe quejas de la carga sobre versiones obsoletas, ejecute:
rustup update
Por último, para trabajar con controladores y scripts de Python (como este tutorial), ejecute este comando para instalar los paquetes requeridos:
pip install pytest pytest-forked ujson posix_ipc numpy requests
El servidor RLLM tiene dos backends, uno basado en libtorch y CUDA ( rllm-cuda ) y el otro basado en llama.cpp ( rllm-llamacpp ).
El backend rllm-cuda solo funciona con las GPU NVIDIA con la capacidad de cómputo 8.0 o posterior (A100 y posterior; RTX 30x0 y posterior) y requiere una configuración complicada de LibTorch; se recomienda usar el DevContainer incluido. Si bien esta guía se centra en el backend rllm-llamacpp , los pasos de compilación son los mismos para rllm-cuda , Modulo el nombre de la carpeta.
Después de la configuración de Dev Env arriba, clone el repositorio AICI y continúe con los siguientes pasos descritos a continuación.
Use el siguiente comando para construir y ejecutar aicirt y rllm-llamacpp :
cd rllm/rllm-llamacpp
./server.sh phi2
Puede pasar otros nombres de modelos como argumento (ejecutar ./server.sh sin argumentos para ver los modelos disponibles). También puede usar una URL de Huggingface a un archivo .gguf o una ruta local a un archivo .gguf . (Para rllm-cuda use ID de modelo Huggingface o ruta a la carpeta).
./server.sh orca
Puede encontrar más detalles sobre rllm-llamacpp aquí.
El servidor RLLM proporciona una interfaz HTTP, utilizada para tareas de configuración y solicitudes de procesamiento. También puede usar esta interfaz para verificar de inmediato su estado. Por ejemplo, si abre http://127.0.0.1:4242/v1/models, debería ver:
{
"object" : " list " ,
"data" : [
{
"object" : " model " ,
"id" : " TheBloke/phi-2-GGUF " ,
"created" : 946810800 ,
"owned_by" : " owner "
}
]
}confirmando que el modelo seleccionado está cargado.
AICI permite alojar la lógica personalizada, llamadas controladores , que inician, terminan e interactúan con la generación de tokens LLMS. Los controladores toman argumentos de entrada, los procesan y devuelven un resultado con registros, tokens LLM y variables.
El repositorio incluye algunos ejemplos, en particular:
En este ejemplo, utilizaremos PYCTRL para administrar la generación de tokens utilizando un script de Python simple. Si lo desea, puede construir y cargar PYCTRL, sin embargo, de manera predeterminada, el servidor descargará automáticamente la última versión de PYCTRL desde GitHub.
En general, los controladores requieren construcción e implementación, mientras que los scripts (Python o JavaScript) se envían con cada solicitud.
Lo siguiente ilustra la relación entre el servidor RLLM, el tiempo de ejecución AICI y el controlador:
erdiagram
Host ||-| {CPU: ""
Host ||-| {GPU: ""
CPU ||-|| "servidor RLLM": ejecutar
CPU ||-| {"Aici Runtime": ejecutar
"Aici Runtime" ||-|| "Controlador": instanciar
GPU ||-| {"LLM Generación de token": ejecutar
Supongamos que apuntamos a que un modelo genere una lista, adhiriéndose a un formato específico y que contenga solo cinco elementos.
Por lo general, lograr esto implica ingeniería rápida, elaborar el aviso precisamente con instrucciones claras, como:
What are the five most popular types of vehicles?
Return the result as a numbered list.
Do not add explanations, only the list.
El aviso también variaría según el modelo en uso, dado que cada modelo tiende a agregar explicaciones y comprende las instrucciones de diferentes maneras.
Con AICi, cambiamos el control al código, y podemos simplificar la solicitud a:
What are the most popular types of vehicles?
Uso del código para:
Creemos una list-of-five.py Python con el siguiente contenido:
import pyaici . server as aici
# Force the model to generate a well formatted list of 5 items, e.g.
# 1. name 1
# 2. name 2
# 3. name 3
# 4. name 4
# 5. name 5
async def main ():
# This is the prompt we want to run.
# Note how the prompt doesn't mention a number of vehicles or how to format the result.
prompt = "What are the most popular types of vehicles? n "
# Tell the model to generate the prompt string, ie. let's start with the prompt "to complete"
await aici . FixedTokens ( prompt )
# Store the current position in the token generation process
marker = aici . Label ()
for i in range ( 1 , 6 ):
# Tell the model to generate the list number
await aici . FixedTokens ( f" { i } ." )
# Wait for the model to generate a vehicle name and end with a new line
await aici . gen_text ( stop_at = " n " )
await aici . FixedTokens ( " n " )
# Store the tokens generated in a result variable
aici . set_var ( "result" , marker . text_since ())
aici . start ( main ())Ejecutar el script no es muy diferente de enviar un mensaje. En este caso, estamos enviando lógica de control e instrucciones todas juntas.
Para ver el resultado final, ejecute el siguiente comando:
./aici.sh run list-of-five.py
Resultado:
Running with tagged AICI Controller: gh:microsoft/aici/pyctrl
[0]: FIXED 'What are the most popular types of vehicles?n'
[0]: FIXED '1.'
[0]: GEN ' Carsn'
[0]: FIXED '2.'
[0]: GEN ' Motorcyclesn'
[0]: FIXED '3.'
[0]: GEN ' Bicyclesn'
[0]: FIXED '4.'
[0]: GEN ' Trucksn'
[0]: FIXED '5.'
[0]: GEN ' Boatsn'
[0]: FIXED 'n'
[DONE]
[Response] What are the most popular types of vehicles?
1. Cars
2. Motorcycles
3. Bicycles
4. Trucks
5. Boats
response saved to tmp/response.json
Usage: {'sampled_tokens': 16, 'ff_tokens': 37, 'cost': 69}
Timing: {'http_response': 0.05193686485290527, 'data0': 0.05199289321899414, 'first_token': 0.0658726692199707, 'last_token': 0.1784682273864746}
Tokens/sec: {'prompt': 861.0913072488067, 'sampling': 89.65181217019571}
Storage: {'result': '1. Carsn2. Motorcyclesn3. Bicyclesn4. Trucksn5. Boatsnn'}
Este repositorio contiene una serie de componentes, y cuáles necesita depende de su caso de uso.
Puede usar un módulo de controlador existente . Proporcionamos PYCTRL y JSCTRL que le permiten a los controladores de script utilizando Python y JavaScript del lado del servidor, respectivamente. El paquete Pyaici contiene aici herramienta de línea de comandos AICI que le permite cargar y ejecutar scripts con cualquier controlador (también proporcionamos una definición de API REST para los curiosos).
? Python muestras de código para secuencias de comandos Pyctrl y un JavaScript Hello World para JSCTRL
Anticipamos que las bibliotecas se construirán sobre los controladores. Proporcionamos un ejemplo en TartrLib: una biblioteca de Python del lado del cliente que genera interacción con DeclCTRL a través del paquete PyaiCI.
? Ejemplo de cuaderno que usa ToRLIB para interactuar con DeclCTRL.
Los controladores se pueden ejecutar en una nube o un motor LLM de inferencia LLM habilitado para AICI local. Puede ejecutar el motor de referencia proporcionado (RLLM) localmente con Libtorch+Cuda o Llama.cpp Backend.
Para desarrollar un nuevo controlador , use un proyecto de inicio de óxido que muestra el uso de la biblioteca AICI_ABI, lo que simplifica la implementación de la interfaz AICI de bajo nivel.
? Código de muestra para un nuevo controlador mínimo para comenzar
Para agregar soporte AICI a un nuevo motor de inferencia de LLM , deberá implementar el lado de LLM del protocolo que habla con el tiempo de ejecución de AICI.
Finalmente, es posible que desee modificar cualquiera de los componentes proporcionados: ¡los PR son bienvenidos!
Aici Abstracts LLM Inference Engine del controlador y viceversa, como en la imagen a continuación. Los nodos redondeados son aspiracionales. Se pueden construir capas adicionales en la parte superior: proporcionamos practLib, pero creemos firmemente que la orientación, LMQL, SGLANG, los contornos, JSONFormer, LMFE, etc. también pueden ejecutarse encima de AICI (ya sea con controladores personalizados o utilizando PYCTRL o JSCTRL).
Gráfico TD
Pyctrl-aici-> aicirt [aici-runtime]
Jsctrl -aici -> aicirt
Guía ([GuidanCectrl]) -Aici -> Aicirt
LMQL ([LMQL CTRL]) -AICI -> AICIRT
aicirt -Posix shm -> rllm
Aicirt -Posix SHM -> Llama [Llama.cpp]
Aicirt -Posix SHM -> Pyaici
Pyaici -Python -> Vllm (VLLM)
Pyaici -Python -> HF [HF Transformers]
El paquete Pyaici facilita la integración de AICI con los motores de inferencia LLM con sede en Python. Eche un vistazo a la integración con Huggingface Transformers, aunque tenga en cuenta que no es compatible con el bifurcado (generación de secuencias múltiples en paralelo). El servidor REST VLLM está actualmente desactualizado. Utilice el rllm-cuda o rllm-llama.cpp por ahora.
aicirt se ejecuta en un proceso separado y puede funcionar bajo un usuario diferente al motor LLMaici_host_* , implementadas en hostimpl.rsaicirt también expone una interfaz WASI parcial; Sin embargo, casi todas las funciones son NO-OP, a excepción de fd_write , que los descriptores de archivos 1 y 2 (stdout y stderr) imprimen mensajes de depuraciónEn particular, los módulos WASM no pueden acceder al sistema de archivos, la red o cualquier otro recurso. Tampoco pueden hacer hilos o acceder a ningún temporizador (esto es relevante para ataques Spectre/Meltdown).
La mayor parte del cálculo en los controladores AICI ocurre en la CPU, en paralelo con la generación logit en la GPU. La generación ocurre en pasos, donde los logits se generan en paralelo para un nuevo token para cada secuencia en un lote (típicamente entre 1 y 50). Esto implica leer todo el modelo y los cachés de KV para secuencias en el lote de la memoria de la GPU. Para un rendimiento de lotes óptimo, el modelo y los cachés de KV deberían utilizar una fracción importante de la memoria de GPU, y leer la memoria completa toma aproximadamente 40 ms en A100 GPU (80 GB).
Por lo tanto, cada paso de generación adquiere el orden de 20-50 ms. Con una ingeniería cuidadosa, esto es más que suficiente para calcular el conjunto de tokens permitidos en óxido compilados a WASM. Estos se pueden combinar de forma nativa en óxido, o a través de intérpretes de Python o JavaScript que proporcionamos.
Por ejemplo, la computación permitida se establece en el modelo de Vocabulario de Llama de 32000.
Los números anteriores son para una sola secuencia, sin embargo, cada secuencia se procesa en un proceso separado y, por lo tanto, si hay más núcleos que secuencias (lo cual es típico), no cambian. También incluyen la sobrecarga de llamar al intérprete de Python implementado en WASM, y luego volver al código WASM generado por el óxido para la restricción en sí. Todos están dentro del presupuesto de 20-50 ms, por lo que no afecten el tiempo de generación en absoluto.
También hay algo de sobrecarga en la ruta crítica del muestreo. Se reduce a aproximadamente 0.3 ms por paso de generación al ejecutar 10 secuencias en paralelo (esto es independientemente de la restricción utilizada). La sobrecarga sube a alrededor de 0.7 ms para 40 secuencias (aunque aún no se ha optimizado completamente).
WebAssembly está diseñado para tener una sobrecarga mínima, en comparación con el código nativo. En nuestra experiencia, el código de óxido altamente optimizado es menos que 2 veces más lento cuando se ejecuta en Wasmtime que nativo. Esto es 10-100x mejor que JavaScript o Python.
Todas las medidas realizadas en AMD EPYC 7V13 con NVIDIA A100 GPU con 80 GB de VRAM.
La interfaz de bajo nivel que proporciona el tiempo de ejecución de AICI permite:
Se puede utilizar desde cualquier idioma que compile a WASM.
Este repositorio proporciona una biblioteca de óxido que facilita la implementación de controladores en óxido, y proporciona implementaciones eficientes de restricciones específicas (expresiones regulares, gramáticas YACC, sustras). También proporcionamos intérpretes de Python y JavaScript que permiten pegar estas limitaciones. Todo esto puede extenderse fácilmente.
Si encuentra la interfaz del controlador AI y sus ideas para definir una nueva capa en la pila de inferencias LLM útil, cite el paquete utilizando la siguiente referencia:
Bibtex:
@misc { Moskal2024 ,
author = { Moskal, Michal and Musuvathi, Madan and {Ki ci man}, Emre } ,
title = { {AI Controller Interface} } ,
year = { 2024 } ,
publisher = { {GitHub} } ,
journal = { {GitHub} repository } ,
howpublished = { url{https://github.com/microsoft/aici/} }
}Este proyecto da la bienvenida a las contribuciones y sugerencias. La mayoría de las contribuciones requieren que acepte un Acuerdo de Licencia de Contributor (CLA) que declare que tiene derecho y realmente hacernos los derechos para utilizar su contribución. Para más detalles, visite https://cla.opensource.microsoft.com.
Cuando envíe una solicitud de extracción, un BOT CLA determinará automáticamente si necesita proporcionar un CLA y decorar el PR adecuadamente (por ejemplo, verificación de estado, comentario). Simplemente siga las instrucciones proporcionadas por el bot. Solo necesitará hacer esto una vez en todos los reposos usando nuestro CLA.
Este proyecto ha adoptado el Código de Conducta Open Open Microsoft. Para obtener más información, consulte el Código de Conducta Preguntas frecuentes o comuníquese con [email protected] con cualquier pregunta o comentario adicional.
Este proyecto puede contener marcas comerciales o logotipos para proyectos, productos o servicios. El uso autorizado de marcas o logotipos de Microsoft está sujeto y debe seguir las pautas de marca y marca de Microsoft. El uso de marcas registradas de Microsoft o logotipos en versiones modificadas de este proyecto no debe causar confusión o implicar el patrocinio de Microsoft. Cualquier uso de marcas comerciales o logotipos de terceros está sujeto a las políticas de esas partes de terceros.