02 — 构建过程,分步详解
2026/7/30 20:31:16 · 更新于 2026/7/30 22:46:47
AI 翻译于 2026/7/30 21:53:59 · 使用 Qwen3.6 35B (fast, default)
一份详尽的分阶段指南,详解如何利用 Ollama、Open WebUI 与自定义 FastAPI 智能体框架构建基于 Mac 的本地 AI 基础设施,内容涵盖从磁盘架构与模型优先级设定,到检索增强生成、延迟瓶颈排查及防护准则实现的方方面面。
本文描述了在本地 macOS 基础设施上从零开始逐步构建 AI 系统的全过程,涵盖从底层准备到自定义代理(agent)框架开发的各个阶段。它将每个安装步骤映射到所解决的具体运行需求,详细说明了模型选择、检索架构、路由逻辑以及随着系统从单一端点扩展为多用户服务过程中,保障系统稳定的迭代式调试纪律。
基础与引擎设置(第 0–2 阶段)
第 0 阶段 — Mac 基础准备
在任何 AI 软件安装之前,必须先完成前置准备工作。 必须禁用睡眠功能,以防止服务器在请求处理过程中中断;随后安装 Homebrew 及轻量级工具链(git、python@3.12、ffmpeg、htop、jq、wget)。生成用于 GitHub 的 SSH 密钥,并单独配置专用外部存储卷(/Volumes/AI_DATA),与系统启动盘物理分离。这种物理隔离为后续实现“在新 Mac 上重建”工作流奠定了基础——整个过程仅需半天而非全新重装:只需重新执行第 0–1 阶段、重新 ollama pull 拉取模型,并恢复外部数据卷即可。在初始化当天,已将 brew list、system_profiler 和 df -h 的输出保存至 backups/ 目录,作为日后依赖关系审计的低成本保险手段。
第 1 阶段 — 核心引擎
通过 Homebrew 安装 Ollama,但在拉取任何模型之前必须先完成存储重定向:
export OLLAMA_MODELS=/Volumes/AI_DATA/models/ollama
若在重定向之前拉取模型,将占用系统启动盘的存储空间。首次拉取的模型是大型推理模型(gpt-oss:120b,约 64 GB,耗时 30–90 分钟)。Ollama 在 localhost:11434/v1 提供 OpenAI 兼容 API——该单一端点成为随后每一层组件(包括 Open WebUI、agent-server 以及约 19 个其他集成项目)的调用目标。
第 2 阶段 — 模型栈其余部分
为了完善推理流水线,又添加了两个额外模型:
qwen3.6:35b-a3b:一旦意识到仅靠大型推理模型处理日常任务过慢,便将其选为快速日常驱动程序。qwen3-vl:30b:与 Whisper(large-v3-turbo)配合使用,分别处理视觉和语音转文本任务。由于 Ollama 仅向 Qwen3-VL 传递静态图像(无原生视频支持),因此文档中记录了通过ffmpeg进行帧提取的变通方案以处理视频输入。
LM Studio 被配置为可选辅助工具,用于通过 MLX 运行时对新模型进行原型开发(在 Apple Silicon 芯片上速度提升约 10–20%)。由此确立了一套固定的升级模式:先在 LM Studio 中试用,再将表现优异的模型晋升至 Ollama。
接口、路由与公共访问(第 3–4½ 阶段)### 第三阶段——使其可用:Open WebUI与知识库
Open WebUI(一款类似 ChatGPT 的界面)部署在其独立的 Python 虚拟环境中,存储路径指向 AI_DATA 卷。通过 --host 0.0.0.0(显式绑定到所有网卡接口,而非单个 IP)在局域网中公开服务,并通过 Tailscale 进行远程访问。一键启动的 start-ai-stack.command 取代了手动终端操作,并利用 nohup 和 pgrep 作为守卫机制,防止双击时重复启动进程。
实际遇到的Bug: 新拉取的模型在 Open WebUI 中默认权限为 Private(私有),导致非管理员用户看到空的模型列表,直到在管理面板中将可见度明确设置为 Public(公开)。
知识库管理遵循 KNOWLEDGE_MANAGEMENT_GUIDE.md 中的三层架构:
- 第一层(填充数据): 脚本抓取了两份文档库——DOD-FM(财务管理条例)和 K-12(教育标准/课程大纲)——存入带有编号前缀的固定文件夹结构(
01-Regulations/、02-DoD-Guidance/等)。静默失败修复: 早期脚本将 HTML 错误页面保存为.pdf文件,这骗过了仅检查大小的有效性验证。修复后的fix-broken-pdfs.sh引入了魔数检查(%PDF文件头)来捕获损坏情况。 - 第二层(自动化):
apps/llm-wiki/llm_wiki.py配合launchd文件监听器,在文档到达后的数秒内自动生成维基百科页面草稿,并在正式发布前始终等待人工审核。 - 第三层(图谱 RAG): 暂时未构建,直到真实的测试题库失败案例证明其带来的开销是合理的。
跨知识库越权Bug: 由于 Open WebUI 在模型层面附加了知识数据,DOD-FM 的内容出现在了 K-12 的对话中。通过实现自定义过滤函数
knowledge_scope_filter.py修复了该问题。
第四阶段——连接其余组件
将外部项目接入本地 AI 遵循严格模式:将项目的 OpenAI 客户端配置指向 Ollama 的端点(http://localhost:11434/v1`` 或 Tailscale 主机名),使用任意字符串作为 API Key(Ollama 不会对其进行验证),并指定模型名称。构建了路由辅助模块(ai_chain.py`),用于在输入图像时自动选择视觉模型,对标准文本默认使用快速主力模型,仅在处理真正困难、多步骤或合规敏感的请求时才升级调用大型推理模型。VS Code 通过 Continue 扩展接入,该扩展指向同一个 Ollama 端点。
第四阶段半——公共演示网关
为了让展示站点能够在公开演示系统时不直接暴露 Ollama,在 Tailscale Funnel 后方构建了一个轻量级代理(gateway.py)。它验证每个应用的 API Key 和模型白名单,应用速率限制,然后才会将流量转发至 Ollama。后续进行了更新,使公共演示流量改为经由 Open WebUI 路由而非直接连接裸机 Ollama,以确保检索管线和越权过滤逻辑同样应用于外部流量。
多用户扩展与备份策略(第 5–6 阶段)### Phase 5 — Opening it up to a small team
随着检索和模型栈趋于平稳,面向小团队的开放访问需要:
- LAN discovery via the Mac's
.localhostname(macOS 的局域网主机名发现机制) - Remote access via Tailscale (免费版,支持多用户同时在线连接)
- A three-layer admin-access model: browser-based administration first, SSH for diagnostics, screen sharing strictly reserved as a last resort. (三层管理员访问机制:首先开放基于浏览器的管理入口,随后通过 SSH 供运维诊断使用,屏幕共享则严格限定为最后的手段。) The workhorse model was set up as the shared default; the larger reasoning model was then moved to an admin-only path to serve multiple concurrent users within memory budget constraints.
Phase 6 — Backup
Implementation of a two-stage backup strategy: first, a temporary phase consisting of inventory snapshots and off-machine copies of irreplaceables; followed by a full plan after acquiring a test-restore at least one file manually before trusting the setup.
Agent Harness Development (Phase 7+)
This phase marks centering of gravity from configuring third-party software to building custom Python service. The original Phase 7 placeholder split out into AGENT_SERVER_GUIDE_v2.md and constructed as numbered sequence:: * 步骤1 —— 裸透传: 一个最小化的 FastAPI 服务器,代理到 Ollama,验证 OpenAI 兼容协议端到端运作正常。
-
步骤1.5 —— 真实认证: 哈希化的 API 密钥(永不明文存储)、作用域 (
chat/tools/admin)、每密钥速率限制和每日令牌配额,以及审计日志。 -
步骤2 —— 将检索作为可调用的工具:
search_knowledge_base允许模型在初次检索结果较弱时迭代地进行后续查询,而不是被静态地绑定在提示词中粘贴的初始内容上。 -
步骤2.5 —— 编排引擎: 早期草稿过于僵化;因此从零构建了一个基于波次的异步任务图 (
graph.py),用于将并发工具调用扇出分发,并在每个请求步骤中自动将它们收束回来。 -
步骤3 / 3.5 —— 行为配置: 关键词匹配的技能系统 (
skills/*.md) 和一个基础系统提示词 (AGENT.md),定义了身份、工具使用策略和护栏约束。文件在每次请求时重新读取,因此编辑无需重启即可立即生效。 -
步骤3.6 —— 记忆: 基于 SQLite 的每用户档案(年级、学科重点、知识盲区),仅从用户的显式输入更新,绝不从检索到的文档或模型输出中更新。
-
步骤4 / 4.5 / 4.6 —— 工具集成: 用于外部工具集成的 MCP 客户端(文件系统、网页搜索、PDF 阅读、规划)、源头权威性重排序(修复低质量文档排名超过实际法规的异常问题),以及检索深度调优。
-
步骤5 —— 护栏即代码: 一个钩子系统,在执行前阻止知识档案文件夹之外的文件写入执行,并在写入后触发后台重新索引。
-
步骤5.5 / 5.6 —— 度量评估: 一个反馈端点、生成的评估仪表板,以及用于测试套件的 LLM-as-judge(大模型评判)评分模式(刻意使用不同的评判模型以避免自我偏好偏差)。
-
步骤5.7 —— 延迟优化: 修复了 Ollama 流式格式与纯 JSON 读取之间的不匹配问题,从而实现实时的逐字令牌流式传输,同时结合连接池化的 HTTP 客户端和初步的生产延迟基线数据。
-
步骤5.9 / 5.10 —— 路由修复: 追踪到一个导致 14 秒延迟的 Bug(模型因幻觉而进行文件搜索,而非直接回答其自身提示词中的内容),为此引入了双重门禁机制:一个快速的正则表达式检查,随后是一个嵌入相似度检查,两者均根据生产日志数据进行了校准。完整记录参见
AGENT_LATENCY_INVESTIGATION_SUMMARY.md。 -
步骤6 —— 公共部署: 第二个 Tailscale Funnel 端口向公众暴露了代理服务器 (
:8443),同时保留 legacy 网关 (:443) 。 -
步骤7 —— 微调(部分完成): 数据采集脚本筛选出了评分通过的问答对;一个 LoRA 训练任务在小型替代模型上成功完成,作为流水线冒烟测试的一部分。
-
步骤8 —— 重新陈述的护栏约束: 默认只读,写入 confined 至沙盒文件夹、完整的审计日志记录,且代理循环中未暴露任何特权凭证(如 Tailscale 管理员权限、备份驱动器访问权)。
</think> -
步骤1 —— 裸透传: 一个最小化的 FastAPI 服务,代理至 Ollama,用以证明 OpenAI 兼容协议端到端运作正常。
-
步骤1.5 —— 真实鉴权: 哈希化 API 密钥(绝不明文存储)、作用域 (
chat/tools/admin)、每密钥速率限制和每日令牌配额,以及审计日志。 -
步骤2 —— 将检索视为可调用的工具:
search_knowledge_base允许模型在初次检索较弱时迭代地重新查询,而不是被死板地绑定在静态拼接到提示词中的内容上。 -
步骤2.5 —— 编排引擎: 早期草稿过于僵化;因此从零构建了基于波次的异步任务图 (
graph.py),以扇出并发工具调用,并在每个请求步骤中自动将结果汇聚回来。 -
步骤3 / 3.5 —— 行为配置: 关键词匹配的技能系统 (
skills/*.md) 和基础系统提示词 (AGENT.md),定义了身份、工具使用策略及护栏规则。文件在每次请求时都会重新读取,因此编辑修改会立即生效而无需重启服务。 -
步骤3.6 —— 记忆: SQLite 驱动的每人档案(年级、关注科目、知识盲区),仅从用户显式输入中更新,绝不从检索到的文档或模型输出中获取。
-
步骤4 / 4.5 / 4.6 —— 工具集成: MCP 客户端用于外部工具集成(文件系统、网页搜索、PDF阅读、规划)、基于源头权威性的重排序机制(解决低质量文档反而排在法规内容之前的问题),以及检索深度调节。
-
步骤5 —— 护栏即代码: 钩子系统在执行前阻止知识档案库文件夹之外的文件写入,并在写入后触发后台重新索引。
-
步骤5.5 / 5.6 —— 度量评估: 反馈端点、生成的评估仪表板,以及用于测试套件的大模型作为评判者(LLM-as-judge)评分模式(刻意使用不同的评判模型以避免自我偏好偏差)。
-
步骤5.7 —— 延迟优化: 修复了 Ollama 流式格式与普通 JSON 读取之间的不匹配问题以启用实时逐 token 流式传输,配合连接池化 HTTP 客户端及初步的生产环境延迟基线数据。
-
步骤5.9 / 5.10 —— 路由修复: 定位到一个导致 14 秒延迟的 Bug(模型产生幻觉去搜索文件而非直接依据其自身的提示词作答),为此实施了双重门禁机制:快速正则检查叠加嵌入相似度检查,两者均根据生产日志数据进行了校准。完整论述见
AGENT_LATENCY_INVESTIGATION_SUMMARY.md。 -
步骤6 —— 公开部署: 第二个 Tailscale Funnel 端口同时暴露了代理服务器 (
:8443) 和旧版网关 (:443)。 -
步骤7 —— 微调(部分完成): 数据集收集脚本隔离出了评分通过的问答对;LoRA 训练任务在小型替代模型上顺利完成,作为管道冒烟测试通过。
-
步骤8 —— 重申护栏规则: 默认为只读模式,写操作限制于沙盒文件夹,拥有完整的审计日志记录,代理循环不接触任何特权凭证(Tailscale 管理员权限、备份驱动器等)。## 贯穿各阶段的核心模式 注意始终如一的关键:每个阶段都产出了一个立即可运行的增量,真实使用场景暴露了具体的故障模式,修复方案瞄准的均是能真正解决问题的最简机制(加一道魔数值校验而非重写流水线;在嵌入门控前增加正则过滤,而不是将一切请求转给大模型)。交付产品、观察现象、精准修复并记录归档。 这种工程纪律——与技术选型本身无关——是本项目最具可迁移价值的成果。操作命令请参阅
04_Cheat_Sheet.md,后续扩展路径请参阅08_Extending_The_Harness_Agent.md。
关键经验总结
- **物理隔离保障快速重建能力:**将AI运行时、模型与外部数据保留在独立的存储卷上,能在更换Mac设备时实现快速重部署,而无需执行全套重新安装流程。
- **通过模型路由避免性能瓶颈:**在正式接入Ollama之前,先在轻量级运行时(LM Studio/MLX)上开展可行性验证,配合严格的主力处理/推理模型扩展策略,确保系统在高负载下的延迟保持稳定且可预测。
- **检索越界需要边界控制:**跨知识库的数据污染与静默的PDF文件损坏问题,通过针对性可见性过滤和魔数格式校验得以解决,而无需进行大范围的架构重构。
- **安全护栏靠执行钩子实现规模化扩展而非策略配置:**将读写限制、审计日志与凭据隔离直接固化到工具前后执行的钩子(hooks)中,在运行时自动强制执行安全控制要求,无需人工监管。
- **客观观察胜过主观假设:**路由修正、延迟调优和存储重定向等问题,均通过优先追踪生产环境日志排查原因,随后实施克制而精准的干预措施得以解决。
学习地图
第一阶段:基础与存储架构
配置 Mac 基础环境,禁用自动休眠,创建专用外部数据卷,确保系统重建只需重新挂载存储,而无需完整重装操作系统配置。
第二阶段:模型引擎部署
通过 Homebrew 安装 Ollama ,在设置时重定向其模型存储路径,并通过分层"试用"方法部署模型——先在 LM Studio 中测试,再拉取至主运行时环境。
第三阶段:接口与可用性层
部署 Open WebUI 以实现局域网访问,填充第一层级和第二层级知识库(法规与课程),同时实现 magic-byte 脚本以防止 HTML 错误损坏 PDF 文档。
第四阶段:AI 代理与集成
使用 FastAPI 构建自定义 Python 代理框架。实现工具路由功能,根据输入类型(视觉、简单文本或复杂合规性)动态选择正确的模型,并集成 MCP 以实现外部工具访问。
第五阶段:优化、安全与路由
通过基于正则的过滤机制而非不必要的嵌入来解决延迟问题,修复令牌流差异,保护管理端到用户端的流量路由,并配置排除大体积模型权重的最终备份策略。
动手实践——分步指南
- 配置 Mac 基础环境:执行 'brew install git python@3.12 ffmpeg htop jq wget'。禁用系统休眠以防止请求中途被中断,并创建独立的数据卷,例如 '/Volumes/AI_DATA'。
- 安装 Ollama 引擎:通过 Homebrew 进行安装(例如 'brew install ollama'),在拉取任何模型之前立即导出环境变量('export OLLAMA_MODELS=/Volumes/AI_DATA/models/ollama')以节省本地存储空间。
- 部署模型栈:使用重定向路径拉取一个重型推理模型和一个日常主力模型。将 LM Studio 配置为可选的沙盒环境,用于在正式通过 Ollama 拉取前试用 MLX 架构的新权重。
- 部署 Open WebUI:在独立的本地 Python 虚拟环境中安装,将配置接口指向 'http://localhost:11434/v1',并通过局域网或 Tailscale 安全地对外提供服务。
- 构建知识检索:搭建一级文档库并使用数字前缀以便轻松排序。编写自动化脚本(利用 launchd 文件监听器)用于为新导入的文件自动生成 Wiki 页面草稿,务必添加魔数检查('%PDF' 头信息)以过滤下载失败的 HTML 错误文件。
- 设计智能体路由:编写一个 Python 代理脚本,以在所有项目(如 VS Code 扩展)中统一访问方式。实现一个路由辅助模块,默认使用快速日常模型,但在必要时能够无缝升级或将图像处理任务路由至视觉专用权重模型。
- 实现自定义智能体框架与安全护栏:构建基于 FastAPI 的自定义服务端层,添加严格的只读安全限制、用户级 SQLite 画像分析,以及真正的逐 Token 流式传输修复。
三大推荐资源
- 1Ollama Official Documentation
The official guide for local model installation, storage redirection (`OLLAMA_MODELS`), and managing the OpenAI-compatible API endpoint.
https://ollama.com/guides
- 2Open WebUI GitHub Repository
The canonical reference for deploying the ChatGPT-style web interface, configuring custom knowledge banks, and handling public LAN/Tailscale exposure.
https://github.com/open-webui/open-webui
- 3FastAPI Official Documentation
Essential documentation for building the custom HTTP proxy, managing concurrent routing, and implementing structured async tool-grabbing within your agent harness.
https://fastapi.tiangolo.com/
链接由 AI 推荐——使用前建议快速核实。