📞

Foundry LocalモデルでFunctionCalling

に公開

2通りの方法を紹介してみます。

inference_model.jsonを変更する方法

https://github.com/microsoft/Foundry-Local/tree/main/samples/python/functioncalling

cacheにダウンロードされたモデルのフォルダの中に「inference_model.json」というファイルがあります。

これを以下のように書き換えます。

Foundry Localのサービスを再起動します。

foundry service restart

上記でclient.chat.completions.create(stream=false)すると、response.choices[0].message.contentが以下ようなフォーマットで出力されます。

functools[{"name": "booking_flight_tickets", "arguments": {"origin_airport_code": "PEK", "destination_airport_code": "CDG", "departure_date": "2025-12-04", "return_date": "2025-12-10"}}, {"name": "booking_hotels", "arguments": {"destination": "Paris", "check_in_date": "2025-12-04", "checkout_date": "2025-12-10"}}]

このやりかたの注意点としては、inference_model.jsonを変更してしまうと、普通のチャットが出来なくなってしまいます。

これだと、変更したら最後、そのモデルはFunctionCallingの宿命を背負い続けることになります。

システムプロンプトでFunctionCallingの応答を強制させる

さきほどのやり方では融通が利かないため、システムプロンプトによる対応をとってみました。

以下サンプルコードです。

from foundry_local import FoundryLocalManager
import openai


alias = "phi-4-mini"
manager = FoundryLocalManager(alias_or_model_id=alias, bootstrap=False)
client = openai.OpenAI(
    base_url=manager.endpoint,
    api_key=manager.api_key  # API key is not required for local usage
)

tool_list = '[{"name": "booking_flight_tickets", "description": "booking flights", "parameters": {"origin_airport_code": {"description": "The name of Departure airport code", "type": "string"}, "destination_airport_code": {"description": "The name of Destination airport code", "type": "string"}, "departure_date": {"description": "The date of outbound flight", "type": "string"}, "return_date": {"description": "The date of return flight", "type": "string"}}}, {"name": "booking_hotels", "description": "booking hotel", "parameters": {"destination": {"description": "The name of the city", "type": "string"}, "check_in_date": {"description": "The date of check in", "type": "string"}, "checkout_date": {"description": "The date of check out", "type": "string"}}}]'

response = client.chat.completions.create(
    model=manager.get_model_info(alias).id,
    messages=[
        {"role":"system", "content": "<|system|> You are a helpful assistant with these tools. If you decide to call functions:\n* all function calls should be generated in a single JSON list formatted as [{\"name\": [function name], \"arguments\": [function arguments as JSON]}, ...]\n  * follow the provided JSON schema. Do not hallucinate arguments or values. Do not blindly copy values from the provided samples\n  * respect the argument type formatting. E.g., if the type is number and format is float, write value 7 as 7.0\n  * make sure you pick the right functions that match the japanese user intent<|end|><|user|>{Content}<|end|><|assistant|>"},
        {"role": "user", "content": "book flight ticket from Beijing to Paris(using airport code) in 2025-12-04 to 2025-12-10 , then book hotel from 2025-12-04 to 2025-12-10 in Paris"}],
    tools=[{"name": "booking_flight_tickets", "description": "booking flights", "parameters": {"origin_airport_code": {"description": "The name of Departure airport code", "type": "string"}, "destination_airport_code": {"description": "The name of Destination airport code", "type": "string"}, "departure_date": {"description": "The date of outbound flight", "type": "string"}, "return_date": {"description": "The date of return flight", "type": "string"}}}, {"name": "booking_hotels", "description": "booking hotel", "parameters": {"destination": {"description": "The name of the city", "type": "string"}, "check_in_date": {"description": "The date of check in", "type": "string"}, "checkout_date": {"description": "The date of check out", "type": "string"}}}],
    temperature=0.00001,
    max_tokens=4096,
    top_p = 1.0,
    stream=False
)

function_call = response.choices[0].message.function_call
print("Function call:", function_call)

answer = response.choices[0].message.content
print("Answer:")
print(answer)

ポイントは、

{"role":"system", "content": "<|system|> You are a helpful assistant with these tools. If you decide to call functions:\n* all function calls should be generated in a single JSON list formatted as [{\"name\": [function name], \"arguments\": [function arguments as JSON]}, ...]\n  * follow the provided JSON schema. Do not hallucinate arguments or values. Do not blindly copy values from the provided samples\n  * respect the argument type formatting. E.g., if the type is number and format is float, write value 7 as 7.0\n  * make sure you pick the right functions that match the japanese user intent<|end|><|user|>{Content}<|end|><|assistant|>"},

の部分です。

これにより、以下の応答が得られます。
※functoolsは邪魔だったので、出力から外すようシステムプロンプトで指示しました。

[{"name":"booking_flight_tickets","arguments":"origin_airport_code":"PEK","destination_airport_code":"CDG","departure_date":"2025-12-04","return_date":"2025-12-10"}},{"name":"booking_hotels","arguments":{"destination":"Paris","check_in_date":"2025-12-04","checkout_date":"2025-12-10"}}]

このやり方のメリットは、システムプロンプトを変更すれば、モデルがチャット形式にもなるし、FunctionCallingの形式にもなれることです。

ヘッドウォータース

Discussion