学习目标
- 复盘本周学了啥,别学了就忘(搞定!✅)
- 搞懂 Token 到底是啥,为啥和字数不一样(搞定!✅)
- 理解 Context Window,知道为啥对话越长越慢(搞定!✅)
- 弄明白 AI 是怎么"一个字一个字"生成内容的(搞定!✅)
- 学会 System Prompt、Few-shot 这些进阶技巧(搞定!✅)
一、本周干了啥?
四天下来,其实就干了这几件事:
| Day | 干了啥 | 一句话总结 |
|---|---|---|
| 1 | 第一次调 API | 会发请求、拿回复了 |
| 2 | 多轮对话 | 会用 messages 存历史了 |
| 3 | 流式输出 | 会让 AI 边想边说了 |
| 4 | 参数调优 | 会用 temperature 控制风格了 |
看起来是四个独立的东西,其实背后都有共同的原理。今天来挖一挖。
二、Token 是啥?为啥和字数不一样?
2.1 每次返回都有这个
你调用 API 的时候,返回结果里一直有个 usage:
json
{
"usage": {
"prompt_tokens": 15,
"completion_tokens": 32,
"total_tokens": 47
}
}
之前没细说,今天解释一下:
| 字段 | 是啥 |
|---|---|
prompt_tokens |
你发过去的内容,消耗了多少 token |
completion_tokens |
AI 回的内容,消耗了多少 token |
total_tokens |
加起来,这次对话总共花了多少 |
重要在哪?
- API 收费按 token 收,不按字数
- token 太多会超限(后面讲 Context Window)
- token 越多处理越慢
2.2 Token ≠ 字数
这是最容易误解的地方。
Token 是大模型处理文本的"最小单位",但一个 token 不等于一个字!
arduino
英文:
"hello" → 1 token
"apple" → 1 token
"ChatGPT" → 2-3 tokens
中文:
"你好" → 1-2 tokens(看模型)
"人工智能" → 2-4 tokens
"好好学习天天向上" → 6-8 tokens
为什么会这样?
模型处理文本前,要先把文本"切开",这个过程叫 Tokenization(分词)。
不同模型切的方法不一样:
- GPT 用 BPE(Byte Pair Encoding)
- Claude 有自己的分词器
- 中文模型可能按字切,也可能按词切
反正记住:中文比英文"费 token",一个汉字可能要 1-2 个 token,英文一个词基本就 1 个 token。
2.3 写个代码看看
别光听我说,自己跑一下看看:
python
# 测不同内容的 token 消耗
test_cases = [
"hello",
"hello world",
"你好",
"你好,很高兴认识你",
"The quick brown fox jumps over the lazy dog"
]
for text in test_cases:
data = {
"model": "your-model",
"messages": [{"role": "user", "content": text}]
}
response = requests.post(url, headers=headers, json=data)
usage = response.json()["usage"]
print(f"'{text}' → {usage['prompt_tokens']} tokens")
跑出来大概是这样:
arduino
'hello' → 1 token
'hello world' → 2 tokens
'你好' → 1-2 tokens
'你好,很高兴认识你' → 4-8 tokens
2.4 实用建议
- 写 prompt 别写废话,省 token 省钱
- 成本估算用 token 数算,别用字数
- 英文比中文省钱(如果内容可以英文表达)
三、Context Window:为啥越聊越慢?
3.1 Day 2 遇到的问题还记得吗?
当时说:
越聊越慢,甚至报错
咋回事:messages 太长了,token 超限
咋办:删掉最早的部分历史
今天解释一下背后的原理。
3.2 Context Window 是啥?
简单说:模型一次能"记住"的最大 token 数量。
就像人的短期记忆有上限一样,模型也有:
| 模型 | 能记多少 |
|---|---|
| GPT-3.5 | 4K tokens(约 3000 字中文) |
| GPT-4 | 8K / 32K tokens |
| Claude 3 | 200K tokens(挺大的) |
| DeepSeek | 64K tokens |
注意 :这个限制是你发的 + AI 回的,加起来不能超过。
3.3 为什么会超限?
你的 messages 是这样一点点变长的:
yaml
聊了 1 轮:messages 里有 2 条 ≈ 20 tokens
聊了 10 轮:messages 里有 20 条 ≈ 200 tokens
聊了 100 轮:messages 里有 200 条 ≈ 2000 tokens
聊了 500 轮:... ≈ 10000 tokens → 可能超了!
超了会咋样?
- API 报错:
context_length_exceeded - 或者模型直接"失忆",忘了前面的内容
3.4 怎么管理?
方法一:滑动窗口(只留最近的)
python
MAX_HISTORY = 10 # 只留最近 10 条
# 每次对话后检查
if len(messages) > MAX_HISTORY:
messages = messages[-MAX_HISTORY:] # 删掉最早的
简单粗暴,大部分场景够用。
方法二:摘要压缩
对话太长了,让 AI 总结一下前面的内容:
python
if len(messages) > 20:
# 让 AI 总结
summary = call_ai("请一句话总结这段对话:" + str(messages[:-4]))
# 用摘要替换历史
messages = [{"role": "system", "content": "之前聊过:" + summary}] + messages[-4:]
方法三:关键信息单独存
python
# 用户的重要信息单独记
user_info = {"name": "小明", "goal": "学英语"}
# 每次对话都带上
system_prompt = f"用户叫{user_info['name']},目标是{user_info['goal']}"
这样即使删了历史,关键信息也不会丢。
四、AI 是怎么生成内容的?
4.1 流式输出暴露了啥
Day 3 学流式输出,AI 一个字一个字蹦:
erlang
AI:Python是...一种...编程语言...
这其实暴露了 AI 的生成方式:它不是想好整个答案再说出来,而是猜一个词,再猜下一个,再猜下一个...
4.2 逐 token 预测
erlang
你问:"今天天气"
AI 猜下一个词可能是:
"很好" (30%)
"不错" (25%)
"很差" (10%)
选了"很好",输入变成"今天天气很好"
再猜下一个词...
一直猜下去,直到:
- 碰到结束符号
- 超过 max_tokens
- 你中断
所以流式输出能工作,是因为模型本来就是逐 token 生成的,只是普通模式是"憋完再给你",流式是"猜出一个就给你一个"。
4.3 从这理解 Temperature
现在你能更好理解 temperature 了。
Temperature 影响的是"猜词的概率分布"
erlang
下一个词的候选:
"很好" → 30%
"不错" → 25%
"还行" → 20%
temperature = 0.1(低温):
"很好"的概率被放大到 80%
→ 更容易选它 → 输出稳定
temperature = 1.5(高温):
概率变得平均,每个词都差不多
→ 低概率词也有机会 → 输出随机、有创意
简单说:
- 低 temperature → AI 更"保守",选最可能的词
- 高 temperature → AI 更"大胆",可能选意想不到的词
4.4 还有什么参数能控制生成?
| 参数 | 干嘛的 |
|---|---|
top_p |
只从累计概率达到 p 的词里选 |
top_k |
只从概率最高的 k 个词里选 |
frequency_penalty |
惩罚重复出现的词 |
presence_penalty |
惩罚已经出现过的词(鼓励新话题) |
top_p 和 temperature 的区别:
temperature 是"调整概率分布的陡峭程度",top_p 是"直接砍掉低概率词"。
ini
top_p=0.9:
按概率排序,累计达到 90% 的词保留,其他扔掉
→ 扔掉那些特别离谱的选项
top_p=0.1:
只保留累计 10% 的词(可能就 1-2 个)
→ 更精准、更保守
一般只用 temperature 就够了,需要更精准时可以配合 top_p。
五、System Prompt:给 AI 设身份
5.1 你只用过 user
之前的 messages 都是这样的:
python
messages = [{"role": "user", "content": "你好"}]
其实还有个 system role:
python
messages = [
{"role": "system", "content": "你是教三年级小朋友的英语老师"},
{"role": "user", "content": "讲一下 cat"}
]
5.2 system 和 user 有什么区别?
| role | 是啥 |
|---|---|
system |
设定 AI 的身份、性格、规则 |
user |
你的问题 |
assistant |
AI 的回复 |
system 的优先级最高,影响整场对话。
5.3 看看效果对比
perl
没 system:
你:"讲一下 cat"
AI:"cat 是猫科动物,学名 Felis catus..."(太学术)
有 system:"你是教小朋友的英语老师"
你:"讲一下 cat"
AI:"小朋友们,cat 就是小猫咪!喵喵叫,很可爱哦~"
5.4 system 能干啥?
python
# 设角色
{"role": "system", "content": "你是资深 Python 程序员"}
# 设输出格式
{"role": "system", "content": "用 JSON 格式回复"}
# 设规矩
{"role": "system", "content": "回答不超过 50 字,不确定就说'不知道'"}
# 设知识范围
{"role": "system", "content": "你只知道三年级英语单词"}
六、Few-shot:给示例让 AI 学
6.1 之前的 prompt
python
{"role": "user", "content": "翻译成英文:你好"}
6.2 Few-shot 是啥?
先给几个示例,再让 AI 做同样的事:
python
messages = [
{"role": "user", "content": "翻译成英文:你好"},
{"role": "assistant", "content": "Hello"},
{"role": "user", "content": "翻译成英文:谢谢"},
{"role": "assistant", "content": "Thank you"},
{"role": "user", "content": "翻译成英文:很高兴认识你"} # AI 会学着格式回答
]
AI 看到示例后,会模仿同样的格式输出。
6.3 适合什么场景?
- 需要 AI 输出特定格式
- 任务规则复杂,说不清楚
- 分类任务(给几个分类示例)
七、Chain-of-Thought:让 AI 分步想
7.1 直接问容易出错
arduino
你:"小明有5个苹果,给小红2个,又买了3个,现在几个?"
AI:"6个"(可能直接跳答案,中间算错)
7.2 让它一步步想
python
{"role": "user", "content": "小明有5个苹果,给小红2个,又买了3个,现在几个?请一步步思考"}
AI 会这样回答:
ini
让我一步步想:
1. 小明原本有 5 个
2. 给小红 2 个,剩 5-2=3 个
3. 又买了 3 个,变成 3+3=6 个
答案:6 个
准确率会高很多。
7.3 适合什么场景?
- 数学题、逻辑题
- 需要推理的任务
- 复杂分析
八、结构化输出:让 AI 返回 JSON
8.1 为啥要 JSON?
程序处理 JSON 最方便,直接转成字典。
8.2 怎么写?
python
prompt = f"""
讲解单词 '{word}',返回 JSON 格式:
{
"word": "单词",
"meaning": "中文意思",
"phonetic": "音标",
"example": "例句"
}
只返回 JSON,别加别的。
"""
AI 返回:
json
{
"word": "cat",
"meaning": "猫",
"phonetic": "kæt",
"example": "I have a cat."
}
8.3 程序里怎么用?
python
import json
result = call_ai(prompt)
word_info = json.loads(result) # 直接转字典
print(word_info["meaning"]) # 输出:猫
九、Agent 开发的框架
昨天做的英语 Agent,其实已经是个简单的 Agent 了。
9.1 Agent 是什么?
Agent = 大模型 + 工具 + 记忆 + 决策
用户输入 → Agent 想想该干啥 → 选工具 → 执行 → 看结果 → 输出
9.2 ReAct 模式
这是 Agent 的经典套路:
bash
Thought(想):用户想学 cat,我得讲解
Action(做):调用 explain_word("cat")
Observation(看):拿到结果 "cat 是猫..."
Answer(答):整理输出给用户
你的英语 Agent 已经是这个模式了,只是用 Python 逻辑判断的。
9.3 记忆系统
Agent 得记住东西:
- 短期记忆:当前对话(messages 数组)
- 长期记忆:用户偏好、学习进度
短期你已经有了,长期可以这样加:
python
user_memory = {
"learned_words": ["cat", "dog"], # 学过的
"wrong_words": ["elephant"], # 错过的
}
system_prompt = f"用户学过:{user_memory['learned_words']}"
9.4 Function Calling(进阶,这里先简单知道,后面单独再学习)
下一步可以学:让 AI 自己决定调用哪个函数。
python
tools = [
{
"type": "function",
"function": {
"name": "explain_word",
"description": "讲解单词",
"parameters": {
"type": "object",
"properties": {
"word": {"type": "string", "description": "单词"}
},
"required": ["word"]
}
}
}
]
# 发请求带上 tools
data = {"model": "xxx", "messages": messages, "tools": tools}
# AI 返回说要调用函数
response["choices"][0]["message"]["tool_calls"] = [
{"id": "call_123", "function": {"name": "explain_word", "arguments": '{"word": "cat"}'}}
]
# 你执行函数,把结果返回给 AI
result = explain_word("cat")
messages.append({"role": "tool", "tool_call_id": "call_123", "content": result})
流程:
- 定义 tools
- 发请求带 tools
- AI 返回要调哪个函数
- 你执行,把结果返回
- AI 继续回复
十、踩坑记录
Q1: token 数和字数对不上
咋回事:中文 token 不是按字算的,一个汉字可能 1-2 token
咋办:别用字数估算成本,用 token 数算
Q2: 对话越长越慢,最后报错
咋回事:messages 太长,超过 Context Window 限制了
咋办:用滑动窗口,只保留最近 N 条消息
Q3: AI 回答风格不稳定
咋回事:没设 system prompt,AI 不知道自己是谁
咋办:加 system role,设定身份和规则
Q4: AI 输出格式乱七八糟
咋回事:没给示例,AI 不知道你想要啥格式
咋办:用 Few-shot,给几个示例让它学着
Q5: AI 数学题算错
咋回事:直接跳答案,中间推理错了
咋办:加"请一步步思考",用 Chain-of-Thought
Q6: max_tokens 设太小,回答被截断
咋回事:max_tokens 是"最多说多少",不是"要求说多少"
咋办:根据场景设合适的值,简短回答 50-100,讲解 300-500,故事 500+
十一、下周学习规划
| Day | 学啥 | 干啥 |
|---|---|---|
| 1 | Token 实验 | 写代码测不同内容的 token 数 |
| 2 | System Prompt | 给英语 Agent 加老师身份 |
| 3 | Few-shot + CoT | 做翻译示例,让 AI 分步思考 |
| 4 | 参数对比 | 同一个 prompt 用不同 temperature 看效果 |
| 5 | 记忆系统 | 给 Agent 加学习进度记录 |
| 6 | Function Calling | 让 AI 自己选调用哪个函数 |
十二、今日总结
今天干了啥:
✅ 复盘了本周四天的学习内容
✅ 搞懂了 Token 是啥,为啥和字数不一样
✅ 理解了 Context Window,知道咋管理对话历史
✅ 弄明白了 AI 是逐 token 生成的
✅ 学会了 System Prompt、Few-shot、CoT 这些技巧
✅ 知道了 Agent 开发的框架
下周目标:把这些理论变成代码,继续升级英语 Agent。
记于 2026-04-08,Week 1 总结,理论补齐了!
