
Local ChatGPT with Gemma 3 源码实战用 Ollama 与 Chainlit 搭建 100% 本地运行的多模态聊天助手【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub本指南以仓库local-chatgpt with Gemma 3项目为核心完整拆解如何基于 Google DeepMind 的 Gemma 3 开源模型与 Chainlit 框架在本地构建一个类 ChatGPT 的多轮对话应用模型权重完全运行在本机、无需调用任何云端 API同时天然支持图像输入与“打字机式”消息渲染。读完你将掌握 Chainlit 的事件回调编程模型、Ollama 本地推理的接入方式、会话级上下文管理与多模态消息构造并能在此模板上自由切换模型或扩展功能。项目概览一台机器上的“迷你 ChatGPT”该项目定位非常清晰利用 Google DeepMind 的 Gemma 3 与 Chainlit创建一个 100% 在本机运行的 mini-ChatGPT见 README 开篇描述。整个技术栈只有三个核心组件组件作用在本项目中的角色Ollama本地模型运行时与推理引擎负责下载权重、启动本地服务并执行gemma3:4b推理Gemma 34BGoogle DeepMind 的开源大语言模型对话与多模态理解的“大脑”模型参数gemma3:4bChainlitPython 聊天应用 UI 框架提供聊天界面、事件回调、会话状态与流式消息渲染app.py应用入口逻辑串联 UI 事件与本地模型调用这种“Ollama 出算力、Chainlit 出界面”的组合带来的直接收益是对话数据不离开本机、不需要 OpenAI/Anthropic 等云端 API Key联网需求几乎为零。从 app.py 源码可以看出整个推理链路只有一个对ollama.chat(...)的本地调用没有发起任何 HTTP 外部请求是名副其实的本地部署方案。环境准备安装 Ollama 并拉取 Gemma 3 模型README 的安装步骤面向 Linux 环境给出了一条可完整照做的命令链。在终端依次执行# 在 Linux 上安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 拉取 Gemma 3 4B 模型权重 ollama pull gemma3:4bollama pull gemma3:4b会从 Ollama 模型仓库下载约 4B 参数的 Gemma 3 权重并缓存在本地后续推理完全离线进行。若你的机器显存充足也可以把4b换成更大规格的标签例如gemma3:12b这只需修改一处模型名详见后文“横向对照”一节。注意一个 README 中的笔误原文档中“pull the DeepSeek-R1 model”的注释是从姊妹项目复制遗留的描述实际应拉取的是gemma3:4b请以命令本身为准。这一笔误恰好说明本仓库内多个“Local ChatGPT”变体共用同一套模板后文会对照验证。如果你在 macOS 或 Windows 上使用README 中的脚本式安装不适用需要改用 Ollama 对应平台的桌面安装方式安装后本机同样会常驻一个 Ollama 本地服务默认监听 11434 端口后续 Python 客户端默认即连接该地址。安装 Python 依赖项目要求Python 3.11 或更高版本依赖仅三个pip install pydantic2.10.1 chainlit ollama各依赖角色如下chainlit聊天 UI 框架提供cl.on_chat_start、cl.on_message等事件装饰器ollamaOllama 官方 Python 客户端用于在 Python 侧发起本地模型推理pydantic2.10.1被 Chainlit 依赖的数据校验库。这里锁定了精确版本而非pydantic2.x从写法上可推断是为了与所用 Chainlit 版本保持严格兼容避免大版本升级带来的接口不兼容问题——本地复现时建议保留该固定版本。启动应用并体验对话依赖装好后在项目目录下运行chainlit run app.py -wapp.py是要启动的应用文件-wwatch开启热重载修改源码后无需手动重启服务会自动刷新。命令执行成功后Chainlit 会在本地启动 Web 界面默认监听localhost:8000浏览器打开即可看到聊天页面。首次运行时它会自动生成 Chainlit 所需的配置文件目录正常启动的前提是本机 Ollama 服务处于运行状态、且已pull过gemma3:4b。仓库还提供了实际运行效果演示点击观看 AI 助手的 Demo 视频可在动手前直观了解最终界面与交互形态。app.py 逐段拆解从聊天事件到本地推理本项目的核心逻辑全部集中在一个仅 65 行的 app.py 文件中堪称“小文件大模式”。它定义了三个 Chainlit 回调装饰器/函数行号触发时机职责cl.on_chat_start→start_chatapp.py#L5-L25每个会话开始初始化 system 上下文与欢迎语cl.step(typetool)→toolapp.py#L27-L46每次收到用户输入后由main调用拼装消息、调用 Gemma 3、写入上下文cl.on_message→mainapp.py#L49-L65收到用户消息/图片解析附件并驱动推理与输出下面逐段说明其工作机制。1.start_chat初始化会话级上下文与打字机欢迎语cl.on_chat_start async def start_chat(): cl.user_session.set( interaction, [{role: system, content: You are a helpful assistant.}], ) msg cl.Message(content) start_message Hello, Im your 100% local ChatGPT powered by Google Deepminds Gemma 3. How can I help you today? for token in start_message: await msg.stream_token(token) time.sleep(0.005) await msg.send()关键点会话级状态存储cl.user_session.set(interaction, [...])把消息列表写入 Chainlit 的用户会话存储。interaction是整个多轮对话的“记忆载体”初始只包含一条 system 指令You are a helpful assistant.后续每一轮问答都会向这个列表追加内容从而让模型具备上下文连续性详见下文“会话级上下文”一节。打字机式欢迎语代码先把欢迎文本逐字符通过msg.stream_token(token)送入消息对象每字符间隔time.sleep(0.005)5 毫秒最后msg.send()一次性发出模拟出“逐字浮现”的 AI 启动效果。2.tool真正的本地推理函数cl.step(typetool) async def tool(input_message, imageNone): interaction cl.user_session.get(interaction) if image: interaction.append({role: user, content: input_message, images: image}) else: interaction.append({role: user, content: input_message}) response ollama.chat(modelgemma3:4b, messagesinteraction) interaction.append({role: assistant, content: response.message.content}) return response这段是整个应用的核心cl.step(typetool)装饰器把该函数注册为一个 Chainlit “工具步骤”。调用它时界面上会显示一个可展开的中间步骤节点方便观察推理过程。多模态消息构造如果本次输入携带图片用户消息会被构造成带images字段的字典{role: user, content: ..., images: image}。image实际是图片文件的本地路径列表Ollama 客户端会读取这些路径对应的图片并随请求发送给模型——这正是 Gemma 3 视觉能力的接入点。本地推理调用ollama.chat(modelgemma3:4b, messagesinteraction)把“完整的 interaction 历史”一次性交给本地 Gemma 3返回的response.message.content即模型生成的回答文本。上下文的双向写入调用前后分别把user消息与assistant回复追加进interaction保证每一轮对话都“记得”之前的全部内容。3.main消息入口与图片附件识别cl.on_message async def main(message: cl.Message): images [file for file in message.elements if image in file.mime] if images: tool_res await tool(message.content, [i.path for i in images]) else: tool_res await tool(message.content) msg cl.Message(content) for token in tool_res.message.content: await msg.stream_token(token) await msg.send()附件识别message.elements是用户上传的文件列表file.mime是文件 MIME 类型代码通过image in file.mime判断是否为图片png、jpeg、gif 等均命中。存在图片时提取所有i.path本地文件路径作为多模态输入传给tool。输出渲染模型完整生成后main同样采用stream_token逐字符渲染回答。注意这里与欢迎语的渲染方式一致——即先整体拿到回复、再逐字播报的“打字机效果”下文会解释它与真正 token 流式推理的区别。4. 一次完整对话的数据流整个请求链路可以用下图概括依据 app.py 各回调的调用关系用户在 Web 界面输入文字 / 上传图片 │ ▼ cl.on_message (main) │ 遍历 message.elements 过滤 image 类型得到图片路径列表 ▼ cl.step(typetool) (tool) │ 将 user 消息(含可选 images 字段)追加到 interaction ▼ ollama.chat(modelgemma3:4b, messagesinteraction) │ 本机 Ollama 推理返回 response ▼ 将 assistant 回复追加到 interaction记忆沉淀 │ ▼ main 用 stream_token 逐字渲染回复 → 展示在聊天界面三个值得深挖的实现机制会话级上下文记忆是如何“沉淀”的interaction列表始终存放在cl.user_session中这是 Chainlit 提供的按用户会话隔离的存储同一会话内所有回调都能读取同一份数据。整个对话期间该列表的生长轨迹如下会话开始[{role: system, content: You are a helpful assistant.}]第一轮提问后追加一条user消息模型回复后追加一条assistant消息第二轮提问、回复……列表持续增长因此模型的每一轮回答都建立在完整的“历史消息序列”之上——这与 OpenAI 等云端 API 的messages协议在结构上完全同构也意味着你随时可以把ollama.chat替换为任何遵循相同消息协议的本地或远程推理接口。“打字机效果”与真正的 token 流式推理源码中所有输出都走for token in content: await msg.stream_token(token)。需要厘清的是这里的content来自response.message.content即模型已经完整生成的一整段文本逐字符渲染只是在 UI 层制造打字机效果中间time.sleep(0.005)制造了节奏感并非逐 token 推理。如果希望实现“边生成边输出”的真正流式体验可以将 app.py#L40-L41 处的调用改为ollama.chat(..., streamTrue)再对迭代返回的块做增量渲染——当前仓库提交的是一个更简单直接的版本这一点从源码结构可以明确推断。多模态链路从拖拽图片到模型“看懂”Gemma 3 属于支持图像输入的开放模型而本项目让这一能力变得几乎零成本Chainlit 聊天框天然支持文件上传 →message.elements暴露上传文件 → 按 MIME 过滤图片 → 把本地路径列表放入消息的images字段 → Ollama 读取图片并送入 Gemma 3。整个图片处理无需任何额外的视觉预处理管线这是该实现最有价值的开箱即用特性之一。配套 notebook最小可复现的推理验证仓库中的 notebook.ipynb 记录了开发过程中对ollama.chat的最小调用验证。值得注意的是其中测试使用的是deepseek-r1模型该 notebook 大概率由 DeepSeek 变体项目复用而来但它验证的能力对 Gemma 3 同样成立import ollama response ollama.chat(modeldeepseek-r1, messages[{role: user, content: Hello, how are you?}]) print(response)从 notebook 输出的响应对象可以看到ollama.chat返回体的关键字段response.message含role与content、created_at、done_reason、以及eval_count/eval_duration等耗时统计。app.py 正是通过response.message.content取出回答文本——理解了这一点就抓住了整个项目“UI 与推理衔接”的接口契约。如果你想绕过 UI 单独验证模型是否就绪这段 notebook 代码是最快的冒烟测试。横向对照仓库内同一模板的多种模型变体本项目并非孤立存在。在当前仓库中local-chatgpt、local-chatgpt with DeepSeek与local-chatgpt with Gemma 3共用几乎相同的工程模板与安装说明差异仅在模型一行仓库目录驱动模型模型拉取命令local-chatgpt with Gemma 3gemma3:4b本主题ollama pull gemma3:4blocal-chatgpt with DeepSeekdeepseek-r1ollama pull deepseek-r1local-chatgptllama3.2-visionollama pull llama3.2-vision例如在 local-chatgpt/app.py#L38 中模型名换成了llama3.2-vision其余回调结构与 Gemma 3 变体完全一致。这揭示了一个可迁移结论这套 Chainlit 回调骨架对模型完全无感。想换模型时只需执行ollama pull 新模型并把 app.py#L40 的modelgemma3:4b改为新模型标签即可若模型不支持视觉则需同步去掉images字段的传参逻辑。常见问题与排查思路基于对安装与源码的分析本地复现时最常见的几类问题及对应处理建议如下模型未找到model not found确认已执行ollama pull gemma3:4b且模型名与代码中modelgemma3:4b完全一致推理无响应/连接失败检查本机 Ollama 服务是否在运行默认端口 11434Linux 安装脚本执行后可通过ollama list验证服务与模型状态界面卡在欢迎语确认start_chat中的time.sleep与渲染逻辑没有因终端中断而异常必要时在启动命令中保留-w以便观察热重载日志上传图片无效main只接收 MIME 类型含image的文件若上传的是非图片文件会被静默忽略。小结与可行的扩展方向local-chatgpt with Gemma 3用极少的代码量演示了一套完整、可离线运行的多模态对话范式Chainlit 负责交互与状态Ollama 负责本地推理Gemma 3 提供文本与视觉理解能力三者以标准messages协议串联。它既是零成本上手本地 LLM 应用开发的样板也是理解会话记忆、多模态消息与 UI 流式渲染的绝佳教材。如果你希望在此基础上继续实验结合源码留出的扩展点以下方向都只需在 app.py 上做局部改动即可实现接入真流式推理把ollama.chat改为streamTrue并增量渲染让回答“边算边出”切换/对比更多模型借助ollama pull拉取gemma3:12b、deepseek-r1等并替换模型名增强 system 角色设定修改start_chat中初始化的 system 内容即可定制助手人设与行为边界为长对话做截断/摘要interaction无限增长会拖慢推理可加入消息窗口裁剪或历史摘要逻辑。上述改动均属于读者在自己本地副本上的实践范畴仓库本身保持只读即可运行验证。【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考