云计算百科
云计算领域专业知识百科平台

Ollama 从入门到实战:本地部署代码大模型,零成本打造你的私人编程助手

目录

  • Ollama 从入门到实战:本地部署代码大模型,零成本打造你的私人编程助手
    • 一、为什么你需要一个本地大模型?
    • 二、Ollama 是什么?一分钟搞懂
      • 2.1 官方定义
      • 2.2 核心特点
      • 2.3 Ollama 是怎么工作的?
    • 三、环境准备与安装(Windows 篇)
      • 3.1 硬件建议
      • 3.2 安装 Ollama
      • 3.3 验证是否安装成功
    • 怎么注销重新登录(Windows)
    • ⚠️ 操作前必看
      • 3.4 修改模型存储位置(可选,但强烈建议)
    • 四、模型下载与管理
      • 4.1 拉取(下载)模型
      • 4.2 查看已下载的模型
      • 4.3 删除模型
      • 4.4 常用命令速查表
    • 五、命令行基础使用
      • 5.1 进入交互式对话
      • 5.2 对话中的实用命令
      • 5.3 一次性的直接提问(非交互)
      • 5.4 指定参数提问(温度、长度等)
    • 六、进阶玩法:OpenAI 兼容 API(彻底讲透)
      • 6.1 先搞懂:API 到底是什么?
      • 6.2 什么叫"OpenAI 兼容"?为什么它很牛?
      • 6.3 一条请求是怎么发出去的?(逐字拆解)
      • 6.4 响应(返回结果)长什么样?(逐字拆解)
      • 6.5 用 curl 命令手动测试(最快验证方式)
      • 6.6 用 Postman 测试(图形化,看得见摸得着)
      • 6.7 一招吃遍:OpenAI 官方 SDK 直接指向本地
      • 6.8 常用参数详解表
      • 6.9 常见错误排查表
      • 6.10 接口一览(Ollama 提供的全部接口)
    • 七、实战一:Python 调用本地模型
      • 7.1 安装依赖
      • 7.2 完整代码:命令行版"代码助手"
      • 7.3 进阶:流式输出(边生成边显示)
      • 7.4 实战升级:多轮对话(带记忆的聊天助手)
      • 7.5 异步版:不阻塞主线程(适合 GUI / Web)
      • 7.6 实战案例:一键"代码审查助手"
      • 7.7 Python 调用常见问题
    • 八、实战二:Java 调用本地模型
      • 8.1 引入依赖(Maven)
      • 8.2 完整代码:调用本地模型生成代码
      • 8.3 规范写法:用 Jackson 构造请求体(推荐生产使用)
      • 8.4 Java 多轮对话(记住上下文)
      • 8.5 Spring Boot 集成:把 Ollama 封装成服务
      • 8.6 Java 调用常见问题
    • 九、实战三:接入 IDE,变身编程助手
      • 9.1 VSCode 接入 Continue 插件(推荐)
      • 9.2 IDEA 接入 Continue 插件
      • 9.3 其他 IDE 插件
      • 9.4 Continue 的配置文件详解(进阶)
      • 9.5 Cline 插件接入(另一个选择)
      • 9.6 前端开发者的 IDE 高频用法
      • 9.7 性能与内存注意事项(16G 机器)
      • 9.8 其他可选的 IDE 插件
    • 十、实战四:前端项目调用本地模型(Vue / jQuery / 原生 JS)
      • 10.1 前端场景能做什么?
      • 10.2 第一个大坑:浏览器跨域(CORS)
      • 10.3 方案A:原生 JS + fetch(ES6,现代浏览器)
      • 10.4 方案B:jQuery + ES5(兼容 IE,老项目适用)
      • 10.5 方案C:Vue2 + Vant 工程化接入
      • 10.6 后端代理解决跨域(Java / Node 二选一)
      • 10.7 前端实战场景提示词清单
      • 10.8 前端流式输出:边生成边显示(打字机效果)
      • 10.9 完整成品页面:一个可直接打开的"AI 代码生成器" HTML
      • 10.10 前端体验优化要点
      • 10.11 移动端 H5 适配提示
    • 十一、模型推荐与选型指南
      • 11.1 面向代码开发
      • 11.2 面向通用对话
      • 11.3 选型口诀
    • 十二、常见问题与避坑指南
      • 12.1 命令找不到 / 报错
      • 12.2 国内镜像加速(下载慢的救星)
      • 12.3 模型存储位置修改
      • 12.4 后台常驻 / 开机自启
    • 十三、总结

Ollama 从入门到实战:本地部署代码大模型,零成本打造你的私人编程助手

文章导读:本文是一篇面向初学者的保姆级实战教程。从 Ollama 是什么讲起,手把手带你完成 Windows 环境下的安装、模型下载、命令行使用、OpenAI 兼容 API 调用,再到接入 VSCode / IDEA 变成你的专属编程助手,最后附上 Python、Java 两套完整可运行的调用代码和避坑指南。全文零基础可上手,跟着操作即可跑通。


一、为什么你需要一个本地大模型?

很多开发者都有这样的困扰:

  • 代码写一半卡壳,想问问 AI,但把公司/项目源码贴给在线工具,心里没底(数据隐私问题);
  • 断网或内网环境,在线 ChatGPT、豆包、DeepSeek 网页版统统用不了;
  • 想在自己项目里集成 AI 能力,但调云 API 要花钱、要申请密钥、要担心限流;
  • 想研究大模型原理,跑个开源模型练手。

Ollama 就是为解决这些问题而生的——它让你在自己的电脑上,用一条命令就能跑起一个开源大模型,数据不出本机,永久免费,还能当 API 服务被你的程序调用。

而且最关键的是:它可以写代码、补全代码、解释代码、查 bug,完全可以当成你的"离线版编程助手"。


二、Ollama 是什么?一分钟搞懂

2.1 官方定义

Ollama 是一个用于在本地运行和管理大型语言模型(LLM)的开源工具,支持 Llama、Qwen、DeepSeek、Gemma 等主流开源模型,提供极简的命令行操作和 OpenAI 兼容的 API 接口。

2.2 核心特点

特性说明
极简安装 一条命令 / 一个安装包,装完即用
一键拉模型 ollama pull 模型名 自动下载,无需手动配置环境
本地运行 数据不出本机,离线可用,隐私安全
API 兼容 提供 OpenAI 风格接口,可被任意编程语言调用
跨平台 支持 Windows / macOS / Linux
模型丰富 Qwen、DeepSeek、Llama、Gemma、Mistral 等全支持
完全免费 开源免费,无使用次数限制

2.3 Ollama 是怎么工作的?

简单说它的工作流程是:

你输入文字 / 提问

Ollama(本地服务,默认端口 11434)

调用本机的开源模型(如 Qwen2.5-Coder)

模型推理生成结果

返回给你 / 返回给调用它的程序

它本质上是一个"模型管家":负责模型的下载、加载、运行和暴露 API,你不用关心底层的 Python 环境、CUDA 配置、模型权重文件放哪,全部交给它。


三、环境准备与安装(Windows 篇)

3.1 硬件建议

不同参数量模型对内存(RAM)的要求不同,先对照一下你的电脑:

模型规模参数量最低内存推荐内存适用场景
轻量 3B 8GB 8~16GB 代码补全、轻量对话
主流 7B 8GB 16GB 代码生成、对话、翻译
中大型 14B 16GB 32GB 复杂代码、长文本
大型 32B+ 32GB 64GB 高质量推理(需强机)

3.2 安装 Ollama

