AttorneyTao/local-ai-service

local-ai-service for mac

1

stars

3

commits

Python

primary language

Jun 16, 2026

updated

README

local-ai-service (pii + mlx)

单进程常驻 HTTP 服务,在 Apple Silicon 上同时提供:

  • PII 检测/脱敏fastino/gliner2-privacy-filter-PII-multi(GLiNER2 / mDeBERTa-v3,PyTorch + MPS)
  • MLX LLM 文本生成 — 任意 mlx-community/* 模型(mlx_lm

注意:这不是 MLX 移植的 PII 模型。PII 走 PyTorch 的 Metal(MPS) 后端;MLX 仅用于 LLM 生成。两者在同一个 venv、同一个进程里,互不冲突。


0. 一键命令 localai(已加入 PATH)

localai start     # 启动 服务 + Docker + Open WebUI, 并打开 http://localhost:3000
localai stop      # 停服务和前端容器 (保留 Colima, 下次启动更快)
localai down      # 全部关闭 (含 Colima)
localai restart   # 仅重启本服务 (改了 server.py / 换模型后用)
localai status    # 查看各组件状态 + 已加载的 MLX 模型
localai logs      # 跟踪服务日志

脚本本体:~/local-ai-service/localai,已软链到 /opt/homebrew/bin/localai。 所有操作幂等(已在运行不会重复启动)。日常只需 localai start 一条。


1. 目录结构

路径说明是否可删
~/local-ai-service/server.py常驻 HTTP 服务(核心)
~/local-ai-service/pii.py命令行/库版 PII 工具,可脱离服务单用
~/local-ai-service/test_run.py冒烟测试脚本
~/local-ai-service/server.log运行日志可(会重建)
~/local-ai-service/pyproject.tomluv 项目定义 + 依赖声明
~/local-ai-service/uv.lock锁定的精确依赖版本(可复现)
~/local-ai-service/.python-version固定 Python 版本(3.14)
~/local-ai-service/.venv/uv 管理的虚拟环境(~1G)可,uv sync 重建
~/.cache/huggingface/hub/模型权重缓存(~1.5G)删了会重新下载

环境由 uv 管理:Python 3.14 · gliner2 1.3.1 · torch 2.12.0 · mlx_lm 0.31.3。 依赖声明在 pyproject.toml、精确版本锁在 uv.lock,全部隔离在 .venv,不污染系统 Python。

clone 后一键就绪:

cd ~/local-ai-service && uv sync     # 按 uv.lock 还原完全一致的环境

2. 启停与日常运维

所有命令默认 cd ~/local-ai-service

# 启动(后台常驻,默认 127.0.0.1:8000)
nohup uv run python server.py > server.log 2>&1 &

# 自定义端口/对外开放/默认 MLX 模型
HOST=0.0.0.0 PORT=8080 MLX_MODEL=mlx-community/Qwen2.5-3B-Instruct-4bit \
  nohup uv run python server.py > server.log 2>&1 &

# 查看是否在跑
pgrep -fl local-ai-service/server.py

# 看日志
tail -f server.log

# 停止
pkill -f local-ai-service/server.py

# 重启
pkill -f local-ai-service/server.py; sleep 1; \
  nohup uv run python server.py > server.log 2>&1 &

# 健康检查
curl -s http://127.0.0.1:8000/health

可配置环境变量:HOST(默认 127.0.0.1)、PORT(8000)、PII_REPOMLX_MODEL


3. 接口速查

方法路径body
GET/health
GET/用法 JSON
POST/pii/extract{"text","labels"?,"threshold"?}
POST/pii/redact{"text","labels"?,"threshold"?}
POST/mlx/generate{"prompt","model"?,"max_tokens"?,"temperature"?,"top_p"?,"chat"?}
# PII 脱敏
curl -s -X POST http://127.0.0.1:8000/pii/redact \
  -H 'Content-Type: application/json' \
  -d '{"text":"Email John at john@acme.com, call +1 415 555 0199"}'

# LLM 生成
curl -s -X POST http://127.0.0.1:8000/mlx/generate \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"你好","max_tokens":80}'

行为:后端懒加载(首次请求才载入,启动 2s 即就绪);共享一把 GPU 锁串行推理; MLX 按 model 字段多模型缓存,传不同 repo 即可并存。

不经过服务,直接命令行用 PII:

uv run python pii.py --redact "Marie au 06 12 34 56 78"

4. 常见运维场景

换 / 加 MLX 模型:请求里带 "model":"mlx-community/<repo>" 即可,首次自动下载到 HF 缓存; 或设 MLX_MODEL 改默认。

改默认 PII 标签:编辑 server.py 顶部的 DEFAULT_LABELS(模型支持 42 种 PII 类型,标签是自由文本)。

漏检/误报:调 threshold(默认 0.5;漏检调低到 0.3,误报调高)。

升级依赖(uv):

uv lock --upgrade        # 重新解析最新版本并更新 uv.lock
uv sync                  # 应用到 .venv
# 或加单个依赖: uv add <包名>

清理空间:删某个模型缓存 rm -rf ~/.cache/huggingface/hub/models--mlx-community--Qwen2.5-0.5B-Instruct-4bit(下次用会重下)。

重建整个环境(.venv 损坏时):

cd ~/local-ai-service && rm -rf .venv && uv sync

5. 注意事项

  • PII 语言:可靠语言为 英/法/西/德/意/葡/荷 7 种;中文里 email、电话等模式化信息能识别, 但中文人名/地址不可靠(不在训练语言内)。
  • 安全:服务无鉴权。默认只绑 127.0.0.1 仅本机可访问;设 HOST=0.0.0.0 暴露到局域网前请自行加防护,切勿直接挂公网。
  • 进程模型nohup ... & 启动的进程在关机/注销后不会自动拉起。需要开机自启/掉线重启,用 launchd(见下)。

6. 可选:开机自启(launchd)

把服务交给 macOS 守护,开机自动启动、崩溃自动重启。创建 ~/Library/LaunchAgents/com.local.local-ai-service.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.local.local-ai-service</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/ryantao/local-ai-service/.venv/bin/python</string>
    <string>/Users/ryantao/local-ai-service/server.py</string>
  </array>
  <key>WorkingDirectory</key><string>/Users/ryantao/local-ai-service</string>
  <key>EnvironmentVariables</key>
  <dict><key>PORT</key><string>8000</string></dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>/Users/ryantao/local-ai-service/server.log</string>
  <key>StandardErrorPath</key><string>/Users/ryantao/local-ai-service/server.log</string>
</dict></plist>
launchctl load  ~/Library/LaunchAgents/com.local.local-ai-service.plist   # 启用
launchctl unload ~/Library/LaunchAgents/com.local.local-ai-service.plist  # 停用

7. Web 前端:Open WebUI(聊天界面)

服务自带 OpenAI 兼容接口(GET /v1/modelsPOST /v1/chat/completions,支持流式), 因此可接任何 OpenAI 客户端。这里用 Open WebUI(开源、类 ChatGPT)。

PII 也能在 Open WebUI 里直接用:模型下拉里除了 LLM,还有两个 PII 伪模型 pii-redact(回脱敏文本)和 pii-extract(回检测清单)——选中后把文本发过去即可。 本机 Python 3.14 装不了 pip 版 Open WebUI(要求 <3.13),所以走 Docker(Colima 运行时)。

前提:本服务必须绑 0.0.0.0,容器才能从 host.docker.internal 访问到它:

cd ~/local-ai-service
HOST=0.0.0.0 nohup uv run python server.py > server.log 2>&1 &

(launchd 自启同理:在 plist 的 EnvironmentVariables 里加 <key>HOST</key><string>0.0.0.0</string>

启动 Docker 运行时 + Open WebUI 容器(已用环境变量预配好后端、关掉登录):

colima start                       # 启动 Docker 运行时(Linux VM),开机后只需跑一次
docker run -d -p 3000:8080 \
  --add-host=host.docker.internal:host-gateway \
  -v open-webui:/app/backend/data \
  --name open-webui \
  -e OPENAI_API_BASE_URL=http://host.docker.internal:8000/v1 \
  -e OPENAI_API_KEY=local \
  -e WEBUI_AUTH=False \
  --restart unless-stopped \
  ghcr.io/open-webui/open-webui:main

访问:浏览器打开 http://localhost:3000 —— 模型下拉里会出现 mlx-community/Qwen2.5-0.5B-Instruct-4bit,直接对话即可(首条消息会触发 MLX 懒加载,稍慢)。

容器运维

docker ps                          # 看是否在跑
docker logs -f open-webui          # 看日志
docker stop open-webui             # 停
docker start open-webui            # 启
docker rm -f open-webui            # 删容器(数据在 named volume open-webui 里, 不丢)
colima stop                        # 关掉整个 Docker 运行时(省资源)

换模型给前端用:先随便发一条带新模型的请求让服务加载它,或改 MLX_MODEL 重启服务; Open WebUI 的模型下拉来自 GET /v1/models,会自动反映已加载/默认模型。

连不上排查:① 服务是否绑了 0.0.0.0(不是 127.0.0.1);② curl http://127.0.0.1:8000/v1/models 本机是否通; ③ 容器内 docker exec open-webui curl -s http://host.docker.internal:8000/v1/models 是否通。

Contributors

AttorneyTao

3 commits

AttorneyTao/local-ai-service

local-ai-service for mac

1

stars

3

commits

Python

primary language

Jun 16, 2026

updated

README

local-ai-service (pii + mlx)

单进程常驻 HTTP 服务,在 Apple Silicon 上同时提供:

  • PII 检测/脱敏fastino/gliner2-privacy-filter-PII-multi(GLiNER2 / mDeBERTa-v3,PyTorch + MPS)
  • MLX LLM 文本生成 — 任意 mlx-community/* 模型(mlx_lm

注意:这不是 MLX 移植的 PII 模型。PII 走 PyTorch 的 Metal(MPS) 后端;MLX 仅用于 LLM 生成。两者在同一个 venv、同一个进程里,互不冲突。


0. 一键命令 localai(已加入 PATH)

localai start     # 启动 服务 + Docker + Open WebUI, 并打开 http://localhost:3000
localai stop      # 停服务和前端容器 (保留 Colima, 下次启动更快)
localai down      # 全部关闭 (含 Colima)
localai restart   # 仅重启本服务 (改了 server.py / 换模型后用)
localai status    # 查看各组件状态 + 已加载的 MLX 模型
localai logs      # 跟踪服务日志

脚本本体:~/local-ai-service/localai,已软链到 /opt/homebrew/bin/localai。 所有操作幂等(已在运行不会重复启动)。日常只需 localai start 一条。


1. 目录结构

路径说明是否可删
~/local-ai-service/server.py常驻 HTTP 服务(核心)
~/local-ai-service/pii.py命令行/库版 PII 工具,可脱离服务单用
~/local-ai-service/test_run.py冒烟测试脚本
~/local-ai-service/server.log运行日志可(会重建)
~/local-ai-service/pyproject.tomluv 项目定义 + 依赖声明
~/local-ai-service/uv.lock锁定的精确依赖版本(可复现)
~/local-ai-service/.python-version固定 Python 版本(3.14)
~/local-ai-service/.venv/uv 管理的虚拟环境(~1G)可,uv sync 重建
~/.cache/huggingface/hub/模型权重缓存(~1.5G)删了会重新下载

环境由 uv 管理:Python 3.14 · gliner2 1.3.1 · torch 2.12.0 · mlx_lm 0.31.3。 依赖声明在 pyproject.toml、精确版本锁在 uv.lock,全部隔离在 .venv,不污染系统 Python。

clone 后一键就绪:

cd ~/local-ai-service && uv sync     # 按 uv.lock 还原完全一致的环境

2. 启停与日常运维

所有命令默认 cd ~/local-ai-service

# 启动(后台常驻,默认 127.0.0.1:8000)
nohup uv run python server.py > server.log 2>&1 &

# 自定义端口/对外开放/默认 MLX 模型
HOST=0.0.0.0 PORT=8080 MLX_MODEL=mlx-community/Qwen2.5-3B-Instruct-4bit \
  nohup uv run python server.py > server.log 2>&1 &

# 查看是否在跑
pgrep -fl local-ai-service/server.py

# 看日志
tail -f server.log

# 停止
pkill -f local-ai-service/server.py

# 重启
pkill -f local-ai-service/server.py; sleep 1; \
  nohup uv run python server.py > server.log 2>&1 &

# 健康检查
curl -s http://127.0.0.1:8000/health

可配置环境变量:HOST(默认 127.0.0.1)、PORT(8000)、PII_REPOMLX_MODEL


3. 接口速查

方法路径body
GET/health
GET/用法 JSON
POST/pii/extract{"text","labels"?,"threshold"?}
POST/pii/redact{"text","labels"?,"threshold"?}
POST/mlx/generate{"prompt","model"?,"max_tokens"?,"temperature"?,"top_p"?,"chat"?}
# PII 脱敏
curl -s -X POST http://127.0.0.1:8000/pii/redact \
  -H 'Content-Type: application/json' \
  -d '{"text":"Email John at john@acme.com, call +1 415 555 0199"}'

# LLM 生成
curl -s -X POST http://127.0.0.1:8000/mlx/generate \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"你好","max_tokens":80}'

行为:后端懒加载(首次请求才载入,启动 2s 即就绪);共享一把 GPU 锁串行推理; MLX 按 model 字段多模型缓存,传不同 repo 即可并存。

不经过服务,直接命令行用 PII:

uv run python pii.py --redact "Marie au 06 12 34 56 78"

4. 常见运维场景

换 / 加 MLX 模型:请求里带 "model":"mlx-community/<repo>" 即可,首次自动下载到 HF 缓存; 或设 MLX_MODEL 改默认。

改默认 PII 标签:编辑 server.py 顶部的 DEFAULT_LABELS(模型支持 42 种 PII 类型,标签是自由文本)。

漏检/误报:调 threshold(默认 0.5;漏检调低到 0.3,误报调高)。

升级依赖(uv):

uv lock --upgrade        # 重新解析最新版本并更新 uv.lock
uv sync                  # 应用到 .venv
# 或加单个依赖: uv add <包名>

清理空间:删某个模型缓存 rm -rf ~/.cache/huggingface/hub/models--mlx-community--Qwen2.5-0.5B-Instruct-4bit(下次用会重下)。

重建整个环境(.venv 损坏时):

cd ~/local-ai-service && rm -rf .venv && uv sync

5. 注意事项

  • PII 语言:可靠语言为 英/法/西/德/意/葡/荷 7 种;中文里 email、电话等模式化信息能识别, 但中文人名/地址不可靠(不在训练语言内)。
  • 安全:服务无鉴权。默认只绑 127.0.0.1 仅本机可访问;设 HOST=0.0.0.0 暴露到局域网前请自行加防护,切勿直接挂公网。
  • 进程模型nohup ... & 启动的进程在关机/注销后不会自动拉起。需要开机自启/掉线重启,用 launchd(见下)。

6. 可选:开机自启(launchd)

把服务交给 macOS 守护,开机自动启动、崩溃自动重启。创建 ~/Library/LaunchAgents/com.local.local-ai-service.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.local.local-ai-service</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/ryantao/local-ai-service/.venv/bin/python</string>
    <string>/Users/ryantao/local-ai-service/server.py</string>
  </array>
  <key>WorkingDirectory</key><string>/Users/ryantao/local-ai-service</string>
  <key>EnvironmentVariables</key>
  <dict><key>PORT</key><string>8000</string></dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>/Users/ryantao/local-ai-service/server.log</string>
  <key>StandardErrorPath</key><string>/Users/ryantao/local-ai-service/server.log</string>
</dict></plist>
launchctl load  ~/Library/LaunchAgents/com.local.local-ai-service.plist   # 启用
launchctl unload ~/Library/LaunchAgents/com.local.local-ai-service.plist  # 停用

7. Web 前端:Open WebUI(聊天界面)

服务自带 OpenAI 兼容接口(GET /v1/modelsPOST /v1/chat/completions,支持流式), 因此可接任何 OpenAI 客户端。这里用 Open WebUI(开源、类 ChatGPT)。

PII 也能在 Open WebUI 里直接用:模型下拉里除了 LLM,还有两个 PII 伪模型 pii-redact(回脱敏文本)和 pii-extract(回检测清单)——选中后把文本发过去即可。 本机 Python 3.14 装不了 pip 版 Open WebUI(要求 <3.13),所以走 Docker(Colima 运行时)。

前提:本服务必须绑 0.0.0.0,容器才能从 host.docker.internal 访问到它:

cd ~/local-ai-service
HOST=0.0.0.0 nohup uv run python server.py > server.log 2>&1 &

(launchd 自启同理:在 plist 的 EnvironmentVariables 里加 <key>HOST</key><string>0.0.0.0</string>

启动 Docker 运行时 + Open WebUI 容器(已用环境变量预配好后端、关掉登录):

colima start                       # 启动 Docker 运行时(Linux VM),开机后只需跑一次
docker run -d -p 3000:8080 \
  --add-host=host.docker.internal:host-gateway \
  -v open-webui:/app/backend/data \
  --name open-webui \
  -e OPENAI_API_BASE_URL=http://host.docker.internal:8000/v1 \
  -e OPENAI_API_KEY=local \
  -e WEBUI_AUTH=False \
  --restart unless-stopped \
  ghcr.io/open-webui/open-webui:main

访问:浏览器打开 http://localhost:3000 —— 模型下拉里会出现 mlx-community/Qwen2.5-0.5B-Instruct-4bit,直接对话即可(首条消息会触发 MLX 懒加载,稍慢)。

容器运维

docker ps                          # 看是否在跑
docker logs -f open-webui          # 看日志
docker stop open-webui             # 停
docker start open-webui            # 启
docker rm -f open-webui            # 删容器(数据在 named volume open-webui 里, 不丢)
colima stop                        # 关掉整个 Docker 运行时(省资源)

换模型给前端用:先随便发一条带新模型的请求让服务加载它,或改 MLX_MODEL 重启服务; Open WebUI 的模型下拉来自 GET /v1/models,会自动反映已加载/默认模型。

连不上排查:① 服务是否绑了 0.0.0.0(不是 127.0.0.1);② curl http://127.0.0.1:8000/v1/models 本机是否通; ③ 容器内 docker exec open-webui curl -s http://host.docker.internal:8000/v1/models 是否通。

Contributors

AttorneyTao

3 commits

Languages

Python

80.6%

Shell

19.4%