Learn how to implement advanced RAG by giving your agent tools to retrieve information on-demand from both structured databases and document collections.
This guide is designed for educational purposes to help you understand RAG concepts and how they work in LarAgent and AI development. The prompts, configurations, and implementations provided here are not fine-tuned or extensively tested for production use.Use this guide to learn and experiment, then build upon it with production-grade practices.
Retrieval-as-Tool is an advanced RAG approach where the AI agent decides
when and what to retrieve based on the conversation context. Unlike
traditional RAG that retrieves context for every query, this method gives the
agent tools to fetch information only when needed, making it more efficient
and context-aware.
In this guide, we’ll implement a smart support agent with two retrieval tools:
SQL Query Tool - For retrieving structured data from databases (users, orders, settings, etc.)
Document Search Tool - For searching unstructured documentation using vector embeddings
The agent will intelligently choose which tool (or both) to use based on the user’s question.
The SQL query tool in this guide is designed for structured data retrieval
(database records like users, orders, products) and NOT for document
retrieval. For unstructured documents and FAQs, we’ll use the Document
Search tool with vector embeddings.
This dual-tool approach allows your agent to:
Query database tables for precise, structured information
Search documentation for conceptual knowledge and procedures
Combine both when needed (e.g., “Show me user John’s order history and the return policy”)
# PurposeYou are an intelligent customer support agent with access to both database and documentation.Your role is to assist users by:- Retrieving relevant information from the database when needed (user data, orders, settings)- Searching documentation for policies, procedures, and how-to guides- Combining information from multiple sources when necessary**Important Guidelines:**- Use the `queryDatabase` tool for structured data queries (users, orders, products, etc.)- Use the `searchDocumentation` tool for unstructured information (FAQs, guides, policies)- Only retrieve data when necessary to answer the question- Be helpful, accurate, and professional- Never make up information - only use data from tools or general knowledgeCurrent Date: {{ $date }}## Current User ContextName: {{ $user->name ?? 'Guest' }}Email: {{ $user->email ?? 'N/A' }}User ID: {{ $user->id ?? 'N/A' }}## Database SchemaYou have access to the following database tables for queries:### users- id (int, primary key)- name (string)- email (string)- email_verified_at (timestamp)- subscription_type (string: 'free', 'basic', 'premium')- created_at (timestamp)- updated_at (timestamp)### orders- id (int, primary key)- user_id (int, foreign key to users.id)- total (decimal)- status (string: 'pending', 'completed', 'cancelled', 'refunded')- created_at (timestamp)- updated_at (timestamp)### products- id (int, primary key)- name (string)- description (text)- price (decimal)- category (string)- stock (int)- is_active (boolean)- created_at (timestamp)- updated_at (timestamp)### order_items- id (int, primary key)- order_id (int, foreign key to orders.id)- product_id (int, foreign key to products.id)- quantity (int)- price (decimal)- created_at (timestamp)- updated_at (timestamp)**Schema Notes:**- Always use proper JOIN statements when querying related tables- Use appropriate WHERE clauses to filter results- Include LIMIT clauses to prevent large result sets- Remember to respect user privacy and only query data relevant to the question
Now, let’s implement the SQL query tool using the #[Tool] attribute:
app/AiAgents/SmartSupportAgent.php
Copy
<?phpnamespace App\AiAgents;use LarAgent\Agent;use LarAgent\Attributes\Tool;use App\AiAgents\SqlGuardAgent;use Illuminate\Support\Facades\DB;class SmartSupportAgent extends Agent{ protected $model = 'gpt-4o'; protected $history = 'cache'; protected $temperature = 0.7; protected $maxCompletionTokens = 1000; public function instructions() { return view('prompts.smart_support_instructions', [ 'date' => now()->format('F j, Y'), 'user' => auth()->user(), ])->render(); } /** * Query the database for structured data * * This tool allows retrieval of structured information like users, orders, products, etc. * The query must be read-only (SELECT statements only). */ #[Tool( 'Query the database to retrieve structured data like users, orders, products, or settings. Only use for structured data queries.', [ 'query' => 'A read-only SQL SELECT query. Must not contain INSERT, UPDATE, DELETE, or other modification statements.', ] )] public function queryDatabase(string $query): string { try { // Validate query using guardrail agent $validation = SqlGuardAgent::for("check")->validateQuery($query); // Check if query is safe if (!$validation['is_safe']) { return "Query rejected: {$validation['reason']}\n" . "Detected operations: " . implode(', ', $validation['detected_operations']) . "\n" . "Only SELECT queries are allowed for data retrieval."; } // Execute the query $results = DB::select($query); // Format results if (empty($results)) { return "Query executed successfully but returned no results."; } // Convert to array and return as JSON for better parsing $formattedResults = json_encode($results, JSON_PRETTY_PRINT); return "Query executed successfully. Results:\n{$formattedResults}"; } catch (\Exception $e) { return "Error executing query: " . $e->getMessage() . "\nPlease check your SQL syntax and try again."; } }}
The queryDatabase tool validates every SQL query through the SqlGuardAgent
before execution, ensuring only safe SELECT statements are processed. This
prevents any data modification attempts.
Step 5: Add Document Search Tool with Enum Constraints
Now let’s add the document search tool. First, create an Enum to constrain the limit parameter:
app/Enums/DocumentLimit.php
Copy
<?phpnamespace App\Enums;enum DocumentLimit: int{ case THREE = 3; case FOUR = 4; case FIVE = 5;}
Using an Enum for the limit parameter frames the LLM’s ability to choose
by providing a predefined set of valid options. Instead of allowing any
integer (which could lead to values like 1, 100, or even negative numbers),
the LLM can only select from the three specific cases: 3, 4, or 5. This
ensures more predictable behavior and prevents edge cases while still giving
the agent flexibility to adjust the number of retrieved documents based on the
query complexity.
Now add the document search tool to your agent:
Copy
use App\Enums\DocumentLimit;use App\Services\QdrantSearchService;// Add this method to your SmartSupportAgent class/** * Search documentation for unstructured information * * This tool searches through documentation, FAQs, guides, and policies * using semantic vector search. */#[Tool( 'Search the documentation for unstructured information like FAQs, guides, policies, and procedures. Use this for conceptual questions or how-to queries.', [ 'query' => 'The search query or question to find relevant documentation for.', 'limit' => 'Number of documents to retrieve. Choose based on query complexity.', ])]public function searchDocumentation(string $query, DocumentLimit $limit = DocumentLimit::THREE): string{ try { // Search using Qdrant $searchService = new QdrantSearchService(); $documents = $searchService->search($query, $limit->value); // Check if we found any relevant documents if (empty($documents)) { return "No relevant documentation found for the query: {$query}"; } // Format and return results directly return json_encode($documents, JSON_PRETTY_PRINT); } catch (\Exception $e) { return "Error searching documentation: " . $e->getMessage(); }}
The simplified implementation returns raw JSON results, allowing the agent to
interpret and present the information in the most appropriate way based on the
conversation context. The Enum constraint ensures the agent can only request
3, 4, or 5 documents, preventing excessive retrieval while maintaining
flexibility.
Try different types of questions to test both tools:
Copy
"Show me details for user with email [email protected]""What are my recent orders?""List all active products in the electronics category""How many users registered this month?"
✅ "SELECT * FROM users WHERE email = '[email protected]'"✅ "SELECT COUNT(*) FROM orders WHERE created_at > '2024-01-01'"✅ "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id"
use App\AiAgents\SmartSupportAgent;// Test with authenticated user$response = SmartSupportAgent::forUser(auth()->user()) ->respond('Show me my order history');str_contains($response, "test_string");// Test documentation search$response = SmartSupportAgent::for('test_session') ->respond('What is your refund policy?');str_contains($response, "test_string");// Test combined retrieval$response = SmartSupportAgent::forUser(auth()->user()) ->respond('Show my account details and explain how to upgrade to premium');str_contains($response, "test_string");
The agent will automatically synthesize information from multiple tool calls. For example:User Question: “Show me the top 5 customers and explain the loyalty program benefits”Agent’s Process:
Calls queryDatabase with: SELECT name, email, total_purchases FROM customers ORDER BY total_purchases DESC LIMIT 5
Calls searchDocumentation with: “loyalty program benefits”
You’ve now implemented a sophisticated Retrieval-as-Tool RAG system with LarAgent! Your agent can:
✅ Intelligently decide when to retrieve information
✅ Query databases safely with SQL guardrails
✅ Search documentation using vector embeddings
✅ Combine multiple sources for comprehensive answers
✅ Validate and secure all data access
This approach provides maximum flexibility and efficiency, allowing your agent to handle both structured data queries and unstructured document searches while maintaining security through intelligent guardrails.