Drogon 框架完全指南:C++ 后端开发的新选择

Drogon 框架完全指南:C++ 后端开发的新选择

目录

Drogon 框架完全指南:C++ 后端开发的新选择

Drogon 简介

环境搭建

快速入门:第一个 Drogon 应用

CMakeLists.txt

main.cpp

路由系统详解

routes.cpp

控制器模式

UserController.h

UserController.cpp

main.cpp

ORM 与数据库操作

首先创建模型类 User.h

DbUserController.h

DbUserController.cpp

main.cpp

中间件

LoggingMiddleware.h

LoggingMiddleware.cpp

AuthMiddleware.h

AuthMiddleware.cpp

main.cpp

配置文件

config.json

main.cpp

总结


Drogon(中文常被开发者亲切地称为 "龙")是一个基于 C++17 的高性能 HTTP/Web 框架,它让 C++ 开发 Web 应用变得简单而高效。本文将全面介绍 Drogon 框架的核心特性、使用方法和实战案例,帮助你快速上手这个强大的后端框架。

Drogon 简介

Drogon 是一个跨平台的 C++ 后端框架,具有以下特点:

  • 基于 C++17 标准,充分利用现代 C++ 特性
  • 异步非阻塞架构,性能卓越
  • 支持 HTTP 1.0/1.1,WebSocket
  • 内置 ORM 系统,轻松操作数据库
  • 支持 RESTful API 开发
  • 模块化设计,易于扩展
  • 轻量级,低资源消耗

环境搭建

首先,我们需要安装 Drogon 框架。以下是在 Ubuntu 系统上的安装步骤:

# 安装依赖 sudo apt-get install cmake g++ git libssl-dev zlib1g-dev libjsoncpp-dev # 克隆源码 git clone https://github.com/drogonframework/drogon.git cd drogon git submodule update --init # 编译安装 mkdir build cd build cmake .. make -j4 sudo make install 

快速入门:第一个 Drogon 应用

让我们创建一个最简单的 Drogon 应用,实现一个 "Hello World" 服务。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10) project(hello_drogon) # 设置C++标准 set(CMAKE_CXX_STANDARD 17) # 查找Drogon库 find_package(Drogon REQUIRED) # 添加可执行文件 add_executable(hello_drogon main.cpp) # 链接Drogon库 target_link_libraries(hello_drogon PRIVATE Drogon::Drogon) 

main.cpp

#include <drogon/drogon.h> int main() { // 设置路由 drogon::app().registerHandler("/", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody("Hello, Drogon!"); callback(resp); }); // 设置服务器监听地址和端口 drogon::app().addListener("0.0.0.0", 8080); // 启动服务器 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

编译运行:

mkdir build && cd build cmake .. make ./hello_drogon 

现在访问http://localhost:8080,你将看到 "Hello, Drogon!" 的响应。

路由系统详解

Drogon 的路由系统非常灵活,支持多种路由方式:

routes.cpp

#include <drogon/drogon.h> #include <string> using namespace drogon; void initRoutes() { // 1. 基本路由 app().registerHandler("/", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Home Page</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 2. 带参数的路由 app().registerHandler("/user/{name}", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, const std::string& name) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Hello, " + name + "!</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 3. 正则表达式路由 app().registerHandler("/product/(\\d+)", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, const std::string& productId) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Product ID: " + productId + "</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 4. 带HTTP方法限定的路由 app().registerHandler("/api/data", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"status": "success", "data": "example data"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Get}); // 5. 路由组 auto userApi = app().createResourceGroup("user_api", "/api/user"); userApi->registerHandler("/profile", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"name": "John Doe", "email": "[email protected]"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Get}); userApi->registerHandler("/update", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { // 处理用户更新逻辑 auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"status": "updated"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Post}); } int main() { app().addListener("0.0.0.0", 8080); initRoutes(); std::cout << "Server running on http://localhost:8080" << std::endl; app().run(); return 0; } 

控制器模式

对于大型应用,推荐使用控制器模式来组织代码:

UserController.h

#pragma once #include <drogon/HttpController.h> using namespace drogon; class UserController : public HttpController<UserController> { public: METHOD_LIST_BEGIN // 注册路由 ADD_METHOD_TO(UserController::getUser, "/user/{id}", HttpMethod::Get); ADD_METHOD_TO(UserController::createUser, "/user", HttpMethod::Post); ADD_METHOD_TO(UserController::updateUser, "/user/{id}", HttpMethod::Put); ADD_METHOD_TO(UserController::deleteUser, "/user/{id}", HttpMethod::Delete); METHOD_LIST_END // 控制器方法 void getUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; void updateUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void deleteUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; }; 

UserController.cpp

#include "UserController.h" #include <nlohmann/json.hpp> using json = nlohmann::json; void UserController::getUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟从数据库获取用户 json user = { {"id", id}, {"name", "John Doe"}, {"email", "[email protected]"} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(user.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { // 解析请求体 auto jsonBody = req->getJsonObject(); if (!jsonBody) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k400BadRequest); resp->setBody(R"({"error": "Invalid request body"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 模拟创建用户 json response = { {"status", "success"}, {"message", "User created"}, {"userId", 123} // 假设生成的用户ID }; auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k201Created); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::updateUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟更新用户 json response = { {"status", "success"}, {"message", "User updated"}, {"userId", id} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::deleteUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟删除用户 json response = { {"status", "success"}, {"message", "User deleted"}, {"userId", id} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } 

main.cpp

#include <drogon/drogon.h> #include "UserController.h" int main() { // 设置服务器端口 drogon::app().addListener("0.0.0.0", 8080); // 注册控制器 drogon::app().registerController(std::make_shared<UserController>()); // 运行应用 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

ORM 与数据库操作

Drogon 内置了强大的 ORM 系统,支持多种数据库。以下是使用 ORM 操作 MySQL 的示例:

首先创建模型类 User.h

#pragma once #include <drogon/orm/ORM.h> #include <string> using namespace drogon::orm; class User { public: // 定义表结构 std::string name; std::string email; int age = 0; std::string created_at; // 映射到数据库表 DROGON_MAPPING(User, (name, VARCHAR, 50) (email, VARCHAR, 100, UNIQUE) (age, INT) (created_at, TIMESTAMP) ) }; 

DbUserController.h

#pragma once #include <drogon/HttpController.h> #include "User.h" using namespace drogon; class DbUserController : public HttpController<DbUserController> { public: METHOD_LIST_BEGIN ADD_METHOD_TO(DbUserController::getAllUsers, "/db/users", HttpMethod::Get); ADD_METHOD_TO(DbUserController::getUserById, "/db/users/{id}", HttpMethod::Get); ADD_METHOD_TO(DbUserController::createUser, "/db/users", HttpMethod::Post); METHOD_LIST_END void getAllUsers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; void getUserById(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; }; 

DbUserController.cpp

#include "DbUserController.h" #include <nlohmann/json.hpp> #include <drogon/drogon.h> using json = nlohmann::json; using namespace drogon::orm; void DbUserController::getAllUsers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { // 获取数据库客户端 auto client = app().getDbClient(); // 查询所有用户 client->execSqlAsync( "SELECT * FROM users", [callback](const Result& result) { json response; for (const auto& row : result) { json user; user["id"] = row["id"].as<int>(); user["name"] = row["name"].as<std::string>(); user["email"] = row["email"].as<std::string>(); user["age"] = row["age"].as<int>(); user["created_at"] = row["created_at"].as<std::string>(); response.push_back(user); } auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } ); } void DbUserController::getUserById(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { auto client = app().getDbClient(); client->execSqlAsync( "SELECT * FROM users WHERE id = $1", [callback](const Result& result) { auto resp = HttpResponse::newHttpResponse(); if (result.size() == 0) { resp->setStatusCode(k404NotFound); resp->setBody(json{{"error", "User not found"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } const auto& row = result[0]; json user; user["id"] = row["id"].as<int>(); user["name"] = row["name"].as<std::string>(); user["email"] = row["email"].as<std::string>(); user["age"] = row["age"].as<int>(); user["created_at"] = row["created_at"].as<std::string>(); resp->setBody(user.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, id ); } void DbUserController::createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { auto jsonBody = req->getJsonObject(); if (!jsonBody || !jsonBody->isMember("name") || !jsonBody->isMember("email")) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k400BadRequest); resp->setBody(json{{"error", "Missing required fields"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } std::string name = (*jsonBody)["name"].asString(); std::string email = (*jsonBody)["email"].asString(); int age = jsonBody->isMember("age") ? (*jsonBody)["age"].asInt() : 0; auto client = app().getDbClient(); client->execSqlAsync( "INSERT INTO users (name, email, age, created_at) VALUES ($1, $2, $3, NOW()) RETURNING id", [callback](const Result& result) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k201Created); resp->setBody(json{ {"status", "success"}, {"message", "User created"}, {"userId", result[0]["id"].as<int>()} }.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, name, email, age ); } 

