【AI大模型接入SDK】Trae生成main方法

🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:


文章目录

  • [1 ~> ChatServer main.cpp 工程实现](#1 ~> ChatServer main.cpp 工程实现)
    • [1.1 整体需求规约](#1.1 整体需求规约)
      • [1.1.1 业务需求清单](#1.1.1 业务需求清单)
      • [1.1.2 文件约束](#1.1.2 文件约束)
    • [1.2 ServerConfig 结构体定义](#1.2 ServerConfig 结构体定义)
    • [1.3 gflags 参数定义 main.cpp 头部](#1.3 gflags 参数定义 main.cpp 头部)
    • [1.4 工具函数实现](#1.4 工具函数实现)
      • [1.4.1 环境变量读取工具](#1.4.1 环境变量读取工具)
      • [1.4.2 信号处理回调函数](#1.4.2 信号处理回调函数)
      • [1.4.3 参数校验函数 validateConfig](#1.4.3 参数校验函数 validateConfig)
      • [1.4.4 帮助打印函数 showAPIInfo](#1.4.4 帮助打印函数 showAPIInfo)
    • [1.5 main 主函数完整实现](#1.5 main 主函数完整实现)
    • [1.6 ChatServer::start 内部线程实现 (ChatServer.cpp)](#1.6 ChatServer::start 内部线程实现 (ChatServer.cpp))
  • [2 ~> ChatServer.conf 配置文件模板](#2 ~> ChatServer.conf 配置文件模板)
  • [3 ~> 环境变量配置(云端 API 密钥)](#3 ~> 环境变量配置(云端 API 密钥))
  • [4 ~> 关键易错点总结(面试高频)](#4 ~> 关键易错点总结(面试高频))
    • [4.1 gflags flagfile 加载顺序](#4.1 gflags flagfile 加载顺序)
    • [4.2 线程模型关键点](#4.2 线程模型关键点)
    • [4.3 信号处理注意事项](#4.3 信号处理注意事项)
    • [4.4 密钥安全规范](#4.4 密钥安全规范)
    • [4.5 头文件路径坑](#4.5 头文件路径坑)
    • [4.6 参数校验边界](#4.6 参数校验边界)
  • [5 ~> CMakeLists.txt 关键片段](#5 ~> CMakeLists.txt 关键片段)
  • [6 ~> 程序运行命令示例](#6 ~> 程序运行命令示例)
  • 结尾


1 ~> ChatServer main.cpp 工程实现

背景: 基于 C++ + gflags + spdlog 二次封装日志库,实现 AI 聊天服务入口 main 程序;核心职责:参数解析、配置校验、日志初始化、信号处理、服务启动、主线程保活。

1.1 整体需求规约

1.1.1 业务需求清单

  • 使用 gflags 库定义全部ServerConfig配置项;参数来源优先级:gflags 默认值 < ChatServer.conf 配置文件 < 命令行参数
  • 网络服务默认绑定地址0.0.0.0,端口8080;默认日志级别INFO
  • 云端大模型(deepseek /chatgpt/gemini)API 密钥从操作系统环境变量读取,禁止通过命令行传入;Ollama 全套配置通过 gflags 命令行 / 配置文件提供
  • 模型默认参数:temperature=0.7,max_tokens=2048
  • 配置文件ChatServer.conf放置在 ChatServer 项目目录,由 gflags 原生 flagfile 机制加载,禁止手写自定义配置解析逻辑,禁止代码生成配置文件
  • 命令行功能:
    • -h / --help:打印帮助文档、使用示例、全部 HTTP API 接口说明
    • -v / --version:打印程序版本号,默认版本1.0.0
  • 参数合法性校验规则
    1. temperature 取值范围必须0.0 ~ 2.0
    2. max_tokens 必须大于 0,不能为负数
    3. 云端 API Key 至少存在一个不为空;若填写 Ollama 任意一项,则 Ollama 全部三项配置(模型名称、描述、endpoint)必须全部非空
  • 服务器业务线程:ChatServer 内部将 HTTP 服务运行在独立 detach 分离线程;main 主线程负责保活、信号响应,不能阻塞在服务监听逻辑。
  • 日志模块:项目 sdk 封装 spdlog 日志bite::Logger,头文件安装到系统 include,直接引入<ai_chat_sdk/util/myLog.h>,禁止使用相对路径引用头文件。

1.1.2 文件约束

  • main.cpp 存放路径:ChatServer 目录下
  • 需求文档:ChatServer/required/main需求.txt

1.2 ServerConfig 结构体定义

文件位置 ChatServer/ChatServer.h

cpp 复制代码
#pragma once
#include <string>
#include <httplib.h>

namespace ai_chat_server
{
struct ServerConfig
{
    // 网络服务配置
    std::string host = "0.0.0.0";
    int port = 8080;
    std::string logLevel = "INFO";

    // LLM模型公共参数
    double temperature = 0.7;
    int maxTokens = 2048;

    // 云端模型密钥,从环境变量读取
    std::string deepseekAPIKey;
    std::string chatGPTAPIKey;
    std::string geminiAPIKey;

    // Ollama本地大模型配置,由gflags参数传入
    std::string ollamaModelName;
    std::string ollamaModelDesc;
    std::string ollamaEndpoint;
};

class ChatServer
{
public:
    explicit ChatServer(const ServerConfig& config);
    bool start();
    void stop();
    bool isRunning() const;

private:
    // http路由、业务处理成员省略
};
}

1.3 gflags 参数定义 main.cpp 头部

cpp 复制代码
#include "ChatServer.h"
#include <ai_chat_sdk/util/myLog.h>
#include <gflags/gflags.h>
#include <fstream>
#include <thread>
#include <csignal>
#include <cstdlib>

// 网络服务参数
DEFINE_string(host, "0.0.0.0", "服务器绑定监听地址");
DEFINE_int32(port, 8080, "HTTP服务监听端口");
DEFINE_string(log_level, "INFO", "日志级别: TRACE|DEBUG|INFO|WARN|ERROR|CRITICAL");
DEFINE_string(config_file, "./ChatServer.conf", "gflags配置文件路径(flagfile格式)");

// LLM模型公共参数
DEFINE_double(temperature, 0.7, "模型温度,取值范围0.0~2.0");
DEFINE_int32(max_tokens, 2048, "模型最大输出token数量");

// Ollama相关参数,命令行/配置文件传入
DEFINE_string(ollama_model_name, "", "Ollama模型名称");
DEFINE_string(ollama_model_desc, "", "Ollama模型描述信息");
DEFINE_string(ollama_endpoint, "", "Ollama服务API地址,例如http://127.0.0.1:11434");

constexpr const char* VERSION = "1.0.0";

// 全局服务器智能指针,用于信号回调访问服务实例
namespace ai_chat_server {
std::unique_ptr<ChatServer> g_server;
std::atomic<bool> g_running{true};
}

1.4 工具函数实现

1.4.1 环境变量读取工具

cpp 复制代码
// 读取系统环境变量,不存在返回空字符串
static std::string getEnvVar(const std::string& key)
{
    const char* val = std::getenv(key.c_str());
    return val ? std::string(val) : "";
}

1.4.2 信号处理回调函数

捕获SIGINT(Ctrl+C)、SIGTERM信号,优雅停止服务,安全退出进程

cpp 复制代码
static void signalHandler(int sig)
{
    using namespace ai_chat_server;
    (void)sig;
    g_running.store(false);
    if(g_server)
    {
        g_server->stop();
    }
}

1.4.3 参数校验函数 validateConfig

cpp 复制代码
static bool validateConfig(const ai_chat_server::ServerConfig& config)
{
    // 校验temperature范围
    if(config.temperature < 0.0 || config.temperature > 2.0)
    {
        ERR("配置校验失败: temperature必须处于0.0~2.0,当前值={}", config.temperature);
        return false;
    }

    // maxTokens必须大于0
    if(config.maxTokens <= 0)
    {
        ERR("配置校验失败: max_tokens必须大于0,当前值={}", config.maxTokens);
        return false;
    }

    // 云端密钥:至少有一个API Key不为空
    bool hasCloudKey = !config.deepseekAPIKey.empty()
                    || !config.chatGPTAPIKey.empty()
                    || !config.geminiAPIKey.empty();

    // Ollama:只要任意一个字段非空,则全部三个字段必须全部配置
    bool hasAnyOllama = !config.ollamaModelName.empty()
                     || !config.ollamaModelDesc.empty()
                     || !config.ollamaEndpoint.empty();

    bool ollamaComplete = !config.ollamaModelName.empty()
                       && !config.ollamaModelDesc.empty()
                       && !config.ollamaEndpoint.empty();

    if(hasAnyOllama && !ollamaComplete)
    {
        ERR("配置校验失败:Ollama配置项不能部分填写,model_name、model_desc、endpoint必须同时提供");
        return false;
    }

    // 必须至少拥有云端key,或者完整Ollama配置
    if(!hasCloudKey && !ollamaComplete)
    {
        ERR("配置校验失败:至少配置一个云端API Key,或者一套完整Ollama模型配置");
        return false;
    }
    return true;
}

1.4.4 帮助打印函数 showAPIInfo

-h / --help触发,打印参数说明、启动示例、全部 REST API 接口清单

cpp 复制代码
static void showAPIInfo()
{
    std::cout << "\n==== AIChatServer 使用帮助 ====\n";
    std::cout << "版本: " << VERSION << "\n\n";
    std::cout << "启动示例:\n";
    std::cout << "  ./AIChatServer                          使用默认参数启动\n";
    std::cout << "  ./AIChatServer --port=9000              指定端口启动\n";
    std::cout << "  ./AIChatServer --config_file=./ChatServer.conf 加载配置文件\n";
    std::cout << "\n环境变量设置示例(云端密钥):\n";
    std::cout << "  export DEEPSEEK_API_KEY=xxx\n";
    std::cout << "\n可用HTTP API接口:\n";
    std::cout << "  POST  /api/session          创建会话\n";
    std::cout << "  GET   /api/sessions         获取全部会话列表\n";
    std::cout << "  GET   /api/models           获取可用模型列表\n";
    std::cout << "  DELETE/api/session/{id}     删除指定会话\n";
    std::cout << "  GET   /api/session/{id}/history 获取会话历史\n";
    std::cout << "  POST  /api/message          发送消息,全量返回\n";
    std::cout << "  POST  /api/message/async    发送消息,流式返回\n";
    std::cout << "\n";
}

1.5 main 主函数完整实现

执行流程:

  1. 设置 gflags 提示文本、版本字符串
  2. 原生 gflags 解析命令行
  3. 判断配置文件是否存在,使用gflags::SetCommandLineOption("flagfile",xxx)加载配置文件
  4. 打印帮助文档判断
  5. 注册信号捕获
  6. 组装 ServerConfig 结构体:云端 key 读环境变量,Ollama 参数读取 gflags
  7. 参数合法性校验
  8. 初始化 spdlog 日志器,设置日志级别
  9. 实例化 ChatServer,调用 start (),内部 HTTP 服务运行在 detach 分离子线程
  10. 主线程循环保活,等待停止信号
  11. 服务退出,程序返回
cpp 复制代码
int main(int argc, char** argv)
{
    using namespace ai_chat_server;
    try
    {
        // gflags初始化
        gflags::SetUsageMessage("AI聊天服务,AI ChatServer");
        gflags::SetVersionString(VERSION);
        // 解析命令行参数,remove_flags=true将解析过的flag从argv移除
        gflags::ParseCommandLineFlags(&argc, &argv, true);

        // 使用gflags原生flagfile加载配置文件,禁止手写配置解析逻辑
        std::ifstream confFile(FLAGS_config_file);
        if(confFile.is_open())
        {
            gflags::SetCommandLineOption("flagfile", FLAGS_config_file.c_str());
            confFile.close();
            INFO("成功加载配置文件:{}", FLAGS_config_file);
            // 注意:flagfile会重新触发参数解析,优先级:命令行 > flagfile > 默认值
        }
        else
        {
            WARN("配置文件{}不存在,将仅使用命令行与默认参数", FLAGS_config_file);
        }

        // -h / --help 打印帮助信息
        if(argc >= 1)
        {
            std::string opt(argv[1]);
            if(opt == "-h" || opt == "--help")
            {
                showAPIInfo();
                return 0;
            }
        }

        // 注册信号处理器,捕获Ctrl+C、进程终止信号
        signal(SIGINT, signalHandler);
        signal(SIGTERM, signalHandler);

        // =========组装ServerConfig配置=========
        ServerConfig config;
        config.host = FLAGS_host;
        config.port = FLAGS_port;
        config.logLevel = FLAGS_log_level;
        config.temperature = FLAGS_temperature;
        config.maxTokens = FLAGS_max_tokens;

        // 云端大模型密钥从系统环境变量读取,不在命令行暴露密钥
        config.deepseekAPIKey = getEnvVar("DEEPSEEK_API_KEY");
        config.chatGPTAPIKey = getEnvVar("CHATGPT_API_KEY");
        config.geminiAPIKey = getEnvVar("GEMINI_API_KEY");

        // Ollama参数全部取自gflags命令行/配置文件
        config.ollamaModelName = FLAGS_ollama_model_name;
        config.ollamaModelDesc = FLAGS_ollama_model_desc;
        config.ollamaEndpoint = FLAGS_ollama_endpoint;

        // 参数安全校验
        if(!validateConfig(config))
        {
            ERR("服务配置校验失败,程序退出");
            return EXIT_FAILURE;
        }

        // =========初始化spdlog封装日志器bite::Logger=========
        spdlog::level::level_enum logLevel = spdlog::level::info;
        if(config.logLevel == "TRACE") logLevel = spdlog::level::trace;
        else if(config.logLevel == "DEBUG") logLevel = spdlog::level::debug;
        else if(config.logLevel == "INFO") logLevel = spdlog::level::info;
        else if(config.logLevel == "WARN") logLevel = spdlog::level::warn;
        else if(config.logLevel == "ERROR") logLevel = spdlog::level::err;
        else if(config.logLevel == "CRITICAL") logLevel = spdlog::level::critical;

        // 初始化日志实例;输出至控制台+日志文件chat_server.log
        bite::Logger::initLogger("ChatServer", "chat_server.log", logLevel);

        // 打印启动配置信息
        INFO("==== AIChatServer启动配置 ====");
        INFO("版本号:{}", VERSION);
        INFO("监听地址:{}:{}", config.host, config.port);
        INFO("日志级别:{}", config.logLevel);
        INFO("temperature:{}", config.temperature);
        INFO("max_tokens:{}", config.maxTokens);
        INFO("DeepSeek Key:{}", config.deepseekAPIKey.empty() ? "未设置" : "已设置");
        INFO("ChatGPT Key:{}", config.chatGPTAPIKey.empty() ? "未设置" : "已设置");
        INFO("Gemini Key:{}", config.geminiAPIKey.empty() ? "未设置" : "已设置");
        INFO("Ollama模型:{}", config.ollamaModelName.empty() ? "未启用" : config.ollamaModelName);

        // 创建服务实例,ChatServer::start内部启动独立detach线程运行http服务
        g_server = std::make_unique<ChatServer>(config);
        bool startOk = g_server->start();
        if(!startOk)
        {
            ERR("ChatServer服务启动失败");
            return EXIT_FAILURE;
        }
        INFO("ChatServer启动成功,地址 http://{}:{}", config.host, config.port);
        INFO("按下 Ctrl+C 停止服务");

        // =========主线程保活循环=========
        // http服务运行在子线程;主线程不能立刻return,否则进程直接退出
        // g_running原子布尔,收到SIGINT/SIGTERM会被置false,退出循环
        while(g_running.load() && g_server->isRunning())
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        INFO("收到停止信号,服务正常退出");
        g_server.reset();
        return EXIT_SUCCESS;
    }
    catch(const std::exception& e)
    {
        ERR("程序发生异常: {}", e.what());
        return EXIT_FAILURE;
    }
    catch(...)
    {
        ERR("程序发生未知异常");
        return EXIT_FAILURE;
    }
}

1.6 ChatServer::start 内部线程实现 (ChatServer.cpp)

HTTP 服务运行在 detach 分离线程,不阻塞 main 主线程

cpp 复制代码
bool ChatServer::start()
{
    // ...省略路由初始化代码
    std::thread serverThread([this](){
        _chatServer->listen(_config.host, _config.port);
    });
    // detach分离线程,线程独立运行,不需要主线程join
    serverThread.detach();
    _isRunning.store(true);
    return true;
}

2 ~> ChatServer.conf 配置文件模板

放置于 ChatServer 目录;gflags flagfile 格式,每行写--flag_name=value,#代表注释;程序代码不生成该文件,由使用者手动编写维护

conf 复制代码
# ChatServer.conf gflags flagfile配置文件
# 网络服务配置
--host=0.0.0.0
--port=8080
--log_level=INFO

# LLM公共参数
--temperature=0.7
--max_tokens=2048

# Ollama本地模型配置,使用ollama才需要打开注释
#--ollama_endpoint=http://127.0.0.1:11434
#--ollama_model_name=deepseek‑r1:1.5b
#--ollama_model_desc="本地部署开源推理模型"

3 ~> 环境变量配置(云端 API 密钥)

API 密钥属于敏感信息,不在配置文件 / 命令行明文存储,设置 Linux shell 环境变量

bash 复制代码
# ~/.bashrc 添加
export DEEPSEEK_API_KEY="sk‑xxxx"
export CHATGPT_API_KEY="sk‑xxxx"
export GEMINI_API_KEY="xxxx"

# 生效配置
source ~/.bashrc

# 验证环境变量是否生效
echo $DEEPSEEK_API_KEY

4 ~> 关键易错点总结(面试高频)

4.1 gflags flagfile 加载顺序

  1. gflags 内置默认值
  2. flagfile 配置文件参数
  3. 命令行传入参数(优先级最高,覆盖配置文件)
  • 错误做法:手写文件解析,字符串切割模拟 flagfile;正确:调用gflags::SetCommandLineOption("flagfile", path)交给库原生解析。

4.2 线程模型关键点

  • ChatServer HTTP 监听运行在detach()分离子线程;
  • main 主线程必须保留循环保活,如果 main 直接 return,整个进程会销毁,子线程同步终止,服务立刻停止;
  • 使用std::atomic<bool>原子变量做运行标记,在信号处理器修改原子标记,保证多线程内存可见性。

4.3 信号处理注意事项

  • 信号回调函数上下文限制:不能执行复杂 IO、不能调用 spdlog 打印日志;只修改原子标记、调用 stop、重置智能指针。
  • 捕获SIGINT(Ctrl+C),SIGTERM(kill 命令终止进程),实现优雅关闭。

4.4 密钥安全规范

  • 云端 API 密钥禁止 gflags 命令行参数传入;命令行参数可以被 ps 命令全局查看,造成密钥泄露;
  • 密钥从操作系统环境变量读取。

4.5 头文件路径坑

日志库头文件已经安装进系统 include 目录,#include <ai_chat_sdk/util/myLog.h>;禁止使用#include "../sdk/include/util/myLog.h"相对路径,跨编译环境会编译失败。

4.6 参数校验边界

  1. temperature 闭区间[0.0, 2.0];
  2. max_tokens 严格大于 0;
  3. Ollama 配置:部分字段填写属于非法状态,要么全部为空,要么三项全部非空;
  4. 整体至少有一套可用模型:云端 key OR 完整 Ollama 配置。

5 ~> CMakeLists.txt 关键片段

cmake 复制代码
project(AIChatServer)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 依赖库 gflags spdlog
find_package(gflags REQUIRED)
find_package(spdlog REQUIRED)

add_executable(AIChatServer
    ChatServer/main.cpp
    ChatServer/ChatServer.cpp
)

target_link_libraries(AIChatServer
    gflags::gflags
    spdlog::spdlog
    ai_chat_sdk
)

6 ~> 程序运行命令示例

bash 复制代码
# 1. 默认参数启动,读取ChatServer.conf
./AIChatServer

# 2. 指定端口,命令行参数优先级高于配置文件
./AIChatServer --port=9000

#3. 指定自定义配置文件路径
./AIChatServer --config_file=./my.conf

#4. 查看帮助文档
./AIChatServer -h

#5. 查看版本
./AIChatServer -v

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 艾莉丝努力练剑 C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 *** ** * ** *** 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! 不要忘记给博主"一键四连"哦! "今日练剑达成!" "技术之路难免有困惑,但同行的人会让前进更有方向。" |

结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!

往期回顾:

【AI大模型接入SDK】Trae生成代码介绍

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

相关推荐
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章114-视觉与http通讯
图像处理·人工智能·opencv·计算机视觉·c#
伯奥克客服1 小时前
AI视频过滤器工程选型指南:接口、离线推理与联动控制
人工智能·音视频
落樱弥城1 小时前
FlashAttention 完全解析:从 Roofline 诊断到 CUDA 实现
人工智能·算法
JJJennie7771 小时前
大模型网关部署方案?MAI Gateway从部署到上线全流程
人工智能·gateway·ai网关
隔窗听雨眠1 小时前
从行为引导到基础设施约束:AGI代理风险缓解的工程化路径
网络·人工智能·agi
tellmewhoisi1 小时前
深度学习21:PyTorch:激活函数(Sigmoid,Tanh,ReLU,Softmax)
人工智能·pytorch·深度学习
ahccqw1 小时前
Opencv 基础常用API
人工智能·opencv·计算机视觉
FelixZhang0281 小时前
不懂金融或不会编程,如何开始量化?从策略搭建到回测验证
人工智能·python·算法·数学建模·均值算法·自然语言处理·金融
pt10431 小时前
Cisco设备网络安全系列-16:微服务、Kubernetes与无服务器架构安全
网络·安全·微服务·架构