多轮对话的关键,是把前文传回去
用Claude Messages API做多轮对话时,需要由自己的程序管理消息历史,并在下一次请求里传入需要保留的上下文。仅复用同一个API Key、同一个模型名或同一个脚本文件,不会自动恢复上一轮聊天。
最小的第二轮请求通常包含三项:第一轮user消息、第一轮assistant回复、第二轮user消息。回复不能随手标成user,也不能只传“继续”却丢掉它所指的内容。
本文用Node.js演示内存中的单个文本对话,不实现网页聊天产品、持久数据库、工具循环或多用户服务。完整代码放在文末可复制区域。
先定义一次对话属于谁
在写请求之前,先确定历史属于哪个用户、哪项任务,以及何时结束。把所有人的消息塞进一个全局数组,可能使上下文串线;把历史放在进程内存中,也意味着程序重启后不会自动恢复。
这份示例通过createConversation创建一个独立会话对象。你给它密钥与模型ID,然后按顺序调用send。它会在前一次请求结束后接受下一轮,避免同一份数组被并发修改。
模型ID应来自当前账户的可用列表。认证和工作区设置与直接API的首次调用相同;不要为了让例子看起来可运行而在代码里填入真实密钥,或写死未经核验的模型名称。

第一轮、第二轮分别带哪些内容
第一轮先提交一个明确任务,例如“把‘用户提交后没反应’改写为一个需要补充信息的问题”。收到回复后,将服务返回的content内容块作为assistant消息保存,再追加第二轮user要求。
第二轮可以说“保留上一个问题,再补充运行环境”。此时服务能看到前面的提问与回复,才有依据理解“上一个问题”。如果你的程序只发送这一句,它就缺少指代对象。
示例保留完整的assistant content,而不是只提取可见文字后重新拼造内容块。content可能包含其他类型;复杂工具、思考状态和签名还涉及额外规则,实际扩展前应继续核对所用模型文档,不要擅自删改结构。
请求失败后,历史应该怎样处理
最容易出现的细节错误,是发送之前就把新消息永久追加进历史,然后请求失败,再重试时又追加一次。这样一次用户提问可能在上下文里出现两遍。
文末代码先构造候选消息列表,只有获得结构符合预期的成功响应后,才一次性提交这轮历史。HTTP失败或响应读取失败时,原来的已确认历史保持不变;同一对象不会并发发送两轮。
这不意味着网络超时之后可以放心自动重发。服务端是否已经生成、是否计费仍可能未知。程序没有自动重试,也没有虚构服务端幂等保证,需要根据应用自己的风险与任务性质决定下一步。
多轮历史的本地模拟检查
用本地模拟响应测试三件事:第一轮只有一条user消息;第二轮应是user、assistant、user三条;中间失败一次后,再发送新的请求,不应把失败的那条提问当作已完成对话混入历史。
这些检查验证的是客户端消息管理,不是模型理解能力。假如模拟回复是固定文本,它不能证明模型真的理解了代词、记住了任务或能准确改写内容。
本站已经对文末同一份代码做了上述模拟测试,并检查并发拒绝与错误后的状态恢复。没有使用真实账户做付费多轮调用,文中的用户问题属于原创练习,不是客户聊天记录。
历史越来越长,应该保留什么
每轮都带上全部内容最容易理解,但对话变长后输入也会增长。生产系统需要决定哪些消息必须保留、哪些原始资料需要重新检索,以及何时生成可核对的摘要,而不是无上限堆积数组。
摘要也会丢失信息。若任务涉及精确数字、约定条件或代码版本,应保留能回查的原始资料标识,不要让摘要替代唯一证据。需要截断历史时,避免把工具调用与对应结果拆开;本例没有实现这类复杂裁剪。
保存对话到数据库之前,还要确定访问权限、保留期限和删除机制。不要为了调试把所有提示词、附件和密钥一并写入普通日志。
跑起来之后怎样验收
先使用无敏感信息的短任务,检查每次实际发送的角色顺序与返回结构,再观察stop_reason和usage。若没有可见文本,检查模型支持和输出预算,不要直接认定历史丢失。
随后在自己的环境验证重启、失败、并发和多用户隔离。只有这些范围真的跑过,才应在交付说明里写对应的验证结论。本文的内存示例是学习起点,不是完整可上线的聊天服务。
保存与启动完整示例
将文末代码保存为claude-api-conversation.mjs,使用Node.js 22或更新的受支持版本。先在本机安全设置ANTHROPIC_API_KEY,并将CLAUDE_MODEL设为当前账户可用的模型ID;需要指定工作区时设置ANTHROPIC_WORKSPACE_ID。不要把密钥写入代码、聊天、截图或共享命令。
运行node claude-api-conversation.mjs会按顺序发送文中的两个问题:若第一轮成功且继续执行,第二轮也会发起真实API请求,可能产生两次调用费用;这不是离线预览。请先确认账户、工作区和允许发送的材料,再运行,不要以为复制后只能看到请求结构。
标准输出显示提取的回复文本;标准错误输出requestId、stopReason和usage等诊断字段,或失败信息。它不打印密钥。第一轮失败时不会继续第二轮;没有模型可见文本时也不能把提示语当作真实回答。导入createConversation进行本地模拟测试不会自动执行上述启动分支,本文已验证的仍只是模拟范围。
截断的一轮不进入已完成历史
示例现在还要求stop_reason明确为end_turn,才把本轮user与assistant一起提交到已完成历史。max_tokens、refusal、未知或缺失停止原因均抛出带stopReason的错误,并保持此前历史不变。
本地注入响应验证了这些分支,且失败不会暗中自动再发一次;这不是实际模型续写或收费测试。保留历史不等于删除诊断草稿,业务若要存部分结果,应放在未完成区并保留停止原因。
资料来源与核对范围
https://platform.claude.com/docs/en/build-with-claude/working-with-messages
https://platform.claude.com/docs/en/api/messages/create
本文依据本批保存的官方文档正文整理。原创练习与实际运行范围已在正文中区分;涉及账户界面、权限、价格和功能支持时,请按自己的产品与当前官方说明复核。