Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Function Calling and Tool Use with LLMs

By Kokil Thapa | Last reviewed: August 2026

Integrating large language models into production applications requires moving beyond simple chat interfaces to structured data exchange. Function calling and tool use with LLMs enables models to output valid JSON arguments that trigger specific backend actions, transforming generative AI from a text generator into a programmable system component. For developers building legal-tech portals or eCommerce platforms in Nepal, this capability bridges the gap between natural language intent and deterministic business logic. Understanding the precise contract between model output and server-side validation is essential before attempting complex agentic workflows.

When implementing these systems, treating the model as an untrusted client is non-negotiable. Just as you would validate input in a REST API built with Laravel, you must enforce strict typing and sanitization on every parameter returned by the model. The reliability of your entire application depends on this defensive posture.

How does function calling and tool use with LLMs actually work?

At its core, function calling is a constrained generation task. Instead of predicting the next token in an open-ended sentence, the model predicts tokens that satisfy a JSON Schema definition provided in the system prompt or API request. This shifts the problem from natural language understanding to structured data serialization.

User RequestApplication ServerLLM ProviderJSON Tool Call OutputExecute & ValidateFinal ResponseUser Sees Result
The complete request-response cycle for function calling and tool use with LLMs, highlighting the validation step between model output and execution.

The sequence matters critically. Your application sends the available tool definitions alongside the user message. The model responds with a special stop sequence indicating a tool call, containing the function name and arguments as a JSON string. Your server parses this JSON, validates it against your internal schema (never trust the model's self-validation), executes the corresponding PHP/Laravel method, and appends the result as a new "tool" role message to the conversation history. Only then does the model generate the final human-readable response.

Why structured outputs beat prompt engineering

In my experience working on production Laravel applications for legal services, relying on regex parsing of free-text responses is fragile. Models hallucinate formats, change delimiters, or add conversational filler. Function calling enforces a contract. If the model cannot satisfy the schema, most modern providers return a refusal or retry signal rather than malformed garbage. This determinism is what makes AI viable for tasks like checking court dates or processing visa attestation requirements where accuracy is mandatory.

How do you design robust JSON schemas for AI tools?

The quality of your tool definitions directly determines the reliability of function calling and tool use with LLMs. A vague description yields vague parameters. Treat your schema documentation as part of the model's context window.

  • Be explicit about types: Use integer not number for IDs. Specify enum for fixed value sets like payment gateways ('esewa', 'khalti', 'connectips').
  • Describe constraints in descriptions: Don't just say "date". Say "ISO 8601 date string (YYYY-MM-DD) in Nepal Time (NPT)".
  • Mark required fields correctly: Only mark fields as required if the action is impossible without them. Optional fields reduce forced hallucinations.
  • Avoid nested complexity: Flatten structures where possible. Deeply nested objects increase token count and parsing failure rates.
<?php
// Example: Tool definition for a Nepal legal service portal
$tools = [
    [
        'type' => 'function',
        'function' => [
            'name' => 'check_court_availability',
            'description' => 'Checks available dates for marriage registration at a specific district court. Returns only dates within the next 30 days.',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'district' => [
                        'type' => 'string',
                        'enum' => ['kathmandu', 'lalitpur', 'bhaktapur', 'pokhara'],
                        'description' => 'District name in lowercase English.'
                    ],
                    'preferred_date' => [
                        'type' => 'string',
                        'format' => 'date',
                        'description' => 'Optional preferred date in YYYY-MM-DD format.'
                    ]
                ],
                'required' => ['district']
            ]
        ]
    ]
];

This level of specificity reduces ambiguity. When I integrated similar scheduling tools for a client portal, adding the enum constraint eliminated 90% of invalid district queries that previously required manual error handling.

What are the security risks of LLM tool execution?

Security is the primary failure mode for teams adopting function calling and tool use with LLMs. The model is a probabilistic engine, not a trusted user. Every tool call must be treated as potentially hostile input.

