一、Token 是什么?
Token = LLM 处理文字的基本单位
我们平时看到的是:
今天天气很好,我想出去散步。
但是 LLM 通常不会直接把"字、词、句子"作为最底层输入,而是先经过 Tokenizer(分词器) 把文本拆成 Token。
例如:
今天天气很好
可能被拆成类似:
["今天", "天气", "很", "好"]
英文:
I love programming.
可能拆成:
["I", " love", " programming", "."]
注意:Token 不等于汉字,也不等于单词。
具体怎么切,是由模型使用的 Tokenizer 决定的。
二、为什么 LLM 要使用 Token?
因为神经网络不能直接理解:
我喜欢编程
它需要先把文本转换成数字。
大致过程:
人类文本
↓
Tokenizer
↓
Token
↓
Token ID
↓
Embedding
↓
神经网络
↓
预测下一个 Token
例如:
我喜欢编程
可能变成:
Token:
["我", "喜欢", "编程"]
↓
Token ID:
[1234, 5678, 9012]
然后模型处理这些数字。
三、Token 和字数是什么关系?
这是开发 LLM 应用时非常重要的一点。
Token ≠ 字符数 ≠ 单词数。
例如中文:
你好,世界
可能是:
["你好", ",", "世界"]
也可能是其他拆分方式。
英文:
Artificial intelligence
可能被拆成:
["Artificial", " intelligence"]
而比较复杂的单词甚至可能被拆成多个 Token。
所以在开发 LLM 应用时,不应该简单认为:
1000 个汉字 = 1000 Token
或者:
1000 个英文单词 = 1000 Token
实际 Token 数取决于 模型和 Tokenizer。
四、为什么开发者特别关心 Token?
因为很多 LLM API 的计费和限制都是以 Token 为基础。
通常会涉及:
Input Tokens
+
Output Tokens
=
Total Tokens
例如:
用户输入:1000 Tokens
模型输出:500 Tokens
总使用量:1500 Tokens
因此开发 AI 应用时,经常需要关注:
Token 数量
↓
Context Window
↓
API 成本
↓
响应速度
五、Context Window 是什么?
可以把它理解成:
模型一次能够放进"工作记忆"里处理的最大 Token 数量。
例如某个模型:
Context Window = 128K Tokens
意思是:
一次请求中:
系统提示词
+
用户消息
+
历史对话
+
工具调用
+
其他上下文
+
模型输出
需要受到这个上下文容量限制。
六、用程序员熟悉的方式理解 Context Window
可以把它类比成:
Context Window ≈ 程序运行时可用的工作区
例如你和 AI 聊天:
第 1 轮:
用户:你好
AI:你好
第 2 轮:
用户:介绍一下 Go
AI:......
第 3 轮:
用户:Gin 是什么?
AI:......
第 4 轮:
用户:那它和 Echo 有什么区别?
AI:......
模型为了理解:
"它"
可能需要看到前面的:
Gin
所以应用程序通常需要把相关历史消息重新放进 Context:
System Prompt
+
历史消息
+
当前用户消息
↓
Context
↓
LLM
七、Context Window 不等于"记忆"
这是非常容易混淆的概念。
例如:
Context Window
解决的是:
模型当前这一次请求能够看到多少内容。
而:
Memory
解决的是:
跨多次对话保存哪些信息。
例如:
用户第一次说:
我是一名 Go 开发者。
如果下一次请求没有把这个信息放进 Context,模型未必能基于当前请求看到它。
所以 AI 应用经常采用:
长期记忆
↓
数据库 / 向量数据库
↓
检索
↓
相关内容
↓
Context
↓
LLM
这就是很多 AI Agent / RAG 系统的基本思路。
八、Context Window 为什么会成为问题?
假设:
Context Window = 128K
你有一个超长聊天记录:
历史对话:100K Tokens
当前问题:5K Tokens
系统 Prompt:5K Tokens
那么:
100K + 5K + 5K
= 110K
已经占用了大部分 Context。
如果继续加入:
RAG 检索结果
+
工具调用结果
+
新的用户消息
就可能越来越接近限制。
因此实际 AI 应用经常需要:
-
历史消息截断
-
对话摘要
-
RAG 检索
-
Context 压缩
-
删除无关信息
-
分页读取文档
九、Temperature 是什么?
Temperature 可以理解成:
控制模型生成结果"随机性"的参数。
例如你问:
写一句关于春天的句子。
Temperature 较低:
春天万物复苏,百花盛开。
Temperature 较高:
春风像一位调皮的画家,把整个城市涂成了绿色。
两者都可能合理,但是后者的表达空间更大。
十、Temperature 到底改变了什么?
LLM 本质上是在做:
预测下一个 Token。
假设模型预测:
今天天气____
模型可能得到:
很好 0.60
不错 0.20
晴朗 0.10
不错呢 0.05
糟糕 0.05
Temperature 会影响模型对这些候选 Token 的选择分布。
Temperature 较低
概率分布更加"尖锐":
很好 ████████████
不错 ███
晴朗 █
其他
模型更加倾向于选择高概率 Token。
结果通常:
稳定
确定
一致
Temperature 较高
概率分布更加"平":
很好 ██████
不错 ████
晴朗 ███
其他 ██
其他候选 Token 被选择的可能性增加。
结果可能更加:
多样
随机
有创造性
十一、Temperature 应该怎么设置?
没有绝对标准,但可以用一个简单的经验理解:
| 场景 | Temperature 思路 |
|---|---|
| 数据提取 | 低 |
| JSON 输出 | 低 |
| SQL 生成 | 低 |
| 代码生成 | 低~中 |
| 技术问答 | 低~中 |
| 普通聊天 | 中 |
| 文案生成 | 中~高 |
| 小说/创意写作 | 高 |
例如:
用户:
从下面文本中提取姓名、手机号、地址。
Temperature:
较低
因为你希望:
输入相同
↓
输出尽可能稳定
而不是:
今天提取一个格式
明天换一个格式
后天又换一个格式
十二、Streaming 是什么?
Streaming 可以理解成:
模型生成一点,就马上返回一点。
非 Streaming:
用户
↓
API
↓
LLM
↓
生成完整答案
↓
一次性返回
↓
用户看到结果
例如:
等待 8 秒
↓
"你好,我可以帮助你解决这个问题......"
Streaming:
用户
↓
API
↓
LLM
↓
生成 Token
↓
立即返回
↓
继续生成
↓
继续返回
用户看到的效果:
你好
你好,我
你好,我可以
你好,我可以帮助
你好,我可以帮助你
你好,我可以帮助你解决
...
这就是 ChatGPT 这类产品常见的"打字机效果"。
十三、Streaming 的核心原理
假设模型最终生成:
你好,我可以帮助你解决这个问题。
模型不是一定要:
全部生成完成
↓
一次性返回
而可以产生:
Token 1 → 你好
Token 2 → ,
Token 3 → 我
Token 4 → 可以
Token 5 → 帮助
Token 6 → 你
...
然后服务端不断向客户端发送。
典型架构:
┌─────────────┐
│ LLM │
└──────┬──────┘
│
Token Token
│
▼
┌─────────────┐
│ Backend │
└──────┬──────┘
│
Streaming
│
▼
┌─────────────┐
│ Browser │
└─────────────┘
十四、Streaming 通常使用什么技术?
Web 应用里面常见:
方案一:SSE
Server-Sent Events
Browser
│
│ HTTP
▼
Backend
│
│ text/event-stream
▼
Browser
特别适合:
AI 对话
LLM 输出
实时日志
实时状态
例如:
Content-Type: text/event-stream
服务端不断发送:
data: 你好
data: ,我
data: 可以
data: 帮助你
前端不断接收并拼接:
你好
↓
你好,我
↓
你好,我可以
↓
你好,我可以帮助你
十五、也可以使用 WebSocket
WebSocket:
Client
↕
WebSocket
↕
Server
↕
LLM
它适合:
双向实时通信
实时聊天
Agent 状态
语音
实时控制
但是如果只是:
用户发送一个问题 → AI 流式返回答案
SSE 往往已经足够。
十六、以Go语言为例 ,后端实现 Streaming
func stream(w http.ResponseWriter) {
// 设置 SSE
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
for {
token := getNextToken()
if token == "" {
break
}
fmt.Fprintf(w, "data: %s\n\n", token)
// 立即刷新
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
}
}
核心其实就三件事情:
1. HTTP 长连接
2. 不断写入数据
3. Flush 立即发送
十七、完整的 LLM 请求可以这样理解
把这 4 个概念串起来:
用户输入
│
▼
┌─────────────┐
│ Tokenizer │
└──────┬──────┘
│
Tokens
│
▼
┌─────────────────────────┐
│ Context Window │
│ │
│ System Prompt │
│ 历史消息 │
│ 用户输入 │
│ RAG结果 │
│ Tool结果 │
└───────────┬─────────────┘
│
▼
LLM
│
Temperature
控制采样随机性
│
▼
Token Token Token
│
▼
Streaming
│
▼
前端显示
所以可以记成:
| 概念 | 解决什么问题 | 程序员理解 |
|---|---|---|
| Token | 模型处理什么单位 | 字节/字符/词的某种模型化单位 |
| Context Window | 模型一次能看多少 | 工作内存/上下文容量 |
| Temperature | 模型怎么选择输出 | 随机采样程度 |
| Streaming | 输出怎么传给用户 | 流式 HTTP/SSE |
十八、做AI 应用开发,应该重点掌握什么?
做AI 应用开发,这 4 个概念建议按照下面的层次掌握:
第一层:LLM 基础
│
├── Token
├── Tokenizer
├── Context Window
├── Prompt
└── Temperature
│
▼
第二层:LLM API
│
├── Chat Completion
├── Streaming
├── Structured Output
├── Function Calling
└── Embedding
│
▼
第三层:AI 应用
│
├── RAG
├── Vector Database
├── Agent
├── Tool Calling
└── Memory
│
▼
第四层:AI 工程
│
├── Prompt Engineering
├── Evaluation
├── Observability
├── Cost Optimization
├── Context Engineering
└── Production Deployment