azosi · 2026.7.22 04:47 · 조회 0

Kimi Thinking

상위 문서: ← Kimi Model Capabilities 출처: Kimi API Platform 공식 문서 — Thinking Mode 한글화 (2026-07-22) 공급사: Moonshot AI (月之暗面)

Kimi 사고 모델은 최종 답변 전에 reasoning_content(추론 트레이스)를 출력합니다 — 복잡한 추론, 코드 생성, 다단계 도구 호출에 적합합니다. 이 문서는 네 가지 사고 모델(kimi-k3, kimi-k2.7-code, kimi-k2.6, kimi-k2.5)의 차이, K2.x의 thinking 파라미터, K3의 reasoning_effort, 추론 콘텐츠 읽는 법, 다단계 도구 호출 설정과 Preserved Thinking을 설명합니다.


1. 사고 모델 선택

모델사고 모드Preserved Thinking사고 강도 설정
kimi-k3항상 ON항상 ON최상위 reasoning_effort: "low" / "high" / "max" (기본 "max")
kimi-k2.7-code항상 ON항상 ONthinking 파라미터 불필요 (항상 사고, reasoning_content 반환)
kimi-k2.6기본 ON (비활성화 가능)지원 (선택)thinking.type: "enabled"(기본) / "disabled", thinking.keep: null / "all"
kimi-k2.5기본 ON (비활성화 가능)미지원thinking.type: "enabled"(기본) / "disabled", thinking.keep 없음

요청 파라미터 비교:

필드kimi-k3kimi-k2.7-codekimi-k2.6kimi-k2.5
reasoning_effort"low"/"high"/"max" (기본 "max")미지원미지원미지원
thinking.type"enabled"만 (비활성화 시 에러)"enabled"(기본) / "disabled""enabled"(기본) / "disabled"
thinking.keep"all"만 (유효값이 아니면 에러)null(기본) / "all"없음 (미지원)

벤치마크 테스트 시 benchmark best practice 참고.


2. kimi-k2.7-code 호출: thinking 파라미터 불필요

kimi-k2.7-code는 코드 특화 사고 모델로, kimi-k2.6과 동일한 사고 메커니즘(reasoning_content, 다단계 도구 호출, 스트리밍 등)을 공유합니다. 유일한 차이는 thinking 파라미터 처리입니다. thinking 파라미터를 전달할 필요 없고 전달하지 마세요model만 바꾸면 모델이 항상 reasoning_content를 출력합니다. Preserved Thinking이 항상 ON이므로, 멀티턴 대화에서는 모든 assistant 메시지의 reasoning_contentmessages에 그대로 유지해야 합니다.

import os
import openai

client = openai.Client(
    base_url="https://api.moonshot.ai/v1",
    api_key=os.getenv("MOONSHOT_API_KEY"),
)

stream = client.chat.completions.create(
    model="kimi-k2.7-code",
    messages=[
        {"role": "system", "content": "You are Kimi."},
        {"role": "user", "content": "Implement quicksort in Python."}
    ],
    max_tokens=1024*32,
    stream=True,
    # temperature 수정 불가, 사고는 항상 ON — 설정 불필요
)

thinking = False
for chunk in stream:
    if chunk.choices:
        choice = chunk.choices[0]
        if choice.delta and hasattr(choice.delta, "reasoning_content"):
            if not thinking:
                thinking = True
                print("=============Start Reasoning=============")
            print(getattr(choice.delta, "reasoning_content"), end="")
        if choice.delta and choice.delta.content:
            if thinking:
                thinking = False
                print("\n=============End Reasoning=============")
            print(choice.delta.content, end="")

3. kimi-k2.6 호출: 기본적으로 사고 출력

kimi-k2.6은 범용 사고 모델입니다. 사고는 기본 활성화되어 있어, 아래 기본 호출은 thinking 파라미터 없이도 추론 콘텐츠를 출력합니다 (비활성화나 Preserved Thinking은 아래 참고).

import os
import openai

client = openai.Client(
    base_url="https://api.moonshot.ai/v1",
    api_key=os.getenv("MOONSHOT_API_KEY"),
)

stream = client.chat.completions.create(
    model="kimi-k2.6",
    messages=[
        {"role": "system", "content": "You are Kimi."},
        {"role": "user", "content": "Please explain why 1+1=2."}
    ],
    max_tokens=1024*32,
    stream=True,
    # temperature 수정 불가 — 설정 불필요, 사고는 기본 ON
)

thinking = False
for chunk in stream:
    if chunk.choices:
        choice = chunk.choices[0]
        if choice.delta and hasattr(choice.delta, "reasoning_content"):
            if not thinking:
                thinking = True
                print("=============Start Reasoning=============")
            print(getattr(choice.delta, "reasoning_content"), end="")
        if choice.delta and choice.delta.content:
            if thinking:
                thinking = False
                print("\n=============End Reasoning=============")
            print(choice.delta.content, end="")

3-1. thinking 파라미터로 사고 제어

kimi-k2.6의 사고 동작은 thinking 파라미터의 두 하위 필드로 제어합니다.

  • thinking.type: "enabled"(기본) / "disabled" — 사고 ON/OFF
  • thinking.keep: null(기본, 이전 턴 사고 무시) / "all"(이전 턴 reasoning_content 유지 — Preserved Thinking 활성화)

4. 응답에서 reasoning_content 읽기

kimi-k2.7-code, 사고를 활성화한 kimi-k2.6 등 사고 모델의 응답은 reasoning_content 필드에 추론을 담습니다. 읽을 때 주의사항:

  • OpenAI SDK에서 ChoiceDeltaChatCompletionMessage 타입은 reasoning_content를 직접 제공하지 않아 .reasoning_content로 접근 불가 — hasattr(obj, "reasoning_content")로 존재 확인 후 getattr(obj, "reasoning_content")로 값 가져오기
  • 다른 프레임워크나 HTTP API 직접 호출 시 content 필드와 같은 레벨에서 reasoning_content를 직접 얻을 수 있음
  • 스트리밍(stream=True)에서 reasoning_content는 항상 content 이전에 등장 — content 출력을 감지해 추론(추론 과정) 종료 시점 판단 가능
  • reasoning_content의 토큰도 max_tokens 제약을 받음 — reasoning_content + content 토큰 합계가 max_tokens 이하여야 함

5. 다단계 도구 호출 설정

kimi-k2.7-code와 사고를 활성화한 kimi-k2.6은 다단계 도구 호출에 걸친 깊은 추론을 수행하도록 설계되어, 매우 복잡한 작업도 처리 가능합니다. 신뢰할 수 있는 결과를 위해 사고 모델 사용 시 아래 규칙을 반드시 따르세요:

  • 단일 작업(한 번의 도구 호출 루프 내 다단계 추론) 중에는 모든 reasoning content(reasoning_content 필드)를 컨텍스트에 유지하고 요청에 함께 전송. 모델이 필요한 부분만 골라 추론에 활용. 턴 간 사고 보존 여부thinking.keep이 제어 (kimi-k2.6은 기본 null로 보존 안 함, kimi-k2.7-code는 항상 보존)
  • max_tokens >= 16000 설정reasoning_contentcontent가 잘림 없이 반환되도록 보장
  • temperature 설정 금지kimi-k2.7-codekimi-k2.6temperature 수정 불가, 기본값 사용, 명시적으로 전달하지 마세요 (Model Parameter Reference 참고)
  • 스트리밍 활성화 (stream=True) — 사고 모델은 reasoning_content와 일반 content를 함께 반환하므로 응답 크기가 큽니다. 스트리밍이 더 나은 UX를 제공하고 네트워크 타임아웃 회피에 도움

5-1. 완전 예제: 일일 뉴스 리포트 생성

아래 예제는 "일일 뉴스 리포트 생성" 시나리오로, 모델이 순차적으로 date(날짜 조회) → web_search(뉴스 검색) 같은 공식 도구를 호출하고, 이 과정 전반에 깊은 추론을 보여줍니다.

import os
import json
import httpx
import openai


class FormulaChatClient:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url
        self.api_key = api_key
        self.openai = openai.Client(base_url=base_url, api_key=api_key)
        self.httpx = httpx.Client(
            base_url=base_url,
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=30.0,
        )
        self.model = "kimi-k2.6"

    def get_tools(self, formula_uri: str):
        r = self.httpx.get(f"/formulas/{formula_uri}/tools")
        r.raise_for_status()
        return r.json().get("tools", [])

    def call_tool(self, formula_uri: str, function: str, args: dict):
        r = self.httpx.post(
            f"/formulas/{formula_uri}/fibers",
            json={"name": function, "arguments": json.dumps(args)},
        )
        r.raise_for_status()
        fiber = r.json()
        if fiber.get("status") == "succeeded":
            return fiber["context"].get("output") or fiber["context"].get("encrypted_output")
        if "error" in fiber:
            return f"Error: {fiber['error']}"
        return "Error: Unknown error"

    def close(self):
        self.httpx.close()


