mbp pro
1.1 跨平台安装指南
Ollama 作为本地运行大模型的利器,支持三大主流操作系统:
#macOS一键安装
#Windows用户
访问官网https://ollama.com/download下载安装包
#Linux安装(Ubuntu/Debian为例)
curl-fsSLhttps://ollama.com/install.sh|sudobash
sudousermod-aGollama$USER#添加用户权限
sudosystemctlstartollama#启动服务
1.2 服务验证
ollama-v
#输出ollamaversionis0.5.7以 deepseek r1 模型为例:
访问https://ollama.com/library/deepseek-r1,默认为 7b 模型,如需其他模型,可以在当前页搜索所需模型
模型详情页复制安装命令ollama run deepseek-r1
安装完成后在终端执行:
ollamarundeepseek-r1
#执行后
pullingmanifest
pulling96c415656d37...100%▕██████████████▏4.7GB
pulling369ca498f347...100%▕██████████████▏387B
pulling6e4c38e1172f...100%▕██████████████▏1.1KB
pullingf4d24e9138dd...100%▕██████████████▏148B
pulling40fb844194b2...100%▕██████████████▏487B
verifyingsha256digest
writingmanifest
success
>>>Sendamessage(/?forhelp)
>>>`
>>>当看到上述提示,即可开始模型对话。
mac 后台标识
win 后台标识
见任务栏托盘区
运行交互式对话测试:
请用Python写一个快速排序算法
当看到完整代码输出,说明模型已成功加载。
硬件要求建议:
最低配置:16GB 内存 + 8GB 显存
推荐配置:32GB 内存 + 16GB 显存(RTX 3060 级别)
下载地址chatboxai.app
配置本地模型
进入设置页面
选择 ollama api (本地部署)
配置本机地址,默认http://127.0.0.1:11434
至此即可开启问答模式
3.2 Page Assist 浏览器插件
安装地址Page Assist - 本地 AI 模型的 Web UI
安装后简单配置即可开启问答模式,功能丰富,可以参考官方引导
本插件支持本地知识库建设,因本次使用 Dify 建设,在此不赘述。
参考文档地址Docker Compose 部署
1.拉取源代码,准备环境
#macos
#克隆 Dify 源代码至本地环境。
gitclonehttps://github.com/langgenius/dify.git
#进入Dify源代码的Docker目录
cddify/docker
#复制环境配置文件cp.env.example.env
2.启动 Docker 容器(需要先安装 D ocker)
dockercomposeup-d
#如果版本是 Docker Compose V1,使用以下命令:
docker-composeup-d
#正常返回
[+]Running74/9
✔dbPulled834.2s
✔sandboxPulled1120.7s
✔weaviatePulled526.5s
✔webPulled174.0s
✔redisPulled893.7s
✔apiPulled2919.8s
✔workerPulled2919.8s
✔ssrf_proxyPulled494.0s
✔nginxPulled184.7s
[+]Running11/11
✔Networkdocker_defaultCreated0.0s
✔Networkdocker_ssrf_proxy_networkCreated0.0s
✔Containerdocker-db-1Started1.1s
✔Containerdocker-web-1Started1.1s
✔Containerdocker-redis-1Started1.1s
✔Containerdocker-sandbox-1Started1.1s
✔Containerdocker-weaviate-1Started1.1s
✔Containerdocker-ssrf_proxy-1Started1.1s
✔Containerdocker-api-1Started0.7s
✔Containerdocker-worker-1Started0.7s
✔Containerdocker-nginx-1Started0.8s
在此阶段可能会遇到下列失败的情况,可以尝试切换源解决 我当时的条件
修改配置后重启 docker
dockercomposeup-d
[+]Running9/9
✘webErrorcontextcanceled14.9s
✘redisErrorcontextcanceled14.9s
✘dbErrorcontextcanceled14.9s
✘nginxErrorcontextcanceled14.9s
✘ssrf_proxyErrorcontextcanceled14.9s
✘sandboxErrorHead"https://registry-1.do...14.9s
✘apiErrorcontextcanceled14.9s
✘workerErrorcontextcanceled14.9s
✘weaviateErrorcontextcanceled14.9s
Errorresponsefromdaemon:Head"https://registry-1.docker.io/v2/langgenius/dify-sandbox/manifests/0.2.10":Get"https://auth.docker.io/token?scope=repository%3Alanggenius%2Fdify-sandbox%3Apull&service=registry.docker.io":EOF
解决方法
右上角齿轮图标进入设置 -> Docker engine,在配置中添加
写入以下内容 ocker)
{
//...
"registry-mirrors":[
"https://docker.hpcloud.cloud",
"https://docker.m.daocloud.io",
"https://docker.unsee.tech",
"https://docker.1panel.live",
"http://mirrors.ustc.edu.cn",
"https://docker.chenby.cn",
"http://mirror.azure.cn",
"https://dockerpull.org",
"https://dockerhub.icu",
"https://hub.rat.dev"
]}
访问http://localhost/(默认 80 端口) 进入 dify
首次进入初始化设置账号密码
点击 Dify 平台右上角头像 → 设置 → 模型供应商,选择 Ollama,轻点“添加模型”。
在配置 url 时,因为是 docker 服务,http://localhost:11434 存在无法访问的情况,可以尝试http://host.docker.internal:11434
4.至此,可以开始创建应用,在主页选择 全部 -> 创建空白应用 -> 填入应用信息即可
主页选择 知识库 -> 创建知识库 -> 上传知识 -> 等待处理完成
进入聊天应用,选择刚才创建的知识库,即可开始带有私域知识的沟通
1.本地客户端具有部分国际化测试文件需要执行翻译,格式示例如下,多层嵌套的 json 格式,value 为string类型。需要利用大模型对整个 json 文件进行翻译,将中文翻译为英文后按原格式返回
//zh.json
{
"window":{
"willUnload":{
"title":"确认刷新当前页面吗?",
"message":"系统可能不会保存您做的更改",
"unload_bt":"重新加载",
"cancel_bt":"取消"
}
}
}
ocker)
2.实际应用测试,以deepseek-r1:7b/14b模型做测试。得到结果如下
3.执行脚本trans.js
constfs=require("fs");
constaxios=require("axios");
//1.读取本地JSON文件
constreadJsonFile=(filePath)=>{
returnnewPromise((resolve,reject)=>{
fs.readFile(filePath,"utf8",(err,data)=>{
if(err){
reject(err);
}else{
resolve(JSON.parse(data));
}
});
});
};
constMODEL="deepseek-r1:14b";
//2.调用本地大模型接口进行翻译
consttranslateText=async(text,key)=>{
letresponse;
try{
console.time(`runworker${key}`);
response=awaitaxios.post("http://localhost:11434/api/generate",{
//model:'deepseek-r1:7b',
model:MODEL,
prompt:`有部分客户端国际化的配置文件,内容为json格式,需要翻译,要求按步骤进行翻译:
1.将中文翻译为英文
2.保持原有json格式不变,将value替换成翻译后的文本
3.你始终以合法的JSON格式响应,返回结果格式如:{"key1":"翻译后的文本1","key2":"翻译后的文本2"},直接返回结果,不需要符号包裹
配置文件
"""${JSON.stringify(text)}"""`,
stream:false,
});
console.timeEnd(`runworker${key}`);
constsplitText="</think>";
conststartIndex=response.data.response.indexOf(splitText);
constresult=response.data.response
.slice(startIndex+splitText.length)
.trim()
.replace(/<<+|>>+/g,"");
//console.log('response.data.response:',response.data.response,JSON.parse(result),result)
returnJSON.parse(result);//假设接口返回的翻译结果在response.data.translatedText中
}catch(error){
console.error("翻译出错:",key);
returntranslateText(text,key);//如果翻译失败,返回原文
}
};
//3.并行翻译逻辑(手动控制并发)
consttranslateJson=async(jsonData,concurrency=5)=>{
constentries=Object.entries(jsonData);
consttranslatedData={};
letcurrentIndex=0;//当前处理的任务索引
//定义工作线程:每个线程不断处理下一个任务
constworker=async()=>{
while(currentIndex<entries.length){
constindex=currentIndex++;
if(index>=entries.length)break;//所有任务已完成
const[key,value]=entries[index];
try{
translatedData[key]=awaittranslateText(value,key);
}catch(error){
translatedData[key]=value;//保留原文
}
}
};
//启动指定数量的工作线程
constworkers=Array(concurrency).fill(null).map(worker);
awaitPromise.all(workers);//等待所有线程完成
constresult={};
//保持原有顺序
entries.forEach(([key,value])=>{
result[key]=translatedData[key]||value;
});
returnresult;
};
//4.将翻译后的内容生成新的文件
constwriteTranslatedJson=(filePath,data)=>{
returnnewPromise((resolve,reject)=>{
fs.writeFile(filePath,JSON.stringify(data,null,2),"utf8",(err)=>{
if(err){
reject(err);
}else{
resolve();
}
});
});
};
functioncompareObjectsWithPath(obj1,obj2,path=""){
//类型不同时直接返回路径
if(typeofobj1!==typeofobj2){
return{success:false,path:path||"root"};
}
//处理可遍历对象(对象或数组)
if(typeofobj1==="object"&&obj1!==null&&obj2!==null){
constisArr1=Array.isArray(obj1);
constisArr2=Array.isArray(obj2);
//数组类型不一致
if(isArr1!==isArr2){
return{success:false,path:path||"root"};
}
if(isArr1){
//数组长度不同
if(obj1.length!==obj2.length){
return{success:false,path:path||"root"};
}
//递归检查数组元素
for(leti=0;i<obj1.length;i++){
constcurrentPath=`${path}[${i}]`;
constresult=compareObjectsWithPath(obj1[i],obj2[i],currentPath);
if(!result.success)returnresult;
}
return{success:true};
}else{
//检查是否为纯对象(字面量对象)
constisPlainObj1=isPlainObject(obj1);
constisPlainObj2=isPlainObject(obj2);
if(isPlainObj1!==isPlainObj2){
return{success:false,path:path||"root"};
}
//非纯对象(如Date、RegExp)需检查是否均为字符串
if(!isPlainObj1){
returntypeofobj1==="string"&&typeofobj2==="string"
?{success:true}
:{success:false,path:path||"root"};
}
//合并所有key并检查数量
constkeys1=Object.keys(obj1);
constkeys2=Object.keys(obj2);
constallKeys=newSet([...keys1,...keys2]);
if(allKeys.size!==keys1.length||allKeys.size!==keys2.length){
return{success:false,path:path||"root"};
}
//递归检查每个属性
for(constkeyofallKeys){
constcurrentPath=path?`${path}.${key}`:key;
if(!keys1.includes(key)||!keys2.includes(key)){
return{success:false,path:currentPath};
}
constresult=compareObjectsWithPath(
obj1[key],
obj2[key],
currentPath
);
if(!result.success)returnresult;
}
return{success:true};
}
}else{
//基本类型:检查是否均为字符串
returntypeofobj1==="string"&&typeofobj2==="string"
?{success:true}
:{success:false,path:path||"root"};
}
}
//判断是否为纯对象(字面量对象)
functionisPlainObject(value){
returnObject.prototype.toString.call(value)==="[objectObject]";
}
//主函数
constmain=async()=>{
console.time("runmain");
constinputFilePath="./locales/zh.json";//输入的JSON文件路径
constoutputFilePath=`output_${MODEL}.json`;//输出的JSON文件路径
try{
//读取JSON文件
constjsonData=awaitreadJsonFile(inputFilePath);
//翻译JSON内容
consttranslatedData=awaittranslateJson(jsonData);
//将翻译后的内容写入新文件
awaitwriteTranslatedJson(outputFilePath,translatedData);
console.log(
"翻译完成,结果是否存在遗漏项:",
compareObjectsWithPath(jsonData,translatedData)
);
console.log("翻译完成,结果已写入:",outputFilePath);
}catch(error){
console.error("处理过程中出错:",error);
}
console.timeEnd("runmain");
};
//执行主函数
main();
7b
runworkerwindow:1:16.909(m:ss.mmm)
翻译出错:window
runworkercontextMenu:1:19.915(m:ss.mmm)
翻译出错:contextMenu
runworkerautoUpdater:1:24.182(m:ss.mmm)
runworkermenu:1:54.272(m:ss.mmm)
runworkeropenWindowWarn:2:08.219(m:ss.mmm)
翻译出错
penWindowWarn
runworkercontextMenu:54.257s
翻译出错:contextMenu
runworkercreatePreloadFileWarn:1:05.595(m:ss.mmm)
翻译出错:createPreloadFileWarn
runworkerwindow:1:13.320(m:ss.mmm)
翻译出错:window
runworkeropenWindowWarn:42.933s
runworkerrenderer:1:06.620(m:ss.mmm)
runworkercontextMenu:58.129s
runworkercreatePreloadFileWarn:51.205s
runworkerwindow:1:10.067(m:ss.mmm)
翻译出错:window
runworkerwindow:17.583s
翻译出错:window
runworkerwindow:16.479s
翻译出错:window
runworkerwindow:53.783s
翻译完成,结果是否存在遗漏项:{ success:false,path:'menu'}
翻译完成,结果已写入
utput_deepseek-r1:7b.json
runmain:5:08.166(m:ss.mmm)

----------------
runworkeropenWindowWarn:27.835s
翻译出错
penWindowWarn
runworkerwindow:47.317s
翻译出错:window
runworkercontextMenu:1:00.365(m:ss.mmm)
翻译出错:contextMenu
runworkeropenWindowWarn:42.320s
runworkerwindow:1:00.580(m:ss.mmm)
翻译出错:window
runworkermenu:2:01.575(m:ss.mmm)
翻译出错:menu
runworkercontextMenu:1:05.158(m:ss.mmm)
runworkerautoUpdater:2:08.553(m:ss.mmm)
runworkercreatePreloadFileWarn:1:41.123(m:ss.mmm)
runworkerwindow:1:28.518(m:ss.mmm)
翻译出错:window
runworkerrenderer:1:46.725(m:ss.mmm)
runworkermenu:1:54.031(m:ss.mmm)
翻译出错:menu
runworkerwindow:57.867s
runworkermenu:1:16.267(m:ss.mmm)
翻译完成,结果是否存在遗漏项:{ success:false,path:'menu'}
翻译完成,结果已写入
utput_deepseek-r1:7b.json
runmain:5:11.880(m:ss.mmm)

翻译结果
"window":{
"willUnload":{
"title":"Whatshouldyouconfirmbeforerefreshingthecurrentpage?",
"message":"thesystemmightnotsaveyourchanges",
"unload_bt":"Reload",
"cancel_bt":"Cancel"
}
},
14b
runworkerwindow:2:15.983(m:ss.mmm)
runworkercontextMenu:2:17.554(m:ss.mmm)
runworkerautoUpdater:3:02.960(m:ss.mmm)
runworkermenu:4:06.753(m:ss.mmm)
runworkeropenWindowWarn:4:14.074(m:ss.mmm)
runworkercreatePreloadFileWarn:2:04.443(m:ss.mmm)
runworkerrenderer:2:21.099(m:ss.mmm)
翻译完成,结果是否存在遗漏项:{ success:true}
翻译完成,结果已写入
utput_deepseek-r1:14b.json
runmain:4:38.673(m:ss.mmm)
------------------------
runworkerautoUpdater:1:34.068(m:ss.mmm)
runworkeropenWindowWarn:1:57.715(m:ss.mmm)
runworkerwindow:2:09.907(m:ss.mmm)
runworkercontextMenu:2:14.214(m:ss.mmm)
runworkerrenderer:1:38.631(m:ss.mmm)
runworkercreatePreloadFileWarn:2:24.484(m:ss.mmm)
runworkermenu:4:16.409(m:ss.mmm)
翻译出错:menu
runworkermenu:2:00.482(m:ss.mmm)
翻译完成,结果是否存在遗漏项:{ success:true}
翻译完成,结果已写入
utput_deepseek-r1:14b.json
runmain:6:16.900(m:ss.mmm)
翻译结果
"window":{
"willUnload":{
"title":"Confirmtorefreshthecurrentpage?",
"message":"Thesystemmaynotsaveyourchanges.",
"unload_bt":"Reload",
"cancel_bt":"Cancel"
}
},
4.整体体验下来,14b 模型在翻译工作上比 7b 模型更为准确,一次性翻译成功率高。7B 模型翻译结果噪声多,返回结果可序列化效果差。翻译结果远远不如 14b。
14b 在 macos 执行效率能满足特定业务场景要求
| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |