最近在准备 Claude 相关体系化学习时很多同学都卡在同一个地方第一次调用 Claude API 成功后不知道如何让模型在多轮对话里保持上下文也不知道 System Prompt 到底应该放在哪个位置、和用户消息有什么区别。这两个问题恰好是 Claude API 知识体系中非常关键的组成也是很多人从“能调通接口”走向“能设计完整对话应用”的分水岭。这篇文章围绕 Claude API 学习路线的第二部分展开聚焦 Conversations多轮会话与 System系统提示两个核心概念。文章会从最基础的概念讲起配合完整的 Python 和 HTTP 调用示例逐步演示如何实现带角色设定的多轮对话并整理高频报错的排查思路和工程落地建议。无论你是准备 Claude 相关认证还是在做实际项目集成这篇文章都能帮你把基础打牢。1. 背景与核心概念1.1 什么是 Conversations在 Claude API 的语境里Conversations 表示的并不是一个像数据库会话那样由服务端长期维持的连接而是模型在一次连续交互中看到的消息序列。Claude 的 Messages API 设计上是无状态的。也就是说每一次请求模型并不会自动记住你上一次问了什么。为了让模型在多轮对话中表现正常客户端必须把之前的对话历史拼接好在每次请求时一起发给 API。这个由历史消息组成的序列就是 Conversations。从研究者的角度看这有点像语言模型的工作记忆机制模型每处理一个新请求都要重新读取全部相关上下文才能生成合理回复。因此 Conversations 的管理本质上是一个“上下文重建”的过程。1.2 什么是 System与 Conversations 不同System 是独立于用户消息和助手回复之外的一条指令层用来设定模型在整个对话期间需要遵守的全局规则。System Prompt 可以做的事情非常多比如指定角色身份例如“你是一名资深后端工程师”规定输出格式例如“请以 JSON 返回”划定回答边界例如“只回答与数据库相关的问题”注入业务约束例如“如果信息不足请明确要求用户补充”。在 Claude API 的请求参数中System 是通过顶层参数传入的而不是放在 messages 数组里作为一条普通消息。这一点非常重要很多新手会把 system 消息写成 messages 数组里的role: system导致行为不符合预期。1.3 为什么掌握这两部分是认证和实战的必修课如果你在准备 Claude Certified Architect 或类似的进阶认证Claude API 知识体系里 Conversations 和 System 几乎是必考的基础支柱。理由也很直接认证考察的不是“会不会调用一个接口”而是你能不能设计出一个稳定、可控、可扩展的对话应用。而“稳定”依赖对多轮会话的正确处理“可控”则依赖 System Prompt 的设计。从工程角度看这两个能力直接决定产品体验没有正确的多轮会话管理用户一多问两句模型的回答就开始“失忆”没有好的 System Prompt模型输出就会飘忽不定难以满足业务约束。因此这篇文章会花较多篇幅在原理和代码示例上而不是只给结论。2. 环境准备与 API 基础2.1 准备 API Key 与网络环境调用 Claude API 的第一步是准备 API Key。访问 Anthropic 控制台登录后可以在 API Keys 页面创建密钥。创建后要立即复制保存因为密钥只会完整显示一次。这里强调两个安全习惯API Key 是敏感凭据不要提交到 Git 仓库不要把 Key 硬编码到前端代码中服务端调用时建议通过环境变量注入。在本地开发和测试时可以把 Key 写入环境变量。以 Windows 和 macOS/Linux 为例常见做法如下# macOS / Linux export ANTHROPIC_API_KEYsk-ant-xxxx # Windows PowerShell $env:ANTHROPIC_API_KEYsk-ant-xxxx2.2 安装 Python SDK官方提供了anthropicPython SDK安装命令如下pip install anthropic安装完成后可以验证版本python -c import anthropic; print(anthropic.__version__)如果显示正常版本号说明 SDK 已安装成功。这里需要提醒一句SDK 版本更新比较频繁不同版本之间的 API 参数可能有细微差异示例代码中的用法以最常见的 SDK 写法为准如果遇到参数报错优先查看当前版本的官方文档。2.3 第一个 Messages 请求先写一个最简单的请求验证 API Key 和网络环境是否正常。# 文件路径quickstart.py import anthropic client anthropic.Anthropic() response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, messages[ {role: user, content: 你好请用一句话介绍你自己。} ] ) print(response.content[0].text)运行python quickstart.py这里有三点需要说明model参数指定要使用的模型名称实际可用模型以你的账号权限和官方文档为准max_tokens是必填参数表示模型最多生成多少个 tokenmessages参数接收一个消息数组单轮对话时只需要包含一条 user 消息。如果代码运行顺利你会看到模型返回一段自我介绍。但请注意这个请求里没有任何 System Prompt也没有历史消息当用户继续追问“我刚才问了你什么”时模型是回答不上来的。3. Conversations 多轮会话机制拆解3.1 API 的无状态设计理解 Claude API 的多轮会话最关键的一点就是接受“API 无状态”这个事实。什么是无状态简单来说Claude 不会在服务端保存你每一次调用的上下文。每一次messages.create请求模型都只根据当前请求内的参数生成回复。这样的设计带来了一个好处API 服务器不需要维护每个用户的对话状态请求易于横向扩展也更容易做负载均衡。但对开发者来说这意味着你必须自己管理对话历史。来看一个直观对比。错误示例两次请求互相独立模型无法得知第一次请求的内容。import anthropic client anthropic.Anthropic() # 第一次请求 response1 client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, messages[ {role: user, content: 我的名字是张三。} ] ) print(第一次回复, response1.content[0].text) # 第二次请求没有携带历史 response2 client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, messages[ {role: user, content: 我叫什么名字} ] ) print(第二次回复, response2.content[0].text)运行后你会发现第二次请求模型并不知道你叫张三因为它没有收到第一条消息。正确示例把历史消息按顺序传给模型。import anthropic client anthropic.Anthropic() messages [ {role: user, content: 我的名字是张三。}, {role: assistant, content: 好的张三很高兴认识你有什么我可以帮你的吗}, {role: user, content: 我叫什么名字} ] response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, messagesmessages ) print(回复, response.content[0].text)这次模型能正确回答出“张三”。3.2 messages 数组的结构与 role 规则Claude API 的 messages 数组遵循一个非常清晰的规则数组内按时间顺序排列消息每条消息包含role和content两个核心字段支持的 role 有user和assistant消息角色应该严格交替不能出现连续两条 user 或连续两条 assistant。为什么角色要交替因为模型的训练数据中对话通常是 user/assistant 轮流出现的。如果请求中出现连续的两条 user 消息模型在理解上会产生歧义无法判断哪一条是用户的当前意图。开发者常见的错误是每次请求时只把新增的用户消息追加到数组中忽略了上一轮模型的回复。正确的做法是messages.append({role: user, content: 当前用户输入}) response client.messages.create(..., messagesmessages) messages.append({role: assistant, content: response.content[0].text})也就是说每次请求后要把模型的回复也追加到历史数组中下一次请求再整体携带。3.3 多轮对话的完整实现下面用一个完整示例演示如何构建多轮对话循环。# 文件路径conversation_demo.py import anthropic client anthropic.Anthropic() messages [] print(开始对话输入 exit 退出。) while True: user_input input(你) if user_input.lower() exit: break messages.append({role: user, content: user_input}) response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, messagesmessages ) assistant_reply response.content[0].text print(Claude, assistant_reply) messages.append({role: assistant, content: assistant_reply})这个脚本的关键点在于维护一个messages列表作为对话历史每次用户输入后先追加 user 消息请求完成后再把 assistant 回复追加到列表下一轮循环时messages 记录了完整上下文。3.4 上下文长度与 Token 管理多轮对话看似简单但实践中最容易踩坑的就是 Token 超出限制。Claude 模型的上下文长度是有限的。不同模型的上下文窗口大小不同以常见的 Sonnet 模型为例通常有 200K 级别的上下文窗口但实际使用时还会受到max_tokens参数和请求头字节数的影响。当历史消息过多时你会遇到类似下面的错误Request too large for the model或者This conversation has too many messages解决思路通常有几种滑动窗口截断只保留最近 N 轮消息丢弃最早的历史摘要压缩当历史超过阈值时让模型把之前的对话生成一段摘要之后用摘要替代原始历史关键信息抽取只保留用户资料、偏好、待办事项等结构化信息丢弃闲聊内容。滑动窗口是最简单的方案适合 MVP 阶段。下面是一个示例MAX_HISTORY_ROUNDS 5 # 最多保留 5 轮 def trim_messages(messages: list, max_rounds: int MAX_HISTORY_ROUNDS) - list: # messages 长度为 round * 2每轮包含 user 和 assistant max_len max_rounds * 2 if len(messages) max_len: return messages # 保留最后 max_len 条同时始终保留第一条 user 消息作为上下文开场 return [messages[0]] messages[-max_len:]这个函数的核心思路是保留一条固定的开场消息同时只保留最近 N 轮对话。这种方式能有效控制 Token 消耗缺点是比较粗暴可能丢失早期关键信息。生产环境中更推荐结合摘要压缩方案。4. System Prompt 详解与设计方法4.1 System 参数的位置与作用System Prompt 在 Claude API 中有独立的参数位置。以 Python SDK 为例它位于顶层response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, system你是一名严谨的数据库管理员回答时只提供经过验证的 SQL 建议。, messages[ {role: user, content: 如何优化这条查询} ] )很多同学会把 System Prompt 写成 messages 数组里的一条messages [ {role: system, content: 你是助手}, {role: user, content: 你好} ]这种做法在 Claude Messages API 中是不正确的。Messages API 的 messages 数组只接受 user 和 assistant 两种 rolesystem 必须放在顶层参数中。如果你使用了不支持的消息角色SDK 会抛出参数校验错误。4.2 System Prompt 与 User Prompt 的优先级System Prompt 的指令优先级高于普通用户消息中的提示。这意味着即使在用户输入中出现了“忽略你之前的设定”这类内容模型通常会优先遵循 System Prompt 中设定的规则。为什么因为 System Prompt 从机制上位于消息序列的更高层级它在模型内部被视作对话的全局配置。模型在生成回复时会先参考系统指令再理解用户请求。这一特性对工程应用非常有用。你可以在 System Prompt 中写死安全边界和输出规范而不必担心用户通过输入内容绕过限制。但要注意任何提示词都有被“越狱”的可能性System Prompt 不是安全边界而是一种行为引导。对于敏感场景仍然需要服务端的权限校验和内容过滤。4.3 System Prompt 的设计技巧设计一个好的 System Prompt可以从以下四个维度入手。第一角色明确。不要只说“你是一个助手”更有效的写法是你是一名拥有 8 年经验的 Python 后端工程师擅长 FastAPI 和 PostgreSQL回答问题时优先考虑性能与可维护性。角色越具体模型的语言风格和专业知识倾向就越明确。第二行为约束。给模型设定执行规则例如1. 如果问题信息不足先列出你缺少的关键信息再请求用户补充 2. 回答必须包含方案理由不能只给结论 3. 代码示例必须使用 Python 3.10 语法。第三输出格式规范。对于需要程序进一步处理的场景直接规定格式请严格按照以下 JSON 结构返回结果不要包含多余文字 {answer: 你的回答, confidence: 0.0-1.0}第四边界兜底。告诉模型遇到什么情况该拒绝或明确说明如果用户询问的内容与当前业务无关请礼貌拒绝并引导回到主题。 如果你不确定答案请直接说“我不确定”不要编造信息。4.4 带 System Prompt 的多轮对话示例将 System Prompt 与多轮对话结合才是实际项目中最常见的形态。# 文件路径customer_service_demo.py import anthropic client anthropic.Anthropic() system_prompt 你是一家电商平台的智能客服助手。 请遵循以下规则 1. 回答简洁不超过 100 字 2. 涉及订单问题时先确认用户订单号 3. 遇到无法解决的问题引导用户联系人工客服 4. 不要编造促销活动信息。 messages [] print(客服助手已上线输入 exit 退出。) while True: user_input input(用户) if user_input.lower() exit: break messages.append({role: user, content: user_input}) response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, systemsystem_prompt, messagesmessages ) assistant_reply response.content[0].text print(客服, assistant_reply) messages.append({role: assistant, content: assistant_reply})这个示例体现了 System Prompt 的两个价值所有轮次共享同一套规则用户如何追问模型的回答边界都不会漂移历史对话通过 messages 数组传递配合 system 参数模型能同时理解“全局规则”和“实时上下文”。5. 完整实战构建一个带 System Prompt 的多轮对话助手这一节我们做一个综合实战把前文的概念串起来。5.1 需求分析目标实现一个“数据库优化助手”应具备以下能力设定用户为数据库架构师角色输出格式统一为“问题分析 优化建议”当用户没有提供表结构或 SQL 时主动要求补充支持多轮追问保留最近的对话上下文。5.2 项目结构db_assistant/ ├── config.py # 配置项 ├── assistant.py # 对话助手核心逻辑 └── main.py # 命令行入口5.3 核心代码先写配置模块。# 文件路径config.py MODEL_NAME claude-3-5-sonnet-20241022 MAX_TOKENS 1024 MAX_HISTORY_ROUNDS 6 SYSTEM_PROMPT 你是一名资深数据库架构师专注于 MySQL 和 PostgreSQL 的性能优化。 你的工作方式 1. 如果用户没有提供完整的 SQL 和表结构请先请求补充不要直接猜测 2. 每次回答分为两部分问题分析、优化建议 3. 优化建议必须先写结论再写理由 4. 涉及索引优化时需要说明索引生效的条件 5. 回答要专业但避免堆砌术语。 接下来是对话助手的核心逻辑。# 文件路径assistant.py import anthropic from config import MODEL_NAME, MAX_TOKENS, SYSTEM_PROMPT class DBAssistant: def __init__(self): self.client anthropic.Anthropic() self.messages [] self.max_history_rounds 6 def _trim_history(self): 裁剪历史消息保留最开始的 user 消息和最近 N 轮对话。 max_len self.max_history_rounds * 2 if len(self.messages) max_len: return self.messages [self.messages[0]] self.messages[-max_len:] def ask(self, user_input: str) - str: self.messages.append({role: user, content: user_input}) response self.client.messages.create( modelMODEL_NAME, max_tokensMAX_TOKENS, systemSYSTEM_PROMPT, messagesself.messages ) reply response.content[0].text self.messages.append({role: assistant, content: reply}) self._trim_history() return reply最后是命令行入口。# 文件路径main.py from assistant import DBAssistant def main(): assistant DBAssistant() print(数据库优化助手已启动输入 exit 退出。\n) while True: question input(你) if question.lower() exit: break answer assistant.ask(question) print(\n助手) print(answer) print() if __name__ __main__: main()5.4 运行与验证执行python main.py推荐按以下顺序测试直接问一句“我的查询很慢怎么办”模型应该会要求你补充 SQL 和表结构提供完整的 SQL 和表结构模型应该按“问题分析 优化建议”的结构回答接着追问“如果去掉这个索引呢”模型应该能结合上一轮的对话上下文继续分析。这里要重点说明_trim_history的作用。当对话轮次超过 6 轮后旧消息被裁剪但始终保留第一条 user 消息这样模型能维持基本的任务背景又不会让请求体无限膨胀。5.5 结果说明运行效果大致如下你我的查询很慢怎么办 助手 问题分析你还没有提供具体的 SQL 语句和表结构我无法判断慢查询的根因。 优化建议请先补充以下信息—— 1. 完整的 SQL 语句 2. 涉及的建表语句或表结构 3. 表的数据量和索引情况。如果你接着补充表结构它会基于上下文给出更有针对性的优化建议。6. 常见问题与排查思路6.1 API Error: 529 Overloaded这是 Claude API 使用中最常见的高频错误之一错误信息类似api error: 529 overloaded. this is a server-side issue, usually temporary.含义是 Anthropic 服务端当前负载过高暂时无法处理请求。这不是你的代码问题而是服务端暂时性过载。处理建议不要立即高频重试避免加重服务端压力使用指数退避策略例如第一次等待 1 秒、第二次等待 2 秒、第三次等待 4 秒在服务端代码中加入重试逻辑但设置最大重试次数。Python 示例import time import anthropic client anthropic.Anthropic() def create_with_retry(max_retries5, **kwargs): for attempt in range(max_retries): try: return client.messages.create(**kwargs) except anthropic.APIStatusError as e: if e.status_code 529 and attempt max_retries - 1: time.sleep(2 ** attempt) continue raise6.2 请求体过大或上下文超限当对话历史过长时会收到类似“Request too large”的错误。处理思路对历史消息做滑动窗口裁剪将早期上下文压缩成摘要将大段历史写入外部存储只保留结构化摘要使用更长的上下文窗口模型如果业务允许。6.3 多轮对话模型“失忆”这是最常见的开发误区。根因不是模型问题而是你没有在请求中传递历史消息。排查顺序检查 messages 数组是否包含之前的 user 和 assistant 消息检查 messages 顺序是否是从早到晚检查代码中是否有误把历史列表重置为空。6.4 消息角色错误如果你在 messages 中使用了role: systemSDK 会报参数错误。正确做法是把 System Prompt 放到system顶层参数中messages 数组只保留 user 和 assistant。6.5 认证与权限错误如果返回 401 或 403通常是 API Key 无效或账号权限不足。排查建议确认 API Key 复制完整没有多余空格确认环境变量已正确加载确认账号有权限访问指定的模型。6.6 常见问题速查表问题现象常见原因解决思路529 Overloaded服务端过载指数退避重试错峰请求上下文超限历史消息无限累积滑动窗口裁剪或摘要压缩模型“失忆”请求未携带完整历史每次请求拼接 messages 历史system 参数报错把 system 写入 messages 数组使用顶层 system 参数401 UnauthorizedAPI Key 错误检查 Key 与环境变量403 Forbidden账号无模型权限检查账号权限并申请对应模型7. 最佳实践与工程建议7.1 会话管理宁可多传不可漏传在 Token 预算允许的情况下多传历史消息通常比少传更安全。模型看到完整上下文才能做出一致的回答。但需要注意历史消息越长响应延迟和成本越高。工程上建议设置每轮对话的最大历史轮数对关键业务信息用户身份、偏好、订单号做结构化抽取在 API 层对历史列表做序列化缓存方便后续审计和追踪。7.2 System Prompt用版本化思维管理System Prompt 是产品的“灵魂”它会直接影响输出质量。建议把它当作代码一样管理不要直接在请求中拼接字符串而是放在配置中心或单独文件中每次修改保留历史版本方便 AB 测试使用变量占位符根据不同场景注入不同配置。示例system_prompt_template 你是{role}。 规则 1. {rule_1} 2. {rule_2} system_prompt system_prompt_template.format( role电商客服, rule_1回答不超过 100 字, rule_2不要编造订单信息 )7.3 异常处理与重试策略任何外部 API 调用都必须假设可能失败。建议在项目中统一封装请求逻辑捕获网络异常、超时、限流、服务端错误对 429 和 529 做指数退避重试对 4xx 错误直接上报不要无意义重试为所有外部调用添加超时时间避免线程长时间阻塞。7.4 安全边界与权限控制即使 System Prompt 设定了禁止行为也不能把它当作安全防线。对于敏感业务在应用层校验用户输入过滤危险指令对模型输出做内容审核API Key 只保存在服务端环境变量中不传递到前端对用户身份做鉴权后再调用模型接口。7.5 成本控制多轮对话的成本随历史消息增长而上升。建议在请求前估算 token 数超过阈值时自动压缩历史。可以通过response.usage字段查看每次请求消耗的 token 数并据此调整策略。response client.messages.create(...) print(response.usage) # 输出类似Usage(input_tokens123, output_tokens45)8. 总结与学习路线通过这篇文章我们从原理到实战完整拆解了 Claude API 中的两个核心知识点。关于 Conversations最关键的是理解 API 的无状态设计并把多轮对话历史的拼接、裁剪和管理作为工程问题来处理。所有“模型失忆”的根因几乎都能追溯到请求中缺少历史消息或历史消息顺序错乱。关于 System最重要的转变是意识到它和普通用户消息不是一回事。System Prompt 是全局规则层适合放置角色、格式、边界等稳定配置而 messages 数组则负责承载实时对话流。如果继续深入学习建议按下面的路线延伸掌握 Claude API 完整的请求参数包括 temperature、top_p、stop_sequences 等采样参数学习 Function Calling / Tool Use让模型具备调用外部工具的能力研究流式输出Streaming优化对话应用的交互体验了解 Embedding 与 RAG把知识库能力接入对话系统最后回到认证体系本身把 API 能力映射到架构设计题目中。实际项目中优先关注的是会话历史的成本控制、System Prompt 的版本管理以及错误重试的稳定性设计。这三件事做好了对话应用的可用性会明显提升。希望这篇文章能帮你在 Claude API 的学习中少走一些弯路。如果本文对你有帮助可以收藏备用遇到具体问题时也欢迎在评论区留言交流。