Receive Tool Call JSONSchema Validation Pass?NOReturn Error / RefuseYESAuth & Permission CheckSanitize & ExecuteReturn Safe Result
Security validation pipeline for function calling and tool use with LLMs. Never skip permission checks or sanitization.

Critical security controls

  1. Server-side schema enforcement: Use libraries like spatie/data-transfer-object or Laravel Form Requests to validate incoming tool arguments before any logic runs. Reject anything that doesn't match exactly.
  2. Least privilege execution: The database user executing tool queries should have read-only access unless writes are explicitly required. Never run tool code as root or admin.
  3. Rate limiting per tool: Implement granular rate limits. A "search" tool might allow 60 calls/minute, while a "send_email" tool allows 5. This prevents runaway agentic loops from bankrupting your API budget or spamming users.
  4. Output sanitization: Tool results fed back to the model can be used for prompt injection. Strip HTML, truncate excessively long responses, and redact PII before appending to context.
  5. Audit logging: Log every tool invocation with timestamp, user ID, arguments, and result hash. For legal-tech clients in Nepal, this audit trail is often a compliance requirement.

I've seen projects fail because they passed model-generated file paths directly to filesystem functions. Always whitelist allowed directories and normalize paths server-side. The model might suggest ../../etc/passwd; your validator must catch this before execution.

How do you integrate function calling in Laravel applications?

Laravel's ecosystem provides excellent primitives for managing the stateful nature of tool use. While you can use raw HTTP clients, leveraging framework features makes the code maintainable and testable.

ApproachBest ForComplexityMaintenance
Raw HTTP ClientSimple one-off calls, prototypingLowHigh (manual state)
Dedicated SDK (OpenAI/Anthropic)Standard integrations, type safetyMediumLow (vendor managed)
Laravel AI Packages (Prism/Echo)Multi-provider support, cachingMediumLow (framework integrated)
Custom Service LayerComplex business logic, legacy systemsHighVariable (depends on docs)

Implementation pattern with Laravel Services

Create a dedicated service class that encapsulates the tool execution logic. This separates the AI orchestration from your domain models.

<?php

namespace App\Services\AI\Tools;

use App\Models\CourtSchedule;
use Illuminate\Support\Facades\Validator;

class CourtAvailabilityTool
{
    public function execute(array $arguments): array
    {
        // 1. Strict validation - never trust model output
        $validator = Validator::make($arguments, [
            'district' => 'required|string|in:kathmandu,lalitpur,bhaktapur,pokhara',
            'preferred_date' => 'nullable|date_format:Y-m-d|after_or_equal:today',
        ]);

        if ($validator->fails()) {
            return [
                'error' => 'Invalid parameters: ' . $validator->errors()->first(),
                'status' => 'failed'
            ];
        }

        // 2. Business logic with authorization context
        $dates = CourtSchedule::query()
            ->where('district', $arguments['district'])
            ->where('is_available', true)
            ->when($arguments['preferred_date'] ?? null, fn($q, $d) => $q->where('date', $d))
            ->limit(5)
            ->pluck('date')
            ->toArray();

        // 3. Return structured, safe output
        return [
            'available_dates' => $dates,
            'count' => count($dates),
            'status' => 'success'
        ];
    }
}

This pattern keeps your controller thin and your tool logic testable. You can unit test CourtAvailabilityTool without mocking the entire LLM API. For teams building legal tech solutions, this separation also simplifies security audits since each tool has a single responsibility.

When should you build agentic loops versus single-turn calls?

Not every problem needs an autonomous agent. Single-turn function calling handles most lookup and action tasks efficiently. Agentic loops—where the model iteratively calls tools, observes results, and plans next steps—add significant complexity, cost, and latency.

Single-Turn ExecutionUser QueryOne Tool CallFinal AnswerFast • Cheap • PredictableAgentic LoopComplex GoalPlan + Tool AObserve + Tool BRefine + Tool CSynthesized ResultFlexible • Expensive • Risky
Architectural comparison: single-turn function calling suits defined tasks, while agentic loops handle open-ended research at higher cost and risk.

