> ## Documentation Index
> Fetch the complete documentation index at: https://platform.kimi.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 Kimi API 进行多轮对话

Kimi API 与 Kimi 智能助手不同，**API 本身不具有记忆功能，它是无状态的**，这意味着，当你多次请求 API 时，Kimi 大模型并不知道你前一次请求的内容，也不会记忆任何请求的上下文信息。例如，你在前一次请求中告诉 Kimi 大模型你今年 27 岁，在下一次请求中，Kimi 大模型并不会记住你 27 岁这件事。

因此，我们需要手动维护每次请求的上下文，即 Context，把上一次请求过的内容手动加入到下一次请求中，让 Kimi 大模型能正确看到此前我们都聊了什么。我们将改造上一章节中使用的示例，来展示如何通过维护 messages 列表让 Kimi 大模型拥有记忆，并实现多轮对话功能。

*注：我们将实现多轮对话的要点以注释的形式添加到代码中。*

<Tabs>
  <Tab title="python">
    ```python theme={null}
    from openai import OpenAI

    client = OpenAI(
        api_key = "MOONSHOT_API_KEY", # 在这里将 MOONSHOT_API_KEY 替换为你从 Kimi 开放平台申请的 API Key
        base_url = "https://api.moonshot.cn/v1",
    )

    # 我们定义一个全局变量 messages，用于记录我们和 Kimi 大模型产生的历史对话消息
    # 在 messages 中，既包含我们向 Kimi 大模型提出的问题（role=user），也包括 Kimi 大模型给我们的回复（role=assistant）
    # 当然，也包括初始的 System Prompt（role=system）
    # messages 中的消息按时间顺序从小到大排列
    messages = [
        {"role": "system", "content": "你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。"},
    ]

    def chat(input: str) -> str:
        """
        chat 函数支持多轮对话，每次调用 chat 函数与 Kimi 大模型对话时，Kimi 大模型都会"看到"此前已经
        产生的历史对话消息，换句话说，Kimi 大模型拥有了记忆。
        """

        global messages

        # 我们将用户最新的问题构造成一个 message（role=user），并添加到 messages 的尾部
        messages.append({
            "role": "user",
            "content": input,
        })

        # 携带 messages 与 Kimi 大模型对话
        completion = client.chat.completions.create(
            model="kimi-k2.6",
            messages=messages
        )

        # 通过 API 我们获得了 Kimi 大模型给予我们的回复消息（role=assistant）
        assistant_message = completion.choices[0].message

        # 为了让 Kimi 大模型拥有完整的记忆，我们必须将 Kimi 大模型返回给我们的消息也添加到 messages 中
        messages.append(assistant_message)

        return assistant_message.content

    print(chat("你好，我今年 27 岁。"))
    print(chat("你知道我今年几岁吗？")) # 在这里，Kimi 大模型根据此前的上下文信息，将会知道你今年的年龄是 27 岁
    ```
  </Tab>

  <Tab title="node.js">
    ```js theme={null}
    const OpenAI = require("openai")

    const client = new OpenAI({
      apiKey: "MOONSHOT_API_KEY", // 在这里将 MOONSHOT_API_KEY 替换为你从 Kimi 开放平台申请的 API Key
      baseURL: "https://api.moonshot.cn/v1",
    });

    // 我们定义一个全局变量 messages，用于记录我们和 Kimi 大模型产生的历史对话消息
    // 在 messages 中，既包含我们向 Kimi 大模型提出的问题（role=user），也包括 Kimi 大模型给我们的回复（role=assistant）
    // 当然，也包括初始的 System Prompt（role=system）
    // messages 中的消息按时间顺序从小到大排列
    let messages = [
      {
        role: "system",
        content: "你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。",
      },
    ];

    async function chat(input) {
      /**
       * chat 函数支持多轮对话，每次调用 chat 函数与 Kimi 大模型对话时，Kimi 大模型都会"看到"此前已经
       * 产生的历史对话消息，换句话说，Kimi 大模型拥有了记忆。
       */

      // 我们将用户最新的问题构造成一个 message（role=user），并添加到 messages 的尾部
      messages.push({
        role: "user",
        content: input,
      });

      // 携带 messages 与 Kimi 大模型对话
      const completion = await client.chat.completions.create({
        model: "kimi-k2.6",
        messages: messages
      });

      // 通过 API 我们获得了 Kimi 大模型给予我们的回复消息（role=assistant）
      const assistantMessage = completion.choices[0].message;

      // 为了让 Kimi 大模型拥有完整的记忆，我们必须将 Kimi 大模型返回给我们的消息也添加到 messages 中
      messages.push(assistantMessage);

      return assistantMessage.content;
    }

    // 使用示例
    (async () => {
      console.log(await chat("你好，我今年 27 岁。"));
      console.log(await chat("你知道我今年几岁吗？")); // 在这里，Kimi 大模型根据此前的上下文信息，将会知道你今年的年龄是 27 岁
    })();
    ```
  </Tab>
