《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
🎬 艾莉丝的简介:
文章目录
- 1 ~> ChatServer 接口整体测试体系
- 1.1 测试前置准备
- 1.1.1 接口清单录入(Apifox)
- 1.1.2 Apifox 环境配置
- 1.1.3 会话 ID 生成规则
- 2 ~> 逐个接口测试流程与业务逻辑
- 2.1 GET /api/models 获取可用模型
- 2.1.1 请求规约
- 2.1.2 返回 JSON 结构
- 2.1.3 测试校验点
- 2.2 POST /api/session 创建会话
- 2.2.1 请求规约
- 2.2.2 返回 JSON 结构
- 2.2.3 业务逻辑
- 2.3 GET /api/sessions 获取会话列表
- 2.3.1 请求规约
- 2.3.2 返回 JSON 结构
- 2.3.3 业务校验
- 2.4 DELETE /api/session/{session_id} 删除会话
- 2.4.1 请求规约
- 2.4.2 返回 JSON
- 2.4.3 业务校验
- 2.5 GET /api/session/{session_id}/history 获取会话历史消息
- 2.5.1 请求规约
- 2.5.2 典型故障点(代码 BUG 复盘)
- 2.5.3 校验标准
- 2.6 POST /api/message 发送消息‑全量返回
- 2.6.1 请求规约
- 2.6.2 业务逻辑
- 2.6.3 校验
- 2.7 POST /api/message/async 发送消息‑SSE 流式增量返回
- 2.7.1 请求规约
- 2.7.2 SSE 流式协议关键知识点
- 2.7.3 代码故障复盘
- 2.7.4 测试校验点
- 3 ~> 多模型兼容性测试
- 3.1 测试策略
- 3.2 外部模型环境依赖
- 3.3 测试流程示例(gpt‑4o‑mini)
- 4 ~> SQLite 数据库存储层关键要点
- 4.1 数据表
- 4.2 开发调试手段
- 5 ~> 整体排错方法论
- 结尾
1 ~> ChatServer 接口整体测试体系
1.1 测试前置准备
1.1.1 接口清单录入(Apifox)
共 7 个后端接口,服务基于 http‑lib 实现路由注册
表格
请求方法 接口路径 接口功能 POST /api/session创建会话 GET /api/sessions获取会话列表 GET /api/models获取可用模型列表 DELETE /api/session/{session_id}删除指定会话 GET /api/session/{session_id}/history获取会话历史消息 POST /api/message发送消息‑全量返回 POST /api/message/async发送消息‑流式增量返回
// ChatServer 路由注册核心代码片段voidChatServer::setupHttpRoutes(){// 创建会话_chatServer->Post(pattern="/api/session",handler=[this](consthttplib::Request&request,httplib::Response&response){handleCreateSessionRequest(request,response);});// 获取会话列表_chatServer->Get(pattern="/api/sessions",handler=[this](consthttplib::Request&request,httplib::Response&response){handleGetSessionListsRequest(request,response);});// 获取可用模型_chatServer->Get(pattern="/api/models",handler=[this](consthttplib::Request&request,httplib::Response&response){handleGetModelListsRequest(request,response);});// 删除会话_chatServer->Delete(pattern="/api/session/(.*)",handler=[this](consthttplib::Request&request,httplib::Response&response){handleDeleteSessionRequest(request,response);});// 获取会话历史消息_chatServer->Get(pattern="/api/session/(.*)/history",handler=[this](consthttplib::Request&request,httplib::Response&response){handleGetHistoryMessagesRequest(request,response);});// 发送消息-全量返回_chatServer->Post(pattern="/api/message",handler=[this](consthttplib::Request&request,httplib::Response&response){handleSendMessageRequest(request,response);});// 发送消息-流式增量返回_chatServer->Post(pattern="/api/message/async",handler=[this](consthttplib::Request&request,httplib::Response&response){handleSendMessageStreamRequest(request,response);});}1.1.2 Apifox 环境配置
- 配置测试环境前置 URL:
http://服务器IP:端口,示例http://192.168.100.238:8080 - 环境变量配置各类大模型 API‑KEY 密钥
- 接口录入规范
- 严格对齐 HTTP 请求方法、Path 路径参数、Body JSON 参数
- 测试阶段无需维护 Mock 响应结构体,仅校验请求可达性、返回数据有效性两个核心指标
- Path 参数禁止携带
$变量符号填入实际参数值,该符号为 Apifox 变量标识,直接填入会造成参数解析失败
1.1.3 会话 ID 生成规则
- 会话 ID 格式:
session_时间戳_序号 - 序号由服务内部静态计数器维护;服务器进程不重启,计数器持续累加,不会重置
- SessionManager 初始化会从数据库读取已有会话,恢复计数器基数
// 会话ID生成关键片段std::stringSessionManager::generateSessionId(){// _sessionCounter 静态成员变量,进程生命周期持续自增_sessionCounter.fetch_add(1);std::time_t t=std::time(nullptr);return"session_"+std::to_string(t)+"_"+std::to_string(_sessionCounter);}2 ~> 逐个接口测试流程与业务逻辑
2.1 GET /api/models 获取可用模型
2.1.1 请求规约
- HTTP 方法:GET,无请求参数
2.1.2 返回 JSON 结构
{"success":true,"message":"get model lists success","data":[{"name":"deepseek-chat","desc":"一款基于Deepseek的实用性强、功能强大的、中文优化的通用聊天模型,用于生成自然语言回复,适合用于聊天、问答、对话等场景"}]}2.1.3 测试校验点
- HTTP 200;success 字段为 true;data 数组返回全部配置好的模型元数据。
2.2 POST /api/session 创建会话
2.2.1 请求规约
- HTTP 方法:POST
- Content‑Type: application/json
- 请求 Body
{"model":"deepseek-chat"}2.2.2 返回 JSON 结构
{"success":true,"message":"create session success","data":{"model":"deepseek‑chat","session_id":"session_1789031979_00000001"}}2.2.3 业务逻辑
- 指定模型创建全新会话,生成唯一 session_id;会话初始化消息计数为 0;写入 SQLite 数据库
sessions表。
2.3 GET /api/sessions 获取会话列表
2.3.1 请求规约
- HTTP 方法:GET,无请求参数
2.3.2 返回 JSON 结构
{"success":true,"message":"get session lists success","data":[{"id":"session_1789049548_00000002","model":"deepseek‑r1:1.5b","created_at":1789049548,"updated_at":1789049548,"message_count":0}]}2.3.3 业务校验
- 返回全部持久化会话集合;message_count 统计该会话下问答消息总条数。
2.4 DELETE /api/session/{session_id} 删除会话
2.4.1 请求规约
- HTTP 方法:DELETE
- Path 参数:
session_id会话唯一标识
2.4.2 返回 JSON
{"success":true,"message":"delete session success"}2.4.3 业务校验
- 删除会话数据库记录;再次调用获取会话列表接口,该会话不再出现在 data 数组。
2.5 GET /api/session/{session_id}/history 获取会话历史消息
2.5.1 请求规约
- HTTP 方法:GET
- Path 参数:
session_id
2.5.2 典型故障点(代码 BUG 复盘)
- SQLite 执行判断条件错误:
sqlite3_step执行查询单条记录,执行成功读取行返回SQLITE_ROW;查询结束无更多数据返回SQLITE_DONE。- 原始错误:判断返回值不等于
SQLITE_DONE,直接判定执行失败;单条查询读完数据之后会进入SQLITE_DONE,直接返回空会话指针,提示 session not found。
- 原始错误:判断返回值不等于
// 错误代码片段intrc=sqlite3_step(stmt);if(rc!=SQLITE_DONE){// 错误:单条记录读取完毕 rc=SQLITE_DONE,误判为执行失败}// 修正后逻辑intrc=sqlite3_step(stmt);if(rc!=SQLITE_ROW){// 只有读到行才算有效数据,SQLITE_DONE代表查询结束}- Apifox 测试故障:Path 参数误输入带
$的模板变量标识,后端拿到非法 session_id,返回会话不存在。
2.5.3 校验标准
- 根据 session_id 读取 messages 表,返回该会话完整历史问答消息集合。
2.6 POST /api/message 发送消息‑全量返回
2.6.1 请求规约
- POST,Content‑Type:application/json
{"session_id":"session_xxxx","message":"请讲一个笑话"}2.6.2 业务逻辑
- 根据 session_id 定位会话;校验会话合法性
- 将用户提问持久化写入 messages 表
- 调用大模型 SDK 完成完整对话,等待模型全部应答完成
- 将模型完整回答写入 messages 表;更新会话
updated_at时间戳与message_count计数 - 将完整模型应答一次性返回客户端。
2.6.3 校验
- 返回完整应答文本;获取历史消息接口可以看到新增两条消息(用户提问 + 模型回复)。
2.7 POST /api/message/async 发送消息‑SSE 流式增量返回
2.7.1 请求规约
- POST,Content‑Type:application/json,请求体与全量接口完全一致。
2.7.2 SSE 流式协议关键知识点
Response 的 Content‑Type 必须设置为
text/event‑stream,禁止使用 application/json;application/json 会让客户端把整体当做 JSON 报文解析,不会逐块流式渲染。SSE 报文格式:
data: 分片内容\n\n data: 分片内容\n\n data:[DONE]\n\ndata: [DONE]为流结束标记;HTTP 长连接保持,分块传输 chunked 编码。
2.7.3 代码故障复盘
- 预发送空数据块防客户端长等待的 BUG
// 错误代码,第二个参数last=true直接标记流结束,连接立刻关闭writeChunk("",true);// 修复代码 last=false,代表不是流的最后一块writeChunk("",false);writeChunk 第二个布尔参数 last 语义:true 表示当前 chunk 是流的最后一个分片,发送
data:[DONE]结束 SSE 会话;false 代表后续还有数据分片。
- 响应头 content‑type 错误写成
application/json,客户端无法逐片解析事件流。
// 错误response->set_chunked_content_provider("application/json",providerLambda);// 修正response->set_chunked_content_provider("text/event‑stream",providerLambda);// 流式请求处理修正后完整核心逻辑voidChatServer::handleSendMessageStreamRequest(consthttplib::Request&request,httplib::Response&response){std::string sessionId=request.json["session_id"].asString();std::string message=request.json["message"].asString();if(sessionId.empty()||message.empty()){response->status=400;return;}response->status=200;response->set_header("Cache‑Control","no‑cache");response->set_header("Connection","keep‑alive");// SSE必须使用 text/event‑streamresponse->set_chunked_content_provider("text/event‑stream",[this,sessionId,message](size_t offset,httplib::DataSink&dataSink)->bool{autowriteChunk=[&](conststd::string&chunk,boollast)->void{// 转SSE报文格式std::string sseData="data: "+json::valueToQuotedString(chunk.c_str())+"\n\n";dataSink.write(sseData.c_str(),sseData.size());if(last){std::string doneData="data: [DONE]\n\n";dataSink.write(doneData.c_str(),doneData.size());dataSink.done();}};// 发送空块,防止客户端超时等待;last=false,流不关闭writeChunk("",false);// 调用SDK流式回调_chatSDK->sendMessageStream(sessionId,message,writeChunk);returntrue;});}2.7.4 测试校验点
- Apifox 时间线分片接收模型输出文本,逐块到达;
- 流末尾收到
data: [DONE]结束标记; - 会话消息计数更新;历史消息接口可以拿到完整问答。
3 ~> 多模型兼容性测试
3.1 测试策略
- 基础会话、会话列表、删除会话、获取模型接口仅需针对一个模型完成验证。
- 其余模型只需要重点验证全量返回、SSE 流式增量返回两个消息发送接口。
3.2 外部模型环境依赖
- 云端模型(GPT 系列等)服务器访问受限场景,启动服务进程前需要配置代理环境变量。
- Ollama 本地模型无需外网代理,服务本地访问 ollama 服务端口。
3.3 测试流程示例(gpt‑4o‑mini)
- POST
/api/session,body 指定"model":"gpt‑4o‑mini"创建会话拿到 session_id - 调用 POST
/api/message全量接口发送提问,校验完整应答返回 - 调用 POST
/api/message/async流式接口,校验 SSE 分片输出正常。
4 ~> SQLite 数据库存储层关键要点
4.1 数据表
sessions表:存储会话元数据:session_id、model 名称、created_at、updated_at、message_countmessages表:存储会话所有对话消息,关联 session_id 外键。
4.2 开发调试手段
- 使用 sqlite3 命令行工具直接打开 db 文件,select 查询表数据,确认业务数据是否真正持久化,区分「内存对象正常」与「数据库持久化异常」两类 BUG。
5 ~> 整体排错方法论
- 分层定位:
- Apifox 层:检查请求 URL、Path 参数、JSON 请求体、请求头 Content‑Type;排除参数拼写错误、混入 Apifox 模板变量符号。
- HTTP 服务层:看服务终端日志,确认请求已经抵达后端;区分网络不通、路由未匹配、参数解析失败。
- SDK / 业务逻辑层:日志打印关键入参出参,区分 HTTP 链路正常,业务逻辑 BUG。
- 数据库层:命令行直连 sqlite 数据库,确认数据是否真正写入。
- 修改 SDK 底层代码后完整操作流程
- 修改源码;
- 执行编译;
make install更新系统静态库与头文件;- 重新编译链接 ChatServer 可执行程序;
- 重启 ChatServer 服务,执行接口复测。
重点:静态库更新之后,上层服务必须重新编译链接,否则运行程序依旧加载旧版本 SDK 二进制。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
|
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
【AI大模型接入SDK】ChatServer问题修复
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა