Tool Calling Quick Start

Get started with Captain’s tool calling in 5 minutes.

What is Tool Calling?

Tool calling (function calling) lets your AI use external functions like:

  • 🧮 Perform calculations
  • 🌐 Call APIs
  • 💾 Query databases
  • 📁 Read files
  • 🔧 Execute custom code

Key Point: Tools execute on your side (client), not Captain’s servers. You maintain full control.

Quick Example

Python

1from openai import OpenAI
2
3client = OpenAI(
4 base_url="https://api.runcaptain.com/v1",
5 api_key="your_api_key",
6 default_headers={"X-Organization-ID": "your_org_id"}
7)
8
9# Define your tool
10tools = [{
11 "type": "function",
12 "function": {
13 "name": "calculate",
14 "description": "Perform arithmetic",
15 "parameters": {
16 "type": "object",
17 "properties": {
18 "operation": {"type": "string", "enum": ["add", "multiply"]},
19 "a": {"type": "number"},
20 "b": {"type": "number"}
21 },
22 "required": ["operation", "a", "b"]
23 },
24 "strict": True # Required!
25 }
26}]
27
28# Make request
29response = client.chat.completions.create(
30 model="captain-voyager-latest",
31 messages=[{"role": "user", "content": "What is 50 times 3?"}],
32 tools=tools
33)
34
35# Check if model wants to use tool
36if response.choices[0].finish_reason == "tool_calls":
37 import json
38 tool_call = response.choices[0].message.tool_calls[0]
39 args = json.loads(tool_call.function.arguments)
40
41 # Execute tool on your side
42 if args["operation"] == "multiply":
43 result = args["a"] * args["b"]
44 print(f"Result: {result}")

TypeScript (Vercel AI SDK)

1import { createOpenAI } from '@ai-sdk/openai';
2import { generateText } from 'ai';
3import { z } from 'zod';
4
5const captain = createOpenAI({
6 apiKey: process.env.CAPTAIN_API_KEY!,
7 baseURL: 'https://api.runcaptain.com/v1',
8 headers: { 'X-Organization-ID': process.env.CAPTAIN_ORG_ID! }
9});
10
11const result = await generateText({
12 model: captain.chat('captain-voyager-latest'),
13 messages: [
14 { role: 'user', content: 'What is 50 times 3?' }
15 ],
16 tools: {
17 calculate: {
18 description: 'Perform arithmetic',
19 parameters: z.object({
20 operation: z.enum(['add', 'multiply']),
21 a: z.number(),
22 b: z.number()
23 }),
24 execute: async ({ operation, a, b }) => {
25 // Execute on your side
26 return operation === 'multiply' ? a * b : a + b;
27 }
28 }
29 },
30 maxSteps: 5 // Allow multiple tool calls
31});
32
33console.log(result.text);

How It Works

  1. You define tools with names, descriptions, and parameters
  2. Send request to Captain with tools
  3. Captain returns tool call request (if needed)
  4. You execute the tool in your environment
  5. Continue conversation with results (optional)

Tool Definition Format

Every tool needs:

1{
2 "type": "function", # Always "function"
3 "function": {
4 "name": "tool_name", # Unique name
5 "description": "...", # Clear description
6 "parameters": {...}, # JSON Schema
7 "strict": True # REQUIRED!
8 }
9}

Common Use Cases

API Call Tool

1tools = [{
2 "type": "function",
3 "function": {
4 "name": "get_weather",
5 "description": "Get current weather",
6 "parameters": {
7 "type": "object",
8 "properties": {
9 "city": {"type": "string"}
10 },
11 "required": ["city"]
12 },
13 "strict": True
14 }
15}]

Database Query Tool

1tools = [{
2 "type": "function",
3 "function": {
4 "name": "query_users",
5 "description": "Query user database",
6 "parameters": {
7 "type": "object",
8 "properties": {
9 "user_id": {"type": "string"}
10 },
11 "required": ["user_id"]
12 },
13 "strict": True
14 }
15}]

File Operation Tool

1tools = [{
2 "type": "function",
3 "function": {
4 "name": "read_file",
5 "description": "Read file contents",
6 "parameters": {
7 "type": "object",
8 "properties": {
9 "filename": {"type": "string"}
10 },
11 "required": ["filename"]
12 },
13 "strict": True
14 }
15}]

Best Practices

✅ Do This

1# Clear, specific descriptions
2"description": "Calculate the sum of two numbers. Use for addition only."
3
4# Strict parameter types
5"parameters": {
6 "type": "object",
7 "properties": {
8 "amount": {"type": "number"},
9 "currency": {"type": "string", "enum": ["USD", "EUR"]}
10 },
11 "required": ["amount", "currency"]
12}
13
14# Validate inputs before execution
15def execute_tool(name, args):
16 if name not in ALLOWED_TOOLS:
17 raise ValueError("Tool not allowed")
18 return ALLOWED_TOOLS[name](**args)

❌ Don’t Do This

1# Vague description
2"description": "Does stuff"
3
4# Missing types
5"parameters": {
6 "type": "object",
7 "properties": {
8 "data": {} # What type?
9 }
10}
11
12# No input validation
13def execute_tool(name, args):
14 return eval(f"{name}(**{args})") # Dangerous!

Framework Support

FrameworkStatusMulti-TurnBest For
OpenAI Python SDKManualPython apps
OpenAI Node.js SDKManualNode.js apps
Vercel AI SDKAuto (maxSteps)Best DX
LangChainVia agentsComplex workflows

Recommendation: Use Vercel AI SDK for automatic multi-turn handling.

Troubleshooting

Tool Not Being Called

1# Make description more explicit
2"description": "ALWAYS use this tool for math. Never calculate manually."
3
4# Strengthen system prompt
5messages = [
6 {
7 "role": "system",
8 "content": "You MUST use provided tools. Don't do calculations yourself."
9 },
10 {"role": "user", "content": "What is 5 + 3?"}
11]

Empty Tool Arguments

1# Check for missing args
2args = json.loads(tool_call.function.arguments)
3if not args.get("required_param"):
4 # Provide default or skip
5 args["required_param"] = "default"

Tool Execution Errors

1# Wrap in try-catch
2try:
3 result = execute_tool(name, args)
4except Exception as e:
5 result = {"error": str(e)}

Next Steps

Get Help