😜 LLM 说"我不记得你了",因为它根本就没打算记

2 阅读7分钟

写在前面:今天学了一个让我"恍然大悟"的知识点——LLM 是"无状态"的。以前我以为 ChatGPT 记得我们聊过什么,是因为它"聪明"。结果老师说:不,它根本不记得,是你每次手动把聊天记录发给它,它才"假装"记得。我听完整个人都不好了——原来我一直被 AI "骗"了!


一、无状态:HTTP 的"健忘症"

1.1 什么是无状态?

老师说:

"调用 LLM 接口的本质是什么?HTTP 调用,算力生成结果。"

LLM 接口和普通的 RESTful API 一样,都是基于 HTTP 协议的。而 HTTP 协议本身是无状态的。

什么是"无状态"?

"每次请求都是独立的,不依赖于之前的请求。服务器不需要维护请求状态,只需要处理当前请求即可。"

通俗地说:服务器对每一个请求都"一视同仁",不管你是谁、之前聊过什么。

这就像你去理发店:

  • 有状态:Tony 老师记得你上次剪了什么发型,这次直接按上次的来。
  • 无状态:每次去都是新顾客,你得重新描述"两边推短、上面留长"。

1.2 为什么 LLM 要无状态?

老师说:

"有状态?你是谁?LLM 服务器压力太大了。"

如果 LLM 服务器要维护每个用户的对话状态:

  • 几亿用户同时在线,服务器内存直接爆炸。
  • 某台服务器挂了,用户状态就丢了,体验极差。
  • 无法水平扩展——新加的服务器没有老用户的状态。

无状态的好处:

特性说明
公平所有人一视同仁,没有"VIP 记忆"
可扩展随便加服务器,每台都能处理任何请求
高可用某台挂了,请求自动转到其他机器
简单服务器不需要维护复杂的会话状态

"所有人都公平"——无状态的核心哲学。


二、LLM 的"记忆"骗局:chatHistory 的真相

2.1 LLM 真的不记得你

看这段代码:

const chatHistory = [
    { role: "system", content: "你是一个严谨的助手" }
];

async function testStateless() {
    // 第一次请求:告诉模型我的名字
    chatHistory.push({
        role: "user",
        content: "请记住我的名字叫字节Q"
    });

    const response = await client.chat.completions.create({
        model: "deepseek-v4-flash",
        messages: chatHistory  // 带上全部历史
    });

    // 把模型回复也加入历史
    chatHistory.push({
        role: "assistant",
        content: response.choices[0].message.content
    });

    // 第二次请求:问它我叫什么
    chatHistory.push({
        role: "user",
        content: "请问我的名字是什么?"
    });

    const response2 = await client.chat.completions.create({
        model: "deepseek-v4-flash",
        messages: chatHistory  // 再次带上全部历史
    });
}

关键发现:每次请求都要带上 messages: chatHistory

LLM 根本不记得你之前说过什么。是你每次手动把聊天记录发过去,它才能"假装"记得。

这就像你和一个金鱼朋友聊天:

  • 金鱼只有 7 秒记忆(LLM 无状态)。
  • 但你每次聊天前,都把之前的对话写在纸条上给金鱼看(chatHistory)。
  • 金鱼看了纸条,说"哦对,你叫字节Q"。
  • 实际上金鱼根本没记住,它只是读了纸条。

2.2 代码演示:不带历史会怎样?

如果你第二次请求不带历史:

// 错误示范:不带 chatHistory
const response2 = await client.chat.completions.create({
    model: "deepseek-v4-flash",
    messages: [
        { role: "user", content: "请问我的名字是什么?" }
    ]
});

LLM 会一脸懵:"你是谁?我们认识吗?"

因为这次请求里没有任何上下文,LLM 只能根据当前问题回答——它根本不知道"你"是谁。


三、chatHistory 的隐患:Token 大爆炸

3.1 messages 越来越大,钱包越来越瘪

老师说:

"messages 越来越大,token 开销越大。"

每次请求都要带上全部历史,这意味着:

  • 聊得越久,chatHistory 越长。
  • 每次请求的 Token 数 = 历史 Token + 新问题 Token。
  • Token 就是钱,聊久了钱包受不了。

举个例子:

第 1 轮:历史 100 Token + 新问题 20 Token = 120 Token
第 2 轮:历史 120 Token + 新问题 20 Token = 140 Token
第 3 轮:历史 140 Token + 新问题 20 Token = 160 Token
...
第 50 轮:历史 1000+ Token + 新问题 20 Token = 1020+ Token

Token 消耗呈线性增长,钱包呈线性出血。

3.2 LRU 策略:给聊天记录"减肥"

老师说了一个解决方案:

"LRU:一次对话一直聊?任务还没完成。Tokens 开销变大,最近在聊的留下,久远了的可以适当删除。"

LRU(Least Recently Used,最近最少使用) 是一种缓存淘汰策略:

策略说明比喻
保留最近 N 条只保留最近的 10-20 条对话像微信聊天记录,只显示最近几条
按 Token 限制总 Token 不超过某个上限像手机存储满了,自动删旧照片
摘要压缩把久远对话压缩成摘要像写会议纪要,把长篇大论缩成几句话
// 简单的 LRU 实现:只保留最近 10 条
const MAX_HISTORY = 10;

function addMessage(chatHistory, message) {
    chatHistory.push(message);
    if (chatHistory.length > MAX_HISTORY) {
        // 保留 system 提示词,删除最早的用户/助手对话
        const systemMessages = chatHistory.filter(m => m.role === 'system');
        const otherMessages = chatHistory.filter(m => m.role !== 'system');
        const recentMessages = otherMessages.slice(-(MAX_HISTORY - systemMessages.length));
        return [...systemMessages, ...recentMessages];
    }
    return chatHistory;
}

这就像你的衣柜:空间有限,只能放最近常穿的衣服,旧衣服要么扔掉,要么收进箱子(摘要)。


四、从 Prompt Engineering 到 Loop Engineering:AI 协作的三次升级

4.1 三次升级路线

老师总结了 AI 协作方式的演进:

Prompt Engineering(提示词工程)
    ↓
Context Engineering(上下文工程)
    ↓
Loop Engineering(循环工程)

4.2 Prompt Engineering:抽卡式聊天

"历史对话、知识库 claude.md、agent.md 上下文。抽卡,prompt 质量或设计只能提升抽到金卡的概率,不是特别可控。"

Prompt Engineering 就是"写好提示词,让 AI 一次性给出好答案"。

但问题是:

  • 结果不可控——同样的 prompt,每次答案可能不一样。
  • 没有记忆——每次对话都是新的开始。
  • 像抽卡——prompt 写得好,只是提高了"抽到好答案"的概率。

4.3 Context Engineering:给 AI "喂"上下文

"RAG:LLM 不懂、没有,更加优质的 MCP、skill。"

Context Engineering 的核心:让 LLM 拥有更丰富的上下文。

技术作用
RAG检索增强生成,从知识库中检索相关信息
MCP模型上下文协议,标准化上下文传递
Skill预定义的技能模板,提升输出质量

Context Engineering 解决的是"LLM 不知道"的问题。 通过外部知识库、文档、技能,让 LLM 拥有更专业的知识。

4.4 Loop Engineering:让 AI 自己迭代

"Harness AI 工程。"

Loop Engineering 就是上一节课学的 AI Loop——让 AI 自己生成、检查、循环,直到满足条件。

阶段核心解决的问题
Prompt Engineering写好提示词一次性输出质量
Context Engineering丰富上下文LLM 知识不足
Loop Engineering自动化循环结果不可控

从"抽卡"到"喂知识"再到"自动迭代",AI 协作方式在持续进化。


五、总结:理解无状态,才能用好 LLM

知识点说明
无状态(Stateless)每次请求独立,服务器不维护状态
HTTP 无状态LLM 接口基于 HTTP,天然无状态
chatHistory手动维护对话历史,让 LLM "假装"有记忆
Token 开销历史越长,每次请求消耗的 Token 越多
LRU 策略保留最近对话,删除久远内容
Prompt Engineering优化提示词,提升一次性输出质量
Context Engineering丰富上下文,解决知识不足问题
Loop Engineering自动化循环,解决结果不可控问题

理解 LLM 的无状态本质,是正确使用它的前提。 不要幻想 LLM 会"记住"你——它不会。你要做的是:设计好 chatHistory 的管理策略,控制 Token 开销,用 Context 和 Loop 弥补无状态的不足。


写在最后

今天最大的收获,是打破了"LLM 有记忆"的幻觉。它每次回答你,都是基于你发送的完整上下文,而不是因为它"记得"。这个认知让我对 AI 的理解更深了一层——它不是人,不要用人性的方式去理解它。

下次面试官问你:"LLM 为什么是无状态的?"

你可以淡定地说:

"LLM 接口基于 HTTP 协议,HTTP 是无状态协议。每次请求都是独立的,服务器不维护任何会话状态。这样设计的好处是公平性、可扩展性和高可用性——所有请求一视同仁,服务器可以水平扩展,某台挂了不影响其他请求。为了让 LLM '记得'对话历史,需要客户端手动维护 chatHistory,每次请求带上全部 messages。但这也带来 Token 开销问题,需要通过 LRU 等策略控制历史长度。"

然后看着面试官满意的表情,心里默念:这波,又稳了。


本文所有代码示例均来自课堂学习资料,真实可运行。