Tool calling with Moonshot's Kimi K2 mode

Moonshot's new Kimi 2  model is extremely inexpensive to use. Moonshot AI (月之暗面) is a prominent Chinese artificial intelligence startup focused on developing large language models with the long-term goal of achieving Artificial General Intelligence (AGI). The company gained significant recognition for its Kimi chatbot, which pioneered an exceptionally large context window capable of processing up to two million Chinese characters in a single prompt. Backed by major investors like Alibaba, Moonshot AI has quickly become one of China's most valuable AI unicorns and a key competitor in the global AI race.

The release of Kimi 2 last week has been referred to as "another DeepSeek moment."

You need a Moonshot API access key from https://platform.moonshot.ai/console/account

The direct API pricing from Moonshot AI is approximately:

Input Tokens: ~$0.60 per 1 million tokens

Output Tokens: ~$2.50 per 1 million tokens

Several inference providers in the USA are now supporting Kimi 2 also. Kim 2 is a mixture of expert model with 32 billion parameters active at any time during inference. The total model size is a trillion parameters.

Tool use using the OpenAI Python library is fairly straightforward:

from typing import *
import os
import json
from openai import OpenAI
from openai.types.chat.chat_completion import Choice
client = OpenAI(
base_url="https://api.moonshot.ai/v1",
api_key=os.environ.get("MOONSHOT_API_KEY"),
)

# The specific implementation of the search tool
def search_impl(arguments: Dict[str, Any]) -> Any:
"""
When using the search tool provided by Moonshot AI, you just need to return the arguments as they are,
without any additional processing logic.
"""
return arguments

# START: Added Tool Implementations
# ---------------------------------
def list_files_impl() -> str:
"""Lists files in the current directory, one per line."""
print("--- Calling list_files_impl ---")
try:
files = os.listdir('.')
if not files:
return "The current directory is empty."
return "\n".join(files)
except Exception as e:
return f"Error listing files: {e}"

def get_file_contents_impl(filename: str) -> str:
"""Reads and returns the contents of a file."""
print(f"--- Calling get_file_contents_impl for file: {filename} ---")
try:
with open(filename, 'r', encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
return f"Error: File '{filename}' not found."
except Exception as e:
return f"Error reading file '{filename}': {e}"
# -------------------------------
# END: Added Tool Implementations


def chat(messages) -> Choice:
completion = client.chat.completions.create(
model="moonshot-v1-8k", # Using a standard model for tool use demonstration
messages=messages,
temperature=0.3,
tools=[
# Tool 1: Moonshot's built-in web search
{
"type": "builtin_function",
"function": {
"name": "$web_search",
},
},
# START: Added Tool Schemas
# -------------------------
# Tool 2: List files in current directory
{
"type": "function",
"function": {
"name": "list_files",
"description": "Lists all files in the current working directory, one file per line.",
"parameters": {
"type": "object",
"properties": {},
},
},
},
# Tool 3: Get contents of a file
{
"type": "function",
"function": {
"name": "get_file_contents",
"description": "Returns the full contents of a specified file in the current directory.",
"parameters": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The name of the file whose contents are to be retrieved."
}
},
"required": ["filename"],
},
},
}
]
)
return completion.choices[0]
def main():
messages = [
{"role": "system", "content": "You are Kimi, an AI assistant who can browse the web and interact with the local file system. Return all answers in English."},
]
# Updated question to demonstrate file system tools
messages.append({
"role": "user",
"content": "Please list the files in the current directory, and then show me the contents of the python script you find."
##"content": "Please search for Mark Watson AI consultant and author, and tell me what his hobbies are."
})
finish_reason = None
while finish_reason is None or finish_reason == "tool_calls":
choice = chat(messages)
finish_reason = choice.finish_reason
if finish_reason == "tool_calls":
messages.append(choice.message)
for tool_call in choice.message.tool_calls:
tool_call_name = tool_call.function.name
# Note: Arguments can be an empty string if no parameters are needed.
tool_call_arguments_str = tool_call.function.arguments
tool_call_arguments = {}
if tool_call_arguments_str and tool_call_arguments_str.strip():
tool_call_arguments = json.loads(tool_call_arguments_str)

print(f"Model wants to call tool '{tool_call_name}' with arguments: {tool_call_arguments}")
# START: Updated Tool Handling Logic
# ----------------------------------
if tool_call_name == "$web_search":
tool_result = search_impl(tool_call_arguments)
elif tool_call_name == "list_files":
tool_result = list_files_impl()
elif tool_call_name == "get_file_contents":
filename = tool_call_arguments.get('filename')
if filename:
tool_result = get_file_contents_impl(filename=filename)
else:
tool_result = "Error: 'filename' parameter is required."
else:
tool_result = f"Error: unable to find tool by name '{tool_call_name}'"
# --------------------------------
# END: Updated Tool Handling Logic
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": tool_call_name,
"content": json.dumps({"result": tool_result}) # Encapsulate result in a JSON object for consistency
})
print("\n--- Final Answer ---\n")
print(choice.message.content)
if __name__ == '__main__':
main()




Comments

Popular posts from this blog

I am moving back to the Google platform, less excited by what Apple is offering

Getting closer to AGI? Google's NoteBookLM and Replit's AI Coding Agent

My Dad's work with Robert Oppenheimer and Edward Teller