资讯动态

本地AI接入微信实战:Ollama+WeChatFerry搭建私人AI助手

发布时间:2026/9/19 2:19:49 来源:尧图企业网站定制
1. 为什么非要把本地 AI 塞进微信1.1 这个项目到底在做什么先说明白我做的事在一台带 NVIDIA 显卡的 Windows 主机上用 Ollama 拉起一个本地大模型具体是通义千问 7B 的指令微调版然后通过一套桥接程序把它接到微信里。你在微信里给机器人发一句话它回你一段文字背后所有推理都在本地发生不经过任何云厂商。说白了就是把微信当成一个“聊天输入框”本地 AI 当成“CPU”中间那段胶水代码负责收发消息、调用模型、处理上下文。听起来很简单实际动手之后我发现这东西坑点密集到让人怀疑人生。我从“本地模型能跑起来”到“微信里能收到回复”中间花了两天写这篇文章就是为了让后来的人少走弯路。1.2 为什么选微信当入口其实本地 AI 的可交互形式很多命令行、浏览器里的 Gradio 网页、Open WebUI甚至直接调用 OpenAI 风格接口自己写前端。但这些都有一个共同问题——移动端访问要么要配内网穿透要么要开浏览器日常用起来就是不顺。微信不一样它是绝大多数人每天开得最频繁的 App。把本地 AI 接到微信之后我在手机上和它对话跟在电脑前面敲命令行完全是两种体验。而且微信天然的“会话窗口”本身就适合 AI 对话每条消息都对应一轮交互历史记录还自动保留在手机本地。另外一个很实际的原因微信是一个现成的“通知和交互双向通道”。你的 Python 脚本通过 AI 生成内容后能直接把结果推到微信反过来你在外面也能通过微信给脚本下指令。相当于用一个微信消息界面统一控制本地的多个自动化脚本。1.3 整体方案选型接法主要有三条路线我标一下我自己的选择和建议。路线实现方式稳定性合规与封号风险适合场景我的评价个人微信 Hook/注入WeChatFerry、微信机器人框架依赖注入工具版本较高只能用于个人小号测试个人折腾、内网使用我用的是这个Web 协议逆向早期 web 微信协议不太稳定高已基本不可用不推荐公众号/企业微信开放接口官方 API非常稳定无风险对外提供服务、团队内部工具合规首选但入口和场景不一样这一篇既然标题写的就是“把本地 AI 接入微信”我默认你和我一样是想在个人微信里折腾一个半私人的 AI 助手所以下面的代码全部围绕 WeChatFerry 这套通道来写。如果你更在意合规和稳定建议直接转战企业微信的自建应用思路是相通的——后半部分的本地模型调用代码完全不用改。2. 先把本地 AI 的底座装稳2.1 硬件门槛与模型取舍很多人一听说“本地 AI”就以为要 4090 起步其实没有这么夸张。跑 7B 参数的量化模型8GB 显存就能比较舒服地跑6GB 显存也能用只是生成速度会慢一些。如果只有 16GB 内存没有独显跑 1.8B 到 3B 的小参数模型也完全没问题就是智商肉眼可见地捉急。我列一个参考表基于我自己和朋友圈子的实测显存/内存可流畅运行的模型推理速度体感智商6GB 显存Qwen 1.8B / 3B / 7BQ4量化慢7B 约 8~12 token/s能聊天复杂推理拉胯8GB 显存Qwen2.5 7BQ415~25 token/s日常问答够用12GB 显存Qwen2.5 14BQ412~18 token/s明显聪明一个档次16GB 内存纯 CPUQwen 3B / 1.8B很慢只适合试水我自己用的是 8GB 显卡日常跑qwen2.5:7b-instruct的 Q4 量化版。为什么不直接上 13B因为显存一满就需要用内存兜底速度会断崖式下跌体验完全不能看。2.2 Ollama 部署与模型下载Ollama 是我试过最省心的本地模型运行器没有之一。它把模型下载、推理服务、GPU 调度全都封装好了对外暴露一个 HTTP API省掉自己写推理脚本的功夫。安装过程没什么好讲的官网下载对应系统的安装包Windows 直接双击装完。装完之后打开命令行窗口拉模型ollama pull qwen2.5:7b-instruct这一步会下载大概 4.7GB 的模型文件具体大小看网络情况建议挂个稳定网络再操作。拉完之后验证一下ollama list如果能看到模型列表说明本体已经 OK。这时候在命令行窗口里直接问一句话看看能不能正常回答ollama run qwen2.5:7b-instruct 用一句话介绍你自己到这里本地推理这件事就已经通了。2.3 用 HTTP API 验证服务Ollama 默认会在本机监听11434端口它同时提供/api/generate原始补全和/api/chat聊天补全两个接口。后面接微信时我们要用代码访问它所以先手动调一次确认服务正常curl http://127.0.0.1:11434/api/chat ^ -H Content-Type: application/json ^ -d {\model\:\qwen2.5:7b-instruct\,\messages\:[{\role\:\user\,\content\:\你好\}],\stream\:false}Windows 的 cmd 里转义双引号特别痛苦建议直接用 PowerShell Invoke-RestMethod -Uri http://127.0.0.1:11434/api/chat -Method Post -ContentType application/json -Body {model:qwen2.5:7b-instruct,messages:[{role:user,content:你好}],stream:false}能返回message.content字段就说明模型服务已经对外可用。这里有个很多人踩的坑{stream:false} 必须带不然后端会返回流式数据我们后面用普通 HTTP 请求解析会很麻烦。后面代码里我也会统一处理成非流式。2.4 部署阶段的经典问题我先把这个阶段最容易遇到的坑放在前面方便你对照排查。模型加载到一半显存就满了。这种情况多半是模型版本选大了。Ollama 默认会先尽可能把模型完全加载进 GPU如果显存不够会自动卸载部分层到内存但这会导致推理速度断崖式下降。换更小的模型或者用量化更狠的版本是正路不要和硬件较劲。回答速度慢每个字要等好半天。先看是不是 CPU 在硬扛用ollama ps可以看到模型跑在哪个设备上。如果是 GPU 跑但仍然慢检查显卡驱动和 CUDA 版本别图省事直接用很久以前的驱动。ollama run 和后面的服务互相抢资源。ollama run会把模型保持在内存里导致后面程序调 API 时模型要重新加载。实操时建议只启动ollama serve作为后台服务调试时别再用命令行的方式去拉同一份模型。3. 微信接入通道的选择与搭建3.1 三种通道对比本地模型跑通之后真正的噩梦才刚开始——怎么让微信和程序通信。先说结论个人微信的自动化方案目前处于一个“能用但脆弱”的状态。市面上主流的做法分成三类基于 Hook 的框架通过 DLL 注入微信客户端进程直接调用内部的函数接口收发消息。基于协议逆向的模拟客户端模拟微信客户端与服务端通信的协议不用装真实客户端就“化身”一个客户端。官方开放接口公众号、企业微信自建应用走官方 API。第一类里我用的是 WeChatFerry。它设计简洁、接口清晰、社区活跃在 Windows 平台上有 Python 和 C 的 SDK能监听微信消息、主动发消息满足我们这个小项目的全部需求。第二类风险最大免费方案基本绝迹网上能找到的要么不稳定要么是带木马的“免费版”我踩过几次之后直接放弃。第三类最安全但如果你和我一样只是想折腾个人号那不好意思官方通道在这条路上完全走不通。3.2 WeChatFerry 安装与前置条件WeChatFerry 有一个很硬的前置条件Windows 系统并且微信客户端版本要严格匹配它的要求。我是怎么装的呢大概三步pip install wcferry然后检查本机微信版本确保在 WeChatFerry 文档支持的版本列表里。它一般会提供对应版本的微信号你需要从官方渠道下载一个“专供个人使用的基础版”或旧版微信。这里注意不能直接拿最新版因为 Hook 框架跟不上微信更新迭代的速度版本差一点就会导致崩溃。安装完成后先跑一个最简单的测试脚本from wcferry import Wcf wcf Wcf() # 打印当前登录的微信账号信息 print(wcf.get_self_wxid()) print(wcf.get_user_info())能打印出你自己的 wxid 和昵称说明注入成功。如果脚本卡住或者报连接失败大概率是微信版本不匹配检查这一步最有效。3.3 消息接收的核心机制微信客户端收到消息后WeChatFerry 会把这些消息推送到我们的进程。新版 SDK 提供了一个线程安全的接收机制你调用enable_receiving_msg()开启接收之后通过get_msg()方法从内部队列取消息。这里有个新手最容易踩的误区不要在回调函数里直接做耗时操作。原因很简单微信客户端的事件循环是单线程式的你在回调里阻塞 2 秒整个客户端界面/收发都会卡住甚至触发微信的“无响应检测”。正确做法是回调函数把消息塞进自己的队列立刻返回后台另开一个工人线程从队列里消费消息、调 AI、发回复。import queue msg_queue queue.Queue() # 定义一个消息回调只负责入队 def on_msg_callback(msg): msg_queue.put(msg) wcf.enable_receiving_msg(callbackon_msg_callback)这套“生产者—消费者”模型是整个项目稳定性的基石。后面所有 AI 调用、网络请求、拆分发送的逻辑全部放到消费者线程里。3.4 这个阶段我踩过的坑微信版本不对导致注入失败。我之前装了最新版微信WeChatFerry 一运行就崩溃日志告诉我找不到对应函数。解决办法只有一个把微信换成它要求的版本千万别指望某个版本能“通吃”。Python 环境位数不对。如果你装的是 32 位 Python大概率会加载失败。务必确认用的是 64 位 Python 3.8 以上。杀毒软件拦截 DLL 注入。Hook 类工具的本质就是修改进程内存很多安全软件会把它当病毒处理。我是在自己的开发机上测试直接在杀毒软件里添加了白名单。不要在生产环境或别人的电脑上玩这东西容易被误会。4. 核心代码消息监听、模型调用、回复发送4.1 整体项目结构我整理一下最终的代码组织wechat_ai_bot/ ├─ main.py # 主程序启动消息循环 ├─ bot.py # 微信通道封装 ├─ ai_worker.py # 模型调用 上下文管理 ├─ config.py # 配置项模型名、Ollama地址、用户白名单 └─ requirements.txt # 依赖wcferry、requests希望你能把“微信通道”和“AI 调用”彻底拆开。后面如果你想从微信切到企业微信、钉钉或者反过来在别的通道里调用同一个模型栈会发现这个设计救了大命。4.2 配置项config.py里放所有参数# config.py OLLAMA_URL http://127.0.0.1:11434/api/chat MODEL_NAME qwen2.5:7b-instruct # 只响应这个列表里的联系人 wxid空列表表示允许所有人 ALLOWED_USERS [] # 私聊还是群聊 ENABLE_PRIVATE True ENABLE_GROUP False GROUP_AT_ONLY True # 群聊里只响应 机器人的消息 # 上下文保留的最大轮数一对一轮 MAX_HISTORY_ROUNDS 12 # 长消息拆分长度微信单条上限约 2000 字 MAX_MESSAGE_LENGTH 19004.3 微信通道封装bot.py里做一件最关键的事把 WeChatFerry 的原始消息对象转换成统一结构然后委托给 AI 处理模块。# bot.py import queue from wcferry import Wcf from config import ENABLE_GROUP, ENABLE_PRIVATE, GROUP_AT_ONLY class WeChatBot: def __init__(self): self.wcf Wcf() self.msg_queue queue.Queue() self.self_wxid self.wcf.get_self_wxid() def start(self, on_message): self.wcf.enable_receiving_msg() while True: try: msg self.wcf.get_msg() # 过滤自己发的消息防止死循环 if msg.sender self.self_wxid: continue # 基础过滤私聊/群聊开关 if msg.roomid: if not ENABLE_GROUP: continue # 群里只响应 机器人的消息具体判断逻辑见下方说明 if GROUP_AT_ONLY and not self._is_at_me(msg.content): continue content self._strip_at_me(msg.content) else: if not ENABLE_PRIVATE: continue content msg.content on_message({ roomid: msg.roomid, sender: msg.sender, content: content, }) except queue.Empty: continue except Exception as e: print(f[消息循环错误] {e})群聊里判断“是否 了我”有很多种写法最直接的是看消息内容里是否包含自己的完整微信昵称。WeChatFerry 的消息内容会把 对象显示成形如昵称的文本所以代码里直接查 自己昵称即可。4.4 调用本地模型的代码ai_worker.py是整个项目的脑浆# ai_worker.py import requests from config import OLLAMA_URL, MODEL_NAME, MAX_HISTORY_ROUNDS SYSTEM_PROMPT 你是一个住在本地电脑里的 AI 助手说话简洁、直接、不啰嗦。 class AIWorker: def __init__(self): self.history {} def _get_history(self, session_key: str): return self.history.get(session_key, []) def _save_history(self, session_key: str, messages): # 只保留最近 MAX_HISTORY_ROUNDS 轮每条消息占两段user assistant keep messages[-(MAX_HISTORY_ROUNDS * 2):] self.history[session_key] keep def ask(self, session_key: str, user_text: str) - str: history self._get_history(session_key) messages [ {role: system, content: SYSTEM_PROMPT}, *history, {role: user, content: user_text}, ] payload { model: MODEL_NAME, messages: messages, stream: False, temperature: 0.7, } resp requests.post(OLLAMA_URL, jsonpayload, timeout180) resp.raise_for_status() data resp.json() reply data[message][content].strip() # 把这一轮对话追加到历史记录 history.append({role: user, content: user_text}) history.append({role: assistant, content: reply}) self._save_history(session_key, history) return reply这里我加了session_key的概念。私聊时用sender对方 wxid作为 key群聊时用roomid作为 key。这样每个人/每个群的上下文是相互独立的不会出现张三问天气、李四却看到张三前文的尴尬。4.5 长消息拆分与发送微信对单条消息长度有限制模型如果一口气生成 3000 字直接发是发不出去的。要按长度切分同时尽量保留语义完整性def split_long_message(text: str, max_len: int 1900): 按段落优先切分保证每条不超过 max_len text text.strip() if len(text) max_len: return [text] if text else [] parts [] paragraphs text.split(\n) current for para in paragraphs: if len(current) len(para) 1 max_len: current (para \n) else: if current: parts.append(current.strip()) current para \n # 单个自然段也可能超长这时按硬字符切 if len(current) max_len: while len(current) max_len: parts.append(current[:max_len]) current current[max_len:] current if current.strip(): parts.append(current.strip()) return parts发送的时候遍历调用send_text即可def send_reply(wcf, receiver, reply): for part in split_long_message(reply): wcf.send_text(part, receiver)4.6 完整主流程main.py里把这些串起来# main.py from bot import WeChatBot from ai_worker import AIWorker from config import ALLOWED_USERS def handle_message(msg): sender msg[sender] roomid msg[roomid] content msg[content] # 白名单过滤 if ALLOWED_USERS and sender not in ALLOWED_USERS: return session_key roomid if roomid else sender receiver roomid if roomid else sender ai AIWorker() try: reply ai.ask(session_key, content) send_reply(wcf, receiver, reply) except Exception as e: send_reply(wcf, receiver, f调用 AI 出错了{e}) if __name__ __main__: bot WeChatBot() print(微信机器人已启动...) bot.start(handle_message)这一版代码足够把一个能用的机器人跑起来。你再补一个信号处理让程序退出时能干净收尾就行。4.7 并发与性能别让消息排队卡死实测下来本地模型生成一段 200 字回答可能要 10 秒左右。如果你在群里没加过滤同时来了 5 条消息每一条都阻塞在 AI 调用上后面的只能干等。我自己项目里没做复杂的异步而是用了最简单的“单消费者 任务队列”消息先进队列拿 AI 回复是一个串行过程。为什么不在回调里开多个线程并发调模型因为 Ollama 在单张消费级显卡上同时处理多个请求时显存带宽会被平分导致每个请求都变慢总吞吐量并没有提升。与其并发互相拖垮不如让消息排队逐个处理体验反而更稳定。提示把OLLAMA_NUM_GPU环境变量调成1或显卡编号能避免 Ollama 在 Windows 上把某些层错误地丢给 CPU推理性能会有明显改善。如果你一定要提升并发能力正确的方向是换更大的内存让多个模型常驻、或者换高端卡但那些都是加钱的问题不在代码层面纠结。5. 我踩过的坑从连不上到乱回复5.1 常见问题速查表我把这两天内遇到的所有问题汇总成一张表按“现象—原因—解决”列出来建议你直接收藏踩坑时对照现象原因解决方案微信程序崩溃微信版本与 WeChatFerry 不匹配换成文档指定的微信版本Wcf()初始化失败Python 32 位 / 微信未完全登录换 64 位 Python重新登录微信本地模型调用超时模型太大或设备推理太慢换更小模型调大 HTTP timeout消息队列持续堆积回调里做了耗时操作改造成生产者-消费者模式群聊机器人逐条回复所有人没有按 过滤按 4.3 的_is_at_me逻辑过滤模型回答重复且像复读机温度/重复惩罚参数不合理降低temperature提高repeat_penalty中文乱码终端编码不对 / 代码文件非 UTF-8chcp 65001脚本保存为 UTF-8发消息被微信吞掉或延迟发送频率过高触发风控增加发送间隔降低频率Ollama 偶尔连不上服务崩溃或端口被占用检查ollama serve是否活着重启服务5.2 模型回复质量太差怎么办很多人投完第一版代码兴冲冲给 AI 发“你是谁来着”结果模型回了半个小时的废话。如果要让本地模型更听话我的经验有三条第一把SYSTEM_PROMPT写清楚。本地模型比大厂 API 更容易受 system prompt 影响你可以把它当成“角色说明书”。比如需要翻译角色、编程助手角色指令越具体越好。第二控制temperature参数。0.7 偏发散0.3 以下偏保守。日常问答我建议 0.7如果发现它总爱自由发挥降到 0.4 试试。第三在ollama run的模型初始化阶段加keep_alive参数。模型首次加载需要几秒到十几秒保持常驻能省掉每次开销。在代码里可以在调用顺序上做优化先发一条“预热”消息或者直接用ollama run --keepalive 30m设置常驻时间。ollama run qwen2.5:7b-instruct --keepalive 30m这样接下来 30 分钟内模型都留在内存里响应速度会有质的提升。5.3 长篇回复的断句问题我最初实现拆分时简单地按每 1900 字硬切结果 AI 的回复在中间被拦腰截断语义破碎得厉害。后来改成“按段落优先”的拆分方式先按换行符分成小段再逐步拼接只有单段本身超过 1900 字时才会硬切。实测这样处理之后拆出来的每条消息基本都能保持完整语义。另一个小细节是不要在拆分段之间加多余的“续”之类标记微信端显示起来反而更乱。5.4 风控这回事别把触发红线当技术问题个人微信自动化一直有风险。我用小号测试到目前为止没出什么大事但这个风险必须如实告诉你微信官方并不鼓励任何非官方客户端接口的自动化操作轻则功能受限重则账号受限。我个人的底线是只给自己用不拿它做营销、不拉群、不大量加好友回复频率人工化所有发送之间至少间隔 1~2 秒长期运行用小号不把日常主聊天号挂在这种机器人下面遇到“频繁操作”之类的提示立刻停手不要尝试对抗。很多人把这个项目当灰产工具我不鼓励。我就当它是学习平台接口调用、理解消息队列和并发模型的一个玩具这样才能玩得长久。6. 安全边界与合规提醒6.1 隐私问题本地 AI 接入微信后所有对话内容都会通过程序转发给 Ollama。好消息是全程不出本机这是这个方案相比云 API 的一个核心优势——对话记录不会离开你的电脑。但反过来你必须注意程序代码里不要写死任何密码、明文令牌日志不要打完整消息内容如果数据库里存了聊天记录别忘了做加密和定期清理。另外模型本身也有泄露训练数据的可能不要在对话里发身份证号、银行卡号等真正的敏感信息。6.2 消息过滤给机器人加一层护栏虽然模型是本地私有部署但 AI 生成的内容依然不受控。我在代码里加了一层关键词过滤对明显不合适的内容直接不发送并且返回默认提示。这是一个简单的字符串匹配足够挡住大部分误触# safety.py BLOCK_WORDS [示例词, 另一个示例词] # 按自己需求添加 def is_safe_text(text: str) - bool: for w in BLOCK_WORDS: if w in text: return False return True这个方案很土但胜在简单有效。更复杂的思路是基于 embedding 做语义过滤对个人项目来说没必要。6.3 账号与使用边界再次强调这类个人微信自动化工具有针对性风控风险。我在部署时专门注册了一个小号只用它来测试和日常使用不打扰任何真实好友。所有代码也都放在内网环境运行不暴露到公网。如果你需要对外提供服务请务必转向企业微信自建应用或公众号后台那才是合规的玩法。6.4 后续还可以怎么扩展这个项目跑通之后底座就搭好了。我顺着这个结构做过几个扩展给你点参考把消息流接到家里的 NAS 上通过 AI 自然语言控制下载、备份、查询文件把 Ollama 换成支持更复杂 Agent 的工具链配合一个简单的任务规划器让机器人具备多步任务能力加入语音支持把微信语音消息转成文本再调用本地 TTS 生成语音回复把“微信通道”抽象成一层通用接口同时接入 Telegram、企业微信、短信平台共用同一套 AI 推理。基础架构就是“消息入口 队列 AI 推理 发送器”换入口只是换一个适配器的事。7. 写到最后一点个人体会这个项目让我印象最深的地方在于真正的难点根本不是 AI 模型本身而是“让所有零件在同一个进程里顺畅协作”。微信客户端、Hook 注入、消息队列、HTTP 调用、GPU 调度每一个环节单独拿出来都不难但它们凑在一起时出错的方式千奇百怪而且很多错误在官方文档里根本查不到。我后来再遇到“莫名其妙的 bug”第一反应已经不再是翻文档而是先检查三个东西微信版本对不对、Ollama 是不是还活着、消息内容是不是编码出问题了。这三个方向能覆盖掉八成以上的故障。如果你也要动手做类似的事我的建议是不要一上来就接微信先单独跑通 Ollama然后单独跑通 WeChatFerry 的收发消息最后再把两个模块接起来。每一步验证通过后再进入下一步排查时会省太多时间。最后再送一个小技巧调试时一定开两个终端窗口一个跑主程序一个随时用curl手动调 Ollama 的接口。一个报错是微信通道的问题还是模型服务的问题一眼就能看出来这个习惯帮我省了不知道多少根头发。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价