</Tabs>

我们回顾一下上述代码中的要点：

* Kimi API 本身没有上下文记忆功能，我们需要通过 API 中的 messages 参数，手动将"之前聊了什么"告知 Kimi 大模型；
* 在 messages 中，既要存储我们向 Kimi 大模型提出的问题消息（role=user），也要存储 Kimi 大模型给我们的回复消息（role=assistant）；

需要注意的是，在上述代码中，随着 `chat` 调用次数的不断增多，`messages` 列表的长度也在不断增加，这意味着每次请求所消耗的 Tokens 数量也在不断增加，并且最终会在某个时间点，`messages` 中的消息所占用的 Tokens 超过了 Kimi 大模型支持的上下文窗口大小。我们推荐你使用某种策略来保持 `messages` 列表的消息数量在一个可控的范围内，例如，每次只保留最新的 20 条消息作为本次请求的上下文。

我们给出一个示例，以便于你能顺利理解如何控制上下文长度，请注意关注 `make_messages` 函数是如何运作的：

<Tabs>
  <Tab title="python">
    ```python theme={null}
    from openai import OpenAI

    client = OpenAI(
        api_key = "MOONSHOT_API_KEY", # 在这里将 MOONSHOT_API_KEY 替换为你从 Kimi 开放平台申请的 API Key
        base_url = "https://api.moonshot.cn/v1",
    )

    # 我们将 System Messages 单独放置在一个列表中，这是因为每次请求都应该携带 System Messages
    system_messages = [
    	{"role": "system", "content": "你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。"},
    ]

    # 我们定义一个全局变量 messages，用于记录我们和 Kimi 大模型产生的历史对话消息
    # 在 messages 中，既包含我们向 Kimi 大模型提出的问题（role=user），也包括 Kimi 大模型给我们的回复（role=assistant）
    # messages 中的消息按时间顺序从小到大排列
    messages = []


    def make_messages(input: str, n: int = 20) -> list[dict]:
    	"""
    	使用 make_messaegs 控制每次请求的消息数量，使其保持在一个合理的范围内，例如默认值是 20。在构建消息列表
    	的过程中，我们会先添加 System Prompt，这是因为无论如何对消息进行截断，System Prompt 都是必不可少
    	的内容，再获取 messages —— 即历史记录中，最新的 n 条消息作为请求使用的消息，在大部分场景中，这样
    	能保证请求的消息所占用的 Tokens 数量不超过模型上下文窗口。
    	"""
    	global messages

    	# 首先，我们将用户最新的问题构造成一个 message（role=user），并添加到 messages 的尾部
    	messages.append({
    		"role": "user",
    		"content": input,
    	})

    	# new_messages 是我们下一次请求使用的消息列表，现在让我们来构建它
    	new_messages = []

    	# 每次请求都需要携带 System Messages，因此我们需要先把 system_messages 添加到消息列表中；
    	# 注意，即使对消息进行截断，也应该注意保证 System Messages 仍然在 messages 列表中。
    	new_messages.extend(system_messages)

    	# 在这里，当历史消息超过 n 条时，我们仅保留最新的 n 条消息
    	if len(messages) > n:
    		messages = messages[-n:]

    	new_messages.extend(messages)
    	return new_messages


    def chat(input: str) -> str:
    	"""
    	chat 函数支持多轮对话，每次调用 chat 函数与 Kimi 大模型对话时，Kimi 大模型都会"看到"此前已经
    	产生的历史对话消息，换句话说，Kimi 大模型拥有了记忆。
    	"""

    	# 携带 messages 与 Kimi 大模型对话
    	completion = client.chat.completions.create(
            model="kimi-k2.6",
            messages=make_messages(input)
        )

    	# 通过 API 我们获得了 Kimi 大模型给予我们的回复消息（role=assistant）
    	assistant_message = completion.choices[0].message

    	# 为了让 Kimi 大模型拥有完整的记忆，我们必须将 Kimi 大模型返回给我们的消息也添加到 messages 中
    	messages.append(assistant_message)

    	return assistant_message.content

    print(chat("你好，我今年 27 岁。"))
    print(chat("你知道我今年几岁吗？")) # 在这里，Kimi 大模型根据此前的上下文信息，将会知道你今年的年龄是 27 岁
    ```
  </Tab>

  <Tab title="node.js">
    ```js theme={null}
    const OpenAI = require("openai")

    const client = new OpenAI({
      apiKey: "MOONSHOT_API_KEY", // 在这里将 MOONSHOT_API_KEY 替换为你从 Kimi 开放平台申请的 API Key
      baseURL: "https://api.moonshot.cn/v1",
    });

    // 我们将 System Messages 单独放置在一个列表中，这是因为每次请求都应该携带 System Messages
    const systemMessages = [
      {
        role: "system",
        content: "你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。",
      },
    ];

    // 我们定义一个全局变量 messages，用于记录我们和 Kimi 大模型产生的历史对话消息
    // 在 messages 中，既包含我们向 Kimi 大模型提出的问题（role=user），也包括 Kimi 大模型给我们的回复（role=assistant）
    // messages 中的消息按时间顺序从小到大排列
    let messages = [];

    async function makeMessages(input, n = 20) {
      /**
       * 使用 make_messages 控制每次请求的消息数量，使其保持在一个合理的范围内，例如默认值是 20。在构建消息列表
       * 的过程中，我们会先添加 System Prompt，这是因为无论如何对消息进行截断，System Prompt 都是必不可少的
       * 内容，再获取 messages —— 即历史记录中，最新的 n 条消息作为请求使用的消息，在大部分场景中，这样
       * 能保证请求的消息所占用的 Tokens 数量不超过模型上下文窗口。
       */
      // 首先，我们将用户最新的问题构造成一个 message（role=user），并添加到 messages 的尾部
      messages.push({
        role: "user",
        content: input,
      });

      // newMessages 是我们下一次请求使用的消息列表，现在让我们来构建它
      let newMessages = [];

      // 每次请求都需要携带 System Messages，因此我们需要先把 systemMessages 添加到消息列表中；
      // 注意，即使对消息进行截断，也应该注意保证 System Messages 仍然在 messages 列表中。
      newMessages = systemMessages.concat(newMessages);

      // 在这里，当历史消息超过 n 条时，我们仅保留最新的 n 条消息
      if (messages.length > n) {
        messages = messages.slice(-n);
      }

      newMessages = newMessages.concat(messages);
      return newMessages;
    }

    async function chat(input) {
      /**
       * chat 函数支持多轮对话，每次调用 chat 函数与 Kimi 大模型对话时，Kimi 大模型都会"看到"此前已经
       * 产生的历史对话消息，换句话说，Kimi 大模型拥有了记忆。
       */

      // 携带 messages 与 Kimi 大模型对话
      const completion = await client.chat.completions.create({
        model: "kimi-k2.6",
        messages: await makeMessages(input)
      });

      // 通过 API 我们获得了 Kimi 大模型给予我们的回复消息（role=assistant）
      const assistantMessage = completion.choices[0].message;

      // 为了让 Kimi 大模型拥有完整的记忆，我们必须将 Kimi 大模型返回给我们的消息也添加到 messages 中
      messages.push(assistantMessage);

      return assistantMessage.content;
    }

    (async () => {
      console.log(await chat("你好，我今年 27 岁。"));
      console.log(await chat("你知道我今年几岁吗？")); // 在这里，Kimi 大模型根据此前的上下文信息，将会知道你今年的年龄是 27 岁
    })();
    ```
  </Tab>
</Tabs>

请注意，上述的代码示例仅考虑了最简单的调用场景，在实际的业务代码逻辑中，你可能需要考虑更多的场景和边界，例如：

* 并发场景下可能需要额外的读写锁；
* 针对多用户场景，需要为每个用户单独维护 messages 列表；
* 你可能需要对 messages 列表进行持久化；
* 你可能仍然需要更精确的方式计算 messages 列表中需要保留多少条消息；
* 你可能想对被遗弃的消息做一次总结，并生成一条新的消息加入到 messages 列表中；
* ......
