Ollama部署GLM-5.1实战:打造8小时自主AI工作流

发布时间:2026/10/22 2:42:50
Ollama部署GLM-5.1实战:打造8小时自主AI工作流
如果你也折腾过本地大模型应该能理解第一次让模型自主干活的那种兴奋。我花了一个周末用 Ollama 把一套被社区叫做 GLM-5.1 的国产开源模型部署到本地写了一个任务循环让它连续跑了 8 小时自动读取任务文件、生成分析结果、写回报表全程没有人工干预。这篇文章不是简单的一行命令装模型而是把部署—定制—编排—跑通整条链路完整拆开包括我踩过的显存炸裂、上下文失忆、API 超时等一堆坑。想对照着复现的读者建议具备最基础的命令行操作能力懂一点 Python 更好。整个过程可以概括成四件事搞清楚模型为什么适合自主任务、把 Ollama 部署干净、定制一个专门干活的模型配置、再写一个带兜底的重试循环。把这四件事做完8 小时自主 AI 工作就不再是宣传语而是你真正能跑起来的生产工具。1. GLM-5.1 凭什么能扛8 小时自主工作1.1 长上下文与指令遵循自主任务的基础能力先说结论不是所有开源模型都适合丢进自主循环。所谓自主 AI 工作本质是让模型在无人盯守的情况下连续处理一批又一批子任务。这意味着每批任务之间模型要能记住自己的角色、目标、格式要求不能上一批跑完就开始胡说。我最早拿一个 7B 量级的旧模型试过跑了不到半小时就出问题系统提示被上下文冲淡输出格式从 JSON 慢慢变成了散文最后干脆开始编造不存在的字段。换成 GLM-5.1 后同样一个任务循环连续处理几百个小任务输出格式依然稳定。它的指令遵循能力明显更强而且中文本地化的表达更自然不会在批量摘要里突然冒出一段翻译腔。这个模型的官方上下文窗口参数我没法拉满跑因为显存有限但在我自己配置的 8192 上下文下它依然能维持角色—任务—约束三合一的稳定记忆。对于自主循环里最常见的读入一段输入、按固定 schema 输出这个能力已经足够硬。1.2 工具调用能力模型负责决策代码负责执行自主工作的第二层能力是模型能不能给出结构化的动作指令。我在脚本里设计了这样一个模式模型不直接操作文件系统而是输出一个 JSON比如我要调用 write_file 函数参数是路径和内容再由外部 Python 代码真正执行。GLM-5.1 对这类函数调用的输出格式掌握得比我预期好。给它一个函数清单它基本不会把参数名写错。这意味着我可以构建一个安全的工具舱让模型只通过白名单函数操作文件、调接口、跑查询。其他开源模型经常在这个环节翻车输出一些似是而非的 JSON导致解析失败而它给我的体感是基本不需要修正 schema。1.3 8小时不是模型连续烧脑而是编排循环在持续驱动很多人误解自主 AI 工作以为是让模型一口气生成 8 小时内容。实际不是。模型单次推理的时间窗口很有限通常是几十秒到几分钟。真正的 8 小时是外部编排程序把一个大任务拆成无数个小请求逐个喂给模型再把结果收集起来。所以能不能跑 8 小时三分看模型能力七分看你的代码能不能扛住长时间调度。模型会中断吗大概率不会。但你的循环、文件读写、异常处理、上下文管理任何一个环节出问题整个流程就会提前死掉。后面几章我把这些环节分别讲清楚。2. 选 Ollama 部署的底层逻辑与硬件前置准备2.1 为什么我不用纯 Python 推理框架而是选 Ollama第一次部署时我尝试过直接用 Python 加载模型权重来做推理。这条路不是说走不通而是太绕你得手动处理分词器、显存分配、缓存管理还要自己写一个可以被外部访问的服务接口。对于快速验证一个自主任务来说启动成本有点高。Ollama 最香的地方在于它把推理服务封装成了现成的 HTTP API。我只要一行命令启动服务然后任何机器上的程序都能通过localhost:11434调用模型。它底层帮你处理了模型权重的加载、GPU 内存的分配、请求队列的管理。对写业务逻辑的人来说这一步算是不用重复造轮子。另外 Ollama 的模型管理非常友好。不同模型、不同量化版本通过ollama pull一键下载用标签区分。我要在同一个电脑上跑多个模型做对比也只是多几条命令的事。它甚至支持Modelfile自定义系统提示和参数这刚好符合我后面定制自主任务专用模型的需求。2.2 硬件配置清单最低下限、推荐上限本地跑 GLM-5.1 到底需要什么配置我列一张表是我实测后的体感阈值不是官方要求。配置项最低下限推荐配置说明CPU8 核以上16 核以上纯 CPU 模式也能跑但速度慢到崩溃内存16 GB32 GB 及以上加系统缓存和模型映射GPU 显存8 GB24 GB 及以上决定你是否能用更大上下文磁盘空闲30 GB80 GB SSD模型文件通常 5-30 GB 不等网络不稳定能续传稳定即可首次拉取模型体积大断点续传很重要如果你的显卡只有 8 GB 显存建议选择量化版本并且把num_ctx控制在 4096 以下不然推理到一半就会显存溢出。我自己的环境是 16 GB 显存用的是中等参数量模型加 8192 上下文跑 8 小时过程中显存占用稳定在 80% 附近。2.3 安装前的系统准备和隐藏依赖Ollama 的安装命令很简单curl -fsSL https://ollama.com/install.sh | sh但一键之前有几个容易被忽略的坑。第一它默认监听 11434 端口你得保证这个端口没被别的服务占掉。第二如果你在服务器上跑建议直接用systemctl status ollama确认服务已经常驻而不是每次手动开一个终端。第三下载模型需要稳定的网络环境有些网络下模型文件拉一半就断Ollama 支持续传但偶尔会卡住遇到这种情况直接ollama rm删除残留标签再重新拉。macOS 和 Windows 用户可以直接装官方桌面版图形界面里点一下就能把服务跑起来。但考虑到 8 小时自主任务需要在后台稳定运行我还是更推荐 Linux 服务器加systemd托管的方式至少不会出现合上笔记本盖子就断开这种意外。3. Ollama 拉取 GLM-5.1 的完整实操3.1 拉取模型与本地文件管理先装好 Ollama然后用下面这条命令把模型拉到本地ollama pull glm5下载过程会显示多个层的下载进度。模型被存放在~/.ollama/models目录下所以你不需要关心具体二进制文件在哪。拉取完成后用ollama list可以查看本地所有模型标签。我想强调一点如果你跑 8 小时自主任务一定要把模型名称写对。我习惯在脚本开头定义一个MODEL_NAME常量因为脚本一旦跑起来拼错一个字符所有请求都会立刻失败。日常调试时可以直接命令行对话ollama run glm5 用一句话解释什么是任务队列这个命令会拉起来一个交互式终端适合快速验证模型是否正常。不过正式跑任务时我不会用这个命令而是通过 HTTP API方便脚本自动化。3.2 用 HTTP API 完成第一次接口调用在等待模型正常响应之后可以直接用curl测接口curl http://localhost:11434/api/chat \ -d { model: glm5, messages: [{role: user, content: 11?}], stream: false }返回的 JSON 里有一个message.content字段这就是模型生成的文本。stream设为false我在自主任务里使用因为脚本更好处理一次性返回的完整内容。如果你做交互式聊天可以设成true效果就是打字机流式输出。这个 API 协议与很多常见服务兼容。我后面写 Python 脚本时甚至可以直接用 OpenAI 风格的客户端去访问只要把base_url指到http://localhost:11434/v1就行。这是个极大的便利。3.3 用 Modelfile 定制一个自主任务专用模型直接跑默认模型也可以但默认的系统提示是通用的而自主任务通常要求模型输出严格 JSON不要附额外解释你是数据分析助手等。Ollama 提供了Modelfile相当于给模型套一层自定义配置。我创建了一个Modelfile内容大概是这样FROM glm5 PARAMETER temperature 0.2 PARAMETER num_ctx 8192 PARAMETER top_p 0.9 SYSTEM 你是一个数据处理助手。你只允许输出 JSON 格式的结果不要输出多余解释。 当任务无法完成时输出 {error: 原因说明}。 在每次回应之前先确认你要调用的函数名称和参数。 然后执行ollama create glm5-worker -f Modelfile之后我脚本里的模型名就写glm5-worker而不是glm5。为什么要单独创建一个版本因为默认模型的num_ctx可能只有 2048自主任务里一旦输入稍微长一点模型就会失忆这个我后面详细讲。定制一个自己的标签随时改参数也不会影响原始模型。注意num_ctx设置得越大显存占用越高。如果你是 8 GB 显存建议先设 4096 跑通再慢慢调大。宁可上下文短一点也不要让它 OOM。4. 把一键部署扩展成8 小时自主工作4.1 自主工作循环的设计骨架模型部署好之后真正决定8 小时能跑起来的是外围的这个循环。我的设计分四个模块任务来源一个目录里有若干个 JSON 文件每个文件是一个子任务。模型调用层封装 Ollama API带超时和重试。工具执行层模型输出 JSON 指令后由脚本安全地调用具体函数。日志与熔断每处理一个任务写一行日志连续失败超过阈值自动休眠一段时间。这个设计的好处是模型不直接接触系统而是输出我想做什么由脚本决定是否允许。即使模型被 prompt 恶意引导它也只能调用白名单函数无法直接执行任意命令。4.2 可复用的 Python 自主循环脚本下面是一个简化但能跑的骨架脚本我实际项目中就是在它的基础上增加的细节import json import os import time import requests OLLAMA_URL http://localhost:11434/api/chat MODEL_NAME glm5-worker TASK_DIR ./tasks RESULT_DIR ./results LOG_FILE ./run.log START_TIME time.time() DURATION 8 * 60 * 60 # 8小时 MAX_ATTEMPT 3 def log(msg): line f[{time.time() - START_TIME:.0f}s] {msg} print(line, flushTrue) with open(LOG_FILE, a, encodingutf-8) as f: f.write(line \n) def chat(messages, max_tokens2048): payload { model: MODEL_NAME, messages: messages, stream: False, options: {num_predict: max_tokens, temperature: 0.3}, } last_exc None for attempt in range(5): try: resp requests.post(OLLAMA_URL, jsonpayload, timeout(10, 180)) resp.raise_for_status() return resp.json()[message][content] except Exception as exc: last_exc exc wait_time min(2 ** attempt, 30) log(f调用失败{wait_time}s 后重试{exc}) time.sleep(wait_time) raise RuntimeError(f模型调用多次失败: {last_exc}) def process_task(task): task_id task[id] text task[text] messages [ {role: system, content: 你是GLM-5.1驱动的任务助手只输出JSON。}, {role: user, content: f任务ID: {task_id}\n内容: {text}\n请输出分类和摘要。}, ] result_text chat(messages) try: result json.loads(result_text) except json.JSONDecodeError: # 模型可能输出了注释要求它只输出JSON fallback chat([ {role: system, content: 你是修正助手将上一轮响应转成合法JSON不要加其他内容。}, {role: user, content: result_text}, ]) result json.loads(fallback) return result def main(): log(自主工作循环启动) while time.time() - START_TIME DURATION: pending [f for f in os.listdir(TASK_DIR) if f.endswith(.json)] if not pending: log(暂无任务等待 120 秒) time.sleep(120) continue task_file pending[0] with open(os.path.join(TASK_DIR, task_file), encodingutf-8) as f: task json.load(f) if task.get(attempt, 0) MAX_ATTEMPT: log(f跳过任务 {task[id]}超过最大尝试次数) os.rename(os.path.join(TASK_DIR, task_file), os.path.join(RESULT_DIR, fskip_{task[id]}.json)) continue try: result process_task(task) with open(os.path.join(RESULT_DIR, fdone_{task[id]}.json), w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) os.remove(os.path.join(TASK_DIR, task_file)) log(f完成任务 {task[id]}) except Exception as exc: task[attempt] task.get(attempt, 0) 1 with open(os.path.join(TASK_DIR, task_file), w, encodingutf-8) as f: json.dump(task, f, ensure_asciiFalse, indent2) log(f任务 {task[id]} 失败第 {task[attempt]} 次{exc}) # 小睡一下避免连续打爆API time.sleep(1) log(达到 8 小时停止循环) summary_task { id: summary, text: 统计今天所有任务完成情况输出总结。, } # 最后让模型生成一份执行摘要 summary process_task(summary_task) with open(os.path.join(RESULT_DIR, summary.json), w, encodingutf-8) as f: json.dump(summary, f, ensure_asciiFalse, indent2) if __name__ __main__: main()这个脚本最核心的就是失败—重试—熔断机制。任务文件里记录attempt次数超过 3 次直接跳过并改名避免同一个坏任务卡住整个循环。而DURATION就是8 小时的落点程序到点自动写总结退出。4.3 怎么往任务源里喂不同类型的任务任务源目录里的每个 JSON 文件都可以具备不同字段比如{ id: task_001, type: classification, text: 用户反馈充值到账延迟客服态度差。 }我只要在process_task里根据type字段构建不同的 prompt 和输出 schema就能实现多任务混跑。比如一个 8 小时周期里上午处理客服消息分类下午处理商品评论摘要晚上处理竞品舆情报告。这样的灵活性靠的就是任务源—模型调用—工具执行三者的解耦。4.4 时长控制与优雅退出我额外强调一下优雅退出。你不想让循环写到一半就死所以脚本每小时都会把当前进度写进state.json任务完成一个删一个。这样就算系统意外重启脚本再跑也能从现有任务目录里继续而不是从头开始。8 小时这种长周期任务断点续跑几乎是必须的。5. 实战笔记一次真实跑通 8 小时的自主任务5.1 任务设定批量竞品舆情分析我在自己的服务器上模拟了一个任务负载90 个 JSON 文件每个文件包含 20 条用户评论要求模型对每条评论做三件事情感极性判断、核心主题抽取、一句话摘要。90 个文件总共 1800 条评论如果靠人工大概需要一个白天我想让 GLM-5.1 在我睡觉的 8 小时里自己做完。每个子任务的设计很清晰输入一组评论输出一个包含 20 条结构化结果的 JSON。批量处理时1800 条评论被分层 90 个请求每次请求约需要 50-100 秒左右所以 8 小时窗口勉强够。5.2 运行过程的四个阶段与数据我把运行过程拆成四个阶段方便观察时间段状态处理进度资源占用0-2 小时启动稳定期24 个文件显存约 75%2-4 小时高峰期28 个文件显存稳定CPU 偶发 90%4-6 小时等待期22 个文件出现几次 API 超时自动重试6-8 小时收尾期15 个文件生成了总结报告正常退出第 4-5 小时出现过一次上下文堆积问题。我最初的版本把前一个任务的回答也拼接到下一个任务的上下文里导致上下文越来越长响应速度显著变慢。后面我把每个子任务改成完全独立的对话只有系统指令保留问题立刻缓解。5.3 结果质量与资源占用观察第二天早上醒来我第一件事是随机抽了 50 条结果做人工检查。情感极性的准确率大概在 91%核心主题的命中率稍低一些约 85%。之所以有误差是因为模型偶尔会把表达夸张的评论判定为负面比如这家店太绝了居然还能再烂这类反讽。资源占用方面16 GB 显存在 8192 上下文下会被占到 12-13 GB剩下大约 3 GB 给系统和调度程序整体稳定。但如果在跑的过程中再开一个图形界面程序很容易把显存顶爆。所以真要跑 8 小时建议把机器上的图形化工具全关掉。提示别把 8 小时看成硬性指标。如果任务少模型提前跑完我建议写一个当任务清空后自动进入待机的逻辑而不是空转耗电。6. 踩坑复盘连续运行中的显存、上下文与卡死问题6.1 上下文堆积导致模型失忆这是我遇到的最大坑。最开始我为了让模型记住全局目标把 system 消息、历史对话、之前任务的结果全塞进 messages结果跑了两个多小时模型开始答非所问甚至重复输出上一条任务的答案。原因是num_ctx虽然设成了 8192但几千条消息拼接下来输入长度早就超过窗口。超过之后Ollama 不是报错而是会截断上半部分系统提示恰好被截掉了模型自然就开始忘了自己是谁。解决方式很简单每个子任务独立对话上下文里只放系统提示当前任务输入。如果确实需要跨任务记忆我会在每个子任务开始前让模型生成一段 100 字的上阶段摘要再放在系统提示里。摘要的信息密度远大于几十条原始历史消息。6.2 显存不足与 OOM自主任务和普通聊天不一样它会连续不间断地推理因此显存必须跑长跑而不是短跑冲刺。我有一次尝试把num_ctx从 8192 调到 16384使得单次请求的 KV cache 暴增跑了不到一小时Ollama 直接崩溃日志里有CUDA out of memory。解决方式把上下文降到 8192 甚至 4096。换用更低精度的量化版模型。在 Ollama 环境变量里设置 GPU 层数上限给系统留点显存。24 小时定时重启一次服务释放临时缓存。如果你用的是 Windows 版还需要额外注意集成显卡和独立显卡的切换问题否则 Ollama 可能加载到你不想用的显卡上。6.3 API 请求卡死、超时重试有一次运行到第 5 个小时整个循环停滞日志显示一条请求已经挂了三分钟。后来发现是某条用户评论特别长模型生成时间也跟着变长而requests默认没有设置读取超时。我修复的方法是在请求里指定timeout(10, 180)10 秒是连接超时180 秒是读取超时。超过 180 秒还没返回就认为这次请求失败触发重试。重试的时候我会退避等待第一次等 2 秒第二次等 4 秒最多等 30 秒避免在模型已经卡死时反复轰炸 API。6.4 自主循环失控的兜底策略所谓失控一种表现是同一任务反复失败反复重试永远不前进另一种表现是模型开始输出大量无效 JSON解析失败率上升。我的兜底策略是一个连续失败熔断器脚本记录最近 10 个任务的成功率如果成功率低于 30%就暂停 10 分钟然后清理失败任务只保留成功率高的任务类型。这个设计非常管用。有一次模型因为某类 prompt 格式问题连续失败熔断器介入后我保住了一批已完成的结果而不是让整个循环在白费力气。7. 一些值得单独记住的经验7.1 给模型一个截止时间点在系统提示里加上你剩余时间还剩 2 小时这句话会让模型输出更克制。它不会在一个问题上反复展开而是更倾向于快速完成。我实测两种模式下的平均响应时间有 20% 左右差距。7.2 定期生成摘要而不是堆砌历史如果一个自主工作任务需要跨子任务记忆不要把所有历史都放在上下文里。更优的做法是每完成 N 个任务调用模型生成一份当前进展摘要然后清空历史对话。摘要几十个字就能概括一大段结果而且不会撑爆num_ctx。7.3 安全边界模型只发指令代码才执行最后再强调一次安全。真正跑 8 小时无人值守你不可能盯着每次输出。所以我会在脚本里保证模型永远只输出 JSON 指令实际读写文件、调外部 API 的都是 Python 代码。程序里有一个全局ALLOWED_FUNCTIONS白名单不在名单里的函数一概拒绝执行。这个设计让我敢在睡觉时让它自动写文件、改文件名、跑统计而不是在提心吊胆中度过一个晚上。7.4 Ollama 服务也需要守护进程Ollama 默认服务在 Linux 下通过 systemd 管理一般不会崩。但如果你用的是普通命令行启动一旦 SSH 断开会话服务可能跟着死掉。最简单的方式是nohup ollama serve ollama.log 21 再写一个 cron 每分钟探活发现端口 11434 没响应就重新拉起。做这步之后我的8 小时才真正变成无人值守 8 小时。我自己跑通这一整套之后最大的感受是开源模型的进度比很多人想象中要快。GLM-5.1 这类模型已经具备稳定输出结构化指令的能力缺的只是外层这套把它当员工使唤的工作流。你现在拿这套 Ollama 部署加 Python 循环的底子完全可以扩展到更复杂的自动化场景——比如定时舆情巡检、夜间批量数据处理、多模型交叉验证。只要把任务拆细、上下文管住、失败熔断做好让模型替你值一个夜班真的不是什么科幻故事。