OA0
OA0 是一个探索 AI 的社区
现在注册
已注册用户请  登录
OA0  ›  代码  ›  AICI — 面向可控文本生成的推理约束引擎

AICI — 面向可控文本生成的推理约束引擎

 
  jwt ·  2026-02-25 22:58:46 · 6 次点击  · 0 条评论  

人工智能控制器接口 (AICI)

LLGuidance 库 是 AICI 的一个积极维护的演进和专门化版本,如果你只需要约束解码,推荐使用它。

人工智能控制器接口 (AICI) 允许你构建控制器,以实时约束和引导大型语言模型 (LLM) 的输出。
控制器是灵活的程序,能够实现约束解码、动态编辑提示词和生成文本,并协调多个并行生成过程的执行。
控制器在逐个令牌的解码过程中融入自定义逻辑,并在 LLM 请求期间维护状态。这使得从程序化或基于查询的解码到多智能体对话等多样化的控制器策略,能够与 LLM 本身紧密集成并高效执行。

AICI 的目的是让构建和试验现有及全新的控制器策略以改进 LLM 生成变得容易。
通过抽象底层 LLM 推理和服务引擎的实现细节,AICI 旨在简化控制器的开发,使编写快速控制器更容易,并提高跨 LLM 推理和服务引擎的兼容性。

AICI 设计用于本地和云端执行,包括(最终)多租户 LLM 部署。
控制器作为轻量级 WebAssembly (Wasm) 模块实现,这些模块在与 LLM 推理引擎相同的机器上运行,在 GPU 忙于令牌生成时利用 CPU。
AICI 是推理栈中的一层,旨在允许 Guidance、LMQL 等控制库在其上运行,并获得效率和性能的提升,以及跨 LLM 推理和服务引擎的可移植性。

AICI 目前集成了 llama.cpp、HuggingFace Transformers 和 rLLM(基于 tch 的自定义 LLM 推理引擎),vLLM 正在开发中。

AICI 具有以下特点:

  • 灵活:控制器可以用任何能编译成 Wasm 的语言(Rust、C、C++ 等)编写,也可以在 Wasm 内解释执行(Python、JavaScript 等)
  • 安全:控制器被沙箱化,无法访问文件系统、网络或任何其他资源
  • 快速:Wasm 模块被编译成本地代码,并与 LLM 推理引擎并行运行,对生成过程仅引入极小的开销

AICI 是一个原型,由 微软研究院 设计和构建。

目录

快速开始:示例演练

在这个快速开始中,我们将指导你完成以下步骤:

  • 设置 rLLM 服务器AICI 运行时
  • 构建并部署一个 控制器
  • 使用 AICI 控制 LLM 输出,以便你可以在生成文本时定制 LLM 遵循特定规则

开发环境设置

要编译 AICI 组件,你需要为 Rust 设置开发环境。对于本快速开始,你还需要 Python 3.11 或更高版本来创建控制器。

Windows WSL / Linux / macOS

[!NOTE]
Windows 用户:请使用 WSL2 或附带的 devcontainer。添加原生 Windows 支持 在此处跟踪

MacOS 用户:请确保已安装 XCode 命令行工具,运行 xcode-select -p 检查,如果未安装,运行 xcode-select --install

CUDA:CUDA 构建依赖于特定的 libtorch 安装。强烈建议你使用附带的 devcontainer。

如果你使用 devcontainer,可以跳到 下一节

使用系统包管理器安装构建代码仓库所需的工具,包括 gitcmakeccache

例如,在 WSL / Ubuntu 中使用 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

或者在 macOS 上使用 Homebrew:

brew install git cmake ccache

然后按照 此处此处 提供的说明安装 Rust、Rustup 和 Cargo

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装后,通过从终端运行 rustup --version 命令来验证其是否可访问。如果命令无法识别,请尝试打开新的终端会话。

接下来安装 wasm32-wasi Rust 组件:

rustup target add wasm32-wasi

如果你已经安装了 Rust,或者 Cargo 抱怨版本过时,请运行:

rustup update

最后,为了使用 Python 控制器和脚本(如本教程),运行以下命令安装所需的包:

pip install pytest pytest-forked ujson posix_ipc numpy requests

构建并启动 rLLM 服务器和 AICI 运行时

rLLM 服务器有两个后端,一个基于 libtorch 和 CUDA (rllm-cuda),另一个基于 llama.cpp (rllm-llamacpp)。

rllm-cuda 后端仅适用于计算能力 8.0 或更高版本的 NVidia GPU(A100 及以后;RTX 30x0 及以后),并且需要繁琐的 libtorch 设置——强烈建议使用附带的 devcontainer。
虽然本指南侧重于 rllm-llamacpp 后端,但构建步骤对于 rllm-cuda 是相同的,除了文件夹名称。

完成上述 开发环境设置 后,克隆 AICI 仓库并按照下面概述的后续步骤进行。

使用以下命令构建并运行 aicirtrllm-llamacpp

cd rllm/rllm-llamacpp
./server.sh phi2

你可以传递其他模型名称作为参数(不带参数运行 ./server.sh 以查看可用模型)。
你也可以使用 HuggingFace 上 .gguf 文件的 URL 或本地 .gguf 文件的路径。
(对于 rllm-cuda,使用 HuggingFace 模型 ID 或文件夹路径)。

./server.sh orca

你可以在 这里 找到关于 rllm-llamacpp 的更多详细信息。

rLLM 服务器提供了一个 HTTP 接口,用于配置任务和处理请求。你也可以使用此接口快速验证其状态。例如,如果你打开 http://127.0.0.1:4242/v1/models,你应该看到:

{
  "object": "list",
  "data": [
    {
      "object": "model",
      "id": "TheBloke/phi-2-GGUF",
      "created": 946810800,
      "owned_by": "owner"
    }
  ]
}

确认所选模型已加载。

使用 AICI 控制器控制 AI 输出

AICI 允许托管称为 控制器 的自定义逻辑,这些逻辑启动、终止并与 LLM 令牌生成交互。控制器接收输入参数,处理它们,并返回包含日志、LLM 令牌和变量的结果。

该仓库包含一些示例,特别是:

  • jsctrl:一个接受 JavaScript 代码作为输入执行的控制器。此代码可以与模型交互以生成文本和令牌。
  • pyctrl:一个接受 Python 代码作为输入执行的控制器。此代码也可以与模型交互以生成文本和令牌。

在这个例子中,我们将使用 pyctrl 通过一个简单的 Python 脚本 来管理令牌生成。
如果你愿意,可以 构建并上传 pyctrl
但默认情况下,服务器会自动从 GitHub 下载最新版本 的 pyctrl。

通常,控制器需要构建和部署,而脚本(Python 或 JavaScript)则随每个请求一起发送。

下图说明了 rLLM 服务器、AICI 运行时和控制器之间的关系:

