【三个月 AI Agent 实战学习】Day 3 详细展开:Transformer 直觉(下)—— 上下文窗口与温度采样
Day 3 详细展开Transformer 直觉下—— 上下文窗口与温度采样欢迎来到第三天今天我们将完成 Transformer 直觉的最后一块拼图并动手实验两个对实际开发至关重要的概念上下文窗口Context Window和温度Temperature。理解它们将帮助你更好地控制模型的行为避免踩坑。一、今日学习目标理解上下文窗口是什么为什么它决定了模型能“记住”多少内容。掌握 Temperature 参数的作用它如何控制模型输出的随机性与确定性。通过代码实验直观感受不同 Temperature 值对生成文本的影响。学会使用tiktoken计算输入文本的 Token 数并处理超长输入截断或摘要。了解max_tokens与上下文窗口的关系以及如何处理输出截断问题。二、详细实现步骤步骤 1上下文窗口Context Window的概念大语言模型在处理文本时并不是逐字逐句地“阅读”而是将整个输入包括系统提示、历史对话、用户问题拼接成一个 Token 序列然后一次性输入到 Transformer 中。这个序列的最大长度就是上下文窗口。DeepSeek-chat 的上下文窗口是 64K Token即约 64000 个 Token。这意味着你的messages列表中所有内容的 Token 总数 模型将要生成的 Token 数不能超过这个限制。如果输入超过了窗口API 会报错通常提示maximum context length。上下文窗口决定了模型能“看到”多少信息。对于 Agent 来说这意味着对话历史不能无限累积必须进行管理裁剪、摘要或使用外部记忆。为什么重要在构建 Agent 时你经常需要将工具返回的结果、历史对话、知识库片段拼接起来。如果不加控制很容易撑爆窗口导致请求失败。步骤 2动手实验 —— 不同 Temperature 下的生成差异Temperature 控制采样时的随机性。值越低模型越倾向于选择概率最高的词确定性高值越高模型越可能选择概率较低的词创造性高但可能跑题或产生胡言乱语。新建temperature_experiment.pyimportosfromdotenvimportload_dotenvfromopenaiimportOpenAI load_dotenv()clientOpenAI(api_keyos.getenv(DEEPSEEK_API_KEY),base_urlhttps://api.deepseek.com)prompt请写一首关于秋天的五言绝句要求押韵。temperatures[0,0.5,1.0,1.5]fortempintemperatures:responseclient.chat.completions.create(modeldeepseek-chat,messages[{role:user,content:prompt}],temperaturetemp,max_tokens60,seed42# 设置随机种子DeepSeek 支持 seed 参数可使结果可复现)contentresponse.choices[0].message.contentprint(f--- Temperature {temp}---)print(content)print()运行脚本python temperature_experiment.py观察与思考Temperature 0模型几乎是贪婪解码输出非常确定通常每次运行结果相同如果设置了seed则完全一致。诗句可能比较“保守”但可能缺乏新意。Temperature 1.5模型开始“放飞自我”可能会出现不常见的词语、奇怪的搭配甚至语句不通顺。创造性高但质量不稳定。Temperature 1.0是默认值通常是一个平衡点。对于需要事实准确性的任务如数学计算、知识问答应该使用较低的 Temperature0 或 0.2对于创意写作、头脑风暴可以适当提高0.7~1.0。步骤 3处理上下文窗口 —— 超长输入的测试与截断现在我们编写一个脚本演示如何检测输入长度并处理超长情况。新建context_window_demo.pyimportosimporttiktokenfromdotenvimportload_dotenvfromopenaiimportOpenAI load_dotenv()clientOpenAI(api_keyos.getenv(DEEPSEEK_API_KEY),base_urlhttps://api.deepseek.com)# 使用 tiktoken 进行 Token 估算DeepSeek 推荐使用 cl100k_base 近似enctiktoken.get_encoding(cl100k_base)defcount_tokens(text:str)-int:returnlen(enc.encode(text))deftruncate_text(text:str,max_tokens:int)-str:将文本截断到 max_tokens 个 Token 以内tokensenc.encode(text)iflen(tokens)max_tokens:returntext truncated_tokenstokens[:max_tokens]returnenc.decode(truncated_tokens)# 模拟一个很长的用户输入重复一段话long_text人工智能正在改变世界。*2000# 大约 2000 * 10 20000 字符Token 数可能更多print(f原始文本长度字符:{len(long_text)})print(f原始文本 Token 数:{count_tokens(long_text)})# 假设我们设定一个安全阈值例如只保留前 5000 Token 作为上下文MAX_INPUT_TOKENS5000truncated_texttruncate_text(long_text,MAX_INPUT_TOKENS)print(f截断后 Token 数:{count_tokens(truncated_text)})# 现在用截断后的文本调用模型这里我们只截取一部分实际可能还需要加系统提示等try:responseclient.chat.completions.create(modeldeepseek-chat,messages[{role:system,content:你是文本摘要助手请总结用户输入的核心内容。},{role:user,content:truncated_text}],temperature0.2,max_tokens100)print(模型摘要:,response.choices[0].message.content)exceptExceptionase:print(调用失败:,e)# 另外故意发送超过上下文窗口的文本可选注意可能会产生费用谨慎操作# 这里我们模拟一个超过 64K Token 的文本但为了不真的发送只演示计算huge_text测试 *40000# 大约 40000 个 Token? 实际可能更多print(f\n模拟超长文本 Token 数:{count_tokens(huge_text)})ifcount_tokens(huge_text)64000:print(警告此文本超过了 DeepSeek 的 64K 上下文窗口直接发送会报错。)# 实际可以尝试发送但会报错不建议花这个钱运行脚本python context_window_demo.py观察与思考我们使用了tiktoken来估算 Token 数这是防止上下文溢出的第一步。truncate_text函数简单粗暴地截断了尾部但在实际应用中你可能需要更智能的策略如保留开头和结尾或使用摘要模型。在实际开发中你应该根据模型的最大上下文窗口减去max_tokens输出预留来设置输入的安全阈值。测试超长文本时可以先计算 Token 数而不发送请求避免浪费。步骤 4max_tokens与输出截断max_tokens参数控制模型最多生成多少个 Token。如果生成的文本达到这个上限模型会停止输出可能导致句子不完整。你需要根据上下文窗口预留足够的输出空间。修改temperature_experiment.py将max_tokens设得很小例如 10观察输出是否被截断# 在上述脚本中将 max_tokens 改为 10再运行一次responseclient.chat.completions.create(modeldeepseek-chat,messages[{role:user,content:prompt}],temperature0.7,max_tokens10)print(截断输出:,response.choices[0].message.content)print(结束原因:,response.choices[0].finish_reason)# 可能为 lengthfinish_reason为length表示因为达到max_tokens而停止这通常不是我们想要的结果需要增加max_tokens或让模型在有限 Token 内完成。三、常见问题与调试Q1设置temperature0后为什么输出仍然不完全确定→ 理论上temperature0应该使用贪婪解码每次选择概率最高的词但实际 API 可能仍然存在浮点计算差异或模型服务端的微小随机性。此外如果你没有设置seed参数多次调用可能因服务器负载导致细微差异。对于确定性要求高的场景可以设置seedDeepSeek 支持并固定所有参数。Q2如何知道我的输入到底有多少 Token→ 使用tiktoken的encode方法进行估算。对于非 OpenAI 模型比如 DeepSeek官方推荐使用cl100k_base编码虽然可能不是 100% 精确但足够用来规划。Q3我的对话历史太长除了截断还有什么办法→ 常见策略有滑动窗口只保留最近的 N 条消息。摘要使用模型将较旧的历史摘要成一段简短的文本再拼接到新的上下文中。向量检索我们后面会学到将历史对话存入向量数据库只检索最相关的部分。Q4上下文窗口是不是越大越好→ 上下文窗口越大模型能一次处理的信息越多但也有缺点更长的输入意味着更多的计算量成本更高、速度更慢而且模型对长文本中间部分的注意力可能下降“迷失在中间”现象。因此合理管理上下文比盲目追求大窗口更重要。四、今日总结与作业今天你完成了✅ 理解了上下文窗口的概念及其限制。✅ 通过实验对比了不同 Temperature 值对生成结果的影响学会了如何选择适合任务的温度。✅ 使用tiktoken计算 Token 数并实现了简单的文本截断。✅ 了解了max_tokens与输出截断的关系。今日作业必做写一个 Python 脚本让模型用三种不同的 Temperature0、0.7、1.5分别为同一个产品比如“智能手表”写一句广告语对比风格差异。编写一个函数safe_chat(messages, max_input_tokens5000)该函数接收消息列表计算总 Token 数如果超过max_input_tokens则自动裁剪最早的消息或采取其他策略然后调用模型并返回结果。测试该函数。思考题在构建一个客服 Agent 时如果用户连续问了 20 个问题对话历史很可能超过上下文窗口。你打算如何设计记忆管理策略用文字描述你的思路不需要代码。明日预告我们将进入 Prompt 工程的基础篇学习 Zero-shot 和 Few-shot 提示技巧并通过实验感受提供示例的重要性。有任何问题欢迎随时提问