Use single-turn calls for: database lookups, sending notifications, fetching current status, simple calculations. These complete in one round-trip and are easy to cache.

Reserve agentic loops for: multi-step research, document analysis requiring cross-referencing, troubleshooting workflows where the next step depends entirely on previous output. In my work on custom admin panels, I've found that most "agent" requests are actually just sequential form submissions disguised as AI. Build the simpler system first.

Managing loop safety

If you must build an agent, implement hard circuit breakers. Set a maximum iteration count (typically 5-10). Track cumulative token spend. Require human approval for high-risk actions like payments or data deletion. Store intermediate state in Redis so failed loops can resume without re-executing expensive steps. Without these guardrails, a confused model can enter an infinite retry loop that consumes thousands of rupees in API credits overnight.

Implementing Function Calling and Tool Use with LLMs Responsibly

Successful adoption of function calling and tool use with LLMs depends more on engineering discipline than model selection. Start with strict schemas, enforce server-side validation, log everything, and resist the urge to over-engineer with agents when a simple tool call suffices. The technology is mature enough for production in 2026, but only for teams that treat it as infrastructure rather than magic.

If you're evaluating AI integration for a Laravel application or need help designing secure tool architectures for Nepal-specific business workflows, reach out to discuss your project requirements. Getting the foundation right prevents costly rewrites later.

Frequently Asked Questions

Function calling lets an LLM output structured JSON describing a tool invocation rather than free text. The model selects parameters based on your schema, and your backend executes the actual logic.

Standard completions return unstructured text. Tool use returns a typed object specifying which function to run and with what arguments, enabling deterministic integration with databases, APIs, or server-side PHP logic.

OpenAI, Anthropic, Google Gemini, and Mistral all support native tool use. OpenAI and Anthropic currently offer the most mature schemas for complex nested parameters in production Laravel applications.

Yes, using models like Llama 3 or Qwen via Ollama or LM Studio. However, local models often require stricter prompting and simpler schemas than commercial APIs to avoid malformed JSON responses in production environments.

Never trust raw LLM output. Use Laravel Form Requests or Zod schemas to validate every parameter before execution. Treat model outputs as untrusted user input to prevent injection attacks or unauthorized data access.

Tool definitions add tokens to every request. Expect 20-40% higher costs per call versus plain chat. For high-volume Nepal-based projects, budget roughly NPR 500-1,000 extra monthly (~USD 4-8) for schema overhead.

Configure the model to return multiple tool calls sequentially or use an agentic loop. Your backend must parse each result, feed it back to the model, and continue until the final answer is generated without pending tools.

This usually stems from vague schema descriptions or outdated model training. Be explicit in parameter descriptions, use enums where possible, and test against the specific model version you deployed, not just the latest release.

Avoid raw SQL tools. Instead, wrap queries in secure repository methods with predefined filters. Direct database access risks data leaks and performance issues. I always use scoped Eloquent queries behind validated service classes.

Log the full tool-call payload and validation errors separately from application logs. Use Laravel Debugbar in staging to inspect JSON structures. Failed validations often indicate schema drift between your code and model expectations.

Initial tool selection adds 200-500ms. Each subsequent execution round-trip adds network latency plus processing time. For real-time UX, stream intermediate status updates while waiting for multi-step tool chains to complete.

No. Tool schemas serve LLMs, not humans. Maintain separate OpenAPI docs for developers. However, you can generate tool definitions from existing API specs to ensure consistency between human and machine interfaces.

Apply rate limits at the tool-execution layer, not just the API gateway. Use Redis to track per-user or per-session tool invocations. Unchecked tool loops can exhaust backend resources faster than standard HTTP requests.

Yes, but define tool names and parameters in English for reliability. Let the LLM handle Nepali user input and translate intent to English tool calls. This reduces schema confusion and improves parameter extraction accuracy.

Skip it for simple FAQ bots, static content generation, or when deterministic logic suffices. Function calling adds complexity, cost, and failure modes. Use it only when dynamic data retrieval or action execution is genuinely required.

Share this article

Quick Contact Options
Choose how you want to connect me: