GitHub_Trending/ai/aici机器人控制:用自然语言生成精确的机器人指令
【免费下载链接】aici 项目地址: https://gitcode.com/GitHub_Trending/ai/aici
你是否还在为AI生成内容格式混乱而烦恼?是否尝试过无数次提示词工程却依然无法让模型严格遵循指令?GitHub_Trending/ai/aici项目为你提供了全新解决方案——通过编程控制LLM输出,让自然语言生成精确可控的机器人指令。本文将带你快速掌握如何利用AICI框架实现对AI输出的精准控制,无需复杂的提示词技巧,直接用代码定义生成规则。
AICI框架简介
AICI(Artificial Intelligence Controller Interface)是一个由微软研究院开发的AI控制器接口,它允许开发者构建控制器来实时约束和引导大型语言模型(LLM)的输出。控制器是灵活的程序,能够实现约束解码、动态编辑提示和生成文本,以及协调多个并行生成的执行。
AICI的核心优势在于:
- 灵活性:控制器可以用任何能编译为Wasm的语言编写(Rust、C、C++等),或在Wasm中解释执行(Python、JavaScript等)
- 安全性:控制器运行在沙箱中,无法访问文件系统、网络或其他资源
- 高性能:Wasm模块被编译为本地代码,与LLM推理引擎并行运行,仅产生最小的生成过程开销
AICI的整体架构如下:
AICI运行时(aicirt)作为中间层,连接控制器和各种LLM后端,如rLLM、llama.cpp、vLLM等,实现了对不同LLM引擎的统一控制接口。
快速开始:环境搭建与运行
开发环境准备
要开始使用AICI,首先需要设置开发环境。以下是在不同操作系统上的安装步骤:
Windows WSL / Linux / macOS
-
安装必要的构建工具:
对于Ubuntu/Debian系统:
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 -
安装wasm32-wasi目标:
rustup target add wasm32-wasi -
安装Python依赖:
pip install pytest pytest-forked ujson posix_ipc numpy requests
构建并启动rLLM服务器和AICI运行时
AICI提供了两种rLLM后端:基于libtorch和CUDA的rllm-cuda,以及基于llama.cpp的rllm-llamacpp。这里我们以rllm-llamacpp为例:
cd rllm/rllm-llamacpp
./server.sh phi2
你可以传递不同的模型名称作为参数,例如:
./server.sh orca
服务器启动后,可以通过访问http://127.0.0.1:4242/v1/models来验证是否成功运行,你应该能看到类似以下的JSON响应:
{
"object": "list",
"data": [
{
"object": "model",
"id": "TheBloke/phi-2-GGUF",
"created": 946810800,
"owned_by": "owner"
}
]
}
使用AICI控制机器人指令生成
基本原理:从提示工程到代码控制
传统上,要让AI生成特定格式的内容,需要精心设计提示词。例如,要生成一个包含5项的车辆列表,可能需要这样的提示:
What are the five most popular types of vehicles?
Return the result as a numbered list.
Do not add explanations, only the list.
而使用AICI,我们可以将提示简化为:
What are the most popular types of vehicles?
然后通过代码来控制生成过程:
- 限制列表为5个项目
- 防止模型添加初始解释
- 格式化为编号列表
- 阻止模型在列表后添加额外文本
示例:生成格式化的车辆列表
下面是一个使用Python编写的控制器脚本(list-of-five.py),它能精确控制AI生成一个包含5项的车辆列表:
import pyaici.server as aici
# 强制模型生成格式良好的5项列表,例如:
# 1. name 1
# 2. name 2
# 3. name 3
# 4. name 4
# 5. name 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
...
高级控制:分支生成与变量共享
AICI还支持更复杂的控制逻辑,如分支生成和变量共享。以下是一个使用fork功能的示例,同时生成"hello"的法语和德语翻译:
async def test_fork():
if not aici.fork_supported():
print("skipping fork test")
return
await aici.FixedTokens("The word 'hello' in")
id = await aici.fork(3)
if id == 0:
# 主分支:等待其他分支的结果并合并
french, german = await aici.wait_vars("french", "german")
await aici.FixedTokens(f"{french} is the same as {german}.")
await aici.gen_tokens(max_tokens=5)
aici.check_vars({"german": ' "hallo"', "french": ' "bonjour"'})
elif id == 1:
# 分支1:生成德语翻译
await aici.FixedTokens(" German is")
await aici.gen_tokens(regex=r' "[^"\.]+"', store_var="german", max_tokens=5)
elif id == 2:
# 分支2:生成法语翻译
await aici.FixedTokens(" French is")
await aici.gen_tokens(regex=r' "[^"\.]+"', store_var="french", max_tokens=5)
这个示例展示了AICI的强大功能:可以将生成过程分为多个并行分支,每个分支负责不同的任务,然后在主分支中汇总结果。这种方式特别适合需要同时处理多个子任务的复杂机器人指令生成场景。
AICI控制器开发详解
核心API与功能
AICI提供了丰富的API来控制LLM生成过程,主要包括:
- FixedTokens:添加固定文本到输出
- gen_text/gen_tokens:生成符合特定规则的文本/令牌
- Label/Following:标记位置并支持回溯
- fork/wait_vars:创建并行分支并共享变量
- set_var/get_var:设置和获取共享变量
下面是一个展示多种API用法的综合示例:
async def test_sample():
# 初始化代码
print("I'm going in the logs!")
prompt = await aici.GetPrompt()
# 添加固定文本到输出,类似于添加到提示
await aici.FixedTokens("The word 'hello' in French is")
# 生成匹配正则表达式的文本(令牌)
french = await aici.gen_text(regex=r' "[^"]+"', max_tokens=5)
# 设置共享变量(它们以JSON形式返回,在使用aici.fork()时非常有用)
aici.set_var("french", french)
await aici.FixedTokens(" and in German")
# 上述操作的简写形式
await aici.gen_text(regex=r' "[^"]+"', store_var="german")
await aici.FixedTokens("\nFive")
# 从选项列表中生成文本
await aici.gen_text(options=[" pounds", " euros", " dollars"])
常用控制器类型
AICI提供了多种现成的控制器,适用于不同场景:
-
PyCtrl:允许使用Python编写控制逻辑
- 代码位置:controllers/pyctrl
- 示例:Python代码示例
-
JsCtrl:允许使用JavaScript编写控制逻辑
-
DeclCtrl:声明式控制器,适合定义复杂规则
- 代码位置:controllers/declctrl
-
uppercase:简单的大小写转换控制器,适合作为新控制器开发的起点
性能优化与最佳实践
AICI经过精心设计,确保控制器逻辑不会显著影响LLM生成速度。关键性能指标包括:
- Yacc语法解析(C编程语言):约2.0ms
- 正则表达式匹配:约0.3ms
- 子字符串约束检查(4kB字符串):约0.2ms
这些操作都远低于LLM生成单个令牌所需的20-50ms,因此不会增加整体生成时间。
开发高性能AICI控制器的最佳实践:
- 利用编译型语言:对于性能关键的控制器,优先使用Rust等编译型语言
- 最小化生成步骤:在单个gen_text/gen_tokens调用中完成尽可能多的工作
- 合理使用分支:只有在必要时才使用fork,避免过多并行分支
- 优化正则表达式:复杂正则表达式会增加处理时间,尽量简化
实际应用案例
医疗领域:提取药物信息
在医疗领域,精确提取和格式化药物信息至关重要。以下示例展示了如何使用AICI从医生笔记中提取药物名称和服用时间:
async def test_drugs():
drug_syn = "\nUse <drug>Drug Name</drug> syntax for any drug name, for example <drug>Advil</drug>.\n\n"
notes = "The patient should take some tylenol in the evening and aspirin in the morning. Exercise is highly recommended. Get lots of sleep.\n"
notes = "Start doctor note:\n" + notes + "\nEnd doctor note.\n"
await aici.FixedTokens("[INST] ")
start = aici.Label()
def inst(s: str) -> str:
return s + drug_syn + notes + " [/INST]\n"
# 第一遍:提取药物名称
await aici.FixedTokens(
inst("List specific drug names in the following doctor's notes.")
+ "\n1. <drug>"
)
s = await aici.gen_text(max_tokens=30)
drugs = re.findall(r"<drug>([^<]*)</drug>", "<drug>" + s)
# 第二遍:提取服用时间
await aici.FixedTokens(
inst("Make a list of each drug along with time to take it, based on the following doctor's notes.")
+ "Take <drug>",
following=start,
)
pos = aici.Label()
await aici.gen_tokens(options=[d + "</drug>" for d in drugs])
# 提取每个药物的服用时间
for _ in range(5):
fragment = await aici.gen_text(max_tokens=20, stop_at="<drug>")
if "<drug>" in fragment:
assert fragment.endswith("<drug>")
await aici.gen_tokens(options=[d + "</drug>" for d in drugs])
else:
break
aici.set_var("times", "<drug>" + pos.text_since())
这个示例展示了AICI如何通过多阶段处理和回溯,精确提取和格式化医疗文本中的关键信息,为医疗机器人系统提供可靠的数据输入。
数学问题求解:确保计算准确性
AICI还可以用于确保AI生成内容的准确性,例如在数学计算场景中:
async def test_backtrack_one():
await aici.FixedTokens("3+")
l = aici.Label()
await aici.FixedTokens("2")
await aici.gen_tokens(regex=r"=\d\d?\.", store_var="x", max_tokens=5)
print("X", aici.get_tokens(), aici.detokenize(aici.get_tokens()))
# 回溯并尝试另一种可能性
await aici.FixedTokens("4", following=l)
await aici.gen_tokens(regex=r"=\d\d?\.", store_var="y", max_tokens=5)
print("Y", aici.get_tokens(), aici.detokenize(aici.get_tokens()))
# 验证结果是否正确
aici.check_vars({"x": "=5.", "y": "=7."})
这个示例展示了如何使用AICI的回溯功能(Label和Following)来尝试不同的计算路径,并验证结果的正确性,确保机器人指令中的数学计算部分准确无误。
总结与展望
AICI为机器人指令生成提供了革命性的解决方案,通过将控制逻辑从自然语言提示词转移到结构化代码,实现了前所未有的精确性和可靠性。本文介绍了AICI的基本概念、环境搭建、核心功能和实际应用案例,展示了如何利用这一强大工具来生成精确可控的机器人指令。
AICI的主要优势在于:
- 精确控制:通过代码而非自然语言提示来控制生成过程,结果更加可靠
- 灵活性:支持多种编程语言和控制策略,适应不同场景需求
- 高性能:Wasm运行时确保控制逻辑不会显著影响生成速度
- 安全性:沙箱环境确保控制器代码无法访问敏感资源
随着AICI的不断发展,我们可以期待更多高级功能的出现,如更丰富的约束类型、更强大的分支控制、以及与各种机器人平台的深度集成。无论是工业机器人、服务机器人还是家庭自动化系统,AICI都将成为连接自然语言理解和精确指令执行的关键桥梁。
要深入了解AICI的更多功能和高级用法,可以参考以下资源:
通过AICI,我们正在迈入一个新的时代:自然语言不再是模糊的指令,而是精确可控的机器人操作语言。这不仅将大大提升机器人系统的可靠性和效率,还将为人工智能的应用开辟全新的可能性。
【免费下载链接】aici 项目地址: https://gitcode.com/GitHub_Trending/ai/aici
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



