OpenAI SDK के साथ Ollama API टूल कॉलिंग उदाहरण
टूल कॉलिंग मॉडल को आपके कोड में एक फ़ंक्शन चलाने के लिए कहने देती है और फिर परिणाम का उपयोग अपने उत्तर में करती है। नीचे एक होस्टेड एंडपॉइंट के खिलाफ OpenAI SDK के साथ एक पूर्ण उदाहरण दिया गया है, साथ ही स्ट्रीमिंग और अधिकांश विफलताओं का कारण बनने वाली गलतियाँ।
अद्यतन

मुख्य बिंदु
- अपने फ़ंक्शन को tools में JSON स्कीमा के रूप में भेजें; मॉडल टेक्स्ट के बजाय tool_calls के साथ जवाब देता है।
- आप फ़ंक्शन चलाते हैं, परिणाम को role tool संदेश के रूप में जोड़ते हैं, और API को फिर से कॉल करते हैं।
- सदैव तर्कों को रक्षात्मक रूप से पार्स करें, क्योंकि एक मॉडल खराब या अप्रत्याशित JSON लौटा सकता है।
- स्ट्रीम किए गए टूल कॉल टुकड़ों में आते हैं जिन्हें आपको इंडेक्स द्वारा जोड़ना होगा।
लूप कैसा दिखता है
यदि आप एक होस्टेड एंडपॉइंट के खिलाफ काम करने वाले ollama API टूल कॉलिंग उदाहरण की तलाश में हैं, तो आकार मानक OpenAI वाला है। आप अपने फ़ंक्शन्स को tools सरणी में वर्णित करते हैं। मॉडल या तो टेक्स्ट में जवाब देता है या tool_calls सूची लौटाता है जो फ़ंक्शन और उसके तर्कों को नामित करती है। मॉडल कभी कुछ भी नहीं चलाता। आपका कोड फ़ंक्शन चलाता है, आउटपुट वापस भेजता है, और मॉडल अंतिम जवाब लिखता है।
इससे टूल उपयोग का एक राउंड ट्रिप दो API कॉल्स बनाता है:
- यूज़र संदेश और टूल परिभाषाएँ भेजें।
tool_callsवाले एक असिस्टेंट संदेश प्राप्त करें। प्रत्येक कॉल को स्थानीय रूप से चलाएं।- मूल संदेश, असिस्टेंट संदेश, और प्रत्येक कॉल के लिए एक
role: "tool"संदेश भेजें जिसमें उसका परिणाम हो। - अंतिम टेक्स्ट जवाब प्राप्त करें।
उदाहरणों में बेस URL https://api.ollamaapi.com/v1 और मॉडल ID uncensored का उपयोग किया गया है। एंडपॉइंट एक होस्टेड सेवा है, इसलिए कुंजी API कुंजी पृष्ठ से आती है। यदि आप बेस URL, कुंजी और मॉडल नाम बदल दें, तो यह कोड स्थानीय Ollama सर्वर पर भी चलता है, बशर्ते स्थानीय मॉडल टूल्स का समर्थन करता हो।
एक पूर्ण Python उदाहरण
उदाहरण मॉडल को एक फ़ंक्शन, get_order_status, देता है, जो एक छोटे शब्दकोश द्वारा संचालित है। एक वास्तविक अनुप्रयोग उस बिंदु पर एक डेटाबेस या आंतरिक सेवा से क्वेरी करेगा।
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.ollamaapi.com/v1", api_key="YOUR_KEY")
ORDERS = {"A1001": "shipped", "A1002": "processing", "A1003": "delivered"}
def get_order_status(order_id: str) -> str:
return ORDERS.get(order_id, "not found")
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "Order ID such as A1001"}
},
"required": ["order_id"],
},
},
}]
messages = [{"role": "user", "content": "Where is order A1002?"}]
first = client.chat.completions.create(
model="uncensored",
messages=messages,
tools=tools,
tool_choice="auto",
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # keep the assistant turn with its tool_calls
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_order_status(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
final = client.chat.completions.create(
model="uncensored",
messages=messages,
tools=tools,
)
print(final.choices[0].message.content)
else:
print(msg.content)यहाँ तीन बातें महत्वपूर्ण हैं। असिस्टेंट संदेश जिसमें tool_calls हैं, को टूल परिणामों से पहले इतिहास में वापस जाना चाहिए, वरना अगला अनुरोध अस्वीकार या भ्रमित हो जाएगा। प्रत्येक टूल संदेश में उस कॉल का tool_call_id होना चाहिए जिसका वह जवाब देता है। और दूसरे अनुरोध में अभी भी tools शामिल होना चाहिए, क्योंकि मॉडल पहले परिणाम को देखने के बाद एक अन्य फ़ंक्शन को कॉल करना चाह सकता है।
curl के साथ वही अनुरोध
curl के साथ परीक्षण करने से संदर्भ से SDK हट जाता है, जो मदद करता है जब आप अनिश्चित हैं कि कोई समस्या आपके कोड में है या अनुरोध में।
curl https://api.ollamaapi.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [{"role": "user", "content": "Where is order A1002?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]
}
}
}],
"tool_choice": "auto"
}'सफल प्रथम प्रतिक्रिया में finish_reason, tool_calls पर सेट, एक खाली या null content, और एक tool_calls सरणी होती है। arguments फ़ील्ड JSON रखने वाला एक स्ट्रिंग है, कोई नेस्टेड ऑब्जेक्ट नहीं, इसलिए पायथन उदाहरण json.loads को कॉल करता है।
tool_choice फ़ील्ड अनुरोध की कठोरता को नियंत्रित करती है। auto मॉडल को निर्णय लेने देता है। एक वस्तु पास करना जो एक फ़ंक्शन का नाम बताती है उस विशिष्ट फ़ंक्शन की मांग करती है। auto का उपयोग करें जब तक कि आपके पास कारण न हो, क्योंकि एक संदेश पर एक कॉल को जबरन करने जिसकी आवश्यकता नहीं है, काल्पनिक तर्क पैदा करता है।
Node में वही लूप
Node संस्करण आधिकारिक openai पैकेज का उपयोग करता है और समान चरणों का पालन करता है। यह संस्करण Promise.all के साथ प्रति टर्न एक से अधिक कॉल संभालता है।
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.ollamaapi.com/v1",
apiKey: process.env.API_KEY,
});
const handlers = {
get_order_status: async ({ order_id }) =>
({ A1001: "shipped", A1002: "processing" })[order_id] ?? "not found",
};
const tools = [{
type: "function",
function: {
name: "get_order_status",
description: "Look up the status of an order by its ID.",
parameters: {
type: "object",
properties: { order_id: { type: "string" } },
required: ["order_id"],
},
},
}];
const messages = [{ role: "user", content: "Where is order A1001?" }];
const first = await client.chat.completions.create({
model: "uncensored", messages, tools,
});
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
const results = await Promise.all(msg.tool_calls.map(async (call) => {
const args = JSON.parse(call.function.arguments);
const out = await handlers[call.function.name](args);
return { role: "tool", tool_call_id: call.id, content: String(out) };
}));
messages.push(...results);
const final = await client.chat.completions.create({
model: "uncensored", messages, tools,
});
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}स्ट्रीमिंग टूल कॉल्स
stream: true के साथ जवाब SSE के माध्यम से आता है, और फ़ंक्शन कॉल टुकड़ों में आते हैं। प्रत्येक चंक में delta.tool_calls प्रविष्टि होती है जिसमें index होता है। किसी इंडेक्स के लिए पहला टुकड़ा कॉल ID और फ़ंक्शन नाम रखता है। बाद के टुकड़े arguments स्ट्रिंग के टुकड़े जोड़ते हैं। प्रत्येक इंडेक्स के लिए टुकड़ों को संयोजित करें, और स्ट्रीम समाप्त होने के बाद ही JSON पार्स करें।
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Where is order A1003?"}],
tools=tools,
stream=True,
)
calls = {}
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
for part in (delta.tool_calls or []):
slot = calls.setdefault(part.index, {"id": "", "name": "", "args": ""})
if part.id:
slot["id"] = part.id
if part.function and part.function.name:
slot["name"] = part.function.name
if part.function and part.function.arguments:
slot["args"] += part.function.arguments
for slot in calls.values():
print(slot["name"], json.loads(slot["args"]))याद रखें कि एक स्ट्रीम किए गए अनुरोध में कॉन्करेंसी स्लॉट स्ट्रीम समाप्त होने तक बना रहता है। एक पूर्ण कुंजी एक साथ 8 अनुरोध और प्रति मिनट 300 की अनुमति देती है, एक ट्रायल कुंजी 2 और 60। यदि आप कई उपयोगकर्ताओं के लिए समानांतर टूल लूप चलाते हैं, तो प्रत्येक खुली स्ट्रीम को पहले संख्या के खिलाफ गिनें।
चूक और उन्हें ठीक करने के तरीके
दोषपूर्ण या अनुपस्थित तर्क
मॉडल एक ओपन-वेट मॉडल है, और ओपन मॉडल कभी-कभी ऐसे तर्क लौटाते हैं जो मान्य JSON नहीं हैं, एक आवश्यक फ़ील्ड छोड़ देते हैं, या एक अतिरिक्त फ़ील्ड बनाते हैं। json.loads को एक try ब्लॉक में लपेटें, अपने स्कीमा के खिलाफ मान्य करें, और जब यह विफल हो जाए, तो त्रुटि को एक टूल संदेश के रूप में वापस भेजें। मॉडल आमतौर पर अगली बारी में स्वयं को ठीक कर लेता है। लूप को कुछ पुनरावृत्तियों तक सीमित करें ताकि एक जिद्दी विफलता अनंत तक न चले।
बहुत अस्पष्ट विवरण
मॉडल अपने नाम और विवरण पढ़कर एक फ़ंक्शन चुनता है। "डेटा प्राप्त करता है" जैसे विवरण में काम करने के लिए कुछ नहीं होता। बताएं कि फ़ंक्शन क्या करता है, इनपुट का क्या अर्थ है, और पैरामीटर विवरण में एक उदाहरण मान शामिल करें।
एक साथ बहुत सारे टूल्स
प्रत्येक टूल परिभाषा प्रत्येक अनुरोध पर इनपुट टोकन गिना जाता है। 1M इनपुट टोकन प्रति $0.15 पर, 150 टोकन वाले दस टूल 1,500 टोकन जोड़ते हैं, जो प्रति अनुरोध $0.000225 है, छोटा लेकिन मात्रा में शून्य नहीं। इससे भी महत्वपूर्ण बात, एक लंबी सूची चयन को कम विश्वसनीय बनाता है। केवल वर्तमान चरण से संबंधित टूल प्रदान करें।
बहुत बड़े टूल परिणाम
जो भी आप लौटाते हैं उसे इनपुट के रूप में वापस दिया जाता है। बड़े डेटाबेस पंक्तियों या वेब पेजों को मॉडल को आवश्यक फ़ील्ड्स तक सीमित करें। कॉन्टेक्स्ट विंडो कुल मिलाकर 100,000 टोकन की है, इसलिए एक बहुत बड़ा परिणाम बातचीत को बाहर धकेल सकता है।
JSON मोड के साथ टूल्स का मिश्रण
JSON मोड (response_format के साथ json_object) उपलब्ध है, लेकिन इसे अंतिम उत्तर के लिए उपयोग करें, न कि उन टर्न्स के लिए जहां आप मॉडल से फ़ंक्शन कॉल करना चाहते हैं। इस पर भरोसा करने से पहले इसे अपने प्रॉम्प्ट पर परीक्षण करें।
स्थानीय Ollama से स्थानांतरित होना और क्या जांचें
यदि आपने अपने पहले टूल लूप को स्थानीय Ollama सर्वर के खिलाफ बनाया था, तो लगभग कुछ भी नहीं बदलता है। बेस URL को https://api.ollamaapi.com/v1 के साथ बदलें, एक वास्तविक कुंजी का उपयोग करें, और मॉडल को uncensored पर सेट करें। मूल Ollama राउट जैसे /api/chat यहाँ मौजूद नहीं हैं। केवल POST /v1/chat/completions और GET /v1/models उपलब्ध हैं, इसलिए नेटिव API के लिए लिखे गए कोड को OpenAI-शैली के कॉल की आवश्यकता होती है।
शिप करने से पहले, यह छोटा चेकलिस्ट पूरा करें:
- सुनिश्चित करें कि कुंजी
GET /v1/modelsके साथ काम करती है। - हर कॉल के लिए
X-Request-Idहेडर को लॉग करें, ताकि खराब रन का पता लगाया जा सके। - यदि आप टूल लूप बिना निगरानी के चलाते हैं, तो प्रतिक्रिया हेडर में
X-Balance-USDपर नज़र रखें। - HTTP 429 हैंडल करें:
rate_limitedयाconcurrencyपर प्रतीक्षा करें, और ओवरलोड परRetry-After: 5का सम्मान करें। - लूप इटरेशन के लिए एक कठोर कैप सेट करें।
एक टूल लूप प्रत्येक उपयोगकर्ता प्रश्न के लिए कम से कम दो अनुरोध बनाता है, इसलिए लागत उसी के अनुसार बढ़ती है। उदाहरण के लिए, 2,000 लूप, 1,200 इनपुट टोकन और 150 आउटपुट टोकन प्रति अनुरोध, दो अनुरोध प्रत्येक, 4,000 अनुरोध, 4.8M इनपुट टोकन और 0.6M आउटपुट टोकन में आते हैं। यह $0.72 प्लस $0.30, या कुल मिलाकर $1.02 है। मूल्य निर्धारण पृष्ठ में टॉप-अप विकल्प हैं, और दस्तावेज़ समर्थित अनुरोध फ़ील्ड्स सूचीबद्ध करते हैं। नए उपयोगकर्ता $0.50 ट्रायल क्रेडिट के साथ इसका परीक्षण कर सकते हैं, जिसके लिए कार्ड की आवश्यकता नहीं है।
अधिक गाइड
प्रश्न और उत्तर
क्या एंडपॉइंट फ़ंक्शन कॉलिंग का समर्थन करता है?
हाँ। यह टूल और tool_choice स्वीकार करता है, tool_calls लौटाता है, उन्हें डेल्टा के रूप में स्ट्रीम करता है, और role tool वाले संदेशों के रूप में परिणाम स्वीकार करता है।
टूल कॉल के बाद दूसरा अनुरोध विफल क्यों हो जाता है?
सामान्य कारण एक अनुपस्थित असिस्टेंट संदेश या एक टूल संदेश है जिसके पास मेल खाने वाला tool_call_id नहीं है। पहले tool_calls वाला असिस्टेंट टर्न जोड़ें, फिर प्रत्येक कॉल के लिए एक टूल संदेश।
क्या मॉडल एक ही टर्न में कई टूल्स को कॉल कर सकता है?
यह एक सूची लौटा सकता है जिसमें एक से अधिक आइटम हों, इसलिए उन सभी पर लूप चलाएं और प्रत्येक के लिए एक परिणाम भेजें। यह न मानें कि सूची में केवल एक आइटम है।
इसके लिए क्या मुझे Ollama लाइब्रेरी की आवश्यकता है?
नहीं। आधिकारिक OpenAI SDK पर्याप्त हैं। बेस URL को एंडपॉइंट पर सेट करें और मॉडल uncensored का उपयोग करें।
आपकी कुंजी बस एक फॉर्म दूर है
एक खाता बनाएँ, कुंजी कॉपी करें, बेस URL बदलें। सेटअप यही है।