erDiagram
    Host    ||--|{ CPU : ""
    Host    ||--|{ GPU : ""

    CPU     ||--|| "rLLM Server" : execute
    CPU     ||--|{ "AICI Runtime" : execute

    "AICI Runtime" ||--|| "Controller" : instantiate

    GPU     ||--|{ "LLM token generation" : execute

控制 LLM 令牌生成

假设我们的目标是让模型生成一个列表,遵循特定格式并且只包含五个项目。

通常,实现这一点需要提示工程,精确地设计提示,给出清晰的指令,例如:

五种最受欢迎的交通工具是什么?
以编号列表的形式返回结果。
不要添加解释,只返回列表。

提示也会因使用的模型而异,因为每个模型倾向于以不同的方式添加解释和理解指令。

使用 AICI,我们将控制权交还给代码,并且可以将提示简化为:

最受欢迎的交通工具有哪些?

使用代码来:

  1. 将列表限制为 5 个项目
  2. 防止模型添加一些初始解释
  3. 格式化为编号列表
  4. 阻止模型在列表后添加一些文本。

让我们创建一个 list-of-five.py Python 文件,内容如下:

import pyaici.server as aici

# 强制模型生成一个格式良好的包含 5 个项目的列表,例如:
#   1. 名称 1
#   2. 名称 2
#   3. 名称 3
#   4. 名称 4
#   5. 名称 5
async def main():

    # 这是我们想要运行的提示。
    # 注意提示中没有提到交通工具的数量或如何格式化结果。
    prompt = "What are the most popular types of vehicles?\n"

    # 告诉模型生成提示字符串,即,让我们从要“完成”的提示开始
    await aici.FixedTokens(prompt)

    # 存储令牌生成过程中的当前位置
    marker = aici.Label()

    for i in range(1,6):
      # 告诉模型生成列表编号
      await aici.FixedTokens(f"{i}.")

      # 等待模型生成一个交通工具名称并以换行符结束
      await aici.gen_text(stop_at = "\n")

    await aici.FixedTokens("\n")

    # 将生成的令牌存储在结果变量中
    aici.set_var("result", marker.text_since())

aici.start(main())

运行脚本与发送提示没有太大区别。在这种情况下,我们同时发送控制逻辑和指令。

要查看最终结果,执行以下命令:

./aici.sh run list-of-five.py

结果:

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 ' Cars\n'
[0]: FIXED '2.'
[0]: GEN ' Motorcycles\n'
[0]: FIXED '3.'
[0]: GEN ' Bicycles\n'
[0]: FIXED '4.'
[0]: GEN ' Trucks\n'
[0]: FIXED '5.'
[0]: GEN ' Boats\n'
[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. Cars\n2. Motorcycles\n3. Bicycles\n4. Trucks\n5. Boats\n\n'}

综合指南:深入探索

此仓库包含许多组件,你需要哪些取决于你的用例。

你可以 使用现有的控制器模块
我们提供了 PyCtrlJsCtrl,分别允许你使用服务器端 Python 和 JavaScript 编写控制器脚本。
pyaici 包包含 aici 命令行工具,允许你 上传和运行脚本 与任何控制器
(我们还为好奇者提供了 REST API 定义)。

🧑‍💻用于编写 PyCtrl 脚本的 Python 代码示例用于 JSCtrl 的 JavaScript Hello World

我们预计 将建立在控制器之上。
我们在 promptlib 中提供了一个示例 - 一个客户端 Python 库,它通过 pyaici 包与 DeclCtrl 交互。

🧑‍💻 使用 PromptLib 与 DeclCtrl 交互的示例笔记本

控制器可以在支持 AICI 的云端或本地 LLM 推理引擎中运行。
你可以 在本地运行提供的参考引擎 (rLLM),使用 libtorch+CUDAllama.cpp 后端

开发一个新的控制器,使用一个 Rust 入门项目,它展示了 aici_abi 库的用法,该库简化了 低级 AICI 接口 的实现。

🧑‍💻用于最小化新控制器的示例代码 帮助你入门

为新的 LLM 推理引擎添加 AICI 支持
你需要实现与 AICI 运行时 通信的 协议 的 LLM 端。

最后,你可能想要修改任何提供的组件 - 非常欢迎 PR!

架构

AICI 将 LLM 推理引擎与控制器相互抽象,如下图所示。
圆角节点是愿景。
可以在其上构建额外的层 - 我们提供了 promptlib
但我们坚信
Guidance
LMQL
SGLang
Outlines
jsonformer
LMFE
等也可以在 AICI 上运行(通过自定义控制器或利用 PyCtrl 或 JsCtrl)。

graph TD
    PyCtrl -- AICI --> aicirt[AICI-runtime]
    JsCtrl -- AICI --> aicirt
    guidance([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]

pyaici 包使得将 AICI 与基于 Python 的 LLM 推理引擎集成更容易。
查看与 HuggingFace Transformers 的集成,
但请注意它不支持分叉(并行生成多个序列)。
vLLM REST 服务器 目前已经过时。
请暂时使用 rLLM-cudarLLM-llama.cpp

安全性

  • aicirt 在单独的进程中运行,并且可以作为与 LLM 引擎不同的用户运行
  • Wasm 模块 由 Wasmtime 沙箱化
  • Wasm 只能访问在 hostimpl.rs 中实现的 aici_host_* 函数
  • aicirt 还暴露了一个部分的 WASI 接口;然而,几乎所有函数都是无操作的,除了 fd_write,它将文件描述符 1 和 2(stdout 和 stderr)桥接以打印调试消息
  • 每个 Wasm 模块在单独的进程中运行,有助于缓解 Spectre/Meltdown 攻击并允许限制 CPU 使用

特别是,Wasm 模块无法访问文件系统、网络或任何其他资源。
它们也无法启动线程或访问任何计时器(这与 Spectre/Meltdown 攻击相关)。

性能

AICI 控制器中的大部分计算发生在 CPU 上,与 GPU 上的 logit 生成并行进行。
生成以步骤进行,其中为批次中每个序列的新令牌并行生成 logits(通常在 1 到 50 之间)。
这涉及从 GPU 内存中读取整个模型和批次中序列的 KV 缓存。
为了获得最佳批次吞吐量,模型和 KV 缓存应占用 GPU 内存的主要部分,读取整个内存在 A100 GPU(80GB)上大约需要 40ms。

因此,生成的每个步骤大约需要 20-50

6 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
关于 ·  帮助 ·  PING ·  隐私 ·  条款   
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
耗时 374 ms
Developed with Cursor