ドキュメンテーション
LLM のローカル実行
プリセット
API
ユーザーインターフェース
高度な設定
LLM のローカル実行
プリセット
API
ユーザーインターフェース
高度な設定
ツール使用
ツール使用により、LLM は LM Studio の REST API (または任意の OpenAI クライアント) を介して、/v1/chat/completions
エンドポイントを通じて外部関数や API の呼び出しを要求できるようになります。これにより、LLM の機能はテキスト出力の範囲をはるかに超えて拡張されます。
🔔 ツール使用には LM Studio 0.3.6 以降が必要です。こちらから入手してください。
ご自身のコードから LM Studio をプログラム的に使用するには、LM Studio をローカルサーバーとして実行してください。
LM Studio の「開発者」タブから、または lms
CLI を介してサーバーを起動できます。
lms server start
npx lmstudio install-cli
を実行して lms
をインストールします。これにより、OpenAI のような REST API を介して LM Studio と対話できるようになります。LM Studio の OpenAI のような API の概要については、「LM Studio をサーバーとして実行する」を参照してください。
LM Studio の「チャット」または「開発者」タブから、または lms
CLI を介してモデルをロードできます。
lms load
Curl
Python
ツール使用とは
┌──────────────────────────┐ │ SETUP: LLM + Tool list │ └──────────┬───────────────┘ ▼ ┌──────────────────────────┐ │ Get user input │◄────┐ └──────────┬───────────────┘ │ ▼ │ ┌──────────────────────────┐ │ │ LLM prompted w/messages │ │ └──────────┬───────────────┘ │ ▼ │ Needs tools? │ │ │ │ Yes No │ │ │ │ ▼ └────────────┐ │ ┌─────────────┐ │ │ │Tool Response│ │ │ └──────┬──────┘ │ │ ▼ │ │ ┌─────────────┐ │ │ │Execute tools│ │ │ └──────┬──────┘ │ │ ▼ ▼ │ ┌─────────────┐ ┌───────────┐ │Add results │ │ Normal │ │to messages │ │ response │ └──────┬──────┘ └─────┬─────┘ │ ▲ └───────────────────────┘
LM Studio は、リクエストボディの tools
パラメータに関数定義が与えられた場合、/v1/chat/completions
エンドポイントを介したツール使用をサポートしています。ツールは、そのパラメータと使用方法を記述する関数定義の配列として指定されます。例:
これは OpenAI のFunction Calling API と同じ形式に従っており、OpenAI クライアント SDK を介して動作することが期待されます。
この例のフローでは、lmstudio-community/Qwen2.5-7B-Instruct-GGUF をモデルとして使用します。
LLM にツールのリストを提供します。これらはモデルが呼び出しを要求できるツールです。例:
// the list of tools is model-agnostic [ { "type": "function", "function": { "name": "get_delivery_date", "description": "Get the delivery date for a customer's order", "parameters": { "type": "object", "properties": { "order_id": { "type": "string" } }, "required": ["order_id"] } } } ]
このリストは、モデルのチャットテンプレートに応じて、モデルの system
プロンプトに挿入されます。Qwen2.5-Instruct
の場合、これは次のようになります。
<|im_start|>system You are Qwen, created by Alibaba Cloud. You are a helpful assistant. # Tools You may call one or more functions to assist with the user query. You are provided with function signatures within <tools></tools> XML tags: <tools> {"type": "function", "function": {"name": "get_delivery_date", "description": "Get the delivery date for a customer's order", "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}} </tools> For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags: <tool_call> {"name": <function-name>, "arguments": <args-json-object>} </tool_call><|im_end|>
重要: LLM は関数、API、その他のツールを直接呼び出すことはできないため、モデルはこれらのツールへの呼び出しを要求することしかできません。LLM はテキストのみを出力し、そのテキストを解析して関数をプログラム的に呼び出すことができます。
プロンプトが与えられると、LLM は次のいずれかを決定できます。
User: Get me the delivery date for order 123 Model: <tool_call> {"name": "get_delivery_date", "arguments": {"order_id": "123"}} </tool_call>
User: Hi Model: Hello! How can I assist you today?
LM Studio は、モデルからのテキスト出力を OpenAI に準拠した chat.completion
応答オブジェクトに解析します。
tools
へのアクセスを与えられた場合、LM Studio はツール呼び出しを chat.completion
応答オブジェクトの response.choices[0].message.tool_calls
フィールドに解析しようとします。response.choices[0].message.content
フィールドに返されます。tool_calls
フィールドに解析できません。これは、期待通りに tool_calls
が受信されない場合のトラブルシューティングに役立ちます。Qwen2.5-Instruct
の不適切にフォーマットされたツール呼び出しの例:<tool_call> ["name": "get_delivery_date", function: "date"] </tool_call>
括弧が正しくなく、呼び出しが
name, argument
の形式に従っていないことに注意してください。
ご自身のコードは、モデルからのツール呼び出しをチェックするために chat.completion
応答を解析し、モデルによって指定されたパラメータで適切なツールを呼び出します。次に、ご自身のコードは次の両方を追加します。
モデルに送り返す messages
配列に
# pseudocode, see examples for copy-paste snippets if response.has_tool_calls: for each tool_call: # Extract function name & args function_to_call = tool_call.name # e.g. "get_delivery_date" args = tool_call.arguments # e.g. {"order_id": "123"} # Execute the function result = execute_function(function_to_call, args) # Add result to conversation add_to_messages([ ASSISTANT_TOOL_CALL_MESSAGE, # The request to use the tool TOOL_RESULT_MESSAGE # The tool's response ]) else: # Normal response without tools add_to_messages(response.content)
LLM は、更新されたメッセージ配列で再度プロンプトを与えられますが、ツールへのアクセスはありません。これは以下の理由によるものです。
# Example messages messages = [ {"role": "user", "content": "When will order 123 be delivered?"}, {"role": "assistant", "function_call": { "name": "get_delivery_date", "arguments": {"order_id": "123"} }}, {"role": "tool", "content": "2024-03-15"}, ] response = client.chat.completions.create( model="lmstudio-community/qwen2.5-7b-instruct", messages=messages )
この呼び出し後の response.choices[0].message.content
フィールドは次のようになります。
Your order #123 will be delivered on March 15th, 2024
ループはフローのステップ2に戻って続行されます
注: これはツール使用の厳密な(pedantic)
フローです。ただし、ご自身のユースケースに最も合うようにこのフローを試すことができます。
LM Studio を介して、すべてのモデルが少なくともある程度のツール使用をサポートしています。
ただし、現在、エクスペリエンスの品質に影響を与える可能性のある2つのサポートレベル(ネイティブとデフォルト)があります。
ネイティブツール使用をサポートするモデルは、アプリ内でハンマーバッジが表示され、一般的にツール使用シナリオでより優れたパフォーマンスを発揮します。
「ネイティブ」なツール使用サポートとは、以下の両方を意味します。
tools
配列をシステムプロンプトにフォーマットし、モデルにツール呼び出しのフォーマット方法を伝えるために使用されます。chat.completion
オブジェクトに解析するために必要です。現在 LM Studio でネイティブツール使用サポートを持つモデル(変更される可能性があります)
GGUF
lmstudio-community/Qwen2.5-7B-Instruct-GGUF (4.68 GB)MLX
mlx-community/Qwen2.5-7B-Instruct-4bit (4.30 GB)GGUF
lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF (4.92 GB)MLX
mlx-community/Meta-Llama-3.1-8B-Instruct-8bit (8.54 GB)GGUF
bartowski/Ministral-8B-Instruct-2410-GGUF (4.67 GB)MLX
mlx-community/Ministral-8B-Instruct-2410-4bit (4.67 GB)「デフォルト」のツール使用サポートとは、以下のいずれかを意味します。
内部的には、デフォルトのツール使用は次のように機能します。
tool
ロールのメッセージを user
ロールに変換し、tool
ロールがないチャットテンプレートでも互換性を持たせるassistant
ロールの tool_calls
をデフォルトのツール呼び出しフォーマットに変換する結果はモデルによって異なります。
ネイティブツール使用サポートがないモデルに対して、ターミナルで lms log stream
を実行し、その後 tools
を含むチャット完了リクエストを送信することで、デフォルトのフォーマットを確認できます。デフォルトのフォーマットは変更される可能性があります。
→ % lms log stream Streaming logs from LM Studio timestamp: 11/13/2024, 9:35:15 AM type: llm.prediction.input modelIdentifier: gemma-2-2b-it modelPath: lmstudio-community/gemma-2-2b-it-GGUF/gemma-2-2b-it-Q4_K_M.gguf input: "<start_of_turn>system You are a tool-calling AI. You can request calls to available tools with this EXACT format: [TOOL_REQUEST]{"name": "tool_name", "arguments": {"param1": "value1"}}[END_TOOL_REQUEST] AVAILABLE TOOLS: { "type": "toolArray", "tools": [ { "type": "function", "function": { "name": "get_delivery_date", "description": "Get the delivery date for a customer's order", "parameters": { "type": "object", "properties": { "order_id": { "type": "string" } }, "required": [ "order_id" ] } } } ] } RULES: - Only use tools from AVAILABLE TOOLS - Include all required arguments - Use one [TOOL_REQUEST] block per tool - Never use [TOOL_RESULT] - If you decide to call one or more tools, there should be no other text in your message Examples: "Check Paris weather" [TOOL_REQUEST]{"name": "get_weather", "arguments": {"location": "Paris"}}[END_TOOL_REQUEST] "Send email to John about meeting and open browser" [TOOL_REQUEST]{"name": "send_email", "arguments": {"to": "John", "subject": "meeting"}}[END_TOOL_REQUEST] [TOOL_REQUEST]{"name": "open_browser", "arguments": {}}[END_TOOL_REQUEST] Respond conversationally if no matching tools exist.<end_of_turn> <start_of_turn>user Get me delivery date for order 123<end_of_turn> <start_of_turn>model "
モデルがこのフォーマットに正確に従ってツールを呼び出す場合、つまり
[TOOL_REQUEST]{"name": "get_delivery_date", "arguments": {"order_id": "123"}}[END_TOOL_REQUEST]
その場合、LM Studio はネイティブサポートされるモデルと同様に、それらのツール呼び出しを chat.completions
オブジェクトに解析できます。
ネイティブツール使用サポートがないすべてのモデルには、デフォルトのツール使用サポートがあります。
curl
を使用した例curl を使用した例'へのリンク">この例では、モデルが curl
ユーティリティを使用してツール呼び出しを要求する方法を示します。
この例を Mac または Linux で実行するには、任意のターミナルを使用してください。Windows では、Git Bash を使用してください。
curl http://localhost:1234/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "lmstudio-community/qwen2.5-7b-instruct", "messages": [{"role": "user", "content": "What dell products do you have under $50 in electronics?"}], "tools": [ { "type": "function", "function": { "name": "search_products", "description": "Search the product catalog by various criteria. Use this whenever a customer asks about product availability, pricing, or specifications.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "Search terms or product name" }, "category": { "type": "string", "description": "Product category to filter by", "enum": ["electronics", "clothing", "home", "outdoor"] }, "max_price": { "type": "number", "description": "Maximum price in dollars" } }, "required": ["query"], "additionalProperties": false } } } ] }'
/v1/chat/completions
で認識されるすべてのパラメータが尊重され、利用可能なツールの配列は tools
フィールドで提供される必要があります。
モデルがユーザーメッセージをツール呼び出しで満たすのが最適であると判断した場合、ツール呼び出しリクエストオブジェクトの配列が応答フィールド choices[0].message.tool_calls
で提供されます。
トップレベルの応答オブジェクトの finish_reason
フィールドにも "tool_calls"
が入力されます。
上記の curl
リクエストに対する応答例は次のようになります。
{ "id": "chatcmpl-gb1t1uqzefudice8ntxd9i", "object": "chat.completion", "created": 1730913210, "model": "lmstudio-community/qwen2.5-7b-instruct", "choices": [ { "index": 0, "logprobs": null, "finish_reason": "tool_calls", "message": { "role": "assistant", "tool_calls": [ { "id": "365174485", "type": "function", "function": { "name": "search_products", "arguments": "{\"query\":\"dell\",\"category\":\"electronics\",\"max_price\":50}" } } ] } } ], "usage": { "prompt_tokens": 263, "completion_tokens": 34, "total_tokens": 297 }, "system_fingerprint": "lmstudio-community/qwen2.5-7b-instruct" }
平易な英語で言えば、上記の応答はモデルが次のように言っていると考えることができます。
「
search_products
関数を引数付きで呼び出してください」
query
パラメータには 'dell'、category
パラメータには 'electronics'、max_price
パラメータには '50'として結果を返してください」
tool_calls
フィールドは、実際の関数/API を呼び出すために解析する必要があります。以下の例でその方法を示します。
python
を使用した例python を使用した例'へのリンク">ツール使用は、Python のようなプログラミング言語と組み合わせることで真価を発揮します。Python では、tools
フィールドで指定された関数を実装し、モデルが要求したときにそれらをプログラム的に呼び出すことができます。
以下は、モデルがコンソールに「Hello」という挨拶を出力する say_hello
関数を呼び出すことを可能にする、シンプルなシングルターン(モデルは1回のみ呼び出される)の例です。
single-turn-example.py
from openai import OpenAI # Connect to LM Studio client = OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio") # Define a simple function def say_hello(name: str) → str: print(f"Hello, {name}!") # Tell the AI about our function tools = [ { "type": "function", "function": { "name": "say_hello", "description": "Says hello to someone", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "The person's name" } }, "required": ["name"] } } } ] # Ask the AI to use our function response = client.chat.completions.create( model="lmstudio-community/qwen2.5-7b-instruct", messages=[{"role": "user", "content": "Can you say hello to Bob the Builder?"}], tools=tools ) # Get the name the AI wants to use a tool to say hello to # (Assumes the AI has requested a tool call and that tool call is say_hello) tool_call = response.choices[0].message.tool_calls[0] name = eval(tool_call.function.arguments)["name"] # Actually call the say_hello function say_hello(name) # Prints: Hello, Bob the Builder!
このスクリプトをコンソールから実行すると、次のような結果が得られます。
→ % python single-turn-example.py Hello, Bob the Builder!
名前をいじってみてください
messages=[{"role": "user", "content": "Can you say hello to Bob the Builder?"}]
モデルが異なる名前で say_hello
関数を呼び出すのを確認します。
では、もう少し複雑な例を見てみましょう。
この例では、
get_delivery_date
関数を呼び出せるようにするmulti-turn-example.py
(クリックして展開)from datetime import datetime, timedelta import json import random from openai import OpenAI # Point to the local server client = OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio") model = "lmstudio-community/qwen2.5-7b-instruct" def get_delivery_date(order_id: str) → datetime: # Generate a random delivery date between today and 14 days from now # in a real-world scenario, this function would query a database or API today = datetime.now() random_days = random.randint(1, 14) delivery_date = today + timedelta(days=random_days) print( f"\nget_delivery_date function returns delivery date:\n\n{delivery_date}", flush=True, ) return delivery_date tools = [ { "type": "function", "function": { "name": "get_delivery_date", "description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The customer's order ID.", }, }, "required": ["order_id"], "additionalProperties": False, }, }, } ] messages = [ { "role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user.", }, { "role": "user", "content": "Give me the delivery date and time for order number 1017", }, ] # LM Studio response = client.chat.completions.create( model=model, messages=messages, tools=tools, ) print("\nModel response requesting tool call:\n", flush=True) print(response, flush=True) # Extract the arguments for get_delivery_date # Note this code assumes we have already determined that the model generated a function call. tool_call = response.choices[0].message.tool_calls[0] arguments = json.loads(tool_call.function.arguments) order_id = arguments.get("order_id") # Call the get_delivery_date function with the extracted order_id delivery_date = get_delivery_date(order_id) assistant_tool_call_request_message = { "role": "assistant", "tool_calls": [ { "id": response.choices[0].message.tool_calls[0].id, "type": response.choices[0].message.tool_calls[0].type, "function": response.choices[0].message.tool_calls[0].function, } ], } # Create a message containing the result of the function call function_call_result_message = { "role": "tool", "content": json.dumps( { "order_id": order_id, "delivery_date": delivery_date.strftime("%Y-%m-%d %H:%M:%S"), } ), "tool_call_id": response.choices[0].message.tool_calls[0].id, } # Prepare the chat completion call payload completion_messages_payload = [ messages[0], messages[1], assistant_tool_call_request_message, function_call_result_message, ] # Call the OpenAI API's chat completions endpoint to send the tool call result back to the model # LM Studio response = client.chat.completions.create( model=model, messages=completion_messages_payload, ) print("\nFinal model response with knowledge of the tool call result:\n", flush=True) print(response.choices[0].message.content, flush=True)
このスクリプトをコンソールから実行すると、次のような結果が得られます。
→ % python multi-turn-example.py Model response requesting tool call: ChatCompletion(id='chatcmpl-wwpstqqu94go4hvclqnpwn', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content=None, refusal=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='377278620', function=Function(arguments='{"order_id":"1017"}', name='get_delivery_date'), type='function')]))], created=1730916196, model='lmstudio-community/qwen2.5-7b-instruct', object='chat.completion', service_tier=None, system_fingerprint='lmstudio-community/qwen2.5-7b-instruct', usage=CompletionUsage(completion_tokens=24, prompt_tokens=223, total_tokens=247, completion_tokens_details=None, prompt_tokens_details=None)) get_delivery_date function returns delivery date: 2024-11-19 13:03:17.773298 Final model response with knowledge of the tool call result: Your order number 1017 is scheduled for delivery on November 19, 2024, at 13:03 PM.
上記の原則に基づき、LM Studio モデルとローカルで定義された関数を組み合わせることで、「エージェント」を作成できます。これは、言語モデルとカスタム関数を組み合わせ、リクエストを理解し、基本的なテキスト生成を超えたアクションを実行するシステムです。
以下の例のエージェントは次のことができます。
agent-chat-example.py
(クリックして展開)import json from urllib.parse import urlparse import webbrowser from datetime import datetime import os from openai import OpenAI # Point to the local server client = OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio") model = "lmstudio-community/qwen2.5-7b-instruct" def is_valid_url(url: str) → bool: try: result = urlparse(url) return bool(result.netloc) # Returns True if there's a valid network location except Exception: return False def open_safe_url(url: str) → dict: # List of allowed domains (expand as needed) SAFE_DOMAINS = { "lmstudio.ai", "github.com", "google.com", "wikipedia.org", "weather.com", "stackoverflow.com", "python.org", "docs.python.org", } try: # Add http:// if no scheme is present if not url.startswith(('http://', 'https://')): url = 'http://' + url # Validate URL format if not is_valid_url(url): return {"status": "error", "message": f"Invalid URL format: {url}"} # Parse the URL and check domain parsed_url = urlparse(url) domain = parsed_url.netloc.lower() base_domain = ".".join(domain.split(".")[-2:]) if base_domain in SAFE_DOMAINS: webbrowser.open(url) return {"status": "success", "message": f"Opened {url} in browser"} else: return { "status": "error", "message": f"Domain {domain} not in allowed list", } except Exception as e: return {"status": "error", "message": str(e)} def get_current_time() → dict: """Get the current system time with timezone information""" try: current_time = datetime.now() timezone = datetime.now().astimezone().tzinfo formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S %Z") return { "status": "success", "time": formatted_time, "timezone": str(timezone), "timestamp": current_time.timestamp(), } except Exception as e: return {"status": "error", "message": str(e)} def analyze_directory(path: str = ".") → dict: """Count and categorize files in a directory""" try: stats = { "total_files": 0, "total_dirs": 0, "file_types": {}, "total_size_bytes": 0, } for entry in os.scandir(path): if entry.is_file(): stats["total_files"] += 1 ext = os.path.splitext(entry.name)[1].lower() or "no_extension" stats["file_types"][ext] = stats["file_types"].get(ext, 0) + 1 stats["total_size_bytes"] += entry.stat().st_size elif entry.is_dir(): stats["total_dirs"] += 1 # Add size of directory contents for root, _, files in os.walk(entry.path): for file in files: try: stats["total_size_bytes"] += os.path.getsize(os.path.join(root, file)) except (OSError, FileNotFoundError): continue return {"status": "success", "stats": stats, "path": os.path.abspath(path)} except Exception as e: return {"status": "error", "message": str(e)} tools = [ { "type": "function", "function": { "name": "open_safe_url", "description": "Open a URL in the browser if it's deemed safe", "parameters": { "type": "object", "properties": { "url": { "type": "string", "description": "The URL to open", }, }, "required": ["url"], }, }, }, { "type": "function", "function": { "name": "get_current_time", "description": "Get the current system time with timezone information", "parameters": { "type": "object", "properties": {}, "required": [], }, }, }, { "type": "function", "function": { "name": "analyze_directory", "description": "Analyze the contents of a directory, counting files and folders", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "The directory path to analyze. Defaults to current directory if not specified.", }, }, "required": [], }, }, }, ] def process_tool_calls(response, messages): """Process multiple tool calls and return the final response and updated messages""" # Get all tool calls from the response tool_calls = response.choices[0].message.tool_calls # Create the assistant message with tool calls assistant_tool_call_message = { "role": "assistant", "tool_calls": [ { "id": tool_call.id, "type": tool_call.type, "function": tool_call.function, } for tool_call in tool_calls ], } # Add the assistant's tool call message to the history messages.append(assistant_tool_call_message) # Process each tool call and collect results tool_results = [] for tool_call in tool_calls: # For functions with no arguments, use empty dict arguments = ( json.loads(tool_call.function.arguments) if tool_call.function.arguments.strip() else {} ) # Determine which function to call based on the tool call name if tool_call.function.name == "open_safe_url": result = open_safe_url(arguments["url"]) elif tool_call.function.name == "get_current_time": result = get_current_time() elif tool_call.function.name == "analyze_directory": path = arguments.get("path", ".") result = analyze_directory(path) else: # llm tried to call a function that doesn't exist, skip continue # Add the result message tool_result_message = { "role": "tool", "content": json.dumps(result), "tool_call_id": tool_call.id, } tool_results.append(tool_result_message) messages.append(tool_result_message) # Get the final response final_response = client.chat.completions.create( model=model, messages=messages, ) return final_response def chat(): messages = [ { "role": "system", "content": "You are a helpful assistant that can open safe web links, tell the current time, and analyze directory contents. Use these capabilities whenever they might be helpful.", } ] print( "Assistant: Hello! I can help you open safe web links, tell you the current time, and analyze directory contents. What would you like me to do?" ) print("(Type 'quit' to exit)") while True: # Get user input user_input = input("\nYou: ").strip() # Check for quit command if user_input.lower() == "quit": print("Assistant: Goodbye!") break # Add user message to conversation messages.append({"role": "user", "content": user_input}) try: # Get initial response response = client.chat.completions.create( model=model, messages=messages, tools=tools, ) # Check if the response includes tool calls if response.choices[0].message.tool_calls: # Process all tool calls and get final response final_response = process_tool_calls(response, messages) print("\nAssistant:", final_response.choices[0].message.content) # Add assistant's final response to messages messages.append( { "role": "assistant", "content": final_response.choices[0].message.content, } ) else: # If no tool call, just print the response print("\nAssistant:", response.choices[0].message.content) # Add assistant's response to messages messages.append( { "role": "assistant", "content": response.choices[0].message.content, } ) except Exception as e: print(f"\nAn error occurred: {str(e)}") exit(1) if __name__ == "__main__": chat()
このスクリプトをコンソールから実行すると、エージェントとチャットできます。
→ % python agent-example.py Assistant: Hello! I can help you open safe web links, tell you the current time, and analyze directory contents. What would you like me to do? (Type 'quit' to exit) You: What time is it? Assistant: The current time is 14:11:40 (EST) as of November 6, 2024. You: What time is it now? Assistant: The current time is 14:13:59 (EST) as of November 6, 2024. You: Open lmstudio.ai Assistant: The link to lmstudio.ai has been opened in your default web browser. You: What's in my current directory? Assistant: Your current directory at `/Users/matt/project` contains a total of 14 files and 8 directories. Here's the breakdown: - Files without an extension: 3 - `.mjs` files: 2 - `.ts` (TypeScript) files: 3 - Markdown (`md`) file: 1 - JSON files: 4 - TOML file: 1 The total size of these items is 1,566,990,604 bytes. You: Thank you! Assistant: You're welcome! If you have any other questions or need further assistance, feel free to ask. You:
/v1/chat/completions
(stream=true
) を介してストリーミングを行う際、ツール呼び出しはチャンクで送信されます。関数名と引数は、chunk.choices[0].delta.tool_calls.function.name
および chunk.choices[0].delta.tool_calls.function.arguments
を介して断片的に送信されます。
例えば、get_current_weather(location="San Francisco")
を呼び出す場合、各 chunk.choices[0].delta.tool_calls[0]
オブジェクトのストリーミングされた ChoiceDeltaToolCall
は次のようになります。
ChoiceDeltaToolCall(index=0, id='814890118', function=ChoiceDeltaToolCallFunction(arguments='', name='get_current_weather'), type='function') ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='{"', name=None), type=None) ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='location', name=None), type=None) ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='":"', name=None), type=None) ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='San Francisco', name=None), type=None) ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='"}', name=None), type=None)
これらのチャンクは、実行のための完全な関数シグネチャを形成するために、ストリーム全体で累積される必要があります。
以下の例は、/v1/chat/completions
ストリーミングエンドポイント (stream=true
) を介して、シンプルなツール強化型チャットボットを作成する方法を示しています。
tool-streaming-chatbot.py
(クリックして展開)from openai import OpenAI import time client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio") MODEL = "lmstudio-community/qwen2.5-7b-instruct" TIME_TOOL = { "type": "function", "function": { "name": "get_current_time", "description": "Get the current time, only if asked", "parameters": {"type": "object", "properties": {}}, }, } def get_current_time(): return {"time": time.strftime("%H:%M:%S")} def process_stream(stream, add_assistant_label=True): """Handle streaming responses from the API""" collected_text = "" tool_calls = [] first_chunk = True for chunk in stream: delta = chunk.choices[0].delta # Handle regular text output if delta.content: if first_chunk: print() if add_assistant_label: print("Assistant:", end=" ", flush=True) first_chunk = False print(delta.content, end="", flush=True) collected_text += delta.content # Handle tool calls elif delta.tool_calls: for tc in delta.tool_calls: if len(tool_calls) <= tc.index: tool_calls.append({ "id": "", "type": "function", "function": {"name": "", "arguments": ""} }) tool_calls[tc.index] = { "id": (tool_calls[tc.index]["id"] + (tc.id or "")), "type": "function", "function": { "name": (tool_calls[tc.index]["function"]["name"] + (tc.function.name or "")), "arguments": (tool_calls[tc.index]["function"]["arguments"] + (tc.function.arguments or "")) } } return collected_text, tool_calls def chat_loop(): messages = [] print("Assistant: Hi! I am an AI agent empowered with the ability to tell the current time (Type 'quit' to exit)") while True: user_input = input("\nYou: ").strip() if user_input.lower() == "quit": break messages.append({"role": "user", "content": user_input}) # Get initial response response_text, tool_calls = process_stream( client.chat.completions.create( model=MODEL, messages=messages, tools=[TIME_TOOL], stream=True, temperature=0.2 ) ) if not tool_calls: print() text_in_first_response = len(response_text) > 0 if text_in_first_response: messages.append({"role": "assistant", "content": response_text}) # Handle tool calls if any if tool_calls: tool_name = tool_calls[0]["function"]["name"] print() if not text_in_first_response: print("Assistant:", end=" ", flush=True) print(f"**Calling Tool: {tool_name}**") messages.append({"role": "assistant", "tool_calls": tool_calls}) # Execute tool calls for tool_call in tool_calls: if tool_call["function"]["name"] == "get_current_time": result = get_current_time() messages.append({ "role": "tool", "content": str(result), "tool_call_id": tool_call["id"] }) # Get final response after tool execution final_response, _ = process_stream( client.chat.completions.create( model=MODEL, messages=messages, stream=True ), add_assistant_label=False ) if final_response: print() messages.append({"role": "assistant", "content": final_response}) if __name__ == "__main__": chat_loop()
このスクリプトをコンソールから実行すると、ボットとチャットできます
→ % python tool-streaming-chatbot.py Assistant: Hi! I am an AI agent empowered with the ability to tell the current time (Type 'quit' to exit) You: Tell me a joke, then tell me the current time Assistant: Sure! Here's a light joke for you: Why don't scientists trust atoms? Because they make up everything. Now, let me get the current time for you. **Calling Tool: get_current_time** The current time is 18:49:31. Enjoy your day! You:
他の LM Studio ユーザーとチャットしたり、LLM、ハードウェアなどについてLM Studio Discord サーバーで議論したりできます。
このページの内容
クイックスタート
1. LM Studio をサーバーとして起動する
2. モデルをロードする
3. 例をコピー、貼り付け、実行する!
ツール使用
「ツール使用」とは実際には何か?
高レベルのフロー
詳細なフロー
サポートされているモデル
ネイティブツール使用サポート
デフォルトのツール使用サポート
curl を使用した例
python を使用した例
シングルターンの例
マルチターンの例
高度なエージェントの例
ストリーミング
コミュニティ