Gemma-3-270m实战教程:Ollama + FastAPI封装为标准RESTful接口

你是不是已经体验过在Ollama的Web界面里和Gemma-3-270m模型聊天了?直接在页面上提问,确实很方便。但如果你想在自己的程序里调用它,比如做一个智能客服机器人、一个自动生成周报的工具,或者集成到你的App里,每次都打开网页复制粘贴,是不是太麻烦了?

这时候,我们就需要一个标准的、程序能直接调用的接口。今天,我就带你一步步把Ollama上的Gemma-3-270m模型,用FastAPI封装成一个标准的RESTful API。这样一来,任何支持HTTP请求的程序,无论是Python脚本、Java后端,还是手机App,都能轻松调用这个强大的文本生成模型了。

学完这篇教程,你将掌握:

  1. 如何快速搭建一个基于FastAPI的Web服务框架。
  2. 如何通过代码调用Ollama的API,与Gemma-3-270m模型对话。
  3. 如何设计一个清晰、易用的RESTful接口,并处理各种请求。
  4. 如何启动服务,并通过工具(如curl或Postman)测试你的接口。

整个过程就像搭积木,我们一块块来,保证你能跟上。让我们开始吧!

1. 环境准备与项目搭建

在开始写代码之前,我们需要确保电脑上已经装好了必要的工具,并创建一个干净的项目目录。

1.1 前置条件检查

首先,确认你的系统已经满足以下条件:

  • Python 3.8+:这是运行FastAPI的基础。打开终端(或命令提示符),输入 python --versionpython3 --version 查看。
  • Ollama已安装且运行:确保你已经按照之前的指引,在本地成功安装并运行了Ollama,并且已经拉取了 gemma3:270m 模型。你可以在终端输入 ollama list 来确认模型是否存在。
  • 网络通畅:确保你的开发机能访问到Ollama服务(默认在 http://localhost:11434)。

1.2 创建项目与虚拟环境

一个好的习惯是为每个项目创建独立的Python环境,避免包版本冲突。

  1. 打开终端,创建一个新的项目文件夹并进入:

    mkdir gemma-fastapi-service
    cd gemma-fastapi-service
    
  2. 创建Python虚拟环境:

    # 对于 macOS/Linux
    python3 -m venv venv
    # 对于 Windows
    python -m venv venv
    
  3. 激活虚拟环境:

    # 对于 macOS/Linux
    source venv/bin/activate
    # 对于 Windows (CMD)
    venv\Scripts\activate
    # 对于 Windows (PowerShell)
    venv\Scripts\Activate.ps1
    

    激活后,你的命令行提示符前通常会显示 (venv),表示你正在虚拟环境中工作。

1.3 安装依赖包

我们只需要两个核心的Python包:fastapi 用于创建Web服务,uvicorn 是一个轻量级的ASGI服务器,用于运行FastAPI应用。requests 库用于在FastAPI服务内部调用Ollama的API。

在激活的虚拟环境中,运行以下命令安装:

pip install fastapi uvicorn requests

安装完成后,可以用 pip list 快速查看一下。

2. 核心代码编写:连接Ollama与FastAPI

现在,我们来编写最核心的部分。我们将创建两个文件:一个主应用文件,一个定义数据模型的辅助文件。

2.1 定义请求与响应模型 (models.py)

为了让我们的API接口清晰、规范,并且有自动化的数据验证,我们先定义客户端请求和我们返回响应时应该遵循的“格式”。在项目根目录下创建一个 models.py 文件。

# models.py
from pydantic import BaseModel
from typing import Optional, List

# 客户端发送给我们的请求格式
class ChatRequest(BaseModel):
    prompt: str  # 用户输入的提示词,比如“你好,请介绍一下你自己”
    model: str = "gemma3:270m"  # 指定使用的模型,默认就是我们今天的主角
    stream: bool = False  # 是否使用流式响应(一个字一个字输出),默认关闭
    # 以下是一些可选的模型参数,用于调整生成效果
    temperature: Optional[float] = 0.7  # 温度,控制随机性。越高越有创意,越低越稳定。
    max_tokens: Optional[int] = 512  # 生成的最大令牌数,控制回答长度。

# 我们返回给客户端的响应格式
class ChatResponse(BaseModel):
    success: bool  # 请求是否成功处理
    message: str  # 主要的响应消息(模型生成的文本)
    model_used: str  # 实际使用的模型名称
    prompt_tokens: Optional[int] = None  # 消耗的提示词令牌数(如果Ollama返回了)
    response_tokens: Optional[int] = None  # 生成的响应令牌数(如果Ollama返回了)
    error: Optional[str] = None  # 如果出错,这里会包含错误信息

代码解释

  • 我们使用了 pydanticBaseModel(FastAPI自带),它能让数据验证和文档生成变得非常简单。
  • ChatRequest 定义了客户端调用我们的API时需要传递哪些信息。Optional 表示这个字段是可选的,我们有提供默认值。
  • ChatResponse 定义了我们的API会返回什么信息给客户端,结构一目了然。

2.2 编写FastAPI主应用 (main.py)

接下来,创建主文件 main.py。这里是所有逻辑发生的地方。

# main.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import requests
import logging
from models import ChatRequest, ChatResponse

# 1. 创建FastAPI应用实例
app = FastAPI(
    title="Gemma-3-270m API Service",
    description="一个基于Ollama和FastAPI封装的Gemma-3-270m模型RESTful API服务",
    version="1.0.0"
)

# 2. 添加CORS中间件(非常重要!)
# 这允许其他域的前端网页(比如你的Vue/React应用)能够调用这个API
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 在生产环境中,应该替换为具体的域名,如 ["https://your-frontend.com"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 3. 配置日志,方便我们查看运行情况和调试
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 4. Ollama服务的地址(默认本地11434端口)
OLLAMA_BASE_URL = "http://localhost:11434"

# 5. 健康检查端点 - 用来测试服务是否正常启动
@app.get("/")
async def root():
    return {"message": "Gemma-3-270m API Service is running!"}

# 6. 核心的聊天/completions端点
@app.post("/v1/chat/completions", response_model=ChatResponse)
async def chat_completions(request: ChatRequest):
    """
    处理聊天/文本生成请求。
    接收用户的提示词(prompt),调用Ollama的Gemma模型,返回生成的文本。
    """
    logger.info(f"收到请求: model={request.model}, prompt长度={len(request.prompt)}")

    # 准备发送给Ollama API的请求体
    ollama_payload = {
        "model": request.model,
        "prompt": request.prompt,
        "stream": request.stream,
        "options": {  # 将可选参数放入options中,这是Ollama API要求的格式
            "temperature": request.temperature,
            "num_predict": request.max_tokens
        }
    }

    try:
        # 向Ollama的生成接口发起POST请求
        ollama_url = f"{OLLAMA_BASE_URL}/api/generate"
        response = requests.post(ollama_url, json=ollama_payload, timeout=60)  # 设置60秒超时
        response.raise_for_status()  # 如果HTTP状态码不是200,会抛出异常

        # 解析Ollama返回的JSON数据
        ollama_result = response.json()

        # 构建我们自己的标准响应
        api_response = ChatResponse(
            success=True,
            message=ollama_result.get("response", "").strip(),  # 提取模型生成的文本
            model_used=ollama_result.get("model", request.model),
            prompt_tokens=ollama_result.get("prompt_eval_count"),
            response_tokens=ollama_result.get("eval_count")
        )
        logger.info(f"请求成功处理,生成令牌数: {api_response.response_tokens}")
        return api_response

    except requests.exceptions.Timeout:
        error_msg = "请求Ollama服务超时,模型可能正在加载或提示词过长。"
        logger.error(error_msg)
        raise HTTPException(status_code=504, detail=error_msg)
    except requests.exceptions.ConnectionError:
        error_msg = f"无法连接到Ollama服务,请确保Ollama正在运行于 {OLLAMA_BASE_URL}。"
        logger.error(error_msg)
        raise HTTPException(status_code=503, detail=error_msg)
    except requests.exceptions.RequestException as e:
        error_msg = f"调用Ollama API时发生错误: {str(e)}"
        logger.error(error_msg)
        raise HTTPException(status_code=500, detail=error_msg)
    except Exception as e:
        error_msg = f"服务器内部错误: {str(e)}"
        logger.error(error_msg)
        raise HTTPException(status_code=500, detail=error_msg)

# 7. 一个简单的模型列表查询端点(可选)
@app.get("/v1/models")
async def list_models():
    """返回当前Ollama中可用的模型列表。"""
    try:
        response = requests.get(f"{OLLAMA_BASE_URL}/api/tags")
        response.raise_for_status()
        models_data = response.json()
        # 简化返回格式,只提取模型名
        model_list = [model_info.get("name") for model_info in models_data.get("models", [])]
        return {"models": model_list}
    except requests.exceptions.RequestException:
        # 如果无法获取,至少返回我们默认支持的模型
        return {"models": ["gemma3:270m"]}

代码关键点解析

  • CORS中间件:这是让浏览器中运行的前端应用能调用本地API的关键,务必添加。
  • 端点设计:我们创建了两个端点。/ 用于健康检查,/v1/chat/completions 是核心的文本生成接口。路径设计模仿了OpenAI的风格,方便后续适配。
  • 错误处理:我们使用 try...except 块捕获了网络超时、连接错误、Ollama API错误等常见异常,并返回友好的HTTP状态码和错误信息,这对于API的健壮性至关重要。
  • 日志记录:使用 logging 模块记录关键信息,当出现问题时能快速定位。

3. 启动与测试你的API服务

代码写好了,让我们把它跑起来,并验证它是否工作。

3.1 启动FastAPI服务

在终端(确保还在项目目录且虚拟环境已激活),运行以下命令:

uvicorn main:app --reload --host 0.0.0.0 --port 8000
  • main:appmain 是文件名(不含.py),app 是我们在 main.py 中创建的FastAPI实例变量。
  • --reload:开启热重载。当你修改代码后,服务会自动重启。生产环境不要使用此参数
  • --host 0.0.0.0:让服务监听所有网络接口,这样同一局域网内的其他设备也能访问。
  • --port 8000:指定服务运行在8000端口。

看到类似下面的输出,说明服务启动成功:

INFO:     Will watch for changes in these directories: ['/path/to/your/project']
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

3.2 测试API接口

服务跑起来了,我们怎么知道它好不好用呢?有几种方法:

方法一:使用自动生成的交互式文档(推荐!) FastAPI的一个超棒特性是自动生成API文档。打开你的浏览器,访问:

  • Swagger UI 文档: http://localhost:8000/docs
  • ReDoc 文档: http://localhost:8000/redoc

http://localhost:8000/docs 页面,你可以看到我们定义的两个端点。点击 /v1/chat/completions 右边的 “Try it out” 按钮,在 Request body 里填入JSON数据,然后点击 “Execute” 就能直接测试!这是最直观的测试方式。

方法二:使用curl命令(终端测试) 打开另一个终端窗口,执行以下命令:

curl -X POST "http://localhost:8000/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "用简单的语言解释一下什么是人工智能?",
    "model": "gemma3:270m",
    "temperature": 0.8
  }'

你应该会收到一个格式工整的JSON响应,其中 message 字段就是Gemma模型生成的回答。

方法三:使用Postman或Insomnia(图形化工具) 对于更复杂的测试,可以使用这些专业的API测试工具。创建一个POST请求到 http://localhost:8000/v1/chat/completions,在Body中选择 rawJSON,然后输入和上面curl例子一样的JSON数据即可发送。

3.3 一个完整的客户端调用示例

假设你有一个Python脚本想要调用我们刚建好的API,代码可以这样写:

# client_example.py
import requests
import json

api_url = "http://localhost:8000/v1/chat/completions"

payload = {
    "prompt": "为一家新开的咖啡店写一句吸引人的广告语。",
    "model": "gemma3:270m",
    "temperature": 0.9,
    "max_tokens": 100
}

headers = {
    "Content-Type": "application/json"
}

try:
    response = requests.post(api_url, json=payload, headers=headers)
    response.raise_for_status()  # 检查请求是否成功
    result = response.json()
    
    if result.get("success"):
        print("生成的广告语:")
        print(result.get("message"))
    else:
        print(f"请求失败:{result.get('error')}")
        
except requests.exceptions.RequestException as e:
    print(f"调用API时发生错误: {e}")

保存为 client_example.py,在终端运行 python client_example.py,看看效果吧!

4. 进阶:让服务更健壮、更实用

基础功能已经实现了,但一个准备投入使用的服务还需要考虑更多。这里给你几个进阶方向:

4.1 添加请求速率限制

防止恶意用户短时间内发送大量请求拖垮你的服务。可以使用 slowapifastapi-limiter 等库。

pip install slowapi

然后在 main.py 中添加相应的限流中间件。

4.2 添加身份验证(API Key)

为你的接口增加一层安全保护,只有提供有效API Key的请求才能被处理。FastAPI内置了强大的安全工具。

from fastapi import Depends, HTTPException, status
from fastapi.security import APIKeyHeader

API_KEY_NAME = "X-API-Key"
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)

# 假设你将有效的API Key存储在环境变量或数据库中
VALID_API_KEY = "your-secret-api-key-here"

async def verify_api_key(api_key: str = Depends(api_key_header)):
    if api_key != VALID_API_KEY:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="无效或缺失的API Key"
        )
    return api_key

# 在端点函数上添加依赖
@app.post("/v1/chat/completions", response_model=ChatResponse, dependencies=[Depends(verify_api_key)])
async def chat_completions(request: ChatRequest):
    # ... 原有代码不变

4.3 支持流式响应 (Streaming)

如果你希望实现像ChatGPT那样一个字一个字输出的效果,需要支持Server-Sent Events (SSE)。这需要对 main.py 中的 /v1/chat/completions 端点进行较大改造,使其能够处理 stream: true 的请求,并将Ollama返回的流式数据实时转发给客户端。这涉及到 StreamingResponse 的使用,稍微复杂一些,但能极大提升用户体验。

4.4 使用环境变量管理配置

将Ollama服务地址、API Key、端口号等敏感或易变的信息放在环境变量中,而不是硬编码在代码里。

# 在启动服务前设置环境变量(Linux/macOS)
export OLLAMA_BASE_URL="http://localhost:11434"
export API_PORT=8000

然后在代码中使用 os.getenv(“OLLAMA_BASE_URL”) 来读取。

5. 总结

恭喜你!走到这一步,你已经成功地将一个本地运行的Gemma-3-270m模型,封装成了一个具备生产环境雏形的RESTful API服务。我们来回顾一下今天的成果:

  1. 搭建了基础框架:我们使用FastAPI快速搭建了一个Web服务,并定义了清晰的数据模型 (ChatRequest, ChatResponse)。
  2. 实现了核心逻辑:编写了 /v1/chat/completions 端点,它作为“中间人”,接收客户端的请求,转发给Ollama,再将处理好的结果返回给客户端。我们加入了完善的错误处理和日志记录。
  3. 提供了交互文档:得益于FastAPI,我们几乎零成本获得了一个强大的交互式API文档 (/docs),这对于前后端联调和测试非常方便。
  4. 探索了进阶可能:我们讨论了如何通过速率限制、API Key认证、流式响应等功能来增强服务的安全性、稳定性和用户体验。

现在,这个API已经可以作为一个独立的服务运行了。你可以:

  • 将它部署到服务器上,供你的团队内部使用。
  • 用它作为后端,快速开发一个聊天机器人Web界面或移动应用。
  • 将它集成到自动化工作流中,比如自动生成邮件、总结文档等。

这个项目是一个坚实的起点。你可以根据实际需求,继续为它添加更多功能,比如对话历史管理、多模型切换、性能监控等。希望这篇教程能帮你打开思路,将强大的大模型能力更灵活、更便捷地应用到你的各种项目中去。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