欢迎光临
我们一直在努力

2026 Django+Llama 4 AI应用实战 | 第 1 讲:从零搭建你的第一个 Django+Llama 4 对话应用

前言

在这里插入图片描述

站在2026年的技术浪潮上,AI应用已经不再是“套个API就上线”的玩具阶段,而是深度嵌入业务流程的企业级系统。Meta Llama 4的全面开源,凭借比肩GPT-4级别的推理能力与极低的本地部署成本,让 “Django + 开源大模型” 成为全栈领域最硬核、最吃香的技术组合。

为什么是Django?作为Python生态中最稳重的Web框架,Django的ORM、中间件、权限系统天然适合承载复杂的AI业务逻辑。为什么是Llama 4?它不仅能通过Ollama一键本地部署、彻底解决数据隐私和API费用问题,还完美兼容OpenAI接口协议——这意味着你写的代码,未来可以零成本切换到任意大模型。

本专栏面向有Django基础的读者,跳过枯燥理论,直奔工业级实战。今天的第一讲,我们将用最短的时间,从零跑通一个基于Django后端与本地Llama 4的全栈对话应用。让我们开始。


环境准备

本讲无需昂贵GPU,普通Mac或带基础显卡的Windows/Linux电脑均可运行。

1. Python 与 Django

确保Python版本 >= 3.10,使用Django 5.1+:

pip install django==5.1.3

2. 本地大模型引擎 Ollama 与 Llama 4

Ollama是目前最简单的本地大模型运行工具:

  • 前往 ollama.com 下载安装对应系统版本。
  • 安装完成后,终端执行:ollama run llama4
    首次运行会自动下载模型权重(约20GB),请确保磁盘空间充足且网络通畅。下载完毕后终端会进入对话模式,说明Llama 4已在本地运行。输入 /bye 退出即可,Ollama后台会继续保持服务。

验证Ollama服务:另开一个终端执行 curl http://localhost:11434/api/tags,若返回包含 llama4 的JSON,说明服务正常且API端口可用。

3. 大模型交互 SDK

使用OpenAI兼容的Python SDK与Ollama通信。Ollama实现了OpenAI的 /v1/chat/completions 接口,因此我们可以用官方SDK直接调用,无需额外适配器。

pip install openai==1.40.0


分步实现

我们将遵循Django的MVT架构,分 7 步完成整个应用的搭建。每一步我都会解释代码的作用和设计意图。

第 1 步:创建 Django 项目与应用

在终端执行以下命令,创建项目骨架:

django-admin startproject llama4_chat
cd llama4_chat
python manage.py startapp chat

然后将 chat 应用注册到项目中。打开 llama4_chat/settings.py,修改 INSTALLED_APPS:

# llama4_chat/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'chat', # 新增聊天应用
]

说明:startapp 创建了 chat 目录,我们需要手动将其添加到 INSTALLED_APPS,Django才能识别其中的模型、视图和模板。

第 2 步:配置 Llama 4 连接参数

硬编码API地址是实战大忌。我们将连接信息集中管理,方便后续环境切换(如从本地Ollama切换到云端GPT-4)。在 llama4_chat/settings.py 末尾追加以下配置:

# llama4_chat/settings.py 末尾追加
# ============ Llama 4 本地模型配置 ============
LLAMA4_API_BASE = "http://localhost:11434/v1" # Ollama的OpenAI兼容接口
LLAMA4_API_KEY = "ollama" # 本地运行无需真实Key,随意填写
LLAMA4_MODEL_NAME = "llama4" # 模型名称,需与ollama run一致

设计要点:

  • Ollama默认监听 11434 端口,并提供了 /v1 前缀的OpenAI风格API。
  • api_key 字段在Ollama中被忽略,但OpenAI客户端要求非空,填任意字符串即可。
  • 这种配置方式让我们未来只需修改 LLAMA4_API_BASE 指向云端地址(如 https://api.openai.com/v1)并更换 api_key,业务代码零改动。

第 3 步:编写与 Llama 4 交互的核心服务层

很多初学者把AI调用逻辑直接塞进视图函数,这在实战中是大忌——逻辑耦合、难以测试、无法复用。我们遵循单一职责原则,将模型交互封装在独立的服务层。

在 chat/ 目录下新建 services.py,写入以下代码:

# chat/services.py
import logging
from openai import OpenAI
from django.conf import settings

logger = logging.getLogger(__name__)

class Llama4Service:
"""封装与本地Ollama的通信逻辑,与视图层解耦"""

def __init__(self):
self.client = OpenAI(
base_url=settings.LLAMA4_API_BASE,
api_key=settings.LLAMA4_API_KEY,
)
self.model_name = settings.LLAMA4_MODEL_NAME

def get_chat_response(self, user_message: str) > str:
"""调用Llama 4获取对话回复,失败时返回友好提示"""
try:
messages = [
{
"role": "system",
"content": "你是一个由Django驱动的Llama 4智能助手,回答需简洁、准确、有逻辑。请使用中文回答。",
},
{"role": "user", "content": user_message},
]
# 同步调用(重要:不要加await)
response = self.client.chat.completions.create(
model=self.model_name,
messages=messages,
temperature=0.7, # 控制创造性,0.7是较平衡的值
max_tokens=1024, # 限制输出长度,防止资源耗尽
)
return response.choices[0].message.content
except Exception as e:
# 生产环境使用logging记录完整堆栈
logger.error(f"Llama 4调用失败: {e}", exc_info=True)
return "抱歉,AI服务暂时不可用,请检查Ollama是否已启动。"

# 实例化一个全局服务对象,供视图层直接导入使用
llama4_service = Llama4Service()

关键说明:

  • 这里使用的是OpenAI SDK的同步调用方式(self.client.chat.completions.create 没有 await),完美契合Django的同步视图。切记不要在同步视图中混搭异步调用,否则会导致事件循环冲突(详见后文“常见坑”)。
  • 异常处理中使用 logging.error 记录完整堆栈(exc_info=True),便于排查问题。返回给用户的错误信息应当友好,不暴露内部细节。
  • 将 Llama4Service 实例化为全局单例,避免每次请求都重新创建客户端(连接池复用,提升性能)。

第 4 步:创建 Django 视图

视图负责接收HTTP请求、调用服务层、返回响应。我们设计两个视图:一个渲染聊天页面,一个处理AJAX对话请求。

编辑 chat/views.py:

# chat/views.py
import json
import logging
from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.http import require_POST
from .services import llama4_service

logger = logging.getLogger(__name__)

def chat_index(request):
"""渲染聊天主页面"""
return render(request, "chat/index.html")

@require_POST
def chat_api(request):
"""处理聊天请求的API接口,接收JSON,返回JSON"""
try:
data = json.loads(request.body)
user_message = data.get("message", "").strip()
if not user_message:
return JsonResponse({"error": "消息不能为空"}, status=400)

ai_reply = llama4_service.get_chat_response(user_message)
return JsonResponse({"status": "success", "reply": ai_reply})
except json.JSONDecodeError:
return JsonResponse({"error": "无效的请求数据"}, status=400)
except Exception as e:
logger.error(f"聊天API未处理异常: {e}", exc_info=True)
return JsonResponse({"error": "服务器内部错误,请稍后重试"}, status=500)

设计要点:

  • @require_POST 确保该接口只接受POST请求,防止GET误触。
  • 通过 json.loads(request.body) 获取数据,而非 request.POST,因为前端会使用Fetch API发送 Content-Type: application/json 格式数据——这更符合现代前后端分离习惯。
  • 对空消息返回400状态码,明确告诉客户端请求无效。
  • 未捕获的异常记录日志后返回500,不将异常详情暴露给前端(安全考虑)。

第 5 步:配置路由

有了视图,需要将URL映射上去。先在 chat/ 目录下新建 urls.py:

# chat/urls.py
from django.urls import path
from . import views

app_name = "chat"
urlpatterns = [
path("", views.chat_index, name="index"), # 聊天主页面
path("api/chat/", views.chat_api, name="chat_api"), # 聊天API接口
]

然后将 chat 应用的路由包含到项目总路由中。编辑 llama4_chat/urls.py:

# llama4_chat/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path("admin/", admin.site.urls),
path("", include("chat.urls")), # 将根路径指向chat应用
]

说明:这样配置后,访问根路径 / 就会进入聊天页面,/api/chat/ 则对应API接口。

第 6 步:编写前端聊天界面

现代AI应用离不开流畅的交互体验。我们用原生HTML/CSS/JS编写一个极简但实用的聊天界面,通过Fetch API与后端异步通信。

创建模板目录:chat/templates/chat/(注意是两层 chat 目录,这是Django的模板查找惯例)。在该目录下新建 index.html,完整代码如下(我会在代码后解释关键部分):

<!– chat/templates/chat/index.html –>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Django + Llama 4 智能对话</title>
<style>
/* 极简样式,保证单文件可运行 */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f2f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.chat-container {
width: 100%;
max-width: 800px;
background: white;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
display: flex;
flex-direction: column;
height: 80vh;
overflow: hidden;
}
.chat-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 18px;
text-align: center;
font-size: 1.2em;
font-weight: bold;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
border-bottom: 1px solid #e5e7eb;
}
.message {
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.message.user { align-items: flex-end; }
.message.ai { align-items: flex-start; }
.message-bubble {
max-width: 70%;
padding: 12px 16px;
border-radius: 16px;
line-height: 1.6;
white-space: pre-wrap;
word-wrap: break-word;
}
.user .message-bubble {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-bottom-right-radius: 4px;
}
.ai .message-bubble {
background: #f3f4f6;
color: #1f2937;
border-bottom-left-radius: 4px;
}
.chat-input-area {
padding: 16px;
display: flex;
gap: 12px;
background: white;
}
#message-input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e5e7eb;
border-radius: 12px;
font-size: 1em;
outline: none;
resize: none;
font-family: inherit;
}
#message-input:focus { border-color: #667eea; }
#send-btn {
padding: 12px 28px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 12px;
cursor: pointer;
font-size: 1em;
font-weight: bold;
transition: opacity 0.2s;
}
#send-btn:disabled { opacity: 0.5; cursor: not-allowed; }
#send-btn:hover:not(:disabled) { opacity: 0.9; }
.loading-dots::after {
content: '…';
animation: dots 1.2s steps(4, end) infinite;
}
@keyframes dots {
0%, 20% { content: '.'; }
40% { content: '..'; }
60%, 100%{ content: '…'; }
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">Django + Llama 4 AI 助手</div>
<div class="chat-messages" id="chat-messages">
<div class="message ai">
<div class="message-bubble">你好!我是基于本地Llama 4驱动的AI助手。有什么我可以帮你的吗?</div>
</div>
</div>
<div class="chat-input-area">
<textarea id="message-input" rows="1" placeholder="输入你的问题… (Enter发送,Shift+Enter换行)"></textarea>
<button id="send-btn">发送</button>
</div>
</div>
<script>
// DOM元素引用
const messagesDiv = document.getElementById('chat-messages');
const inputField = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');

// 自动滚动到底部
function scrollToBottom() {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}

// 添加消息气泡,返回气泡元素以便后续更新
function addMessage(content, sender) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', sender);
const bubble = document.createElement('div');
bubble.classList.add('message-bubble');
bubble.textContent = content;
messageDiv.appendChild(bubble);
messagesDiv.appendChild(messageDiv);
scrollToBottom();
return bubble;
}

// 发送消息核心逻辑
async function sendMessage() {
const message = inputField.value.trim();
if (!message) return;

// 清空输入框并禁用控件,防止重复提交
inputField.value = '';
sendBtn.disabled = true;
inputField.disabled = true;

// 显示用户消息
addMessage(message, 'user');
// 显示AI“正在思考”状态,添加加载动画class
const aiBubble = addMessage('正在思考', 'ai');
aiBubble.classList.add('loading-dots');

try {
const response = await fetch('/api/chat/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: message })
});

// 检查HTTP状态码
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.error || `HTTP ${response.status}`);
}

const data = await response.json();
aiBubble.classList.remove('loading-dots');
if (data.status === 'success') {
aiBubble.textContent = data.reply;
} else {
aiBubble.textContent = '出错了:' + (data.error || '未知错误');
}
} catch (error) {
aiBubble.classList.remove('loading-dots');
aiBubble.textContent = '请求失败,请检查Django后端是否运行,或Ollama服务是否正常。';
console.error('聊天请求错误:', error);
} finally {
// 恢复输入控件
sendBtn.disabled = false;
inputField.disabled = false;
inputField.focus();
scrollToBottom();
}
}

// 事件绑定
sendBtn.addEventListener('click', sendMessage);
// Enter发送,Shift+Enter换行
inputField.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
</script>
</body>
</html>

