目录
- 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 用户)
方式二:命令行安装(适合习惯终端的朋友)
在 PowerShell 或 CMD 中执行:
curl -fsSL https://ollama.com/install.sh | sh
# Windows
irm https://ollama.com/install.ps1 | iex
方式三:镜像地址
3.3 验证是否安装成功
按 Win + R 打开运行框,输入 cmd 回车,在命令行中输入:
ollama –version
看到类似输出即成功:
ollama version 0.5.7
如果提示"不是内部或外部命令",重开一个 CMD 窗口再试,或者注销重新登录一次(让环境变量生效)。
怎么注销重新登录(Windows)
方法一:开始菜单(最常用)
方法二:快捷键
方法三:命令行注销
在 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(改成你自己的盘)
四、模型下载与管理
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 一模一样。
这带来的好处巨大:
比喻:就像手机充电口统一成 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 测试(图形化,看得见摸得着)
{
"model": "qwen2.5-coder:7b",
"messages": [
{"role": "user", "content": "用Java写Hello World"}
]
}
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))
核心思路(重要):
⚠️ 注意:历史越长,每次请求越慢、越占内存。实际开发建议只保留最近 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 插件(推荐)
- 选中代码 + Ctrl + I → 对话
- 选中代码 + Ctrl + L → 打开对话框
- 在代码中直接 Tab 触发补全
效果:选中代码,右键"Explain",本地模型直接给你讲这段代码在干嘛;选中代码问"Refactor",帮你重构。
9.2 IDEA 接入 Continue 插件
9.3 其他 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 更"重",会自动读取项目文件树、能自己执行终端命令(适合让它做"自动改代码"),但更耗资源:
⚠️ Cline 的"自动执行命令"功能建议先关闭,等熟悉了再开,避免它在你的项目里乱动文件。
9.6 前端开发者的 IDE 高频用法
针对前端场景(Vue2 / jQuery / ES5),这几个用法最实用:
| 生成 Vue 组件 | 描述需求 + Ctrl+I | 直接生成组件代码 |
| 改 ES5/jQuery 老代码 | 选中代码,问"改成 ES5 兼容写法" | 自动转写,兼容 IE |
| 写表单校验 | 描述字段 + 问"生成 Vant 校验规则" | 生成 rules |
| 解释 JSP/JSTL 代码 | 选中问"这段在干嘛" | 中文解释逻辑 |
| 修复兼容 bug | 报错信息 + 选中代码,问"怎么修" | 定位并修复 |
| 生成接口 mock | 描述接口,问"生成 mock 数据" | 生成假数据 |
9.7 性能与内存注意事项(16G 机器)
9.8 其他可选的 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 前端体验优化要点
10.11 移动端 H5 适配提示
如果要在 H5(手机上)调用,注意几点:
十一、模型推荐与选型指南
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 版本编写,模型推荐基于公开基准与社区反馈,实际体验请以你的硬件环境为准。
网硕互联帮助中心




评论前必须登录!
注册