方式一:官网下载安装包(推荐 Windows 用户)

  • 打开官网:https://ollama.com/download
  • 点击 Windows 下载 OllamaSetup.exe
  • 双击运行,一路 Next 完成安装
  • 安装完成后,Ollama 会自动在后台启动
  • 方式二:命令行安装(适合习惯终端的朋友)

    在 PowerShell 或 CMD 中执行:

  • Win+x,选择 Windows PowerShell (管理员)
  • 复制粘贴指令,回车执行:
  • # macOS Linux
    curl -fsSL https://ollama.com/install.sh | sh

    # Windows
    irm https://ollama.com/install.ps1 | iex

  • 方式三:镜像地址

  • https://shturl.cc//https://github.com/ollama/ollama/releases/download/v0.33.3/OllamaSetup.exe
  • https://ghproxy.cn/https://github.com/ollama/ollama/releases/download/v0.33.3/OllamaSetup.exe
  • https://gh.llkk.cc/https://github.com/ollama/ollama/releases/download/v0.33.3/OllamaSetup.exe
  • 3.3 验证是否安装成功

    按 Win + R 打开运行框,输入 cmd 回车,在命令行中输入:

    ollama –version

    看到类似输出即成功:

    ollama version 0.5.7

    如果提示"不是内部或外部命令",重开一个 CMD 窗口再试,或者注销重新登录一次(让环境变量生效)。

    怎么注销重新登录(Windows)

    方法一:开始菜单(最常用)

  • 点左下角 开始(Windows 图标)
  • 点头像(或左下角头像图标)→ 注销
  • 系统回到登录界面,重新输入密码登录即可
  • 方法二:快捷键

  • 按 Ctrl + Alt + Del
  • 点 注销
  • 重新登录
  • 方法三:命令行注销

    在 CMD 里输入:

    shutdown /l

    (/l 就是 logout,立刻注销)


    ⚠️ 操作前必看

    • 先保存所有正在编辑的文件(代码、文档),注销会关闭所有程序
    • 注销后重新登录,桌面、程序会重新加载,稍等一下即可
    • 重新登录后再打开 CMD 验证:

    echo %OLLAMA_MODELS%

    能显示你设置的路径(如 D:\\ollama_models),就说明环境变量生效了。


    更省事的替代方案:如果你不想注销,改完环境变量后直接重启电脑效果一样;如果只是想让 Ollama 读新配置,也可以右下角托盘右键 Ollama 图标 → Quit,再从开始菜单重新打开 Ollama,比注销快得多

    3.4 修改模型存储位置(可选,但强烈建议)

    默认模型会下载到 C 盘(C:\\Users\\你的用户名\\.ollama\\models),7B 模型约 4.7GB,C 盘紧张的同学一定要改。

  • 右键"此电脑" → 属性 → 高级系统设置 → 环境变量
  • 新建用户变量:
    • 变量名:OLLAMA_MODELS
    • 变量值:D:\\ollama_models(改成你自己的盘)
  • 保存后重启 Ollama / 重启电脑再拉模型

  • 四、模型下载与管理

    4.1 拉取(下载)模型

    在 CMD 中执行:

    ollama pull qwen2.5-coder:7b

    等待进度条跑完即可。这是代码专用模型,接下来我们主要用它。

    想用更轻更快的(低配机器推荐):

    ollama pull qwen2.5-coder:3b

    4.2 查看已下载的模型

    ollama list

    输出示例:

    NAME ID SIZE MODIFIED
    qwen2.5-coder:7b xxxxxxxxxxxx 4.7 GB 2 minutes ago

    4.3 删除模型

    ollama rm qwen2.5-coder:7b

    4.4 常用命令速查表

    命令作用
    ollama list 查看已下载模型
    ollama pull 模型名 下载模型
    ollama rm 模型名 删除模型
    ollama run 模型名 启动并进入对话
    ollama serve 手动启动服务(一般不需要)
    ollama ps 查看当前正在运行的模型
    ollama stop 模型名 停止某个正在运行的模型

    五、命令行基础使用

    5.1 进入交互式对话

    ollama run qwen2.5-coder:7b

    看到 >>> 提示符后,直接输入问题,例如:

    写一个 Java 方法,判断一个整数是否为素数

    模型会现场生成代码:

    public static boolean isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i += 6) {
    if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
    }

    5.2 对话中的实用命令

    输入作用
    /bye 退出对话
    /clear 清空当前对话上下文
    /help 查看帮助
    /? 查看可用参数

    5.3 一次性的直接提问(非交互)

    ollama run qwen2.5-coder:7b "用 Python 写一个快速排序"

    5.4 指定参数提问(温度、长度等)

    ollama run qwen2.5-coder:7b "写一段冒泡排序" –temperature 0.2

    –temperature 越低,输出越稳定严谨(写代码建议 0.1~0.3);越高越有创造力(写文案可以调高)。


    六、进阶玩法:OpenAI 兼容 API(彻底讲透)

    很多人第一次看到"OpenAI 兼容 API"这个词就懵了。别急,这一章我用最直白的方式,从"API 是什么"开始,一步步带你把它彻底搞懂。

    6.1 先搞懂:API 到底是什么?

    一句话:API 就是"程序之间对话的窗口"。

    打个比方:

    • 你去餐厅吃饭,不用走进厨房,只需要对服务员说"来一份番茄炒蛋"
    • 服务员把你的话传给厨房,再把菜端给你

    在这里:

    • 你的程序 = 顾客
    • API = 服务员(传话的窗口)
    • Ollama 服务 = 厨房(真正干活、生成内容的模型)

    所以"调用 API"的意思就是:让你的程序按照规定的格式,给 Ollama 发一段话,Ollama 处理后把结果返回来。

    Ollama 装好后,就等于你的电脑上开了一个"厨房",地址是:http://localhost:11434,任何程序都可以通过这个地址跟它"点菜"。

    6.2 什么叫"OpenAI 兼容"?为什么它很牛?

    OpenAI(ChatGPT 那家公司)定义了一套全世界最流行的 AI 接口规范——什么格式的请求、什么格式的返回,大家都在按这个标准来。

    "Ollama 提供 OpenAI 兼容 API"的意思就是:Ollama 的接口格式和 OpenAI 一模一样。

    这带来的好处巨大:

  • 生态通用:网上所有教你调 OpenAI 的教程、代码、工具,把地址改成本地,就能跑在 Ollama 上
  • 随时切换:同一份代码,今天用本地模型,明天想用云端,只改一行地址
  • 零学习成本:你学会调 OpenAI,就等于学会了调 Ollama
  • 比喻:就像手机充电口统一成 Type-C,换个充电器插上就能用,不用重新学。

    6.3 一条请求是怎么发出去的?(逐字拆解)

    要调 API,你需要 4 样东西,缺一不可:

    组成值说明
    地址(URL) http://localhost:11434/v1/chat/completions 告诉程序"发给谁"
    方法(Method) POST 表示"我要提交数据"
    请求头(Headers) Content-Type: application/json 告诉对方"我发的是 JSON 格式"
    请求体(Body) 下面这个 JSON 具体"说什么"

    请求体(Body)逐行讲解:

    {
    "model": "qwen2.5-coder:7b",
    "temperature": 0.2,
    "messages": [
    {"role": "system", "content": "你是一个资深程序员,只输出可直接运行的代码"},
    {"role": "user", "content": "写一个Java的Hello World"}
    ]
    }

    字段作用通俗理解
    model 用哪个模型 指定"让哪位厨师做菜"
    temperature 生成随机性 越低越严谨(写代码用 0.2),越高越有创意
    messages 对话内容(核心) 把"聊过的天"一起发给它

    messages 是重中之重,它是一个数组,按顺序记录对话:

    • role: "system" → 系统设定,告诉模型"你是什么身份、要怎么干活"(可选,但强烈建议)
    • role: "user" → 用户说的话(就是你的提问)
    • role: "assistant" → 模型之前的回答(多轮对话时,要把它带回来,模型才能"记得"前面聊过什么)

    ⚠️ 关键点:模型本身没有记忆!每次请求都是"全新的"。你想让它记得之前的对话,就必须把历史记录一条条塞进 messages 里一起发过去。这也是为什么你的"聊天助手"程序要自己维护对话历史。

    6.4 响应(返回结果)长什么样?(逐字拆解)

    请求发出去后,Ollama 会返回一段 JSON,大概长这样:

    {
    "id": "chatcmpl-xxxx",
    "model": "qwen2.5-coder:7b",
    "choices": [
    {
    "index": 0,
    "message": {
    "role": "assistant",
    "content": "下面是Java的Hello World代码:\\n```java\\npublic class HelloWorld {\\n public static void main(String[] args) {\\n System.out.println(\\"Hello, World!\\");\\n }\\n}\\n```"
    },
    "finish_reason": "stop"
    }
    ],
    "usage": {
    "prompt_tokens": 15,
    "completion_tokens": 40,
    "total_tokens": 55
    }
    }

    你真正要取的内容藏在最深处:choices[0].message.content

    一层层剥开看:

    • choices → 一个数组(结果列表),通常只有 1 个,所以取 [0]
    • choices[0].message → 模型回复的消息对象
    • choices[0].message.content → 模型真正生成的文字 ← 就是它!

    所以代码里拿结果就一句话:

    result = data["choices"][0]["message"]["content"]

    其他字段含义:

    字段含义
    finish_reason: "stop" 生成正常结束(length 表示超长被截断)
    usage.prompt_tokens 你发的内容占了多少 token
    usage.completion_tokens 模型回复占了多少 token
    usage.total_tokens 总共多少 token

    简单理解 token:大模型按"词块"计算,1 个汉字大约 1~2 个 token。token 数量影响速度(本地不花钱)。

    6.5 用 curl 命令手动测试(最快验证方式)

    不想写程序,先在命令行验证 API 通不通:

    curl http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" -d "{\\"model\\":\\"qwen2.5-coder:7b\\",\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"用Java写Hello World\\"}]}"

    返回一大段 JSON,找 "content": 后面的内容,就是模型生成的代码。

    Windows CMD 里注意:引号要这样转义 \\",建议直接在 PowerShell 里执行。

    6.6 用 Postman 测试(图形化,看得见摸得着)

  • 打开 Postman,新建请求
  • 选择 POST,地址填 http://localhost:11434/v1/chat/completions
  • 切到 Headers 标签,加一条:Content-Type = application/json
  • 切到 Body 标签,选 raw + 右侧类型选 JSON
  • 粘贴请求体:
  • {
    "model": "qwen2.5-coder:7b",
    "messages": [
    {"role": "user", "content": "用Java写Hello World"}
    ]
    }

  • 点 Send,下方就能看到完整的响应 JSON
  • 6.7 一招吃遍:OpenAI 官方 SDK 直接指向本地

    不用自己拼 JSON 了!OpenAI 官方 Python 库,只要把 base_url 改成 Ollama 地址就能用:

    pip install openai

    from openai import OpenAI

    # 关键:把地址指向本地 Ollama,api_key 随便填(本地不校验)
    client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"
    )

    resp = client.chat.completions.create(
    model="qwen2.5-coder:7b",
    messages=[
    {"role": "system", "content": "你是一个资深程序员"},
    {"role": "user", "content": "用Python写一个快速排序"}
    ]
    )

    print(resp.choices[0].message.content)

    就是这么简单。将来想换成云端 OpenAI,只要把 base_url 改成 https://api.openai.com/v1、api_key 换成真 key,代码一行都不用改。

    6.8 常用参数详解表

    参数默认值作用写代码推荐
    temperature 0.8 随机性,越低越稳定 0.1~0.3
    max_tokens 无限制 限制回复最大长度 2048 左右
    stream false 是否流式输出(边生成边返回) 需要实时显示时开 true
    top_p 1.0 另一种采样控制,和 temperature 二选一 0.9
    messages 必填 对话上下文 按需拼接

    6.9 常见错误排查表

    报错现象原因解决办法
    model "xxx" not found 这个模型没下载 ollama pull xxx 先下载
    Connection refused Ollama 服务没启动 / 端口不对 确认 Ollama 在运行,地址端口正确
    404 错误 接口地址拼错 检查是不是 /v1/chat/completions
    请求超时 模型首次加载慢 / 生成的太长 等久一点;或先 ollama run 预热模型
    中文乱码 编码问题 请求头加 charset=utf-8,代码里用 utf-8 读响应

    6.10 接口一览(Ollama 提供的全部接口)

    接口路径用途
    对话补全 /v1/chat/completions 对话、代码生成(最常用)
    文本补全 /v1/completions 纯文本续写
    嵌入向量 /v1/embeddings 把文本转成向量,用于 RAG 检索
    模型列表 /v1/models 获取当前可用模型
    原生接口 /api/generate Ollama 原生生成接口(非 OpenAI 格式)
    原生对话 /api/chat Ollama 原生对话接口(非 OpenAI 格式)

    七、实战一:Python 调用本地模型

    7.1 安装依赖

    pip install requests

    7.2 完整代码:命令行版"代码助手"

    # -*- coding: utf-8 -*-
    """
    Ollama 本地代码助手(命令行版)
    用法:python ollama_code_assistant.py
    """

    import requests

    # ============ 配置 ============
    OLLAMA_URL = "http://localhost:11434/v1/chat/completions"
    MODEL = "qwen2.5-coder:7b" # 换成你下载的模型名
    # ==============================

    def ask_ollama(prompt, system_prompt=None):
    """向本地 Ollama 发送对话请求"""
    messages = []
    if system_prompt:
    messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})

    payload = {
    "model": MODEL,
    "messages": messages,
    "temperature": 0.2, # 写代码用低温,更稳定
    "stream": False
    }
    try:
    resp = requests.post(OLLAMA_URL, json=payload, timeout=120)
    resp.raise_for_status()
    data = resp.json()
    return data["choices"][0]["message"]["content"]
    except Exception as e:
    return f"[错误] {e}"

    if __name__ == "__main__":
    system = "你是一名资深程序员,回答问题给出可直接运行的完整代码,并附简短注释。"
    print("=" * 50)
    print(" Ollama 本地代码助手 | 输入 exit 退出")
    print("=" * 50)
    while True:
    user_input = input("\\n你: ")
    if user_input.strip().lower() in ("exit", "quit", "退出"):
    break
    print("\\nAI 思考中…\\n")
    result = ask_ollama(user_input, system)
    print("AI:", result)

    运行:

    python ollama_code_assistant.py

    7.3 进阶:流式输出(边生成边显示)

    把上面的 ask_ollama 换成流式版本,体验会好很多:

    def ask_ollama_stream(prompt, system_prompt=None):
    """流式版:边生成边打印"""
    messages = []
    if system_prompt:
    messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})

    payload = {
    "model": MODEL,
    "messages": messages,
    "stream": True
    }
    resp = requests.post(OLLAMA_URL, json=payload, stream=True, timeout=120)
    for line in resp.iter_lines():
    if line:
    chunk = line.decode("utf-8")
    try:
    data = json.loads(chunk.split("data: ")[1])
    content = data["choices"][0]["delta"].get("content", "")
    if content:
    print(content, end="", flush=True)
    except Exception:
    pass

    7.4 实战升级:多轮对话(带记忆的聊天助手)

    之前说过"模型没有记忆",所以要自己维护历史记录。下面这个版本会把每次问答都存进列表,实现真正的连续对话:

    # -*- coding: utf-8 -*-
    """
    Ollama 多轮对话助手:模型会记得之前聊过什么
    用法:python ollama_multi_turn.py
    """

    import requests

    OLLAMA_URL = "http://localhost:11434/v1/chat/completions"
    MODEL = "qwen2.5-coder:7b"

    # 对话历史列表(就是 messages 数组)
    history = []

    def chat(user_input):
    """把用户输入追加进历史,整体发给模型"""
    history.append({"role": "user", "content": user_input})

    payload = {
    "model": MODEL,
    "temperature": 0.2,
    "messages": history # 带上全部历史
    }

    resp = requests.post(OLLAMA_URL, json=payload, timeout=120)
    resp.raise_for_status()
    data = resp.json()

    # 把模型回答也存进历史,供下一轮使用
    reply = data["choices"][0]["message"]["content"]
    history.append({"role": "assistant", "content": reply})
    return reply

    if __name__ == "__main__":
    # 初始系统设定
    history.append({"role": "system",
    "content": "你是一名资深 Java/前端工程师,回答问题给出可直接运行的完整代码。"})
    print("=" * 50)
    print(" Ollama 多轮对话助手(记得上下文) | 输入 exit 退出")
    print("=" * 50)
    while True:
    user_input = input("\\n你: ")
    if user_input.strip().lower() in ("exit", "quit", "退出"):
    break
    print("\\nAI: ", end="")
    print(chat(user_input))

    核心思路(重要):

  • 用一个 history 列表存对话
  • 每轮把 history 整个作为 messages 发过去
  • 把模型回复 append 回 history
  • 这样下一轮模型就能"记得"前面聊过什么
  • ⚠️ 注意:历史越长,每次请求越慢、越占内存。实际开发建议只保留最近 N 轮(比如 20 条),更早的丢弃。

    7.5 异步版:不阻塞主线程(适合 GUI / Web)

    用 httpx 实现异步调用,适合给 GUI 程序或 Web 后端用:

    pip install httpx

    # -*- coding: utf-8 -*-
    """Ollama 异步调用示例"""
    import asyncio
    import httpx

    OLLAMA_URL = "http://localhost:11434/v1/chat/completions"
    MODEL = "qwen2.5-coder:7b"

    async def ask_ollama_async(prompt, system_prompt=None):
    messages = []
    if system_prompt:
    messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})

    async with httpx.AsyncClient(timeout=120) as client:
    resp = await client.post(OLLAMA_URL, json={
    "model": MODEL,
    "temperature": 0.2,
    "messages": messages
    })
    resp.raise_for_status()
    data = resp.json()
    return data["choices"][0]["message"]["content"]

    async def main():
    result = await ask_ollama_async(
    "用 Python 写一个读 Excel 文件的脚本",
    "你是一个 Python 数据处理专家"
    )
    print(result)

    if __name__ == "__main__":
    asyncio.run(main())

    7.6 实战案例:一键"代码审查助手"

    这是最实用的一个场景——把一段代码贴给它,让它按检查清单找问题:

    # -*- coding: utf-8 -*-
    """
    Ollama 代码审查助手
    用法:python code_review.py 你的代码文件路径
    """

    import sys
    import requests

    OLLAMA_URL = "http://localhost:11434/v1/chat/completions"
    MODEL = "qwen2.5-coder:7b"

    REVIEW_SYSTEM = (
    "你是一名严格的代码审查专家。请从以下维度审查代码:\\n"
    "1. 逻辑错误和 bug\\n"
    "2. 安全隐患(SQL注入、XSS等)\\n"
    "3. 性能问题\\n"
    "4. 代码规范(命名、格式)\\n"
    "5. 优化建议\\n"
    "按 '问题-原因-修改建议' 的格式逐条输出。"
    )

    def review_code(code_text):
    resp = requests.post(OLLAMA_URL, json={
    "model": MODEL,
    "temperature": 0.1, # 审查要严谨,温度更低
    "messages": [
    {"role": "system", "content": REVIEW_SYSTEM},
    {"role": "user", "content": "请审查下面这段代码:\\n\\n" + code_text}
    ]
    }, timeout=120)
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]

    if __name__ == "__main__":
    if len(sys.argv) < 2:
    print("用法:python code_review.py 文件路径")
    sys.exit(1)

    with open(sys.argv[1], "r", encoding="utf-8") as f:
    code = f.read()

    print("正在审查代码,请稍候…\\n")
    print(review_code(code))

    用法:

    python code_review.py D:\\project\\LoginAction.java

    这个思路可以套用到"解释代码、补全代码、生成单元测试、转写 ES5/jQuery"等任何场景,只要改 REVIEW_SYSTEM 里的系统提示词。

    7.7 Python 调用常见问题

    问题解决
    ModuleNotFoundError: requests 先 pip install requests
    中文乱码 文件头加 # -*- coding: utf-8 -*-,控制台用 UTF-8
    报连接错误 确认 Ollama 正在运行(ollama list 能出结果)
    首次很慢 模型首次加载需几十秒,属正常,第二次就快了

    八、实战二:Java 调用本地模型

    8.1 引入依赖(Maven)

    <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
    </dependency>

    8.2 完整代码:调用本地模型生成代码

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import okhttp3.*;

    import java.util.concurrent.TimeUnit;

    /**
    * Ollama 本地模型 Java 调用示例
    * 通过 OpenAI 兼容接口调用本地 qwen2.5-coder
    */

    public class OllamaClient {

    private static final String OLLAMA_URL = "http://localhost:11434/v1/chat/completions";
    private static final String MODEL = "qwen2.5-coder:7b";

    private final OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(120, TimeUnit.SECONDS)
    .build();

    private final ObjectMapper mapper = new ObjectMapper();

    /**
    * 发送对话请求
    * @param prompt 用户输入
    * @return 模型回复内容
    */

    public String chat(String prompt) throws Exception {
    // 构造请求体
    String requestBody = "{"
    + "\\"model\\":\\"" + MODEL + "\\","
    + "\\"temperature\\":0.2,"
    + "\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"" + prompt + "\\"}]"
    + "}";

    Request request = new Request.Builder()
    .url(OLLAMA_URL)
    .post(RequestBody.create(requestBody, MediaType.parse("application/json; charset=utf-8")))
    .build();

    try (Response response = client.newCall(request).execute()) {
    if (!response.isSuccessful()) {
    return "HTTP 错误: " + response.code();
    }
    // 解析返回 JSON
    JsonNode root = mapper.readTree(response.body().string());
    return root.path("choices").get(0).path("message").path("content").asText();
    }
    }

    public static void main(String[] args) throws Exception {
    OllamaClient ollama = new OllamaClient();
    String question = "用 Java 写一个单例模式,要求线程安全";
    System.out.println("你: " + question);
    System.out.println("\\nAI: ");
    System.out.println(ollama.chat(question));
    }
    }

    💡 注意:chat() 中直接拼 JSON 字符串仅为示例,生产环境请用 Jackson 的 ObjectMapper 构造对象序列化,避免特殊字符转义问题(防注入)。

    8.3 规范写法:用 Jackson 构造请求体(推荐生产使用)

    8.2 里用字符串拼接 JSON 只是为了演示。生产环境推荐用 Jackson 序列化,避免特殊字符转义问题(比如提示词里带了引号会导致 JSON 格式错误,甚至注入风险):

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import okhttp3.*;
    import java.util.*;
    import java.util.concurrent.TimeUnit;

    /**
    * 规范版:Jackson 构造请求体
    */

    public class OllamaClientV2 {

    private static final String OLLAMA_URL = "http://localhost:11434/v1/chat/completions";
    private static final String MODEL = "qwen2.5-coder:7b";

    private final OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(120, TimeUnit.SECONDS)
    .build();

    private final ObjectMapper mapper = new ObjectMapper();

    public String chat(String prompt, String systemPrompt) throws Exception {
    // 1. 用 Map + List 构造请求体
    Map<String, Object> message = new HashMap<>();
    message.put("role", "user");
    message.put("content", prompt);

    List<Object> messages = new ArrayList<>();
    if (systemPrompt != null && !systemPrompt.isEmpty()) {
    Map<String, Object> sys = new HashMap<>();
    sys.put("role", "system");
    sys.put("content", systemPrompt);
    messages.add(sys);
    }
    messages.add(message);

    Map<String, Object> body = new HashMap<>();
    body.put("model", MODEL);
    body.put("temperature", 0.2);
    body.put("messages", messages);

    // 2. Jackson 序列化成 JSON 字符串(自动处理转义)
    String jsonBody = mapper.writeValueAsString(body);

    Request request = new Request.Builder()
    .url(OLLAMA_URL)
    .post(RequestBody.create(jsonBody,
    MediaType.parse("application/json; charset=utf-8")))
    .build();

    try (Response response = client.newCall(request).execute()) {
    if (!response.isSuccessful()) {
    return "HTTP 错误: " + response.code() + " – " + response.body().string();
    }
    JsonNode root = mapper.readTree(response.body().string());
    return root.path("choices").get(0).path("message").path("content").asText();
    }
    }

    public static void main(String[] args) throws Exception {
    OllamaClientV2 ollama = new OllamaClientV2();
    String result = ollama.chat(
    "写一个带分页查询的 Spring Boot Controller",
    "你是一名资深 Java 后端工程师,给出完整可运行代码"
    );
    System.out.println(result);
    }
    }

    这样写的好处:不用手动处理引号、换行、特殊字符,Jackson 全部搞定,天然防注入。

    8.4 Java 多轮对话(记住上下文)

    import com.fasterxml.jackson.databind.*;
    import okhttp3.*;
    import java.util.*;
    import java.util.concurrent.TimeUnit;

    /**
    * 多轮对话:用 history 列表维护上下文
    */

    public class OllamaMultiTurn {

    private static final String OLLAMA_URL = "http://localhost:11434/v1/chat/completions";
    private static final String MODEL = "qwen2.5-coder:7b";

    private final OkHttpClient client = new OkHttpClient.Builder()
    .readTimeout(120, TimeUnit.SECONDS).build();
    private final ObjectMapper mapper = new ObjectMapper();

    // 对话历史
    private final List<Object> messages = new ArrayList<>();

    public OllamaMultiTurn(String systemPrompt) {
    if (systemPrompt != null && !systemPrompt.isEmpty()) {
    Map<String, Object> sys = new HashMap<>();
    sys.put("role", "system");
    sys.put("content", systemPrompt);
    messages.add(sys);
    }
    }

    public String chat(String userInput) throws Exception {
    // 把用户输入加入历史
    Map<String, Object> userMsg = new HashMap<>();
    userMsg.put("role", "user");
    userMsg.put("content", userInput);
    messages.add(userMsg);

    Map<String, Object> body = new HashMap<>();
    body.put("model", MODEL);
    body.put("messages", messages);

    String jsonBody = mapper.writeValueAsString(body);
    Request request = new Request.Builder()
    .url(OLLAMA_URL)
    .post(RequestBody.create(jsonBody,
    MediaType.parse("application/json; charset=utf-8")))
    .build();

    try (Response response = client.newCall(request).execute()) {
    JsonNode root = mapper.readTree(response.body().string());
    String reply = root.path("choices").get(0)
    .path("message").path("content").asText();

    // 把模型回复也加入历史
    Map<String, Object> asstMsg = new HashMap<>();
    asstMsg.put("role", "assistant");
    asstMsg.put("content", reply);
    messages.add(asstMsg);

    return reply;
    }
    }

    public static void main(String[] args) throws Exception {
    OllamaMultiTurn bot = new OllamaMultiTurn("你是一个资深 Java 工程师");
    System.out.println(bot.chat("什么是单例模式?"));
    System.out.println(bot.chat("给我一个线程安全的写法")); // 模型记得上一问
    }
    }

    8.5 Spring Boot 集成:把 Ollama 封装成服务

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.stereotype.Service;
    import okhttp3.*;

    import java.util.*;
    import java.util.concurrent.TimeUnit;

    @Service
    public class AiService {

    private static final String OLLAMA_URL = "http://localhost:11434/v1/chat/completions";
    private static final String MODEL = "qwen2.5-coder:7b";

    private final OkHttpClient client = new OkHttpClient.Builder()
    .readTimeout(120, TimeUnit.SECONDS)
    .build();

    private final ObjectMapper mapper = new ObjectMapper();

    /**
    * 对外提供的 AI 问答方法,Controller 直接调用
    */

    public String ask(String prompt, String systemPrompt) throws Exception {
    List<Object> messages = new ArrayList<>();
    if (systemPrompt != null && !systemPrompt.isEmpty()) {
    Map<String, Object> sys = new HashMap<>();
    sys.put("role", "system");
    sys.put("content", systemPrompt);
    messages.add(sys);
    }
    Map<String, Object> user = new HashMap<>();
    user.put("role", "user");
    user.put("content", prompt);
    messages.add(user);

    Map<String, Object> body = new HashMap<>();
    body.put("model", MODEL);
    body.put("temperature", 0.2);
    body.put("messages", messages);

    Request request = new Request.Builder()
    .url(OLLAMA_URL)
    .post(RequestBody.create(mapper.writeValueAsString(body),
    MediaType.parse("application/json; charset=utf-8")))
    .build();

    try (Response response = client.newCall(request).execute()) {
    if (!response.isSuccessful()) {
    throw new RuntimeException("Ollama 调用失败: " + response.code());
    }
    JsonNode root = mapper.readTree(response.body().string());
    return root.path("choices").get(0)
    .path("message").path("content").asText();
    }
    }
    }

    Controller 里这样用:

    @RestController
    public class AiController {

    @Autowired
    private AiService aiService;

    @PostMapping("/api/ai/ask")
    public Map<String, String> ask(@RequestBody Map<String, String> body) throws Exception {
    String answer = aiService.ask(
    body.get("prompt"),
    "你是一名资深后端工程师"
    );
    Map<String, String> result = new HashMap<>();
    result.put("answer", answer);
    return result;
    }
    }

    结合第十章的前端方案,Spring Boot 后端可以直接用这个 Service 当"代理",帮前端转发请求、解决跨域,还能做权限控制和日志记录。

    8.6 Java 调用常见问题

    问题解决
    找不到 okhttp3 类 确认 Maven 依赖已引入,并执行 mvn clean compile
    RequestBody.create 报错 检查 okhttp 版本(4.x 的 API 与 3.x 不同)
    中文乱码 请求头加 charset=utf-8,读响应用 response.body().string()(默认 UTF-8)
    JSON 解析失败 用 Jackson 构造请求体(见 8.3),别手拼字符串
    连接超时 把 readTimeout 调大到 120 秒以上

    九、实战三:接入 IDE,变身编程助手

    9.1 VSCode 接入 Continue 插件(推荐)

  • 打开 VSCode,左侧扩展栏搜索 Continue,点击安装
  • 安装后,配置模型 Provider 为 Ollama
  • 模型名填写 qwen2.5-coder:7b
  • 使用方式:
    • 选中代码 + Ctrl + I → 对话
    • 选中代码 + Ctrl + L → 打开对话框
    • 在代码中直接 Tab 触发补全
  • 效果:选中代码,右键"Explain",本地模型直接给你讲这段代码在干嘛;选中代码问"Refactor",帮你重构。

    9.2 IDEA 接入 Continue 插件

  • IDEA 插件市场搜索 Continue,安装并重启
  • 在 Continue 设置中选择 Ollama Provider,模型选 qwen2.5-coder:7b
  • 用法同上,支持对选中代码解释、改 bug、生成单测
  • 9.3 其他 IDE 插件

    IDE插件说明
    VSCode Continue / Cline 最主流,功能全
    IDEA Continue 支持 Java 场景
    通用 ollama 官方没有官方插件 都走 Continue 这类第三方

    9.4 Continue 的配置文件详解(进阶)

    Continue 装好后,它的配置文件在 VSCode 的 ~/.continue/config.json(或 config.yaml)。手写配置可以精确控制模型、温度、自定义命令等:

    {
    "models": [
    {
    "title": "qwen2.5-coder (本地)",
    "provider": "ollama",
    "model": "qwen2.5-coder:7b",
    "apiBase": "http://localhost:11434"
    }
    ],
    "customCommands": [
    {
    "name": "review",
    "prompt": "以资深工程师视角审查选中代码,找出 bug、安全隐患和优化点,用中文输出。",
    "description": "代码审查"
    },
    {
    "name": "explain",
    "prompt": "用通俗易懂的中文解释选中代码的作用和逻辑。",
    "description": "解释代码"
    },
    {
    "name": "unit-test",
    "prompt": "为选中代码生成完整的单元测试。",
    "description": "生成单测"
    }
    ]
    }

    自定义命令怎么用? 配置好 customCommands 后,按 Ctrl + I 打开对话框,输入 /review、/explain、/unit-test,就会自动套用对应的提示词,非常方便。

    9.5 Cline 插件接入(另一个选择)

    Cline 是另一个热门的 AI 编程插件,比 Continue 更"重",会自动读取项目文件树、能自己执行终端命令(适合让它做"自动改代码"),但更耗资源:

  • VSCode 扩展搜索 Cline,安装
  • 打开 Cline 设置 → 模型提供商选 Ollama
  • 填写模型 qwen2.5-coder:7b 和地址 http://localhost:11434
  • 使用时在输入框描述需求,Cline 会自动读取相关文件、生成修改建议
  • ⚠️ Cline 的"自动执行命令"功能建议先关闭,等熟悉了再开,避免它在你的项目里乱动文件。

    9.6 前端开发者的 IDE 高频用法

    针对前端场景(Vue2 / jQuery / ES5),这几个用法最实用:

    场景操作效果
    生成 Vue 组件 描述需求 + Ctrl+I 直接生成组件代码
    改 ES5/jQuery 老代码 选中代码,问"改成 ES5 兼容写法" 自动转写,兼容 IE
    写表单校验 描述字段 + 问"生成 Vant 校验规则" 生成 rules
    解释 JSP/JSTL 代码 选中问"这段在干嘛" 中文解释逻辑
    修复兼容 bug 报错信息 + 选中代码,问"怎么修" 定位并修复
    生成接口 mock 描述接口,问"生成 mock 数据" 生成假数据

    9.7 性能与内存注意事项(16G 机器)

  • 一次只跑一个模型:ollama ps 查看,没用的用 ollama stop 停掉,避免多个模型挤爆内存
  • IDE 插件别开太多模型:Continue 里只配一个 7B 模型即可
  • 补全模式会持续占用资源:不想用补全时,在 Continue 设置里关掉 autocomplete
  • 内存不足表现:模型生成明显变慢、卡顿、甚至报 OOM——这时候换 3B 模型或关掉其他大程序
  • 9.8 其他可选的 IDE 插件

    IDE插件特点
    VSCode Continue 轻量、可配置、推荐
    VSCode Cline 能自动读项目文件、自动改代码
    IDEA Continue 支持 Java 场景
    所有 IDE Tabby(需另装服务) 类似 GitHub Copilot 的本地补全服务

    十、实战四:前端项目调用本地模型(Vue / jQuery / 原生 JS)

    前端能不能也直接调用 Ollama?当然能。而且对你这种经常做后台管理系统、H5 商城、旧 JSP 项目的开发者来说,把本地模型接到页面上,就是给你的系统加一个"内置 AI 助手"。

    10.1 前端场景能做什么?

    场景具体用途
    后台"AI 助手"面板 管理员在页面里直接提问,生成 SQL、Excel 公式
    表单校验生成 输入字段描述,自动生成 Vant / jQuery 校验规则
    正则 / JSON 工具 一键生成正则、格式化 JSON、转义字符串
    代码补全 在线代码编辑框里根据注释生成代码
    Mock 数据生成 输入字段名,自动生成接口假数据
    报表解释 把统计数据丢给模型,让它写总结

    10.2 第一个大坑:浏览器跨域(CORS)

    前端页面直接 fetch('http://localhost:11434/v1/chat/completions') 会报错:

    Access to fetch at '…' from origin 'http://localhost:8080' has been blocked by CORS policy

    原因:Ollama 默认不信任浏览器来源。两种解决方式,本地开发用第一种,生产用第二种:

    方式一:给 Ollama 放开跨域(仅限本机调试)

    新建环境变量:

    变量名:OLLAMA_ORIGINS
    变量值:*

    然后重启 Ollama。* 表示允许所有来源访问(只在自己电脑上这么玩,安全没问题)。

    方式二:后端代理转发(推荐,最稳)

    前端请求自己的后端接口,由后端转发到 localhost:11434,彻底绕开跨域。代码见 10.6 节。

    10.3 方案A:原生 JS + fetch(ES6,现代浏览器)

    // 配置
    const OLLAMA_URL = 'http://localhost:11434/v1/chat/completions';
    const MODEL = 'qwen2.5-coder:7b';

    /**
    * 调用本地模型
    * @param {string} prompt 用户提问
    * @param {string} system 系统提示词(可选)
    * @returns {Promise<string>} 模型回复
    */

    async function ollamaChat(prompt, system = '') {
    const messages = [];
    if (system) messages.push({ role: 'system', content: system });
    messages.push({ role: 'user', content: prompt });

    const resp = await fetch(OLLAMA_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
    model: MODEL,
    temperature: 0.2,
    messages: messages
    })
    });

    if (!resp.ok) throw new Error('HTTP ' + resp.status);
    const data = await resp.json();
    return data.choices[0].message.content;
    }

    // 使用示例
    ollamaChat('用 Vue2 写一个带搜索的表格,要求 ES5 语法')
    .then(text => console.log(text))
    .catch(err => console.error(err));

    10.4 方案B:jQuery + ES5(兼容 IE,老项目适用)

    考虑到很多老项目(JSP + jQuery)还在兼容 IE,这里给一个完全 ES5 语法、无箭头函数、无 Promise 的版本,直接复制就能用:

    /**
    * 老项目 jQuery + ES5 版本地模型调用
    * 依赖:jQuery 1.x+
    */

    var OLLAMA_URL = 'http://localhost:11434/v1/chat/completions';
    var MODEL = 'qwen2.5-coder:7b';

    /**
    * 调用本地模型
    * @param {String} prompt 提问内容
    * @param {Function} callback 回调 function(err, result)
    */

    function ollamaChat(prompt, callback) {
    var requestBody = {
    model: MODEL,
    temperature: 0.2,
    messages: [{ role: 'user', content: prompt }]
    };

    $.ajax({
    url: OLLAMA_URL,
    type: 'POST',
    dataType: 'json',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(requestBody),
    timeout: 120000, // 模型生成可能慢,超时给长一点
    success: function (data) {
    var content = '';
    if (data && data.choices && data.choices.length > 0) {
    content = data.choices[0].message.content;
    }
    callback(null, content);
    },
    error: function (xhr, status, err) {
    callback(err || status || '未知错误');
    }
    });
    }

    // ===== 页面使用示例 =====
    // HTML: <input id="prompt"> <button id="btn">生成</button> <pre id="result"></pre>
    $(function () {
    $('#btn').on('click', function () {
    var prompt = $('#prompt').val();
    if (!prompt) { alert('请输入问题'); return; }

    $('#result').text('AI 生成中,请稍候…');
    ollamaChat(prompt, function (err, result) {
    if (err) {
    $('#result').text('调用失败:' + err);
    return;
    }
    $('#result').text(result);
    });
    });
    });

    关键点:timeout 一定要给足(本地模型生成一段代码可能要 10~60 秒),否则 jQuery 会提前报 timeout 错误。

    10.5 方案C:Vue2 + Vant 工程化接入

    在 Vue2 + Vant 项目里做一个"AI 生成"组件,用 Vant 的 Field、Button、Toast 做交互:

    <template>
    <div class="ai-panel">
    <van-field
    v-model="prompt"
    type="textarea"
    rows="3"
    maxlength="200"
    show-word-limit
    placeholder="描述你想生成的代码,例如:写一个表单校验规则"
    />
    <van-button
    type="primary"
    block
    :loading="loading"
    loading-text="AI 生成中…"
    @click="handleGenerate"
    >
    生成
    </van-button>
    <pre v-if="result" class="ai-result">{{ result }}</pre>
    </div>
    </template>

    <script>
    // Vue2 选项式写法,兼容低版本工程
    export default {
    name: 'AiGenerator',
    data: function () {
    return {
    prompt: '',
    result: '',
    loading: false
    };
    },
    methods: {
    handleGenerate: function () {
    var self = this;
    if (!self.prompt.trim()) {
    self.$toast('请输入描述');
    return;
    }
    self.loading = true;
    self.result = '';

    // 走项目封装好的 request(内部转发到后端代理,避免跨域)
    self.$http
    .post('/api/ai/generate', { prompt: self.prompt })
    .then(function (res) {
    self.result = res.data.content;
    self.loading = false;
    })
    .catch(function () {
    self.loading = false;
    self.$toast('调用失败');
    });
    }
    }
    };
    </script>

    <style scoped>
    .ai-panel { padding: 16px; }
    .ai-result {
    margin-top: 12px;
    padding: 12px;
    background: #f7f8fa;
    border-radius: 8px;
    white-space: pre-wrap;
    word-break: break-all;
    font-size: 13px;
    line-height: 1.6;
    }
    </style>

    10.6 后端代理解决跨域(Java / Node 二选一)

    方式一:Java(Spring Boot / Servlet)转发

    /**
    * AI 代理接口:前端调本接口,后端转发到本地 Ollama
    * 路径:POST /api/ai/generate
    */

    @RestController
    @RequestMapping("/api/ai")
    public class AiProxyController {

    private static final String OLLAMA_URL =
    "http://localhost:11434/v1/chat/completions";
    private static final String MODEL = "qwen2.5-coder:7b";

    @PostMapping("/generate")
    public Map<String, Object> generate(@RequestBody Map<String, String> body) {
    String prompt = body.get("prompt");
    // 组装请求体(生产环境用 Jackson ObjectMapper 序列化更规范)
    String requestBody = "{\\"model\\":\\"" + MODEL + "\\","
    + "\\"temperature\\":0.2,"
    + "\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\""
    + prompt.replace("\\"", "\\\\\\"") + "\\"}]}";

    // 用 HttpURLConnection 或 OkHttp 转发请求…
    // 这里省略 HTTP 发送细节,核心是:后端转发 + 返回 choices[0].message.content
    Map<String, Object> result = new HashMap<>();
    result.put("content", sendToOllama(requestBody));
    return result;
    }

    private String sendToOllama(String jsonBody) {
    // 建议用 OkHttp(参考第八节),此处省略
    return "";
    }
    }

    方式二:Node(Express)代理

    const express = require('express');
    const app = express();
    app.use(express.json());

    const OLLAMA_URL = 'http://localhost:11434/v1/chat/completions';

    app.post('/api/ai/generate', async (req, res) => {
    const { prompt } = req.body;
    const resp = await fetch(OLLAMA_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
    model: 'qwen2.5-coder:7b',
    messages: [{ role: 'user', content: prompt }]
    })
    });
    const data = await resp.json();
    res.json({ content: data.choices[0].message.content });
    });

    app.listen(8080);

    10.7 前端实战场景提示词清单

    场景推荐提示词模板
    生成表单校验 “用 jQuery + ES5 写手机号、邮箱、身份证的正则校验”
    生成 Vue 组件 “用 Vue2 写一个带分页的表格组件,使用 Vant 组件库”
    生成 SQL “根据表字段 id,name,price,stock 生成插入语句和查询语句”
    生成正则 “写一个匹配 13/15/18 开头、11 位手机号的正则”
    解释旧代码 “解释这段 JSP + JSTL 代码的逻辑(粘贴代码)”
    生成 mock “生成 5 条商品列表 mock 数据,字段含 name,price,img”

    提示词技巧:描述越具体,模型输出越准确。把"上下文"(项目技术栈、字段名、已有代码片段)一起贴进去,效果翻倍。

    10.8 前端流式输出:边生成边显示(打字机效果)

    一次性等完整响应在代码较长时会等很久,体验差。用流式输出可以让用户"看着"内容一点点出来。现代浏览器用 fetch 的 ReadableStream 即可,无需额外依赖:

    /**
    * 流式调用本地模型,边生成边回调
    * @param {string} prompt
    * @param {(text: string) => void} onChunk 每收到一段内容就回调
    * @param {() => void} onDone 完成回调
    */

    async function ollamaStream(prompt, onChunk, onDone) {
    const resp = await fetch('http://localhost:11434/v1/chat/completions', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
    model: 'qwen2.5-coder:7b',
    stream: true, // 关键:开启流式
    messages: [{ role: 'user', content: prompt }]
    })
    });

    const reader = resp.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let buffer = '';

    while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    // 按行解析 SSE 格式:每行以 data: 开头,内容是一段 JSON
    const lines = buffer.split('\\n');
    buffer = lines.pop(); // 最后一行可能不完整,留到下次

    for (const line of lines) {
    const trimmed = line.trim();
    if (!trimmed.startsWith('data:')) continue;
    const dataStr = trimmed.slice(5).trim();
    if (dataStr === '[DONE]') continue;

    try {
    const data = JSON.parse(dataStr);
    const delta = data.choices?.[0]?.delta?.content;
    if (delta) onChunk(delta);
    } catch (e) {
    // 忽略解析失败的不完整行
    }
    }
    }
    onDone();
    }

    // 使用示例
    const outputEl = document.getElementById('output');
    ollamaStream(
    '用 Vue2 写一个商品列表组件',
    (text) => { outputEl.textContent += text; }, // 逐字追加
    () => { console.log('生成完成'); }
    );

    流式格式说明:Ollama 按 data: {json} 逐行返回,每行的 JSON 里的 choices[0].delta.content 就是新生成的一小段文字。最后一行是 data: [DONE] 表示结束。

    10.9 完整成品页面:一个可直接打开的"AI 代码生成器" HTML

    下面是一整个可直接保存为 .html 打开运行的成品页面(含样式、流式输出),适合直接演示或改造:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>本地 AI 代码生成器(Ollama)</title>
    <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: "Microsoft YaHei", sans-serif; background: #f5f6fa; }
    .container { max-width: 800px; margin: 30px auto; padding: 0 16px; }
    h1 { text-align: center; font-size: 22px; margin-bottom: 6px; }
    .sub { text-align: center; color: #999; font-size: 13px; margin-bottom: 20px; }
    textarea {
    width: 100%; height: 90px; padding: 12px; font-size: 14px;
    border: 1px solid #ddd; border-radius: 8px; resize: vertical;
    font-family: inherit;
    }
    button {
    width: 100%; margin-top: 10px; padding: 12px; font-size: 15px;
    background: #4a6cf7; color: #fff; border: none; border-radius: 8px;
    cursor: pointer;
    }
    button:disabled { background: #a8b4d8; cursor: not-allowed; }
    .output-box {
    margin-top: 16px; padding: 14px; background: #1e1e2e; color: #cdd6f4;
    border-radius: 8px; min-height: 200px; max-height: 500px; overflow: auto;
    font-family: Consolas, monospace; font-size: 13px; line-height: 1.6;
    white-space: pre-wrap; word-break: break-all;
    }
    .tip { margin-top: 12px; font-size: 12px; color: #999; text-align: center; }
    </style>
    </head>
    <body>
    <div class="container">
    <h1>本地 AI 代码生成器</h1>
    <p class="sub">由 Ollama + qwen2.5-coder 驱动,数据不出本机</p>

    <textarea id="prompt" placeholder="描述你想生成的代码,例如:用 Java 写一个线程安全的单例模式…"></textarea>
    <button id="btn" onclick="generate()">生 成</button>

    <div class="output-box" id="output">等待输入…</div>
    <p class="tip">提示:首次生成较慢属正常,请耐心等待</p>
    </div>

    <script>
    // ====== 配置(本地调试建议先设置环境变量 OLLAMA_ORIGINS=*)======
    var OLLAMA_URL = 'http://localhost:11434/v1/chat/completions';
    var MODEL = 'qwen2.5-coder:7b';

    var btn = document.getElementById('btn');
    var output = document.getElementById('output');

    async function generate() {
    var prompt = document.getElementById('prompt').value.trim();
    if (!prompt) { alert('请输入需求'); return; }

    btn.disabled = true;
    btn.textContent = '生成中…';
    output.textContent = '';

    // 流式输出
    await ollamaStream(prompt, function (text) {
    output.textContent += text;
    output.scrollTop = output.scrollHeight;
    });

    btn.disabled = false;
    btn.textContent = '生 成';
    }

    async function ollamaStream(prompt, onChunk) {
    var resp = await fetch(OLLAMA_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
    model: MODEL,
    stream: true,
    temperature: 0.2,
    messages: [{ role: 'user', content: prompt }]
    })
    });

    var reader = resp.body.getReader();
    var decoder = new TextDecoder('utf-8');
    var buffer = '';

    while (true) {
    var r = await reader.read();
    if (r.done) break;
    buffer += decoder.decode(r.value, { stream: true });
    var lines = buffer.split('\\n');
    buffer = lines.pop();

    for (var i = 0; i < lines.length; i++) {
    var line = lines[i].trim();
    if (line.indexOf('data:') !== 0) continue;
    var dataStr = line.slice(5).trim();
    if (dataStr === '[DONE]') continue;
    try {
    var data = JSON.parse(dataStr);
    var delta = data.choices && data.choices[0] && data.choices[0].delta && data.choices[0].delta.content;
    if (delta) onChunk(delta);
    } catch (e) { /* 忽略不完整行 */ }
    }
    }
    }
    </script>
    </body>
    </html>

    使用前提醒:浏览器直连本地 Ollama 会有跨域限制,本地测试请先设置环境变量 OLLAMA_ORIGINS=* 并重启 Ollama;正式项目走后端代理(见 10.6 节)。

    10.10 前端体验优化要点

  • 加载状态:生成期间禁用按钮、显示 loading(Vant 用 loading 属性,jQuery 用 disabled + 文案)
  • 防重复点击:生成中把按钮 disabled,防止并发请求挤爆内存
  • 超时处理:给请求设 timeout(如 120 秒),并提示"生成时间较长,请稍候"
  • 历史记录:像聊天助手一样维护 messages 数组,支持多轮追问(参考 7.4 的思路)
  • 错误提示:捕获异常后给用户友好提示(模型没下载、服务没启动、跨域等),不要白屏
  • 流式优先:长代码建议用 10.8 的流式方案,体验好很多
  • 10.11 移动端 H5 适配提示

    如果要在 H5(手机上)调用,注意几点:

  • 后端代理是必须的:手机浏览器跨域更严格,一定走后端代理(10.6 节)
  • 超时放宽:手机网络下生成更慢,timeout 建议 180 秒以上
  • 接口封装:前端统一走 /api/ai/xxx,不要在前端暴露 localhost:11434
  • iOS/Android 差异:流式解析用标准 fetch + ReadableStream 两端都兼容;老 iOS 需要 polyfill 或降级为非流式
  • 弱网降级:检测到请求失败时,自动降级为非流式完整请求,保证功能可用

  • 十一、模型推荐与选型指南

    11.1 面向代码开发

    模型参数量显存/内存要求特点推荐度
    qwen2.5-coder:3b 3B 8GB 轻量快,适合低配机补全 ⭐⭐⭐
    qwen2.5-coder:7b 7B 16GB 代码生成质量好,性价比王 ⭐⭐⭐⭐⭐
    qwen2.5-coder:14b 14B 32GB 更强,适合复杂任务 ⭐⭐⭐⭐
    deepseek-coder-v2:16b 16B 32GB DeepSeek 代码模型 ⭐⭐⭐

    11.2 面向通用对话

    模型说明
    qwen2.5:7b 通用对话、翻译、总结
    llama3.1:8b Meta 开源,英文能力强
    gemma2:9b Google 出品,轻量均衡

    11.3 选型口诀

    • 16GB 内存 → 首选 qwen2.5-coder:7b
    • 8GB 内存 → 用 qwen2.5-coder:3b
    • 32GB+ 内存 → 直接上 14b 甚至 32b
    • 代码为主 → coder 系列;综合使用 → 通用系列

    十二、常见问题与避坑指南

    12.1 命令找不到 / 报错

    现象原因解决
    ollama 不是内部或外部命令 环境变量未生效 重开 CMD 或注销重登
    下载速度慢 网络问题 配置国内镜像源(见下)
    7B 模型跑起来很卡 内存不足 换 3B 模型,关掉其他大程序
    API 调用超时 模型首次加载慢 首次调用等久点,或先 ollama run 预热
    端口被占用 11434 被占用 设置 OLLAMA_HOST=127.0.0.1:新端口

    12.2 国内镜像加速(下载慢的救星)

    新建环境变量:

    变量名:OLLAMA_HOST
    变量值:你的镜像地址

    (镜像地址需根据你实际网络环境选择可访问的源,这里不展开推荐,避免失效误导。)

    12.3 模型存储位置修改

    参考本文 3.4 节,设置 OLLAMA_MODELS 环境变量指向非系统盘,防止 C 盘爆满。

    12.4 后台常驻 / 开机自启

    Ollama 安装后默认开机自启并在后台运行,如需手动控制:

    # 停止服务
    taskkill /f /im ollama.exe
    # 重新启动
    ollama serve


    十三、总结

    通过本文,你已经可以:

    ✅ 在本地安装 Ollama,一键拉取代码大模型 ✅ 用命令行跟模型对话,生成、解释、修复代码 ✅ 通过 OpenAI 兼容 API,用 Python / Java 调用本地模型 ✅ 把 VSCode / IDEA 变成你的"离线编程助手" ✅ 根据自己的硬件配置选择合适的模型

    Ollama 的价值在于:它是你通往"本地 AI 开发"的入口——数据隐私安全、零成本、离线可用、可编程集成。无论你是前端转后端的学习者,还是日常需要大量写代码的开发者,装一个在本地,相当于随身带了一个不联网、不花钱、还懂代码的"私教"。

    下一步你可以尝试的方向:

    • 用本地模型 + LangChain 搭建 RAG 知识库问答
    • 用 ollama run + 你自己的项目代码,训练"项目专属问答"
    • 把它接入 CI 流程做代码评审

    如果本文对你有帮助,欢迎点赞收藏,有问题评论区交流,一起玩转本地 AI!


    本文基于 Ollama 0.5.x 版本编写,模型推荐基于公开基准与社区反馈,实际体验请以你的硬件环境为准。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Ollama 从入门到实战:本地部署代码大模型,零成本打造你的私人编程助手
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!