client = FormulaChatClient(
    os.getenv("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
    os.getenv("MOONSHOT_API_KEY"),
)

# 공식 도구 Formula URI
formula_uris = ["moonshot/date:latest", "moonshot/web-search:latest"]

# 모든 도구 정의 로드 및 매핑 구축
all_tools = []
tool_to_uri = {}
for uri in formula_uris:
    for tool in client.get_tools(uri):
        func = tool.get("function")
        if func and func.get("name"):
            tool_to_uri[func["name"]] = uri
            all_tools.append(tool)
            print(f"  Loaded: {func['name']} from {uri}")

messages = [
    {"role": "system", "content": "You are Kimi, a professional news analyst. You excel at collecting, analyzing, and organizing information to generate high-quality news reports."},
    {"role": "user", "content": "Please help me generate a daily news report including important technology, economy, and society news."}
]

# 다단계 대화 루프
for iteration in range(10):
    completion = client.openai.chat.completions.create(
        model=client.model,
        messages=messages,
        max_tokens=1024*32,
        tools=all_tools,
    )
    message = completion.choices[0].message

    # 추론 과정 출력
    if hasattr(message, "reasoning_content"):
        reasoning = getattr(message, "reasoning_content")
        if reasoning:
            print(f"--- Round {iteration+1} reasoning ---")
            print(reasoning[:300] + ("..." if len(reasoning) > 300 else ""))

    # assistant 메시지를 컨텍스트에 추가 (reasoning_content 보존)
    messages.append(message)

    if not message.tool_calls:
        print("--- Final answer ---")
        print(message.content)
        break

    for tool_call in message.tool_calls:
        func_name = tool_call.function.name
        args = json.loads(tool_call.function.arguments)
        formula_uri = tool_to_uri.get(func_name)
        if not formula_uri:
            continue
        result = client.call_tool(formula_uri, func_name, args)
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "name": func_name,
            "content": result,
        })

client.close()

6. Preserved Thinking (턴 간 사고 보존)

Preserved Thinking은 멀티턴 대화에서 이전 턴의 reasoning_content를 다음 요청에 함께 전달해, 모델이 현재 턴의 추론에서 이전 사고 사슬을 이어갈 수 있게 합니다.

kimi-k2.6의 경우 thinking.keep 파라미터로 제어:

동작
null / 생략 (기본)이전 reasoning_content 무시. 컨텍스트 짧고 비용 낮음
"all"이전 reasoning_content 완전히 보존 — Preserved Thinking 활성화

thinking.keep이전 턴의 reasoning_content에만 영향. 현재 턴의 사고 생성/출력 여부는 thinking.type이 제어 (thinking.type=enabled와 함께 keep: "all" 사용 권장).

kimi-k2.7-code는 Preserved Thinking이 항상 ON이라 끌 수 없음: thinking.keep을 생략하거나 유일한 유효값 "all"을 전달하면 항상 "all"로 처리 (다른 잘못된 값은 에러). 따라서 이 모델을 사용할 때는 이전 assistant 메시지의 reasoning_contentmessages에 그대로 유지해야 합니다.

keep: "all" 사용 시, 모든 이전 assistant 메시지의 reasoning_contentmessages에 그대로 유지하세요. 가장 간단한 방법은 이전 API 호출에서 반환된 assistant 메시지를 그대로 다시 추가하는 것입니다.

import os
import openai

client = openai.Client(
    base_url="https://api.moonshot.ai/v1",
    api_key=os.getenv("MOONSHOT_API_KEY"),
)

# 이전 API 호출의 assistant 메시지(reasoning_content 포함)를 messages에 그대로 유지
messages = [
    {"role": "system", "content": "You are Kimi."},
    {"role": "user", "content": "First question..."},
    {
        "role": "assistant",
        "reasoning_content": "<이전 API 호출의 reasoning_content>",
        "content": "<이전 API 호출의 최종 답변>"
    },
    {"role": "user", "content": "Please continue the analysis and derive the next step."}
]

response = client.chat.completions.create(
    model="kimi-k2.6",
    messages=messages,
    stream=True,
    extra_body={"thinking": {"type": "enabled", "keep": "all"}},
)

⚠️ reasoning_content는 토큰 소비에 포함됩니다. Preserved Thinking을 활성화하면 이전 사고 콘텐츠가 컨텍스트 윈도우를 계속 차지하고 그만큼 과금됩니다. 신중히 사용하세요.


7. 자주 묻는 질문

Q1. 왜 reasoning_content를 유지해야 하나요? A: reasoning_content 유지는 다단계 추론, 특히 도구 호출 중 연속성을 보장합니다. API가 반환한 완전한 assistant 메시지를 messages에 그대로 다시 전달하세요. K3는 멀티턴 대화와 도구 호출 루프에서 필수입니다. K2.x는 모델별 thinking.keep 동작에 따라 턴 간 보존: kimi-k2.6은 기본 보존 안 함, kimi-k2.7-code는 항상 보존.

Q2. reasoning_content가 추가 토큰을 소모하나요? A: 네, reasoning_content는 입력/출력 토큰 할당량에 포함됩니다. 자세한 가격은 MoonshotAI 가격 문서를 참고하세요.


변경 이력

날짜변경
2026-07-22초판 작성 (공식 Thinking Mode 가이드 한글화)
2026-07-22제목에 "Kimi" 접두사 추가, 본문 H1 중복 제거

댓글

아직 댓글이 없습니다.

댓글을 작성하려면 로그인이 필요합니다.