ドキュメント
インテグレーション
Model Context Protocol (MCP)
モデル (model.yaml)
API
インテグレーション
Model Context Protocol (MCP)
モデル (model.yaml)
API
API
ツール利用
LLMが外部関数やAPIと対話できるようにします。
ツール利用により、LLMはLM StudioのREST API(または任意のOpenAIクライアント)経由で、/v1/chat/completionsエンドポイントを通じて外部関数やAPIの呼び出しをリクエストできるようになります。これにより、機能がテキスト出力以外にも拡張されます。
LM Studioを自身のコードからプログラムで利用するには、LM Studioをローカルサーバーとして実行してください。
サーバーは、LM Studioの「開発者」タブから、またはlms CLI経由で有効にすることができます。
lms server start
lmsをインストールするには、npx lmstudio install-cliを実行してください。これにより、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"] } } } ]
このリストは、モデルのチャットテンプレートに応じて、モデルのシステムプロンプトに挿入されます。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に戻ります。
注:これはツール利用のための*厳格な*フローです。しかし、あなたのユースケースに最適なフローにするために、このフローを実験することができます。
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 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ユーティリティを使用して、モデルがツール呼び出しをリクエストする様子を示します。
この例をMacまたはLinuxで実行するには、任意のターミナルを使用してください。Windowsでは、Git Bashを使用してください。
curl https://: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関数を、引数
- クエリパラメータに「dell」、
- カテゴリパラメータに「electronics」、
- 最大価格パラメータに「50」
を渡して呼び出してください。そして結果を返してください。」
tool_callsフィールドは、実際の関数/APIを呼び出すために解析する必要があります。以下の例は、その方法を示しています。
ツール利用は、Pythonのようなプログラミング言語と組み合わせることで真価を発揮します。そこでは、モデルがリクエストしたときにプログラムで呼び出すために、toolsフィールドで指定された関数を実装できます。
以下は、モデルがsay_helloという名前の関数を呼び出して、コンソールに挨拶メッセージを出力できるようにする、シンプルなシングルターン(モデルは一度だけ呼び出されます)の例です。
single-turn-example.py
from openai import OpenAI # Connect to LM Studio client = OpenAI(base_url="https://: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="https://: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="https://: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")を呼び出す場合、ストリーミングされるChoiceDeltaToolCallは、各chunk.choices[0].delta.tool_calls[0]オブジェクト内で次のようになります。
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 サーバーで議論しましょう。
このページのソースはGitHubで利用可能です。
このページについて
クイックスタート
1. LM Studioをサーバーとして起動する
2. モデルをロードする
3. 例をコピー、ペーストして実行する!
ツール利用
「ツール利用」とは具体的に何ですか?
ハイレベルなフロー
詳細なフロー
サポートされているモデル
ネイティブツール利用サポート
デフォルトツール利用サポート
Curlを使用した例
Pythonを使用した例
シングルターン例
マルチターン例
高度なエージェント例
ストリーミング
コミュニティ