AI大模型基础(二)
一、大模型应用
GPT 与 ChatGPT:
首先先区分两者的差别: 是「模型」和「产品」的关系:GPT 是底层大模型,ChatGPT 是基于 GPT 模型做出来的对话产品。
1. GPT(Generative Pre-trained Transformer)
- OpenAI 研发的大语言模型系列名称
- 代表版本:GPT-3、GPT-3.5、GPT-4、GPT-4o 等
- 本质:一套神经网络权重、基础 AI 能力,可以被多种方式调用
2. ChatGPT
- OpenAI 推出的网页对话产品(应用)
- 底层使用 GPT-3.5 / GPT-4 模型
- 专门针对聊天对话场景微调、加了对话指令对齐
- 普通人在 chat.openai.com 网页使用的就是 ChatGPT
如图:


3. 如图二所示:传统程序和 AI 大模型的对比
传统程序
- ✅ 确定性强、结果稳定 ❌ 超出预设场景直接失效。
- 例子:写一个聊天机器人,你没写对应的问答,它就答不上来。
- 传统程序负责确定性业务(数据库、订单、权限、计算)
AI 大模型
- ✅ 泛化能力极强,能处理从没见过的新问题 ❌ 输出非确定性
- 同样提问两次答案可能不一样,容易出现幻觉(编造事实)
- 大模型负责模糊、自然语言、创意、理解类任务。
4. 大模型的应用结构:

4.1. 步骤流程:
- 用户发起提问 用户在前端页面输入问题,请求发送到咱们自研的传统 Web 服务。
- 传统应用:接收请求 + 前置合规检查 传统程序先做第一层校验:敏感词过滤、权限校验、用户鉴权、请求参数校验、限流。 👉 作用:拦住违规提问,避免无效调用大模型,节省 API 费用。
- 传统应用发起 HTTP 请求,调用大模型 API 后端组装 prompt、上下文聊天记录,通过网络调用大模型厂商开放的 HTTP 接口。
本质就是一次普通 HTTP 网络请求,和后端调用第三方快递接口、短信接口原理一致。
- 大模型服务内部:推理生成答案 大模型接收传入的文本,执行推理计算,输出回复内容(AI 核心能力)。
- 大模型通过 HTTP 响应,把生成结果传回传统应用
- 传统应用:结果后置合规检查 对 AI 返回的内容再次审核,过滤 AI 生成的违规内容、敏感信息。
- 传统应用整理结果,返回给前端用户展示
二、大模型云服务
目前国内绝大多数大模型云服务(豆包 API、通义千问、智谱、文心、Qwen 私有推理服务)基本兼容 OpenAI Chat Completions 协议,这是行业事实标准 ; 不同厂商大模型 API 只是域名、模型名字不同,请求格式、鉴权方式、消息结构高度标准化,全部沿用 OpenAI Chat Completions 规范,极大降低开发适配成本。

1. 差异点
- URL 接口地址不同:每家厂商域名、路径前缀不一样
-
- DeepSeek:
/chat/completions - Qwen:
/v1/chat/completions
- DeepSeek:
- model 模型标识名称不同:每个厂商自有模型代号,不能混用
- 细微参数拓展:各家会额外增加少量自有扩展字段(如上下文长度、工具调用参数),基础字段通用。
2. 工程价值(面试重点)
- 统一接口带来的好处 后端只需要写一套通用请求代码,切换模型服务商几乎不用大规模修改代码,只更换 URL、API_KEY、model 名称即可。 可以轻松实现多模型负载均衡、故障自动切换(通义千问挂了自动切 DeepSeek)。
- 结合你之前的流程图 图里「传统 Web 应用调用大模型 HTTP 接口」,底层发出去的网络请求,就是这样一条 curl 对应的 HTTP 请求。
- 重要提醒
API_KEY属于机密凭证,绝对不能放在前端,必须保存在后端服务,也就是前面架构图的传统应用层中转调用。
三、大模型的会话记忆
1. 核心结论
大模型本身没有持久化会话记忆! 模型推理服务只是一次性接收你传入的 messages 数组,生成回复;调用结束后,不会自动保存本次对话记录。 多轮聊天的记忆,完全依靠业务后端主动把历史对话拼入下一轮请求的 messages 参数传递给模型。
结合刚才的 curl 请求: 第一轮请求发送:[system, user] 模型返回 assistant 回答; 第二轮提问时,后端必须组装:[system, user, assistant, new user提问] 一并传给 API,模型才能 “记得上文”。
2. 举例说明:
第 1 轮请求 :
{
"model": "qwen-plus",
"messages": [
{"role":"system","content":"你是Java助手"},
{"role":"user","content":"什么是线程池?"}
],
"stream": false
}
模型输出回答 assistant 内容。
第 2 轮用户继续追问:“核心参数有哪些?” :
✅ 正确做法(携带上下文) 后端拼接全部历史消息一起传入:
{
"model": "qwen-plus",
"messages": [
{"role":"system","content":"你是Java助手"},
{"role":"user","content":"什么是线程池?"},
{"role":"assistant","content":"线程池是管理线程的容器..."},
{"role":"user","content":"核心参数有哪些?"}
]
}
模型能理解上下文,延续对话。
❌ 错误做法(不带历史) 只传新问题:
"messages": [{"role":"user","content":"核心参数有哪些?"}]
模型完全不知道你在问线程池,上下文断裂。
3. 会话记忆常见的问题:
每一条消息都会占用 token,对话越长,messages 体积越大。 每个模型都有上下文窗口上限(例如 128k tokens、32k tokens)。 一旦总 token 超限,接口直接报错。
3.1. 解决方案:
- 滑动窗口截断(最简单) 只保留最近 N 轮问答,丢弃最久远的历史消息。
- 摘要压缩(进阶方案) 历史久远对话交给大模型总结成简短摘要,用摘要替代大量原始对话,节省 token。
- RAG 检索分离(长期记忆方案) 久远知识不塞进 messages,当需要时通过向量库检索,动态追加相关片段,不占用对话窗口。
4. 两种记忆分类
4.1. 短期记忆(上下文记忆)
就是上面说的 messages 数组,每次请求携带,受模型窗口限制,对话关闭后可清理。
4.2. 2. 长期记忆(持久记忆)
将用户信息、历史偏好、重要内容存入数据库 / 向量库; 后续对话触发相关场景时,检索取出,动态注入 prompt,不受模型窗口限制。
4.3. 流式场景下
流式输出(stream=true)时: 模型分片返回 delta 增量文本; 后端必须等完整回答接收完毕,再把整条 assistant 消息存入会话历史,不能边接收边保存片段。
5. 面试常问:
问:大模型聊天为什么能记住之前的对话?
答:大模型本身不会保存对话记录。我们自研后端持久存储用户会话历史,每次调用大模型 API 时,把历史对话连同新问题一起放到 messages 数组传给模型,以此实现记忆;同时需要监控 token 长度,防止超出模型上下文窗口限制。
答: 我们采用 Redis 存储会话上下文,以 sessionId 作为 key 保存 messages 消息列表。用户每次提问先读取历史消息,拼接新问题调用大模型;拿到 AI 回复后追加消息写回 Redis。同时实现上下文 token 长度检测,超出模型窗口时滑动窗口截断旧消息;流式场景需要先在内存拼接完整回答,接收结束后再更新会话记录。
5.1. 解决方按:
- 使用 Redis 存储单轮会话完整
messages列表(key = 会话 sessionId)
-
- Redis Key:
chat:session:{sessionId}存储类型:List<Message>
- Redis Key:
- 用户发消息 → 读取 Redis 历史上下文
- 拼接新用户消息 → 调用大模型 API
- 接收模型完整回答 → 追加到 messages,写回 Redis
- 设置 Redis 过期时间,自动清理长期不活跃会话
5.2. 会话记忆伪代码:
/**
* 用户提问入口
* @param sessionId 会话唯一标识(前端传入)
* @param userQuery 用户最新提问
* @return 大模型返回回答
*/
public String chat(String sessionId, String userQuery){
// ========== 1. 读取历史会话上下文 ==========
List<Message> messages = redisTemplate.opsForList().range("chat:session:" + sessionId, 0, -1);
if(messages == null){
messages = new ArrayList<>();
// 首次会话:初始化system系统提示词
messages.add(new Message("system","你是一名专业Java后端工程师,回答简洁规范"));
}
// ========== 2. 将当前用户提问加入上下文 ==========
messages.add(new Message("user", userQuery));
// ========== 【重要】Token超限处理:滑动窗口截断(简化版) ==========
// 生产环境:计算总token数量,超出阈值就移除最早非system消息
while(calcTotalTokens(messages) > MODEL_MAX_WINDOW){
// 删除system之后第一条历史消息(保留system指令)
messages.remove(1);
}
// ========== 3. 调用大模型API(参考前面curl接口) ==========
ModelRequest request = new ModelRequest();
request.setModel("qwen-plus");
request.setMessages(messages);
request.setStream(false); // 阻塞模式演示
ModelResponse response = modelApiClient.call(request);
String assistantAnswer = response.getChoices().get(0).getMessage().getContent();
// ========== 4. 将模型回答追加进上下文,存入Redis ==========
messages.add(new Message("assistant", assistantAnswer));
// 覆盖写入Redis,设置会话过期时间 2小时
redisTemplate.opsForList().trim("chat:session:" + sessionId,0,-1);
redisTemplate.opsForList().rightPushAll("chat:session:" + sessionId, messages);
redisTemplate.expire("chat:session:" + sessionId,2, TimeUnit.HOURS);
return assistantAnswer;
}
5.2.1. 注意:
如果是流式输出需要先拼接出一个完整的 assistant 文本,流式接收全部结束后,一次性追加到消息 Redis 中
StringBuilder fullAnswer = new StringBuilder();
// 循环接收SSE分片
sseListener.onMessage(chunk->{
fullAnswer.append(chunk.getDeltaContent());
});
// 流式传输完成回调
sseListener.onComplete(()->{
messages.add(new Message("assistant", fullAnswer.toString()));
// 更新Redis会话
redis更新逻辑...
});
5.3. 生产环境优化点 :
- 持久化兜底:重要会话定时同步 MySQL,防止 Redis 丢失数据
- 会话清理策略:Redis TTL 过期、手动清空会话按钮
- 摘要优化:超长对话不只是截断,调用模型把远古对话压缩摘要
- 隔离:不同用户 sessionId 隔离,禁止上下文串号
- 并发控制:同一个 session 禁止并行发起多次大模型请求
更多推荐


所有评论(0)