编程 Needle:14MB 单文件把会调工具的 AI 塞进手表和智能家居

2026-08-29 19:26:09

在微型设备上跑 AI 一直是个尴尬的选择:大模型塞不进内存,小模型能力不够;请求上云有延迟和隐私问题,纯本地运算又怕内存爆掉。Cactus Compute 开源的 Needle 用单文件方案做了一次取舍:完整模型加推理引擎打包成 14MB,一个会话约 28MB 内存,能跑工具调用、设备控制和结构化提取,全程离线。

项目原理

Needle 是个微型基础模型,针对手机、可穿戴设备、智能家居和机器人这类受限场景设计。它只做三件事:

  • 工具调用:模型根据用户指令选择工具函数、填参数并执行。
  • 设备控制:通过自然语言操作连接到模型接口的智能设备。
  • 结构化提取:从一段文本中按预定义格式抽取字段。

权重和推理引擎全部打包在一个二进制文件里,没有额外模型文件,不发任何网络请求。模型使用 2-bit 量化,在基准测试中与 FunctionGemma 270M、LFM2.5 230M、Apple FM 互有胜负,但体积只有它们的 1/5 到 1/70。

工作原理是用 Python 装饰器注册工具,模型读取函数签名和 docstring 来理解工具用途。输入一句话后,模型决定调用哪个工具、怎么填参数,执行结果返回给模型后生成最终响应。实际在 web demo 里验证了几个场景:

工具调用

后台定义了获取天气的工具。输入:

what's the weather in Tokyo?

对话区自动调用 called get_weather(city='Tokyo') 并返回天气 JSON,右侧面板同步显示决策 JSON、推理过程和置信度进度条(绿色,>0.9)。

设备控制

连续输入:

dim the living room to 30
make it 21 degrees and cool the room

分别触发 set_lights(room='living room', on=True, brightness=30) 和 set_thermostat(temperature=21, mode='cool')。对话历史自动累积,不同设备自动匹配对应工具,cool the room 里的 room 不会被误判成灯光指令。

结构化提取

输入:

Taxi ride with Uber, fare 23.60, paid with mastercard

输出:

{  "merchant": "Uber",  "total": 23.6,  "payment_method": "mastercard"}

另一个示例 Invoice from Acme Corp, $1,200.00, due 2026-09-01 提取出 {"merchant": "Acme Corp", "total": 1200.0}。

关键设计

置信度门控:每次响应附带校准过的置信度分数。可以设阈值,高于阈值直接执行,低于阈值交给人工处理。这避免模型把“调暗客厅灯光到 10%”理解错,半夜把灯全开。

工具检索:可以声明几百个工具,但每次对话只渲染前 5 个最相关的工具,语法约束也只在这 5 个里生效。节省计算量,也减少选错工具的概率。

有界内存:使用 256-token 滑动窗口,工具调用作为 KV sinks 固定在内存里。对话 100 轮还是 1000 轮,总内存始终维持在 28MB 左右。

自包含部署:权重、引擎全在一个 14MB 的 .cact 文件里。pip install 后引擎从 Hugging Face 下载一次并缓存,之后不再需要网络。部署时拷一个文件过去就行。

安装与代码

pip install cactus-needle
pip install "cactus-needle[gpu]"          # NVIDIA GPU
pip install "cactus-needle[metal]"        # Apple Silicon GPU

最简单的工具调用:

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'}]

结构化提取:

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

不想写代码的话,直接起 playground:

needle playground                      # 基础模型,http://127.0.0.1:7860
needle playground --weights my.cact    # 跑自己微调过的模型

也可以在浏览器界面里点 “Finetune on these tools”,自动跑完微调流程并下载 .cact。

边界与不适用场景

Needle 不是通用聊天模型,能力范围限定在上面三类任务。基础模型只能可靠提取标量字段;如果涉及多行商品明细这类复杂结构,需要先做 LoRA 微调才能稳定输出。类似开放式对话、常识问答或高准确率信息抽取需求,不适合直接用它。

工具检索只取前 5 个结果,这意味着被调用的工具需要能出现在检索结果里;置信度门控的阈值设置也要在具体设备场景里验证,否则会有错误放行或频繁拒答的问题。

项目地址:https://github.com/cactus-compute/needle

推荐文章

程序员茄子在线接单