Tool Usage Example
This example demonstrates how to integrate tools with PomlSDK.jl, following the POML standard for tool-enabled prompting.
Basic Tool Definition and Request
using PomlSDK
using JSON
p = Prompt()
# Define a calculator tool
calc_tool = tool_definition(
p,
name="calculator",
description="Performs basic mathematical calculations",
parameters=Dict(
"operation" => Dict(
"type" => "string",
"description" => "The operation to perform: add, subtract, multiply, divide",
"enum" => ["add", "subtract", "multiply", "divide"]
),
"a" => Dict(
"type" => "number",
"description" => "First operand"
),
"b" => Dict(
"type" => "number",
"description" => "Second operand"
)
)
)
# Request the calculator tool
calc_request = tool_request(
p,
name="calculator",
parameters=Dict(
"operation" => "multiply",
"a" => 5,
"b" => 7
)
)
# Serialize to POML
poml_string = dump_poml(p)
println(poml_string)
This will generate POML XML that defines the tool and requests its use.
Complete Tool Workflow
Here's a more comprehensive example showing the full tool integration workflow:
using PomlSDK
using JSON
p = Prompt()
# 1. System instructions
role_node = role(p, caption="System")
add_node!(p, role_node)
add_text(p, "You are a helpful assistant with access to tools. When appropriate, use tools to get accurate information.")
pop_node!(p)
# 2. Define available tools
tool_defs = tool_definition(p)
add_node!(p, tool_defs)
# Calculator tool
calc_tool = tool_definition(
p,
name="calculator",
description="Performs basic math operations",
parameters=Dict(
"operation" => Dict(
"type" => "string",
"description" => "Operation to perform",
"enum" => ["add", "subtract", "multiply", "divide"]
),
"a" => Dict("type" => "number"),
"b" => Dict("type" => "number")
)
)
# Weather tool
weather_tool = tool_definition(
p,
name="get_weather",
description="Gets current weather for a location",
parameters=Dict(
"location" => Dict("type" => "string", "description" => "City and country")
)
)
pop_node!(p) # Pop tool_definitions
# 3. User task
task_node = task(p, caption="User Request")
add_node!(p, task_node)
add_text(p, "What is 15 multiplied by 23? Also, what's the weather in London?")
pop_node!(p)
# 4. Tool requests (simulating what the LLM might generate)
tool_reqs = tag(p, "tool_requests")
add_node!(p, tool_reqs)
# Calculator request
calc_req = tool_request(
p,
name="calculator",
parameters=Dict(
"operation" => "multiply",
"a" => 15,
"b" => 23
)
)
# Weather request
weather_req = tool_request(
p,
name="get_weather",
parameters=Dict(
"location" => "London, UK"
)
)
pop_node!(p) # Pop tool_requests
# 5. Tool responses (simulating actual tool outputs)
tool_responses = tag(p, "tool_responses")
add_node!(p, tool_responses)
# Calculator response
calc_response = tag(p, "tool_response", name="calculator", id=calc_req.id)
add_node!(p, calc_response)
add_text(p, "345")
pop_node!(p)
# Weather response
weather_response = tag(p, "tool_response", name="get_weather", id=weather_req.id)
add_node!(p, weather_response)
add_text(p, JSON.json(Dict(
"location" => "London, UK",
"temperature" => 15,
"conditions" => "Partly cloudy"
)))
pop_node!(p)
pop_node!(p) # Pop tool_responses
# 6. Final answer generation
final_task = task(p, caption="Final Response")
add_node!(p, final_task)
add_text(p, "15 multiplied by 23 is 345. The current weather in London is 15°C with partly cloudy conditions.")
pop_node!(p)
# Serialize to POML
poml_string = dump_poml(p)
println(poml_string)
Tool Chaining Example
This example demonstrates how to structure prompts for tool chaining:
using PomlSDK
using JSON
p = Prompt()
# Define tools
tool_defs = tool_definition(p)
add_node!(p, tool_defs)
search_tool = tool_definition(
p,
name="search_web",
description="Searches the web for information",
parameters=Dict(
"query" => Dict("type" => "string", "description" => "Search query")
)
)
calc_tool = tool_definition(
p,
name="calculate_percentage",
description="Calculates percentages",
parameters=Dict(
"value" => Dict("type" => "number"),
"total" => Dict("type" => "number"),
"description" => Dict("type" => "string")
)
)
pop_node!(p) # Pop tool_definitions
# Initial task
task_node = task(p, caption="Research Request")
add_node!(p, task_node)
add_text(p, "What percentage of the world population lives in Japan?")
pop_node!(p)
# First tool request
tool_reqs = tag(p, "tool_requests")
add_node!(p, tool_reqs)
search_req = tool_request(
p,
name="search_web",
parameters=Dict(
"query" => "current population of Japan, current world population"
)
)
pop_node!(p) # Pop tool_requests
# First tool response
tool_responses = tag(p, "tool_responses")
add_node!(p, tool_responses)
search_resp = tag(p, "tool_response", name="search_web", id=search_req.id)
add_node!(p, search_resp)
add_text(p, JSON.json(Dict(
"japan_population" => 125800000,
"world_population" => 8000000000
)))
pop_node!(p)
pop_node!(p) # Pop tool_responses
# Second tool request using first response
tool_reqs2 = tag(p, "tool_requests")
add_node!(p, tool_reqs2)
# Extract data from first response
response_text = XML.text(search_resp)
response_data = JSON.parse(response_text)
japan_pop = response_data["japan_population"]
world_pop = response_data["world_population"]
calc_req = tool_request(
p,
name="calculate_percentage",
parameters=Dict(
"value" => japan_pop,
"total" => world_pop,
"description" => "Japan's population as percentage of world population"
)
)
pop_node!(p) # Pop tool_requests
# Second tool response
tool_responses2 = tag(p, "tool_responses")
add_node!(p, tool_responses2)
calc_resp = tag(p, "tool_response", name="calculate_percentage", id=calc_req.id)
add_node!(p, calc_resp)
add_text(p, "1.5725")
pop_node!(p)
pop_node!(p) # Pop tool_responses
# Final answer
final_task = task(p, caption="Final Response")
add_node!(p, final_task)
add_text(p, "Approximately 1.57% of the world population lives in Japan.")
pop_node!(p)
# Serialize
poml_string = dump_poml(p)
println(poml_string)
Best Practices for Tool Integration
- Clear parameter definitions: Ensure all tool parameters are well-defined with types and descriptions
- Include examples: Add example tool requests and responses in your prompts
- Handle errors: Include examples of tool errors and how to respond
- Manage state: When chaining tools, ensure responses are properly linked to requests
- Limit tool count: Too many tools can confuse the LLM; focus on the most relevant ones
- Provide context: Explain why a tool is being used and what its output means
- Validate parameters: Ensure tool parameters match the expected format
- Consider token limits: Tool definitions can be lengthy; balance with other content
By effectively integrating tools into your prompts, you can create more powerful, accurate, and capable LLM applications that extend beyond the model's built-in knowledge.