{"id":41108,"date":"2025-10-26T21:29:09","date_gmt":"2025-10-26T20:29:09","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=41108"},"modified":"2025-10-26T21:33:46","modified_gmt":"2025-10-26T20:33:46","slug":"rag-series-agentic-rag","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/","title":{"rendered":"RAG Series \u2013 Agentic RAG"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-introduction\">Introduction<\/h2>\n\n\n\n<p>In earlier parts, we moved from <strong>Naive RAG<\/strong> (vector search) to <strong>Hybrid RAG<\/strong> (dense + sparse) to <strong>Adaptive RAG<\/strong> (query classification and dynamic weighting). Each step improved <em>what<\/em> we retrieve. <strong>Agentic RAG<\/strong> goes further: the LLM decides <em>if<\/em> and <em>when<\/em> to retrieve at all and can take multiple steps (retrieve \u2192 inspect \u2192 refine \u2192 retrieve) before answering. Retrieval stops being a fixed stage and becomes a tool the model invokes when and how it needs to. This blog post will explain the fundamental principles of agentic RAG from a DBA perspective on which you can build on top of all your business logic and governance rules. <\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>RAG Type<\/th><th>Decision Logic<\/th><th>Flexibility<\/th><th>Typical Latency<\/th><th>Best For<\/th><\/tr><\/thead><tbody><tr><td>Naive<\/td><td>None<\/td><td>Fixed<\/td><td>~0.5 s<\/td><td>Simple FAQ<\/td><\/tr><tr><td>Hybrid<\/td><td>Static weights<\/td><td>Moderate<\/td><td>~0.6 s<\/td><td>Mixed queries<\/td><\/tr><tr><td>Adaptive<\/td><td>Query classifier<\/td><td>Dynamic<\/td><td>~0.7 s<\/td><td>Varied, predictable query types<\/td><\/tr><tr><td><strong>Agentic<\/strong><\/td><td><strong>LLM agent (tool use)<\/strong><\/td><td><strong>Fully dynamic<\/strong><\/td><td><strong>~2.0\u20132.5 s<\/strong><\/td><td>Complex, exploratory, multi-hop<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-when-one-retrieval-isn-t-enough\">When One Retrieval Isn\u2019t Enough<\/h2>\n\n\n\n<p><strong>Example:<\/strong> <em>\u201cCompare PostgreSQL and MySQL indexing approaches.\u201d<\/em><\/p>\n\n\n\n<p><strong>Traditional (single-pass) RAG<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieves mixed docs about both systems<\/li>\n\n\n\n<li>LLM synthesizes from noisy context<\/li>\n\n\n\n<li>Often misses nuanced differences or secondary linked subjects.<\/li>\n<\/ul>\n\n\n\n<p><strong>Agentic RAG<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Agent searches \u201cPostgreSQL indexing mechanisms\u201d<\/li>\n\n\n\n<li>Reads snippets; detects a gap for MySQL<\/li>\n\n\n\n<li>Searches \u201cMySQL indexing mechanisms\u201d<\/li>\n\n\n\n<li>Synthesizes a side-by-side comparison from focused contexts<\/li>\n<\/ol>\n\n\n\n<p>This loop generalizes: the agent decomposes questions, detects missing context, and invokes tools until it has enough evidence to answer confidently.<\/p>\n\n\n\n<p><em>Generalization is an ability for an agent to take on new tasks or variations of existing ones by reusing and combining what it already knows rather than memorizing patterns. This is very usefull to handle variations in inputs and allow an agent to adapt faster with fewer codified examples but also comes with new limitations. There are different ways to generalize and you need to measure this functionality to detect when it fails. So far we covered monitoring at the ranking level of retrieval but this part I am not going to extend on is about reliable solving new tasks or shift, one way to measure it would be implement failure detection wired to the agent logs.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-architecture-overview\">Architecture Overview<\/h2>\n\n\n\n<p>Agentic RAG inserts a <strong>decision loop<\/strong> between query and retrieval; the database is explicitly a <strong>tool<\/strong>.<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1352\" height=\"605\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png\" alt=\"\" class=\"wp-image-41232\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png 1352w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12-300x134.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12-1024x458.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12-768x344.png 768w\" sizes=\"auto, (max-width: 1352px) 100vw, 1352px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-about-this-implementation\">About This Implementation<\/h2>\n\n\n\n<p>The code examples in this post are based on the <strong>complete, production-ready implementation<\/strong><br>available in the <a href=\"https:\/\/github.com\/boutaga\/pgvector_RAG_search_lab\">pgvector_RAG_search_lab<\/a> repository.<br>\u200b<br><strong>What&#8217;s included<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 Agentic search engine<\/li>\n\n\n\n<li>\u2705 Modern OpenAI tools API<\/li>\n\n\n\n<li>\u2705 Interactive demo and CLI<\/li>\n\n\n\n<li>\u2705 FastAPI integration<\/li>\n\n\n\n<li>\u2705 n8n workflow template<br>\u200b<br><strong>You don&#8217;t need to build from scratch<\/strong> \u2014 the implementation is ready to use. The post explains<br>the concepts and design decisions behind the working code.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-picking-an-orchestration-style\">Picking an orchestration style<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Approach<\/th><th>Best For<\/th><th>Complexity<\/th><th>Control<\/th><\/tr><\/thead><tbody><tr><td><strong>LangGraph<\/strong><\/td><td>Production agent graphs &amp; branches<\/td><td>Medium<\/td><td>Medium<\/td><\/tr><tr><td><strong>n8n<\/strong><\/td><td>Low-code demos \/ single-decision flows<\/td><td>Low<\/td><td>Low<\/td><\/tr><tr><td><strong>Custom Python<\/strong> (ours)<\/td><td>Full transparency &amp; tight DB integration<\/td><td>Medium<\/td><td>High<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>We\u2019ll keep the loop in <strong>custom Python<\/strong> (testable, observable), while remaining compatible with LangGraph or n8n if you want to wrap it later.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-implementing-the-agent-loop-python\">Implementing the Agent Loop (Python)<\/h2>\n\n\n\n<p>Below are compact, production-minded snippets using the <strong>new client style<\/strong> and <strong>gpt-5 \/ gpt-5-mini<\/strong>. We use <strong>gpt-5-mini<\/strong> for the <em>decision<\/em> step (cheap\/fast) and <strong>gpt-5<\/strong> for the <em>final synthesis<\/em> (quality). You can also run everything on <code>gpt-5-mini<\/code> if cost\/latency is critical.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-1-expose-the-retrieval-tool\">1) Expose the retrieval tool<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# lab\/search\/agentic_search.py\nfrom typing import List\nfrom dataclasses import dataclass\n\n@dataclass\nclass SearchResult:\n    content: str\n    metadata: dict\n\nclass VectorSearchService:\n    def __init__(self, pg_conn):\n        self.pg = pg_conn  # psycopg \/ asyncpg \/ SQLAlchemy\n    def search(self, query: str, top_k: int = 5) -&gt; List&#x5B;SearchResult]:\n        # Implement hybrid\/dense search as in prior posts; this is the dense-only core.\n        # SELECT title, text FROM wiki ORDER BY embedding &lt;-&gt; embed($1) LIMIT $2;\n        ...\n\ndef format_snippets(results: List&#x5B;SearchResult]) -&gt; str:\n    lines = &#x5B;]\n    for i, r in enumerate(results, 1):\n        title = r.metadata.get(&quot;title&quot;, &quot;Untitled&quot;)\n        snippet = (r.content or &quot;&quot;).replace(&quot;\\n&quot;, &quot; &quot;)&#x5B;:220]\n        lines.append(f&quot;&#x5B;{i}] {title}: {snippet}...&quot;)\n    return &quot;\\n&quot;.join(lines)\n\ndef search_wikipedia(vector_service: VectorSearchService, query: str, top_k: int = 5) -&gt; str:\n    results = vector_service.search(query, top_k=top_k)\n    return format_snippets(results)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-register-tool-schema-for-the-llm\">2) Register tool schema for the LLM<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nsearch_tool = {\n  &quot;type&quot;: &quot;function&quot;,\n  &quot;function&quot;: {\n    &quot;name&quot;: &quot;search_wikipedia&quot;,\n    &quot;description&quot;: &quot;Retrieve relevant Wikipedia snippets from Postgres+pgvector.&quot;,\n    &quot;parameters&quot;: {\n      &quot;type&quot;: &quot;object&quot;,\n      &quot;properties&quot;: {\n        &quot;query&quot;: {&quot;type&quot;: &quot;string&quot;},\n        &quot;top_k&quot;: {&quot;type&quot;: &quot;integer&quot;, &quot;default&quot;: 5}\n      },\n      &quot;required&quot;: &#x5B;&quot;query&quot;]\n    }\n  }\n}\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-3-prompts-concise-outcome-oriented\">3) Prompts (concise, outcome-oriented)<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nSYSTEM_PROMPT = &quot;&quot;&quot;\nYou are an expert assistant with access to a Wikipedia database via the tool `search_wikipedia`.\nDecide if retrieval is needed before answering. If you are unsure, retrieve first.\nIf context is insufficient after the first retrieval, you may request one additional retrieval.\nBase answers strictly on provided snippets; otherwise reply &quot;Unknown&quot;.\nConclude with a one-line decision note: `Decision: used search` or `Decision: skipped search`.\n&quot;&quot;&quot;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-4-the-agent-loop-with-gpt-5-mini-decision-gpt-5-final\">4) The agent loop with <strong>gpt-5-mini<\/strong> (decision) + <strong>gpt-5<\/strong> (final)<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nimport json, time\nfrom openai import OpenAI\nclient = OpenAI()\n\ndef agentic_answer(pg_conn, user_question: str, max_retries: int = 1):\n    vs = VectorSearchService(pg_conn)\n\n    messages = &#x5B;\n        {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: SYSTEM_PROMPT},\n        {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: user_question},\n    ]\n\n    # Phase 1: Decision \/ planning (cheap &amp; fast)\n    start = time.time()\n    decision = client.chat.completions.create(\n        model=&quot;gpt-5-mini&quot;,\n        messages=messages,\n        tools=&#x5B;search_tool],\n        tool_choice=&quot;auto&quot;,  # let the model decide\n        temperature=0.2,\n    )\n    msg = decision.choices&#x5B;0].message\n    tool_used = False\n    loops = 0\n\n    # Handle tool calls (allow at most 1 retry cycle)\n    while msg.tool_calls and loops &lt;= max_retries:\n        tool_used = True\n        call = msg.tool_calls&#x5B;0]\n        args = json.loads(call.function.arguments or &quot;{}&quot;)\n        query = args.get(&quot;query&quot;) or user_question\n        top_k = int(args.get(&quot;top_k&quot;) or 5)\n\n        snippets = search_wikipedia(vs, query=query, top_k=top_k)\n        if not snippets.strip():\n            # No results safeguard\n            messages += &#x5B;msg, {&quot;role&quot;: &quot;tool&quot;, &quot;name&quot;: &quot;search_wikipedia&quot;, &quot;content&quot;: &quot;NO_RESULTS&quot;}]\n            break\n\n        messages += &#x5B;\n            msg,\n            {&quot;role&quot;: &quot;tool&quot;, &quot;name&quot;: &quot;search_wikipedia&quot;, &quot;content&quot;: snippets}\n        ]\n        # Optionally allow one more decision round on mini\n        decision = client.chat.completions.create(\n            model=&quot;gpt-5-mini&quot;,\n            messages=messages,\n            tools=&#x5B;search_tool],\n            tool_choice=&quot;auto&quot;,\n            temperature=0.2,\n        )\n        msg = decision.choices&#x5B;0].message\n        loops += 1\n\n    # Phase 2: Final synthesis (high quality)\n    final = client.chat.completions.create(\n        model=&quot;gpt-5&quot;,\n        messages=messages + (&#x5B;msg] if not msg.tool_calls else &#x5B;]),\n        tool_choice=&quot;none&quot;,\n        temperature=0.3,\n    )\n    answer = final.choices&#x5B;0].message.content or &quot;Unknown&quot;\n    total_ms = int((time.time() - start) * 1000)\n\n    return {\n        &quot;answer&quot;: answer,\n        &quot;tool_used&quot;: tool_used,\n        &quot;loops&quot;: loops,\n        &quot;latency_ms&quot;: total_ms,\n    }\n<\/pre><\/div>\n\n\n<p>We use <strong>gpt-5-mini<\/strong> for the <em>decision<\/em> step (cheap\/fast) and <strong>gpt-5<\/strong> for the <em>final synthesis<\/em> (quality).<br>The two-phase strategy (gpt-5-mini for decisions, gpt-5 for synthesis)<br>is an <strong>optional optimization<\/strong> for high-volume production use. The repository implementation uses a<br>single configurable model (default: gpt-5-mini) which works well for most use cases. Implement the<br>two-phase approach only if you need to optimize the cost\/quality balance.<\/p>\n\n\n\n<p><strong>Decision logic<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>LLM Output<\/th><th>Action<\/th><th>Next Step<\/th><\/tr><\/thead><tbody><tr><td>Direct answer<\/td><td>Return<\/td><td>Done<\/td><\/tr><tr><td>Tool call<\/td><td>Execute search<\/td><td>Feed snippets back; allow one re-decision<\/td><\/tr><tr><td>Tool call + no results<\/td><td>Log low confidence<\/td><td>Stop (avoid loops) \u2192 \u201cUnknown\u201d<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Guards<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Max loop (<code>max_retries<\/code>) to prevent infinite cycles<\/li>\n\n\n\n<li>Empty-results check<\/li>\n\n\n\n<li>Low temperature for consistent decisions<\/li>\n\n\n\n<li>Optional <strong>rate limiting<\/strong> (e.g., sleep\/backoff) if your OpenAI or DB tier needs it<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-evaluating-agentic-decisions\">Evaluating Agentic Decisions<\/h2>\n\n\n\n<p>Agentic RAG adds a new layer to measure: <strong>decision quality<\/strong>. Keep the retrieval metrics (precision@k, nDCG), but <strong>add<\/strong> decision metrics and overhead.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-1-decision-accuracy-4-outcomes\">1) Decision Accuracy (4 outcomes)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>TP<\/strong> (True Positive): Agent retrieved when external info was needed \u2713<\/li>\n\n\n\n<li><strong>FP<\/strong> (false Positive): Agent retrieved unnecessarily (latency\/cost waste)<\/li>\n\n\n\n<li><strong>FN<\/strong> (False Negative): Agent skipped retrieval but should have (hallucination risk)<\/li>\n\n\n\n<li><strong>TN<\/strong> (True Negative): Agent skipped retrieval appropriately \u2713<\/li>\n\n\n\n<li>N : total questions evaluated<\/li>\n<\/ul>\n\n\n\n<p><strong>Accuracy<\/strong> = (TP + TN) \/ N<\/p>\n\n\n\n<p><strong>Interpretation<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How often did the agent make the right call about retrieval?<\/li>\n\n\n\n<li>\u201cRight call\u201d means either:\n<ul class=\"wp-block-list\">\n<li>it retrieved when it should (TP), or<\/li>\n\n\n\n<li>it skipped when it could safely skip (TN).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>Example:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>TP = 40<\/li>\n\n\n\n<li>TN = 50<\/li>\n\n\n\n<li>FP = 5<\/li>\n\n\n\n<li>FN = 5<\/li>\n\n\n\n<li>N = 100<\/li>\n<\/ul>\n\n\n\n<p><strong>Accuracy <\/strong>= (40 + 50) \/ 100 = 90%<\/p>\n\n\n\n<p>That means: in 90% of cases, the agent made the correct decision about using retrieval.<\/p>\n\n\n\n<p>Note: This doesn\u2019t judge how <em>good<\/em> the final answer is \u2014 that\u2019s a separate metric. This only measures the <em>decision to retrieve or not retrieve<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-tool-usage-rate\">2) Tool Usage Rate<\/h3>\n\n\n\n<p>% of queries that triggered retrieval.<br>Too low \u2192 overconfident model; too high \u2192 cautious and costly. Track per domain\/query type.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-3-latency-cost-impact\">3) Latency\/Cost Impact<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Scenario<\/th><th>LLM Calls<\/th><th>DB Queries<\/th><th>Avg Latency<\/th><\/tr><\/thead><tbody><tr><td>No retrieval<\/td><td>1<\/td><td>0<\/td><td>~0.5 s<\/td><\/tr><tr><td>Single retrieval<\/td><td>2<\/td><td>1<\/td><td>~2.1 s<\/td><\/tr><tr><td>Double retrieval<\/td><td>3<\/td><td>2<\/td><td>~3.8 s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Report both <strong>p50\/p95<\/strong> to capture long-tail tool loops.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-4-answer-quality-agentic-vs-adaptive\">4) Answer Quality (Agentic vs. Adaptive)<\/h3>\n\n\n\n<p>Run the <strong>same query set<\/strong> through <em>Adaptive<\/em> and <em>Agentic<\/em>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Compare precision@k\/nDCG of retrieved sets<\/li>\n\n\n\n<li>Human-rate final answers for factuality and completeness<\/li>\n\n\n\n<li>Track \u201cUnknown\u201d rate (good: avoids hallucination; too high: under-retrieval)<\/li>\n<\/ul>\n\n\n\n<p><strong>Tip:<\/strong> log a one-liner in every response:<br><code>decision=used_search|skipped_search loops=0|1 latency_ms=...<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-when-agentic-rag-may-not-be-worth-it\">When Agentic RAG May Not Be Worth It<\/h2>\n\n\n\n<p>Prefer <strong>Adaptive<\/strong> if:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>p95 latency must be &lt;1s (agentic adds ~1-2s when searching)<\/li>\n\n\n\n<li>Requests are predictable and schema-bound<\/li>\n\n\n\n<li>Compliance needs strong deterministic behavior<\/li>\n\n\n\n<li>Token cost is primary constraint<\/li>\n<\/ul>\n\n\n\n<p>Choose <strong>Agentic<\/strong> when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Queries are exploratory \/ multi-hop<\/li>\n\n\n\n<li>Multiple tools or sources are available<\/li>\n\n\n\n<li>Context quality &gt; raw speed<\/li>\n\n\n\n<li>You\u2019re building research assistants, not simple FAQ bots<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-repository-integration-pgvector-rag-search-lab\">Repository Integration (pgvector_RAG_search_lab)<\/h2>\n\n\n\n<p><strong>Proposed tree<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nlab\/\n\u251c\u2500\u2500 search\/\n|\t|__ ...other search scritps\n\u2502   \u251c\u2500\u2500 agentic_search.py           # Main agentic engine \n\u2502   \u2514\u2500\u2500 examples\/\n\u2502       \u2514\u2500\u2500 agentic_demo.py         # Interactive demo \n\u251c\u2500\u2500 core\/\n\u2502   \u2514\u2500\u2500 generation.py               # Includes generate_with_tools() for function calling\n\u251c\u2500\u2500 api\/\n\u2502   \u2514\u2500\u2500 fastapi_server.py           # REST endpoint: POST \/search with method=&quot;agentic&quot;\n\u251c\u2500\u2500 workflows\/\n\u2502   \u2514\u2500\u2500 agentic_rag_workflow.json   # n8n visual workflow\n\u2514\u2500\u2500 evaluation\/\n    \u2514\u2500\u2500 metrics.py                  # nDCG and ranking metrics (not agentic-specific)\n<\/pre><\/div>\n\n\n<p><strong>FastAPI endpoint (sketch)<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# lab\/search\/api_agentic.py\nfrom fastapi import APIRouter\nfrom .agentic_search import agentic_answer\nrouter = APIRouter()\n\n@router.post(&quot;\/agent_search&quot;)\ndef agent_search(payload: dict):\n    q = payload.get(&quot;query&quot;, &quot;&quot;)\n    result = agentic_answer(pg_conn=..., user_question=q)\n    return result\n<\/pre><\/div>\n\n\n<p><strong>n8n (optional)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Manual trigger \u2192 HTTP Request <code>\/agent_search<\/code> \u2192 Markdown render<\/li>\n\n\n\n<li>Show \ud83d\udd04 if <code>tool_used: true<\/code> and add latency badge<\/li>\n<\/ul>\n\n\n\n<p><strong>LangGraph (optional)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Map our tool into a graph node; Agent node \u2192 Tool node \u2192 Agent node<\/li>\n\n\n\n<li>Useful if you later add web search \/ SQL tools in parallel branches<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-prompt-tips-small-changes-big-impact\">Prompt Tips (small changes, big impact)<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Goal<\/th><th>Prompt Additions<\/th><\/tr><\/thead><tbody><tr><td>Fewer false positives<\/td><td>\u201cOnly search when facts are needed; avoid unnecessary retrieval.\u201d<\/td><\/tr><tr><td>Fewer false negatives<\/td><td>\u201cNever guess facts; reply \u2018Unknown\u2019 if not in snippets.\u201d<\/td><\/tr><tr><td>Lower latency<\/td><td>\u201cLimit to at most one additional retrieval if context is missing.\u201d<\/td><\/tr><tr><td>Better observability<\/td><td>\u201cEnd with: <code>Decision: used search<\/code> or <code>Decision: skipped search<\/code>.\u201d<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-quickstart\">Quickstart<\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\ngit clone https:\/\/github.com\/boutaga\/pgvector_RAG_search_lab\ncd pgvector_RAG_search_lab\n\n# Export your API key\nexport OPENAI_API_KEY=...\n\n  # Interactive demo (recommended first try)  \npython lab\/search\/examples\/agentic_demo.py  \n\u200b  \n# Command-line single query  \npython lab\/search\/agentic_search.py \\  \n  --source wikipedia \\  \n  --query &quot;Compare PostgreSQL and MySQL indexing&quot; \\  \n  --show-decision \\  \n  --show-sources  \n\u200b  \n# Interactive mode  \npython lab\/search\/agentic_search.py --source wikipedia --interactive  \n\u200b  \n# Start API server  \npython lab\/api\/fastapi_server.py  \n\u200b  \n# Call API endpoint  \ncurl -X POST http:\/\/localhost:8000\/search \\  \n  -H &quot;Content-Type: application\/json&quot; \\  \n  -d &#039;{  \n \u00a0  &quot;query&quot;: &quot;How does PostgreSQL MVCC work?&quot;,  \n \u00a0  &quot;method&quot;: &quot;agentic&quot;,  \n \u00a0  &quot;source&quot;: &quot;wikipedia&quot;,  \n \u00a0  &quot;top_k&quot;: 5,  \n \u00a0  &quot;generate_answer&quot;: true  \n  }&#039;\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-appendix-a-minimal-all-mini-variant-cheapest-path\">Appendix A \u2014 Minimal \u201call-mini\u201d variant (cheapest path)<\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Use gpt-5-mini for both phases\nresp = client.chat.completions.create(\n    model=&quot;gpt-5-mini&quot;,\n    messages=messages,\n    tools=&#x5B;search_tool],\n    tool_choice=&quot;auto&quot;,\n    temperature=0.2,\n)\n# ... identical loop, then final:\nfinal = client.chat.completions.create(\n    model=&quot;gpt-5-mini&quot;,\n    messages=messages + (&#x5B;msg] if not msg.tool_calls else &#x5B;]),\n    tool_choice=&quot;none&quot;,\n    temperature=0.3,\n)\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-appendix-b-simple-metrics-logger\">Appendix B \u2014 Simple metrics logger<\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# lab\/search\/metrics.py\nfrom dataclasses import dataclass\n\n@dataclass\nclass DecisionLog:\n    query: str\n    tool_used: bool\n    loops: int\n    latency_ms: int\n    label_retrieval_required: bool | None = None  # optional gold label\n    hallucinated: bool | None = None             # set via eval\n\ndef summarize(logs: list&#x5B;DecisionLog]):\n    n = len(logs)\n    usage = sum(1 for x in logs if x.tool_used) \/ n\n    p95 = sorted(x.latency_ms for x in logs)&#x5B;int(0.95 * n) - 1]\n    # If labels present, compute TP\/FP\/FN\/TN\n    labeled = &#x5B;x for x in logs if x.label_retrieval_required is not None]\n    if labeled:\n        tp = sum(1 for x in labeled if x.tool_used and x.label_retrieval_required)\n        tn = sum(1 for x in labeled if (not x.tool_used) and (not x.label_retrieval_required))\n        acc = (tp + tn) \/ len(labeled)\n    else:\n        acc = None\n    return {&quot;tool_usage_rate&quot;: usage, &quot;p95_latency_ms&quot;: p95, &quot;decision_accuracy&quot;: acc}\n<\/pre><\/div>\n\n\n<p>This is a simplified example for illustration. The repository currently tracks decision<br>metadata within the response object (<code>decision<\/code>, <code>tool_used<\/code>, <code>search_count<\/code>, <code>cost<\/code>). You can<br>implement this <code>DecisionLog<\/code> class separately if you need persistent decision analytics.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\">Conclusion<\/h2>\n\n\n\n<p>Agentic RAG makes retrieval <strong>intentional<\/strong>. By letting the model decide <em>if<\/em> and <em>when<\/em> to search\u2014and by limiting the loop to one safe retry\u2014you gain better answers on complex queries with measured, predictable overhead. <\/p>\n\n\n\n<p><strong>Takeaways<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Expect latency to be several seconds when the tool is used; near-naive latency when skipped<\/li>\n\n\n\n<li>Measure <strong>decision accuracy<\/strong> and <strong>tool usage rate<\/strong> alongside precision\/nDCG<\/li>\n\n\n\n<li>Start with one tool (wiki search) and one retry; expand only if metrics justify it<\/li>\n\n\n\n<li>Use smaller models for decisions and bigger ones for synthesis to balance quality\/cost<\/li>\n<\/ul>\n\n\n\n<p>In this post we focused only on retrieval quality \u2014 teaching the agent when to call the vector store and when to skip it, and giving it a controlled retrieval loop, that\u2019s the foundation. The next step is to extend the loop with governance and compliance checks (who is asking, what data can they see, should this query even be answered), and only then layer domain-specific business logic on top. That\u2019s how an agentic workflow evolves from \u201csmart retrieval\u201d into something you can actually trust in production.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In earlier parts, we moved from Naive RAG (vector search) to Hybrid RAG (dense + sparse) to Adaptive RAG (query classification and dynamic weighting). Each step improved what we retrieve. Agentic RAG goes further: the LLM decides if and when to retrieve at all and can take multiple steps (retrieve \u2192 inspect \u2192 refine [&hellip;]<\/p>\n","protected":false},"author":153,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[83],"tags":[3685,3523,77],"type_dbi":[2749],"class_list":["post-41108","post","type-post","status-publish","format-standard","hentry","category-postgresql","tag-ai-llm","tag-pgvector","tag-postgresql","type-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>RAG Series \u2013 Agentic RAG - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"RAG Series \u2013 Agentic RAG\" \/>\n<meta property=\"og:description\" content=\"Agentic RAG goes beyond vector search: an LLM that decides when to retrieve, runs controlled retrieval loops, avoids hallucination, and logs decision quality, cost, and latency using PostgreSQL + pgvector.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-26T20:29:09+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-26T20:33:46+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/03\/pixlr-image-generator-5f64d780-c578-477a-9419-7ddcdb807c83.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Adrien Obernesser\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adrien Obernesser\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\"},\"author\":{\"name\":\"Adrien Obernesser\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"headline\":\"RAG Series \u2013 Agentic RAG\",\"datePublished\":\"2025-10-26T20:29:09+00:00\",\"dateModified\":\"2025-10-26T20:33:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\"},\"wordCount\":1325,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png\",\"keywords\":[\"AI\/LLM\",\"pgvector\",\"PostgreSQL\"],\"articleSection\":[\"PostgreSQL\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\",\"name\":\"RAG Series \u2013 Agentic RAG - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png\",\"datePublished\":\"2025-10-26T20:29:09+00:00\",\"dateModified\":\"2025-10-26T20:33:46+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png\",\"contentUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png\",\"width\":1352,\"height\":605},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"RAG Series \u2013 Agentic RAG\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\",\"name\":\"Adrien Obernesser\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"caption\":\"Adrien Obernesser\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/adrienobernesser\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"RAG Series \u2013 Agentic RAG - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/","og_locale":"en_US","og_type":"article","og_title":"RAG Series \u2013 Agentic RAG","og_description":"Agentic RAG goes beyond vector search: an LLM that decides when to retrieve, runs controlled retrieval loops, avoids hallucination, and logs decision quality, cost, and latency using PostgreSQL + pgvector.","og_url":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/","og_site_name":"dbi Blog","article_published_time":"2025-10-26T20:29:09+00:00","article_modified_time":"2025-10-26T20:33:46+00:00","og_image":[{"width":1024,"height":1024,"url":"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/03\/pixlr-image-generator-5f64d780-c578-477a-9419-7ddcdb807c83.png","type":"image\/png"}],"author":"Adrien Obernesser","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Adrien Obernesser","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/"},"author":{"name":"Adrien Obernesser","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"headline":"RAG Series \u2013 Agentic RAG","datePublished":"2025-10-26T20:29:09+00:00","dateModified":"2025-10-26T20:33:46+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/"},"wordCount":1325,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png","keywords":["AI\/LLM","pgvector","PostgreSQL"],"articleSection":["PostgreSQL"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/","url":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/","name":"RAG Series \u2013 Agentic RAG - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png","datePublished":"2025-10-26T20:29:09+00:00","dateModified":"2025-10-26T20:33:46+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2025\/10\/image-12.png","width":1352,"height":605},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/rag-series-agentic-rag\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"RAG Series \u2013 Agentic RAG"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd","name":"Adrien Obernesser","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","caption":"Adrien Obernesser"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/adrienobernesser\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/41108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/153"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=41108"}],"version-history":[{"count":30,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/41108\/revisions"}],"predecessor-version":[{"id":41304,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/41108\/revisions\/41304"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=41108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=41108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=41108"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=41108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}