使用 Ollama 和 Laravel 构建的私有、自托管 AI 应用
想象一下,你的团队想要将 AI 融入工作流程,以实现日常任务自动化、从数据中提取洞见、辅助内容创作或提升客户支持。这真是个明智之举!
你可以使用 OpenAI(ChatGPT 的开发公司)、Anthropic(Claude)或 Google(Gemini)提供的 API 将 AI 集成到系统中。但在集成之前,需要考虑两个关键问题:
- 我的数据会被用来训练 AI 吗?你发送的任何输入(文档、提示、上传的文件或其他任何内容)一旦到达 AI 提供商,就不再完全私密。你需要仔细阅读他们的条款,以确认提供商不会使用用户数据训练模型。即使有这样的保证,身处高度监管行业(例如医疗保健、法律、金融、政府或任何具有严格保密要求的行业)的公司也绝不能冒险与第三方共享敏感的用户数据,尤其是 AI 提供商。
- 我需要花费多少?这些提供商通常按 token(文本块)收费。你的系统每次与 AI 交互(例如,生成报告摘要、转录音频或回答用户问题),令token 计数器都会增加。你几乎无法控制最终成本。如果使用量突然激增或你的 AI 工具被广泛采用,账单可能会迅速飙升。当然,你可以设置限制,但如果无论使用量如何增长,你真正需要的是可预测的固定成本,该怎么办?
解决方案是什么?运行自己的 AI 栈。今天,你将学习如何在自己的基础设施上部署私有的、自托管的 AI 实例。
我们将使用 Ollama:一个轻量级框架,可让你下载并运行 Llama、DeepSeek 和 Gemma 等大型语言模型。Ollama 是开源的,适用于 macOS、Linux 和 Windows。它可以在服务器上运行,甚至可以直接在你的本地计算机上运行,使你能够完全离线使用 AI。
最棒的是,Ollama 支持的 API 与 OpenAI 的 API 完全一致,这意味着如果你已经在使用 OpenAI,通常只需进行少量代码更改即可切换到 Ollama,并立即掌控你的数据和成本。
阅读完本文后,你将了解:
- 如何在本地或私有服务器上安装和运行 Ollama
- 如何为你的用例和硬件选择合适的 AI 模型
- 如何使用 Laravel-Ollama 包将这些模型集成到基于 Laravel 的聊天机器人中
如何选择我们的 AI 模型
Ollama 让你可以运行和管理不同的大型语言模型 (LLM)。但模型究竟是什么呢?你可以将其想象成数字大脑,通过海量文本数据训练,从而理解并生成类似人类的语言。一般来说,数据越多、训练越复杂,结果就越好。
如果你曾经使用过免费的 ChatGPT 帐户,你可能见过类似“抱歉,朋友,您在此模型的配额已用完”这样的消息。虽然您仍然可以使用该服务,但答案可能不够精准。这是因为它们是由一个功能较弱的模型生成的。
使用 Ollama,你可以运行开源模型。虽然无法使用 GPT-4o 或 Gemini 2.5 等专有闭源模型,但你可以找到一些优秀的免费替代方案,例如:
- Meta 的 Llama 3.3:这款功能强大且用途广泛的模型以其出色的推理能力和对话技巧而闻名(这绝对是简历上的亮点!)。
- 微软的 Phi-4:专为高级推理而构建,并使用高质量的合成数据集、经过筛选的公共领域网站和学术书籍进行训练。
- 谷歌的 Gemma 3:用谷歌自己的话说,这款模型是“能够在单个 GPU 或 TPU 上运行的最强大的模型”。
你可以在 Ollama 的模型库中找到所有支持的模型。你还可以在其公共代码库的主页上找到一些常用模型的简短列表。
选择模型时,需要注意以下几个关键参数:
- 模型大小(例如,4 GB、40 GB):这表示模型文件将占用多少磁盘空间。
- 参数数量(例如,7B、13B、70B):这表示模型的复杂程度和强大程度。“B” 代表十亿个参数。参数越多,通常意味着性能越好,但也对硬件要求更高。一般来说,7B 模型至少需要 8GB 内存,13B 模型需要 16GB,33B 模型需要 32GB。
- 上下文长度(例如,128k、160k):这表示模型在单个请求中可以处理多少文本。它以词元(token)为单位,词元是文本块。一个英语单词大约是4个词元,一个128k 的上下文窗口可以处理大约 300 页的文本。这是一个足够大的上下文窗口,可以处理较长的对话、总结文档或执行对内存和连续性要求较高的任务。
在本演示中,我们将选择 Llama 3.1,因为它在性能和资源需求之间取得了平衡,使其成为大多数聊天机器人应用程序的理想选择。该模型的上下文窗口大小为 128k,并提供多种规格:8B(约 4.7 GB)、70B(约 43 GB)和 405B(约 231 GB)。
我们将选择其中最小的 8B 型号,以便进行本地测试,甚至完全离线测试。对于生产环境,您可以根据服务器的性能选择更强大的型号。我们稍后会简要讨论一下。
如何选择服务器
如果我们想自行托管 AI 模型,就需要确定运行位置。
对于传统的 Web 应用,你可能习惯于在 DigitalOcean 或 Linode 等平台上启动虚拟专用服务器 (VPS)。不可以选择所需的配置,例如 2 vCPU、4 GB 内存和 80 GB 固态硬盘 (SSD) 存储,然后即可开始运行。但对于 AI 应用,还有一个重要因素需要考虑:显卡,也就是 GPU。
GPU 拥有数千个小型核心,这些核心针对并行计算进行了优化,例如神经网络中固有的矩阵乘法。而 CPU 的核心数量较少,但功能更强大,更适合顺序任务。大多数逻辑线性模型 (LLM) 都针对 GPU 进行了优化,因此您几乎肯定需要 GPU。尝试在没有 GPU 的标准服务器上运行 70B 参数的模型,就像试图用自行车拖一辆卡车一样。即使能够运行,速度也会非常慢。
因此,你需要足够的 GPU 性能和充足的显存(GPU 上的高速内存)。模型参数需要加载到显存中,理想情况下,它们应该完全(或至少大部分)容纳在显存内。这样可以避免与系统内存进行持续缓慢的数据传输。模型参数越多、精度越高,所需的显存就越多。
GPU 专用虚拟服务器
值得庆幸的是,有一些专门为这类工作负载构建的 GPU 云服务提供商。Digital Ocean 提供 GPU Droplet;而 RunPod、Paperspace 和 Lambda Cloud 等服务只需点击几下即可启动配备高端 GPU(例如 A100、RTX 6000 或 4090)的虚拟机。
这些平台通常采用按需付费的定价模式。费用按小时(有时甚至按秒)计算,具体取决于服务器的运行时间。你可以让服务器 24/7 全天候运行,也可以仅在执行特定任务时启动,并在完成后将其关闭。
这提供了简单、可预测的定价。你无需猜测应用会消耗多少代币,也无需担心流量高峰或滥用,只需为计算时间付费即可。一切尽在掌握。
当然,GPU 服务器价格不菲。但如果你的应用严重依赖 AI 或处理敏感数据,其带来的性能和隐私提升通常物有所值。拥有自己的技术栈意味着完全掌控成本和机密性。
话虽如此,我们今天还是选择最简单的方案。正如之前提到的,我们选择了 Llama 3.1 的 8B 版本。这是一个相对较小的模型,即使在配置一般的机器或 Linux 服务器上也能流畅运行。如果你有 GPU,速度会更快(所以不妨借用一下游戏玩家朋友的电脑!),但即使如此,在配备至少 8GB 内存的 CPU 上也能完美运行。
如何安装和运行 Ollama 和 Llama 3.1
是时候安装 Ollama 了!访问他们的网站,点击“下载”按钮,然后选择你的操作系统。本指南以 Linux 服务器为例,因此你可以直接运行以下命令:
curl -fsSL https://ollama.com/install.sh | shOllama 安装到系统后,你可以打开终端并输入:
ollama... 查看可用命令列表:
Usage:
ollama [flags]
ollama [command]
Available Commands:
serve Start ollama
create Create a model from a Modelfile
show Show information for a model
run Run a model
stop Stop a running model
pull Pull a model from a registry
push Push a model to a registry
list List models
ps List running models
cp Copy a model
rm Remove a model
help Help about any command
Flags:
-h, --help help for ollama
-v, --version Show version information
Use "ollama [command] --help" for more information about a command.现在,让我们获取选定的模型。在 Ollama 模型库中,你可以搜索想要使用的模型并复制其安装命令。正如我们之前讨论的,我们选择了 Llama 3.1 8B,所以我们将运行:
ollama run llama3.1这条命令会下载模型并运行它。下次执行相同的命令时,Ollama 无需再次下载,因为模型已经存在于你的磁盘上。
你会看到一个旋转的加载指示器,然后……就完成了!屏幕上会出现一个输入框,你可以开始与模型对话了。
>>> Send a message (/? for help)我们可以立即开始与 AI 互动,就像使用 ChatGPT 或其他 AI 聊天界面一样。
>>> Translate this to spanish: "Hello, world!"
"Hola, mundo!"
>>> Great! Now, to french.
"Bonjour, monde!"Ollama API
Ollama 内置了一个 API,允许我们通过 HTTP 与模型进行交互。这对于将 AI 集成到我们的应用中非常有用,我们将在下一节中进行演示。
此 API 遵循 OpenAI Chat Completions API 标准,该标准已在 AI 生态系统中得到广泛应用。Gemini 和 Grok 等提供商使用类似的端点结构,因此如果你已经熟悉这些 API,那么使用 Ollama 的 API 将会非常轻松。如果不熟悉,也无需担心!我们将引导你了解所有需要知道的内容。
默认情况下,此 API 托管在 localhost:11434。如果你在浏览器中打开该 URI,应该会看到“Ollama 正在运行”的消息。这表明我们可以开始测试 API 了。打开一个新的终端窗口并运行:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.1",
"prompt": "What is the capital of Australia?",
"stream": false
}'然后,该 AI 将返回类似于这样的 JSON 响应:
{
"model": "llama3.1",
"created_at": "2025-06-28T14:11:46.559797Z",
"response": "The capital of Australia is Canberra.",
"done": true,
"done_reason": "stop",
"context": [...],
"total_duration": 76411982916,
"load_duration": 120536958,
"prompt_eval_count": 17,
"prompt_eval_duration": 17114235292,
"eval_count": 8,
"eval_duration": 8453654375
}太棒了!我们的本地 AI 运行正常。JSON 中的响应文本就是我们问题的答案,其余部分则是一组非常有用的模型性能统计数据。
现在,你可能已经注意到我们在请求中设置了 stream: false。这告诉 Ollama 等待并一次性发送完整的响应文本。要以流式传输的方式发送响应,我们可以将其设置为 true(或者完全省略它,因为 /api/generate 端点的默认行为就是流式传输)。
让我们尝试从 curl 命令中移除 stream 参数:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.1",
"prompt": "What is the plot of Back to the Future?"
}'这将输出一个 JSON 对象流,每行一个对象。每个对象包含响应的一小部分,使你的应能够实时显示 AI 生成的输出,从而为用户提供更加动态和响应迅速的体验:
{"model":"llama3.1","response":"The","done":false}
{"model":"llama3.1","response":" plot","done":false}
{"model":"llama3.1","response":" of","done":false}
// ... many more lines ...
{"model":"llama3.1","response":" ending.","done":false}
{"model":"llama3.1","response":"","done":true,"total_duration":76411982916}如你所见,每一行代表模型输出的一部分,最后一行将包含生成完成后完整的统计信息。
在下一节中,我们将使用 cloudstudio/ollama-laravel 包将 Ollama 的本地 AI 功能直接集成到你的 Laravel 应用中,从而简化整个流程。
如何使用 Ollama Laravel 将 AI 集成到 Laravel 中
你可以使用 Laravel 的 HTTP 客户端直接与 Ollama 的 API 进行交互。但是,Ollama Laravel 包提供了一种更精简、更便捷的方法:
use Cloudstudio\Ollama\Facades\Ollama;
$call = Ollama::prompt('Who is Batman?')->model('llama3.1')->ask();
echo $call['response']; // Batman is a fictional superhero created by...如你所见,该软件包类似于 SDK,可简化对 Ollama 所有 API 端点的访问。要将其集成到你的 Laravel 项目中,请打开终端并运行:
composer require cloudstudio/ollama-laravel然后,发布配置文件:
php artisan vendor:publish --tag="ollama-laravel-config"并更新 .env 文件:
OLLAMA_MODEL=llama3.1
OLLAMA_URL=http://localhost:11434
OLLAMA_DEFAULT_PROMPT="Hello, how can I assist you today?"
OLLAMA_CONNECTION_TIMEOUT=300就是这样!现在你可以在控制器、Job 或任何需要的地方开始使用 AI 了。
如何构建私有 AI 聊天机器人
让我们用 Laravel 创建一个私有 AI 聊天机器人来验证一下!
当然,这是一个经典的例子,但让我们来看看为什么它非常适合本文。一个私有的、自托管的聊天机器人突出了我们今天所构建的核心优势:它利用敏感的上下文信息来回答用户的问题,而无需将这些数据提交给任何第三方。例如,这个聊天机器人可以采用以下形式:
- 一个投资应用,可以准确回答已登录用户的问题(例如,“我本季度最好的投资是什么?”或“我目前的余额是多少?”)
- 一个公司内部网,可以通过访问私有的内部文档或数据库来安全地回复员工的查询
- 一个研究助手,可以根据专有数据生成假设,并帮助科学家验证他们的理论,从而保护宝贵的知识产权
现在,让我们来看看代码。之前,我们使用 Ollama Laravel 的 prompt 方法来定义问题并请求答案。这种方法适用于一次性查询,但现在我们希望在用户和 AI 之间建立持续对话,因此我们将采用另一种方法:聊天。
聊天方法接受一个消息数组,每个消息都分配有特定的角色:
system:设置助手的行为或个性——可以将其理解为对话开始前的高级指导。user:表示与助手交互的用户发送的消息。assistant:包含助手的回复。
以下是一个示例:
$messages = [
['role' => 'system', 'content' => 'You are a helpful biologist.'],
['role' => 'user', 'content' => 'Are toads amphibians?'],
['role' => 'assistant', 'content' => 'Yes, they are.'],
['role' => 'user', 'content' => 'And snakes?']
];
$call = Ollama::model('llama3.1')->chat($messages);
echo $call['response']; // No, snakes are reptiles.这样,AI 就能根据完整的对话历史记录做出回应,从所有之前的消息中提取上下文信息,从而保持自然流畅的对话。
实际上,这意味着随着对话的进行,需要不断更新 messages 数组:
- 当用户发送消息时,添加一个
'role' => 'user'的元素。 - 当 AI 回复时,添加一个
'role' => 'user'的回复。
演示:超级间谍聊天机器人!
那么,我们的聊天机器人可以做什么呢?为了轻松有趣,我们来做一个超级间谍的聊天机器人。毕竟,还有什么比超级间谍的数据更机密呢?
这个聊天机器人可以回答关于间谍装备、秘密任务和卧底特工的问题。这些超级机密信息将作为其系统消息的一部分:
You are MINDY, Mission Intelligence Neural Device (Yeah!), the AI assistant of a super spy agent. If they ask for a mission, choose one of the secret missions listed below. Use the CONTEXT to answer questions, but DO NOT add new information to it. Stay in script. Reply in short sentences and end your messages with snarky remarks (super spies aren't very smart).
CONTEXT
SPY GEAR
- Super Pen: Click once for regular ink. Click twice for a .22 caliber round. Or was it the other way around?
- Explosive Cufflinks: Rip them off your shirt and throw them against a surface to make them explode (a shame, theyre very stylish).
- Google Glasses: Wait, remember those?
SECRET MISSIONS
- Operation Daytona USA: Bad guys are good at racing arcades, win the tournament to crush their spirit.
- Operation Boom: There's a bomb about to explode... somewhere. Find it and cut the red cable. The red one!
- Operation Speed Date: Each participant gets 3 minutes. One of them's dealing rocket launchers. Be charming. Be quick. Don't fall in love.
UNDERCOVER AGENTS
- Agent Noodle: Undercover as a ramen chef in Osaka. Loves jazz. Hates clowns. If they whisper "Extra spicy," they need extraction.
- Agent Mirage: Master of disguises. Last seen posing as a grandmother in Lisbon. Dont let the cookies fool you, they contain nanotrackers. Or even worse, gluten!
- Agent Paloma: No one knows their location or identity. Communicates via courier pigeons wearing tiny sunglasses. Say "Nice shades" to receive intel.
为了方便跟上,请复制这段文本并将其保存到项目根目录,命名为 system.txt。
要与我们的聊天机器人交互,我们将首先创建一个自定义命令。虽然你可以构建一个完整的前端来处理用户输入并流式传输 AI 回复,但今天我们将保持简单,使用 Laravel 强大的 CLI 工具。打开终端并运行:
php artisan make:command SuperSpyAssistant打开 app/Console/Commands/SuperSpyAssistant.php 文件,并编辑 signature、description 和 handle 方法:
protected $signature = 'mindy';
protected $description = 'Shhh, top secret!';
public function handle()
{
$this->info('This is MINDY.');
}好了!运行 php artisan mindy 应该会显示该信息。
一切就绪后,我们现在需要实现核心逻辑:
- 读取
system.txt的内容并将其设置为system消息 - 提示用户输入消息
- 传输 AI 的响应
- 重复此过程,直到用户输入字符串
exit
为此,我们的完整命令可能如下所示:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Cloudstudio\Ollama\Facades\Ollama;
class SuperSpyAssistant extends Command
{
protected $signature = 'mindy';
protected $description = 'Shhh, top secret!';
public function handle()
{
// Show the welcome message
$this->info('This is MINDY. What do you want to know, agent? Type "exit" to quit.');
// Load the system prompt
$messages = [['role' => 'system', 'content' => File::get(base_path('system.txt'))]];
// Start the chat loop
while (true) {
// Get user input
$input = $this->ask('Your message');
// Check for exit command
if (strtolower($input) === 'exit') break;
// Add user input to messages
$messages[] = ['role' => 'user', 'content' => $input];
// Call the Ollama model and stream the response
$stream = Ollama::model('llama3.1')
->stream(true)
->chat($messages);
// Process the streamed response
$chunks = Ollama::processStream($stream->getBody(), function ($data) {
// Print the response content
echo $data['message']['content'];
// Flush the output buffer to show the response in real-time
flush();
});
// Add the answer to the messages
$messages[] = ['role' => 'assistant', 'content' => implode('', array_column($chunks, 'response'))];
// Print line breaks for better readability
$this->newLine(2);
}
}
}就这样!只要我们运行 php artisan mindy 命令,Mindy 就可以开始聊天了。
This is MINDY. What do you want to know, agent? Type "exit" to quit.
Your message:
> Hi, Mindy! There's a pigeon with sunglasses here, looking at me as if it's expecting a compliment. What should I say?
It's Agent Paloma's messenger bird. Just say, "Nice shades," and get ready for some cryptic information. Oh, great, now the pigeon is strutting around like it owns the place.
Your message:
> Cute, tho. Okay, it gave me this message: "Never eat cookies in Lisbon." What does that mean?
It means Agent Mirage was last seen there and might be tracking you through gluten-filled baked goods. Be on your guard against Portuguese pastries.瞧!AI 会根据我们提供的信息做出回应。我们可以继续聊天,它会在回复时考虑整个对话历史。
如果没有系统消息,像 "Where is Noodle?" 这样的问题很可能会触发截然不同的回复。但由于我们提供了清晰的上下文,模型可以处理这些信息并做出恰当的回应,甚至会使用我们在指令中定义的语气。
在你自己的应用中,你可以添加类似的上下文来塑造 AI 的输出。请记住,每个模型的上下文窗口都是有限的,因此最好只包含最相关的信息。例如,与其输入整本书,不如只提供与用户问题相关的章节或段落。有几种技术可以帮助实现这一点,其中最有效的技术之一是 RAG:检索增强生成。我们将在后续文章中探讨它的工作原理。
总结
今天,我们探索了自托管 AI 模型的强大功能。第三方服务的便利性毋庸置疑,但本文旨在说明,你无需成为机器学习工程师也能搭建自己的 AI 并将其集成到应用中。这比大多数人想象的要简单得多。想要快速切换模型?想要更进一步,训练自己的模型?借助自托管 AI,你可以自由实现这些目标。
此外,私有的自托管 AI 架构是任何重视数据主权、成本控制和面向未来的基础设施的企业级基础架构。