main.cpp

#include <drogon/drogon.h> #include "DbUserController.h" int main() { // 配置数据库连接 drogon::app().createDbClient("mysql", "localhost", 3306, "username", "password", "test_db"); // 设置服务器端口 drogon::app().addListener("0.0.0.0", 8080); // 注册控制器 drogon::app().registerController(std::make_shared<DbUserController>()); // 运行应用 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

中间件

Drogon 支持中间件,可以用于实现认证、日志、缓存等功能:

LoggingMiddleware.h

#pragma once #include <drogon/HttpMiddleware.h> using namespace drogon; class LoggingMiddleware : public HttpMiddleware<LoggingMiddleware> { public: void handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) override; }; 

LoggingMiddleware.cpp

#include "LoggingMiddleware.h" #include <chrono> #include <ctime> #include <iomanip> #include <sstream> void LoggingMiddleware::handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) { // 记录请求开始时间 auto start = std::chrono::high_resolution_clock::now(); // 创建自定义回调来记录响应信息 auto newCallback = [callback, start, req](const HttpResponsePtr& resp) { // 计算请求处理时间 auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); // 格式化时间 auto now = std::chrono::system_clock::now(); std::time_t now_time = std::chrono::system_clock::to_time_t(now); std::tm* tm = std::localtime(&now_time); std::stringstream ss; ss << std::put_time(tm, "%Y-%m-%d %H:%M:%S"); // 打印日志 std::cout << "[" << ss.str() << "] " << req->methodString() << " " << req->path() << " " << resp->statusCode() << " " << duration.count() << "µs" << std::endl; // 调用原始回调 callback(resp); }; // 调用下一个中间件或处理程序 next(req, std::move(newCallback)); } 

AuthMiddleware.h

#pragma once #include <drogon/HttpMiddleware.h> using namespace drogon; class AuthMiddleware : public HttpMiddleware<AuthMiddleware> { public: void handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) override; }; 

AuthMiddleware.cpp

#include "AuthMiddleware.h" #include <nlohmann/json.hpp> using json = nlohmann::json; void AuthMiddleware::handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) { // 检查Authorization头 auto authHeader = req->getHeader("Authorization"); if (!authHeader || authHeader->empty()) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k401Unauthorized); resp->setBody(json{{"error", "Authorization header missing"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 简单验证令牌 (实际应用中应该更复杂) if (*authHeader != "Bearer secret_token") { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k403Forbidden); resp->setBody(json{{"error", "Invalid or expired token"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 验证通过,调用下一个中间件或处理程序 next(req, std::move(callback)); } 

main.cpp

#include <drogon/drogon.h> #include "AuthMiddleware.h" #include "LoggingMiddleware.h" int main() { // 全局中间件 - 所有请求都会经过日志中间件 drogon::app().registerMiddleware(std::make_shared<LoggingMiddleware>()); // 路由级中间件 - 只有/api/protected/*路径会经过认证中间件 auto protectedApi = drogon::app().createResourceGroup("protected_api", "/api/protected") .addMiddleware(std::make_shared<AuthMiddleware>()); // 受保护的路由 protectedApi->registerHandler("/data", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody(R"({"data": "This is protected data"})"); resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); callback(resp); }, {drogon::HttpMethod::Get}); // 公开路由 drogon::app().registerHandler("/public/data", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody(R"({"data": "This is public data"})"); resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); callback(resp); }, {drogon::HttpMethod::Get}); // 启动服务器 drogon::app().addListener("0.0.0.0", 8080); std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

配置文件

对于复杂应用,推荐使用配置文件来配置 Drogon 应用:

config.json

{ "listeners": [ { "address": "0.0.0.0", "port": 8080, "https": false } ], "db_clients": [ { "name": "default", "type": "mysql", "host": "localhost", "port": 3306, "dbname": "test_db", "user": "username", "password": "password", "connections": 10 } ], "app": { "name": "My Drogon App", "description": "A sample application using Drogon framework", "version": "1.0.0" }, "log": { "level": "info", "log_to_console": true, "log_to_file": true, "log_file": "app.log" }, "workers": 4 } 

main.cpp

#include <drogon/drogon.h> int main() { // 从配置文件加载配置 drogon::app().loadConfigFile("config.json"); // 注册路由和控制器... drogon::app().registerHandler("/", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody("Hello from configured app!"); callback(resp); }); // 运行应用 std::cout << "Server running with config" << std::endl; drogon::app().run(); return 0; } 

总结

Drogon 框架为 C++ 开发者提供了一个现代化、高性能的后端开发解决方案。它充分利用了 C++17 的新特性,同时提供了简洁易用的 API,让开发者能够快速构建高性能的 Web 应用和 API 服务。

本文介绍了 Drogon 的核心功能,包括路由系统、控制器模式、ORM 数据库操作、中间件和配置文件等。通过这些功能,你可以构建出结构清晰、性能卓越的 C++ 后端应用。

Drogon 的学习曲线虽然比一些脚本语言框架陡峭,但对于需要高性能和低资源消耗的场景,它无疑是一个值得深入学习和使用的优秀框架。

如果你想了解更多关于 Drogon 的信息,可以访问其官方网站和 GitHub 仓库:

Read more

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

🐇明明跟你说过:个人主页 🏅个人专栏:《深度探秘:AI界的007》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、什么是Docker 2、什么是Ollama 二、准备工作 1、操作系统 2、镜像准备 三、安装 1、安装Docker 2、启动Ollama 3、拉取Deepseek大模型 4、启动Deepseek  一、引言 1、什么是Docker Docker:就像一个“打包好的App” 想象一下,你写了一个很棒的程序,在自己的电脑上运行得很好。但当你把它发给别人,可能会遇到各种问题: * “这个软件需要 Python 3.8,但我只有 Python 3.6!

By Ne0inhk
深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金术】,我们一起来解锁更加刺激的剧情!友情提醒:《《《前方高能》》》 目录 在哪使用DeepSeek 如何对提需求  隐藏玩法总结 几个高阶提示词 职场打工人 自媒体创作 电商实战 程序员开挂 非适用场地 “服务器繁忙”如何解决 (1)硅基流动平台 (2)Chatbox + API集成方案 (3)各大云平台 搭建个人知识库 前置准备 下载安装AnythingLLM 选择DeepSeek作为AI提供商 创作工作区 导入文档 编辑  编辑 小编寄语 ——————————————————————————————————————————— 在哪使用DeepSeek 我们解锁剧情前,肯定要知道在哪用DeepSeek!咯,为了照顾一些萌新朋友,它的下载方式我放在下面了,拿走不谢!  (1)

By Ne0inhk
【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek + 通义万相制作AI视频流程 4.1 DeepSeek + 通义万相制作视频优势 4.1.1 DeepSeek 优势 4.1.2 通义万相视频生成优势 4.2

By Ne0inhk
【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

系列篇章💥 No.文章01【DeepSeek应用实践】DeepSeek接入Word、WPS方法详解:无需代码,轻松实现智能办公助手功能02【DeepSeek应用实践】通义灵码 + DeepSeek:AI 编程助手的实战指南03【DeepSeek应用实践】Cline集成DeepSeek:开源AI编程助手,终端与Web开发的超强助力04【DeepSeek开发入门】DeepSeek API 开发初体验05【DeepSeek开发入门】DeepSeek API高级开发指南(推理与多轮对话机器人实践)06【DeepSeek开发入门】Function Calling 函数功能应用实战指南07【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:本地部署与API服务快速上手08【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:Web聊天机器人部署指南09【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:基于vLLM 搭建高性能推理服务器10【DeepSeek部署实战】基于Ollama快速部署Dee

By Ne0inhk