
这次我们来看一个定位很有意思的项目airi一个“眼里仅有你一人”的个人专属 AI 助手。它不是什么花哨的网页演示而是把大模型对话、本地语音合成、API 服务和 Web 界面整合到一台本机设备上的完整方案。核心亮点是数据不出本机、人设可定制、对外提供标准化接口后续想接到自己的前端、IM 工具或自动化脚本里都方便。如果你正打算在本地跑一个具有“专属感”的 AI 助手或者想研究大模型 TTS API 服务的完整链路这篇文章可以直接收藏。下面会把它拆成几个层面来讲这个项目解决什么问题、硬件门槛大概在哪里、环境怎么搭、服务怎么启动、API 怎么调用、批量任务怎么做、消耗多少资源、以及常见的坑怎么排。1. 核心能力速览能力项说明项目类型本地部署的个人专属 AI 助手含对话、语音、接口服务核心定位单用户、私有化、数据留在本机“眼里只有你一个人”主要组成大语言模型底座 语音合成模块 FastAPI 接口 Web 前端推荐硬件建议具备 8GB 以上内存带 NVIDIA 显卡体验更好显存占用取决于底座模型大小4G 到 16G 都有对应方案需按实际版本测试支持平台Windows 10/11、Ubuntu 20.04/22.04、macOS 均可尝试启动方式命令行启动服务或写成 .bat / .sh 一键脚本是否支持 CPU支持量化模型在 CPU 上也能跑速度偏慢是否支持 API支持提供 REST 接口前端与自动化任务可调用是否支持批量任务支持可对一批文本批量生成语音或批量调用对话接口适合场景个人知识助手、离线语音问答、家庭设备集成、二次开发测试需要先说清楚显存占用和启动速度会随模型版本变化没有固定答案。下面给出一套通用的本地部署与验证方法你可以照着在自己的设备上跑出真实数据。2. 适用场景与使用边界airi 这类“个人专属 AI 助手”适合下面这些场景个人知识库问答把本地文档、笔记、代码片段整理好让 AI 基于私有资料回答问题。离线语音助手不希望对话内容上传到云端时用本地大模型 语音合成搭一个断网可用的助手。家庭成员陪伴问答给老人或孩子做一个设定好性格的问答终端答案风格可控。外部工具聚合通过 FastAPI 暴露接口接到微信机器人、智能音箱、自动化脚本里。但也有几个边界要提前讲清楚不适合做医疗、法律、投资建议。本地模型的输出质量不稳定不能替代专业意见。不适合做高并发商用服务。单机设备要同时处理大模型推理和语音合成并发能力有限。不适合替代真实社交关系。AI 陪伴应用要设定边界尤其要避免让使用者产生不健康的心理依赖。不适合未经授权使用他人声音、肖像、文字作品。如果后面接入声音克隆或真人形象必须事先获得当事人明确授权。从合规角度看本地部署并不等于可以随意使用。开源模型有自己的 License不同模型对商用行为规定不同语音合成模型如果参考了真人声音也要先确认授权。项目接入任何第三方模型服务时还要注意 API Key 的保管不要把密钥提交到公开仓库里。3. 环境准备与前置条件本地部署 airi 之前先把基础环境检查一遍。整体依赖不多但缺一个环节就可能启动失败。3.1 操作系统与基础软件建议环境如下组件推荐版本说明操作系统Windows 10/11、Ubuntu 22.04、macOS 12Windows 和 Linux 部署最简单Python3.9 及以上用于运行 FastAPI 服务和调用模型Node.js18 及以上仅在需要编译前端页面时使用Git最新稳定版用于拉取项目代码和模型配置浏览器Chrome / Edge 最新版访问本地 WebUI先确认 Python 版本python --version如果你用的是 Linux 服务器还需要确认系统里有没有装curl、wget等基础工具which curl which wget3.2 显卡驱动与 CUDA 检查如果你打算用 NVIDIA 显卡跑大模型先确认显卡驱动正常nvidia-smi能看到 GPU 型号、驱动版本和显存信息就说明驱动正常。接着确认 PyTorch 能否调用 GPUpython -c import torch; print(torch.cuda.is_available())输出True才说明 PyTorch 正确安装了 CUDA 版本。如果输出False需要重新安装与显卡驱动匹配的 PyTorch 版本或者先走 CPU 推理验证流程。3.3 磁盘与端口规划大模型文件通常有几个 GB 到十几个 GB语音模型也要几百 MB。建议预留至少 20GB 磁盘空间下载前先确认df -hWindows 下可以直接看磁盘剩余空间。端口方面airi 的 API 服务默认可以绑定8000Web 前端常用3000或7860。如果端口被占用可以在启动命令里指定其他端口。检查端口是否被占用netstat -ano | findstr :8000 # Windows ss -lntp | grep 8000 # Linux4. 整体架构与模块分工先理解 airi 是怎么工作的后面部署才不会糊涂。整个项目可以拆成四层前端层一个简洁的 Web 页面用户输入文字或点击语音按钮。服务层FastAPI 提供/api/chat、/api/tts等 REST 接口负责把请求转给大模型和语音模块。模型层本地大语言模型负责生成回复本地 TTS 模型负责把回复文本变成语音。数据层对话记录、配置文件、生成的语音文件统一放在指定目录。典型流程用户输入文字 - 前端请求 FastAPI - FastAPI 调用大模型推理 - 返回回复文本 - 前端展示文字 - 用户选择语音播放 - 前端请求 TTS 接口 - TTS 生成音频文件并返回。这套结构的好处是模块解耦。后续想替换模型底座只改服务层调用逻辑想换更强的 TTS也只替换语音模块。接口稳定了前端和其他客户端都不用跟着改。5. 部署大语言模型底座大模型底座是 airi 的“大脑”。如果你不想自己从零部署模型服务可以用现成的开源推理工具来加载本地模型。5.1 在 Ollama 环境中加载开源模型Ollama 是目前常见的本地模型管理工具适合快速拉起一个 OpenAI 兼容的对话服务。安装完成后启动服务并拉取一个中文开源模型ollama serve新开一个终端拉取模型ollama pull qwen2.5:7b加载完成后先做一次命令行测试ollama run qwen2.5:7b 你好请介绍一下自己能正常回复说明模型底座已经可用。如果你的机器显存偏小可以选择更小的量化版本例如qwen2.5:3b或qwen2.5:1.5b。显存占用、推理速度和回答质量要在三者之间取舍。5.2 自定义人设提示词airi 的“专属感”很大程度来自人设设定。Ollama 支持通过Modelfile自定义系统提示词FROM qwen2.5:7b SYSTEM 你叫 airi是一个温和、耐心、专注的个人助理。你只服务于当前用户一个人回答问题时简洁清晰不要输出空话。构建并加载ollama create airi -f Modelfile ollama run airi这样 airi 的回复风格就稳定下来。后续如果想让语气更活泼或更正式直接改Modelfile里的SYSTEM内容重新创建即可。6. 搭建 airi 的 API 服务模型底座就绪后再写一个 FastAPI 服务把模型能力暴露成接口。6.1 安装依赖pip install fastapi uvicorn requests如果你要调用 Ollama 的 APIOllama 本身提供了http://127.0.0.1:11434/api/chat接口FastAPI 服务可以直接转发请求。6.2 编写 FastAPI 服务新建app.pyfrom fastapi import FastAPI from pydantic import BaseModel import requests app FastAPI(titleairi API) OLLAMA_URL http://127.0.0.1:11434/api/chat MODEL_NAME airi class ChatRequest(BaseModel): message: str uid: str default temperature: float 0.7 class ChatResponse(BaseModel): reply: str session_id: str app.post(/api/chat, response_modelChatResponse) def chat(req: ChatRequest): payload { model: MODEL_NAME, messages: [{role: user, content: req.message}], stream: False, options: {temperature: req.temperature}, } try: r requests.post(OLLAMA_URL, jsonpayload, timeout180) data r.json() reply_text data[message][content] except Exception as e: reply_text fairi 暂时无法回复{e} return ChatResponse(replyreply_text, session_idfairi-{req.uid}-001)这个示例里把 Ollama 的返回结果包装成统一 JSON。实际生产环境建议加历史消息管理把当前会话的对话记录传给模型否则 airi 会失去上下文记忆。6.3 启动服务uvicorn app:app --host 0.0.0.0 --port 8000启动后浏览器访问http://127.0.0.1:8000/docsFastAPI 会显示自动生成的接口文档可以直接在页面上测试/api/chat。6.4 用 curl 验证对话接口curl -X POST http://127.0.0.1:8000/api/chat \ -H Content-Type: application/json \ -d {message: airi今天有什么提醒吗, uid: demo}预期返回{ reply: airi 收到你的消息目前没有待办提醒。, session_id: airi-demo-001 }接口能返回 JSON说明大模型调用链路已经通了。7. 接入语音合成模块airi 的第二层能力是语音回复。这里以常见的开源 TTS 工具为例。安装依赖pip install TTS首次使用会下载对应语言的语音模型。示例代码from TTS.api import TTS # 中文语音模型示例实际模型名以本机安装版本为准 tts TTS(model_nametts_models/zh-CN/baker/model, progress_barFalse) text 你好我是 airi我已经记住你了。 tts.tts_to_file(texttext, file_pathoutput.wav) print(语音文件已生成output.wav)如果 TTS 模型支持参考音频也可以通过参考音色推理tts.tts_to_file( texttext, speaker_wavreference.wav, file_pathoutput_with_ref.wav )注意参考音频必须来自你已获得合法授权的声音素材。未经本人同意不能使用真人声音进行声音克隆或语音合成。生成成功后在浏览器里播放output.wav确认发音清晰、语速正常。如果音频有电流声或卡顿优先检查 TTS 模型在 CPU 上的推理速度以及音频采样率是否设置正确。8. 功能测试与效果验证服务都跑起来之后需要按功能逐项验证。8.1 对话基础能力测试测试目的确认 airi 能正常回复且回复内容不是固定模板。操作步骤保持 Ollama 和 FastAPI 服务运行。在/docs页面调用一次/api/chat。输入不同问题观察回复是否变化。输入示例{ message: 讲一个短故事, uid: test-user }判断标准模型能根据问题生成语义相关、长度合理的回复。如果回复一直是同一句话检查后端代码是否每次都在传同样的历史消息或者人设提示词是否过度限制了模型输出。8.2 流式输出测试对话体验中大模型逐字输出比一次性等待更友好。可以在 FastAPI 中开启流式返回from fastapi.responses import StreamingResponse import json app.post(/api/chat/stream) def chat_stream(req: ChatRequest): # 这里根据实际模型 SDK 的流式接口实现生成器 def generate(): chunks [你, 好, , 我, 是, airi] for chunk in chunks: yield json.dumps({delta: chunk}, ensure_asciiFalse) \n return StreamingResponse(generate(), media_typeapplication/x-ndjson)判断标准客户端能持续收到分片数据而不是等到所有内容生成完毕才看到结果。8.3 语音合成测试测试目的确认 TTS 模块能正常生成语音文件。操作步骤执行 TTS 示例脚本。检查输出目录下是否出现.wav文件。播放音频确认文字和发音一致。判断标准音频文件存在、无破音、无缺字。如果模型输出的中文有数字或英文可以先把文本做一次归一化例如把数字转为汉字再送入 TTS。8.4 接口稳定性测试使用 Python 脚本连续调用接口观察是否有超时和错误import requests url http://127.0.0.1:8000/api/chat seq 0 for message in [你好, 今天天气怎么样, 你是谁]: resp requests.post(url, json{message: message, uid: stress}, timeout120) seq 1 print(f{seq} - status{resp.status_code})判断标准连续多次请求没有出现连接拒绝、响应超时、返回空文本。如果中途卡住通常是模型推理还在排队或者内存不足导致进程被杀。9. 接口 API 与批量任务airi 的价值不只是网页聊天还在于接口对外开放后各类自动化任务都可以接进来。9.1 批量对话调用你可以准备一个questions.txt每行一个问题今天是几号 帮我写一个文件重命名脚本 给菜谱大全写一句推荐语然后写批量脚本import requests import time url http://127.0.0.1:8000/api/chat questions open(questions.txt, encodingutf-8).read().strip().splitlines() for i, question in enumerate(questions): try: resp requests.post(url, json{message: question, uid: batch}, timeout120) print(f{i 1}. Q: {question}) print(f A: {resp.json().get(reply, )[:100]}) except Exception as e: print(f{i 1}. failed: {e}) time.sleep(1) # 避免请求过快挤占内存批量场景要注意三点请求间隔不要太短否则模型还未处理完上一批请求新请求会排队超时。每条请求都要设置超时时间。失败任务单独记录后续重跑时跳过成功项。9.2 批量语音合成把需要批量朗读的文本放到texts/目录逐条生成语音import glob import os from TTS.api import TTS tts TTS(model_nametts_models/zh-CN/baker/model, progress_barFalse) os.makedirs(outputs, exist_okTrue) files glob.glob(texts/*.txt) for i, file in enumerate(files): text open(file, encodingutf-8).read().strip() out_path foutputs/audio_{i:04d}.wav try: tts.tts_to_file(texttext, file_pathout_path) print(fdone: {out_path}) except Exception as e: print(ffail: {file}, error: {e})执行前先处理文本中的特殊符号。批量生成时建议每执行 20 条主动释放一次缓存避免长时间运行导致内存持续上涨。9.3 批量任务队列设计如果任务量很大不要在接口里同步等待模型推理完成而是引入任务队列{ task_id: 20250101-001, type: chat, status: pending, input: {message: 你好}, output: }服务启动时将任务写入本地 SQLite 或 JSON 文件工作进程从队列取任务、更新状态、写回结果。前端或调用方通过 task_id 查询结果。这套设计常见但实用特别适合视频配音、批量字幕生成、文章批量问答这类耗时任务。10. 资源占用与性能观察本地 AI 应用最要紧的就是资源占用问题。这里给出观察方法和常见优化思路。10.1 观察显存占用NVIDIA 显卡用户在模型推理过程中查看显存nvidia-smi -l 1-l 1表示每秒刷新一次。常见观察点模型加载完成后显存占用会先冲高一次。对话回复越长推理期间显存峰值越高。如果显存接近满系统可能把部分数据换到内存导致推理变慢。CPU 推理用户可以在任务管理器或top里观察 CPU 占用率。大模型在 CPU 上推理时回复速度通常明显低于 GPU核心数越多相对越快。10.2 CPU 与 GPU 的差异以 7B 量级模型为例在稍早的消费级显卡上每秒生成速度比较可观纯 CPU 推理时速度会明显下降。不过如果只做日常文字问答CPU 慢一些也能接受。实际速度要结合模型量化等级和本机硬件来测试。建议记录三组数据首次启动耗时、单轮回复耗时、连续多轮回复耗时。这样换模型或改参数时能直观对比提升或劣化。10.3 降低显存占用的方法选择更小的量化模型例如 4bit 量化比 8bit 量化占用更低。限制对话历史长度只把最近 4 到 6 条消息传给模型。设置max_tokens避免回复无限输出。如果本机同时跑 Web 服务和模型分开部署到不同机器或显卡。10.4 服务稳定性观察长时间运行的服务要注意进程残留。手动停止后先确认进程真正退出netstat -ano | findstr :8000找到占用端口的进程 PID再按需结束。Windows 下可以用taskkill /PID 进程号 /FLinux 下用kill -9 进程号。服务不稳定时优先看服务端日志而不是盲目重启。11. 常见问题与排查方法问题现象可能原因排查方式解决方案启动后页面打不开端口被占用或服务未启动检查日志和端口监听换端口重启先杀掉旧进程对话接口返回空回复大模型服务未运行或请求超时单独调用 Ollama 测试先确认ollama serve正常再排查转发代码显存不足模型过大或并发任务太多用nvidia-smi观察显存换小模型或开启量化CPU 推理太慢模型参数过大CPU 核心数少观察 CPU 占用和单轮耗时换 1.5B、3B 等更小参数模型TTS 生成音质差参考音频格式不对或模型采样率设置错误检查 TTS 日志和音频格式统一音频采样率更换清晰参考音频API 返回 400请求参数格式不对查看 FastAPI 文档和日志按/docs页面的入参结构重新组织请求批量任务中途卡住单条任务无限等待增加超时并记录日志每条任务加timeout失败后跳过或重试回复内容不稳定没有配置 system prompt 或温度设置过高检查提示词和 temperature 参数固定人设提示词降低 temperature 到 0.6 至 0.7模型加载一段时间后崩溃内存或显存持续上涨观察负载趋势减少历史消息长度分批处理任务12. 最佳实践与使用建议本地部署类项目最容易出的问题不是装不上而是装好之后不知道怎么维护。下面几条建议值得直接采用。第一次跑通前先选最小的模型和最短的测试文本。不要一上来就下载大模型避免复现成本过高。保留一套最小可运行配置。把启动命令、模型名、端口号写进README.md出问题时快速回退。输入素材、模型文件、输出结果分开目录管理。例如inputs/、models/、outputs/分开脚本里使用相对路径便于迁移和备份。所有批量任务都加日志和失败重试。原始输入、请求参数、返回结果、失败原因要能回溯。接口服务默认只绑定127.0.0.1。需要局域网访问时再绑定0.0.0.0并确认没有把服务直接暴露到公网。涉及人脸、声音、版权素材时先确认授权。文字、图像、声音都可能涉及版权与隐私不能默认“本地使用”就万事大吉。商用或公开发布前检查模型 License。不同模型允许的开源商用范围不同注意模型仓库里的授权协议。安全方面还要提醒一句不要随便把 API 服务放到公网尤其在绑定0.0.0.0且没有鉴权的情况下。即便是个人使用也建议在服务前面加一层简单的 Token 校验或者只通过内网访问。13. 总结与下一步airi 这类个人专属 AI 助手最值得尝试的地方是它把大模型、语音合成和接口服务完整串了起来不依赖云端、不泄露对话记录而且改装成本低。对你来说最先应该验证的是对话接口能不能稳定返回内容这一步决定后面所有功能是否有基础。验证完对话再接入语音合成最后才考虑批量任务和外部工具集成。最容易踩的坑是两个方向一是模型太大导致本机带不动二是批量任务没有加超时导致进程越跑越慢。建议从量化小模型开始等熟悉以后再上更大的底座。后续可以扩展的方向有很多给 airi 接本地知识库做 RAG、给 Web 页面加流式输出、把批量语音合成接到字幕生成工具里、或者用一套任务队列把多台设备整合起来。接口已经留好剩下就是按自己的使用场景继续加模块。