前端关键设计解释:

  • 消息渲染机制:通过 addMessage 动态创建DOM元素,每条消息独立,避免重新渲染整个列表。AI消息气泡先显示“正在思考”并添加动态省略号类 .loading-dots,请求完成后直接修改 textContent,效果平滑。

  • 防重复提交:发送时立即禁用输入框和发送按钮,请求结束后恢复。这防止了用户在等待期间多次点击发送导致并发问题。

  • 快捷键支持:Enter 发送,Shift+Enter 换行,符合主流聊天应用习惯。

  • 错误处理:检查HTTP响应状态码,非2xx时尝试解析后端返回的 error 字段,否则抛出通用错误。控制台输出详细错误便于调试。

  • 自动滚动:每次添加消息或更新内容后调用 scrollToBottom,确保最新消息可见。

  • 第 7 步:数据库迁移与启动服务

    本讲暂未涉及数据库模型(下一讲会引入对话历史存储),只需执行Django默认的迁移即可。在项目根目录依次执行:

    python manage.py migrate
    python manage.py runserver

    终端显示 Starting development server at http://127.0.0.1:8000/ 即为启动成功。


    测试效果

  • 确认后端启动:终端无报错,开发服务器运行在 http://127.0.0.1:8000/。
  • 确认Ollama服务:执行 curl http://localhost:11434/api/tags 能看到 llama4 模型。
  • 访问聊天页面:浏览器打开 http://127.0.0.1:8000/,看到紫色渐变头部和欢迎语。
  • 发起对话:输入 “用Python写一个快速排序” 并回车。
  • 观察现象:
    • 输入框和按钮变为禁用状态,出现“正在思考…”动态气泡。
    • Django终端显示请求日志,Ollama侧会输出推理过程(CPU推理可能需要几秒到十几秒,取决于机器性能)。
    • 思考结束后,Llama 4生成的代码和解释呈现在聊天气泡中。
  • 继续追问:试试输入 “解释一下时间复杂度”,体验模型的多轮对话能力。
  • 恭喜!你已经成功打通了Django与本地Llama 4的全链路通信。


    3 个常见坑

    在本地跑通大模型应用,初学者几乎必踩以下三个坑,这里提前为你排雷。

    坑 1:ConnectionRefusedError / 前端提示“请求失败”

    现象:前端提示“网络请求失败”,Django后台报错连接被拒绝。

    原因:Ollama服务没有启动,或者端口不是默认的11434。

    解决:

    • 在终端运行 ollama serve 确保Ollama后台在运行(Windows用户请确认Ollama应用在系统托盘中处于活跃状态)。
    • 如果Ollama监听了非默认端口,需同步修改 settings.py 中的 LLAMA4_API_BASE。
    • 执行 curl http://localhost:11434/api/tags 验证Ollama是否正常响应。

    坑 2:TemplateDoesNotExist at /

    现象:访问页面时Django报错找不到模板文件。

    原因:Django默认的模板查找机制要求模板放在 应用名/templates/应用名/ 的两层目录下,初学者极易搞错。

    解决:确保路径严格为 chat/templates/chat/index.html。你可以在终端执行 find . -name "index.html" 来确认文件位置。如果你嫌两层目录麻烦,也可以在 settings.py 的 TEMPLATES 中设置 'DIRS': [BASE_DIR / 'templates'],然后把HTML放到项目根目录的 templates/ 下——但我不推荐这种做法,多应用时容易命名冲突。

    坑 3:同步视图中混用异步调用导致崩溃

    现象:如果你在视图里使用 await openai(…) 或 asyncio.run(),Django报错 You cannot use AsyncToSync in a thread that is already async 或直接死锁无响应。

    原因:Django 5虽然支持异步视图(async def),但在同步视图(def chat_api)中直接调用异步的OpenAI SDK方法会引发事件循环冲突,这是Python异步编程的硬性限制。

    解决:本讲代码中,我们使用的是OpenAI SDK的同步调用方式(self.client.chat.completions.create 没有 await),完美契合Django同步视图。如果你确实需要异步视图来提升并发性能,正确的做法是将视图声明为 async def,并配合Django的 sync_to_async 工具和ASGI服务器(如Daphne或Uvicorn)使用。记住一条铁律:同步视图用同步SDK,异步视图用异步SDK,绝不混搭。


    专栏目录与订阅

    本文是《2026 Django+Llama 4 AI应用实战》专栏的第一讲,完整专栏持续更新中,你可以在以下地址查看所有文章和后续章节:

    专栏主页: https://blog.csdn.net/zsh_1314520/category_13175252.html

    本专栏将从零带你搭建生产级可上线的AI全栈项目,涵盖大模型API集成、RAG检索增强、智能对话系统、AI内容生成等核心场景,详解Django后端架构优化、大模型调用封装、流式响应实现等工业级实战内容。全部代码基于真实项目提炼,可直接用于你自己的业务系统。

    建议你收藏专栏主页,方便第一时间获取更新。


    下一篇预告

    今天我们跑通了最基础的“请求→等待→响应”模式,但你可能已经发现一个严重的体验问题:Llama 4生成一段500字的回答,用户需要干等10秒钟,然后文字才一次性全部弹出来。 这显然不是2026年AI应用应有的交互水准。

    在 第 2 讲:《告别漫长等待:Django 接入 Llama 4 流式输出(SSE)实战》 中,我将带你使用Server-Sent Events (SSE)技术,让Llama 4的回复像打字机一样逐字流动输出,大幅提升用户体验。我们还会深入讲解Django的 StreamingHttpResponse 与前端 EventSource 的配合、流式数据的边界处理等工业级细节。干货满满,敬请期待。

    本专栏持续更新中,点击上方专栏主页或关注我获取完整教程。

    赞(0)
    未经允许不得转载:171主机测评 » 2026 Django+Llama 4 AI应用实战 | 第 1 讲:从零搭建你的第一个 Django+Llama 4 对话应用
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址