<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged tool-calling</title>
<link>https://coderlegion.com/tag/tool-calling</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Design Tool Errors AI Agents Can Recover From</title>
<link>https://coderlegion.com/24993/how-to-design-tool-errors-ai-agents-can-recover-from</link>
<description>&lt;p&gt;“Something went wrong” is not an error contract. It is a request for another blind guess.&lt;/p&gt;
&lt;p&gt;That is expensive inside an AI agent loop. The controller has to decide whether to retry the same call, repair an argument, ask for authorization, choose another tool, or stop. A human can infer some of that from a stack trace. A machine needs the next action to be explicit.&lt;/p&gt;
&lt;p&gt;Human strategy, benchmark design, interpretation, and final editorial judgment led this article; AI assisted with research organization, drafting, and code review.&lt;/p&gt;
&lt;p&gt;I built a deterministic benchmark around 12,000 synthetic tool operations to test three response formats: a generic message, an error code, and an actionable error envelope. The test does not measure model intelligence. It measures a smaller systems question: how much useful recovery can a controller perform when the error contract tells it what kind of failure occurred?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=8843500240625635739&quot; alt=&quot;An architecture diagram showing a tool failure converted into an actionable error envelope before the controller chooses retry, repair, or stop.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Original architecture visual. The raw message remains useful for people, while structured fields make the next machine action explicit.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;a-tool-error-is-part-of-the-agent-s-control-plane&quot;&gt;A tool error is part of the agent's control plane&lt;/h3&gt;
&lt;p&gt;In a normal application, an error often ends a request. In an agent, the error becomes input to the next turn.&lt;/p&gt;
&lt;p&gt;That changes the design requirement. The message should still help an operator, but it also needs to support a routing decision:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Retry:&lt;/strong&gt; the same operation may succeed after backoff.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repair:&lt;/strong&gt; the operation can succeed after changing an argument.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorize:&lt;/strong&gt; the call needs a credential or human approval.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replace:&lt;/strong&gt; another tool or resource should be used.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop:&lt;/strong&gt; another attempt would waste time or repeat a side effect.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Model Context Protocol makes a related distinction between protocol errors and tool execution errors. Malformed requests and unknown tools belong at the protocol layer. Validation failures, API failures, and business-logic errors can be returned as tool results with &lt;code&gt;isError: true&lt;/code&gt;, giving the model actionable feedback it can use to adjust a later call (&lt;a rel=&quot;nofollow&quot; href=&quot;https://modelcontextprotocol.io/specification/draft/server/tools&quot;&gt;MCP tool error handling&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;OpenAI's Agents SDK exposes the same underlying control problem from the runner side. An unresolved tool name can either raise an exception or be returned to the model so the loop can recover and select an available tool (&lt;a rel=&quot;nofollow&quot; href=&quot;https://openai.github.io/openai-agents-python/running_agents/&quot;&gt;OpenAI Agents SDK runner documentation&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The protocol can carry an error. The application still has to decide whether that error is useful.&lt;/p&gt;
&lt;h3 id=&quot;i-tested-three-error-formats-across-12-000-operations&quot;&gt;I tested three error formats across 12,000 operations&lt;/h3&gt;
&lt;p&gt;The benchmark generated 60 seeded runs with 200 initial operations in each run. Forty percent of operations failed under an explicit scenario assumption. Failures were divided evenly among four types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;transient;&lt;/li&gt;
&lt;li&gt;validation;&lt;/li&gt;
&lt;li&gt;permission;&lt;/li&gt;
&lt;li&gt;not found.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each strategy received the same generated operations and the same recovery rolls.&lt;/p&gt;
&lt;p&gt;The three strategies were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Generic message:&lt;/strong&gt; retry every failure once because the controller cannot classify it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error code only:&lt;/strong&gt; retry transient failures, attempt to repair validation failures, and stop on permanent failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actionable envelope:&lt;/strong&gt; use the same routing, but include a field and repair suggestion that improves the modeled validation-repair probability.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run the benchmark with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx tsx scripts/run-agent-tool-error-contract-benchmark.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The scenario assumptions are part of the result, not hidden setup. A transient retry succeeds 70% of the time. A validation repair succeeds 45% of the time when the controller receives only a code and 90% when it receives the failing field and a repair hint.&lt;/p&gt;
&lt;p&gt;Those percentages are illustrative assumptions. They are not measurements of a production model.&lt;/p&gt;
&lt;h3 id=&quot;the-actionable-envelope-cut-failed-retries-by-87-7-&quot;&gt;The actionable envelope cut failed retries by 87.7%&lt;/h3&gt;
&lt;p&gt;Here are the aggregate results:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Strategy &lt;/th&gt;&lt;th&gt;Resolution rate &lt;/th&gt;&lt;th&gt;Attempts per operation &lt;/th&gt;&lt;th&gt;Failed retry attempts &lt;/th&gt;&lt;th&gt;Permanent-failure retries&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Generic message &lt;/td&gt;&lt;td&gt;67.1% &lt;/td&gt;&lt;td&gt;1.402 &lt;/td&gt;&lt;td&gt;3,953 &lt;/td&gt;&lt;td&gt;2,449&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Error code only &lt;/td&gt;&lt;td&gt;71.2% &lt;/td&gt;&lt;td&gt;1.198 &lt;/td&gt;&lt;td&gt;1,005 &lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Actionable envelope &lt;/td&gt;&lt;td&gt;75.5% &lt;/td&gt;&lt;td&gt;1.198 &lt;/td&gt;&lt;td&gt;487 &lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1541979796479906598&quot; alt=&quot;A bar chart comparing resolution rate and wasted retry attempts for generic messages, error codes, and actionable error envelopes.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Original deterministic benchmark. Sixty seeded runs contained 200 initial operations each. Resolution is simulated controller success within one recovery attempt; no language model was called.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The generic strategy made 16,823 total attempts for 12,000 operations. It retried permission and not-found failures 2,449 times even though the retry could not change the outcome.&lt;/p&gt;
&lt;p&gt;Adding a code eliminated those permanent-failure retries. Total attempts fell to 14,374, while the resolution rate increased from 67.1% to 71.2% because the controller could treat validation as a repair problem instead of repeating the same invalid call.&lt;/p&gt;
&lt;p&gt;The actionable envelope used the same number of attempts as the code-only strategy but resolved 75.5% of operations. Its failed retry count fell to 487—87.7% below the generic-message strategy.&lt;/p&gt;
&lt;p&gt;The benchmark does not prove that every model will recover at that rate. It shows what the controller can do when recovery policy is encoded rather than guessed.&lt;/p&gt;
&lt;h3 id=&quot;give-the-controller-a-small-stable-error-envelope&quot;&gt;Give the controller a small, stable error envelope&lt;/h3&gt;
&lt;p&gt;The error contract does not need to become a second API specification. It needs enough information to route the failure safely.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ToolError = {
  code: &quot;TRANSIENT&quot; | &quot;VALIDATION&quot; | &quot;PERMISSION&quot; | &quot;NOT_FOUND&quot;;
  message: string;
  retryable: boolean;
  field?: string;
  suggestion?: string;
  retryAfterMs?: number;
  traceId: string;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each field has one job.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;code&lt;/code&gt; selects a known failure class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt; explains the problem to the model and operator.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;retryable&lt;/code&gt; stops the controller from inventing its own retry rule.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;field&lt;/code&gt; identifies the argument that needs repair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;suggestion&lt;/code&gt; supplies a bounded correction rather than an open-ended rewrite.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;retryAfterMs&lt;/code&gt; prevents an immediate retry from amplifying throttling.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;traceId&lt;/code&gt; connects the agent-visible failure to logs and traces.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not put secrets, raw database errors, or internal stack traces into a model-visible message. The public contract should expose the recovery surface, not the server's internals.&lt;/p&gt;
&lt;h3 id=&quot;separate-routing-policy-from-error-prose&quot;&gt;Separate routing policy from error prose&lt;/h3&gt;
&lt;p&gt;A controller can route the envelope without asking a model to interpret every sentence.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function nextAction(error: ToolError): &quot;retry&quot; | &quot;repair&quot; | &quot;authorize&quot; | &quot;stop&quot; {
  if (error.code === &quot;TRANSIENT&quot; &amp;amp;&amp;amp; error.retryable) return &quot;retry&quot;;
  if (error.code === &quot;VALIDATION&quot; &amp;amp;&amp;amp; error.field &amp;amp;&amp;amp; error.suggestion) return &quot;repair&quot;;
  if (error.code === &quot;PERMISSION&quot;) return &quot;authorize&quot;;
  return &quot;stop&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is intentionally boring. A deterministic router is easier to test than a prompt that says, “Use your judgment and try again if appropriate.”&lt;/p&gt;
&lt;p&gt;The model still matters when a validation error requires semantic repair. It may need to convert “next Friday” into an ISO-8601 date or select a replacement resource. But the controller should decide whether a repair turn is allowed before spending another model call.&lt;/p&gt;
&lt;p&gt;GitHub's MCP Scripts specification takes this idea further for execution errors by requiring a &lt;code&gt;data.recoverable&lt;/code&gt; boolean. It limits &lt;code&gt;recoverable: true&lt;/code&gt; to transient failures where the same invocation may succeed on a later attempt (&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.github.com/gh-aw/reference/mcp-scripts-specification/&quot;&gt;GitHub MCP Scripts error handling&lt;/a&gt;). That is the kind of field a controller can enforce without semantic guesswork.&lt;/p&gt;
&lt;h3 id=&quot;the-prompt-trace-should-preserve-the-boundary&quot;&gt;The prompt trace should preserve the boundary&lt;/h3&gt;
&lt;p&gt;Here is the exact interpretation constraint used for the benchmark summary:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Prompt:
Compare the three tool-error strategies using only summary.json. Separate
measured simulation output from scenario assumptions. Do not claim LLM accuracy.

Input:
Generic message: 67.1% resolved, 3,953 failed retry attempts
Error code only: 71.2% resolved, 1,005 failed retry attempts
Actionable envelope: 75.5% resolved, 487 failed retry attempts

Output constraint:
Report resolution rate, attempts per operation, failed retries, and permanent-
failure retries. State that all recovery probabilities are explicit synthetic
assumptions and that no model was called.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last line prevents a common reporting error. A controller simulation can test policy logic. It cannot tell you how reliably a model will interpret a repair hint.&lt;/p&gt;
&lt;h3 id=&quot;retry-safety-needs-more-than-a-boolean&quot;&gt;Retry safety needs more than a boolean&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;retryable: true&lt;/code&gt; is necessary and insufficient.&lt;/p&gt;
&lt;p&gt;A production retry path should also answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the operation idempotent?&lt;/li&gt;
&lt;li&gt;Has this workflow already produced a side effect?&lt;/li&gt;
&lt;li&gt;What is the maximum attempt budget?&lt;/li&gt;
&lt;li&gt;Should the controller use exponential backoff and jitter?&lt;/li&gt;
&lt;li&gt;Did the server provide a rate-limit reset time?&lt;/li&gt;
&lt;li&gt;Does the repaired call need a new idempotency key or the old one?&lt;/li&gt;
&lt;li&gt;Which failures require a human decision?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A retryable payment lookup and a retryable payment creation are different risks. The first may waste capacity. The second may charge twice.&lt;/p&gt;
&lt;p&gt;For state-changing tools, store the operation ID and side-effect status outside the model context. A model should not be the source of truth for whether a transaction already happened.&lt;/p&gt;
&lt;h3 id=&quot;where-this-benchmark-stops&quot;&gt;Where this benchmark stops&lt;/h3&gt;
&lt;p&gt;The benchmark is deterministic and reproducible, but its scope is narrow.&lt;/p&gt;
&lt;p&gt;It does not measure latency, tokens, model interpretation, parallel tool calls, ambiguous repair hints, or side-effect safety. The failure mix is synthetic. The recovery probabilities are declared assumptions. Resolution means success within one modeled recovery attempt, not completion of a full agent task.&lt;/p&gt;
&lt;p&gt;Real evaluations should replay production-shaped traces, vary models and prompts, measure incorrect repairs, and test that terminal failures really stop. They should also include adversarial errors: misleading suggestions, mismatched codes, missing trace IDs, and a server that marks everything retryable.&lt;/p&gt;
&lt;p&gt;The small benchmark is still useful because it tests the first layer without model noise: whether the controller has enough structure to choose a permitted next action.&lt;/p&gt;
&lt;h3 id=&quot;make-failure-actionable-before-making-it-eloquent&quot;&gt;Make failure actionable before making it eloquent&lt;/h3&gt;
&lt;p&gt;Start with four routes: retry, repair, authorize, and stop. Define the codes that lead to each route. Add an explicit retry flag, the smallest useful repair hint, and a trace ID. Then test the controller with fixed seeds before asking a model to interpret the message.&lt;/p&gt;
&lt;p&gt;The practical test is simple: if the model were unavailable, could the runtime still avoid repeating a permission error, respect backoff, and identify the argument that needs repair?&lt;/p&gt;
&lt;p&gt;If not, the error contract is still prose. Give it enough structure to become control flow.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24993/how-to-design-tool-errors-ai-agents-can-recover-from</guid>
<pubDate>Thu, 20 Aug 2026 14:34:07 +0000</pubDate>
</item>
<item>
<title>Fine-Tuning vs Prompt Engineering vs RAG: When to Use Each (And the Fourth Option Nobody Mentions)</title>
<link>https://coderlegion.com/24338/fine-tuning-prompt-engineering-vs-rag-when-use-each-and-the-fourth-option-nobody-mentions</link>
<description>&lt;p&gt;You have an AI model that hallucinates with your company's data. You open a support ticket and ask the chatbot about your returns policy. The chatbot, powered by GPT-4 or Gemini 2.5, responds with a fabricated policy that sounds perfectly plausible but has nothing to do with your company's reality. Your boss stares at you. Your customer complains. You open Google and search &lt;strong&gt;&quot;how to connect LLM to my data&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The top 10 results offer three contradictory answers: &quot;use RAG,&quot; &quot;do fine-tuning,&quot; &quot;improve your prompt.&quot; All three are right. All three are wrong. Because the correct answer isn't any of the three in the abstract — it's &lt;strong&gt;the one that fits your specific use case&lt;/strong&gt;. And there's a fourth option that almost nobody mentions, and which, in my experience, is the right call in more cases than the industry admits.&lt;/p&gt;
&lt;p&gt;This article is the decision tree I wish I'd had when I started building the AI systems behind this blog. I've distilled it after implementing all four techniques in real production: Prompt Engineering across the entire &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part1/&quot;&gt;Autopilot series&lt;/a&gt;, RAG in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part8/&quot;&gt;Ops Copilot&lt;/a&gt; with Algolia, pure Tool Calling in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/obs_part5_radar_agent/&quot;&gt;Obsolescence Radar&lt;/a&gt;, and experimental fine-tuning in industrial classification pipelines. It closes the trilogy that began with &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/rag_antipatterns/&quot;&gt;RAG: 7 Anti-Patterns&lt;/a&gt; and continued with &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/mcp_protocol/&quot;&gt;MCP Protocol&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-question-nobody-asks&quot;&gt;The Question Nobody Asks&lt;/h4&gt;
&lt;p&gt;Before choosing a technique, ask yourself this: &lt;strong&gt;Does the knowledge your LLM needs change, or is it static?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the answer is &quot;it changes frequently&quot; (product documentation, inventory, prices, regulations), you need a technique that accesses data &lt;strong&gt;in real time&lt;/strong&gt; without retraining the model. If the answer is &quot;it's static or changes very slowly&quot; (brand tone, formatting rules, domain nomenclature), you can consider techniques that &lt;strong&gt;incorporate that knowledge into the model&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This distinction is the first node of the decision tree. It seems obvious written this way. Yet most teams I've seen jump straight to whatever technique is trending (RAG in 2024, fine-tuning in 2023, prompt engineering always) without asking this fundamental question.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://datalaria.com/es/posts/finetuning_vs_rag/decision_tree.jpg&quot; alt=&quot;Decision tree: how to choose between the 4 techniques&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;option-1-prompt-engineering-80-of-cases&quot;&gt;Option 1: Prompt Engineering — 80% of Cases&lt;/h4&gt;
&lt;p&gt;The uncomfortable truth the AI tooling industry doesn't want you to know: &lt;strong&gt;for 80% of use cases, a well-designed prompt is sufficient&lt;/strong&gt;. You don't need RAG. You don't need fine-tuning. You need a system prompt that clearly defines the role, context, constraints, and expected output format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When it's sufficient&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The required knowledge fits in the model's context window (Gemini 2.5 handles up to 1 million tokens; Claude up to 200K).&lt;/li&gt;
&lt;li&gt;The task is generic but needs structure (drafting emails, summarizing documents, classifying text, generating code).&lt;/li&gt;
&lt;li&gt;You don't need updated proprietary data — the model's general knowledge is enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Advanced techniques that make the difference&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structured system prompts&lt;/strong&gt;: Define the role (&quot;You are a senior supply chain engineer&quot;), constraints (&quot;Always respond in technical English&quot;), and output format (&quot;Return a JSON with fields: analysis, recommendation, confidence&quot;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Few-shot prompting&lt;/strong&gt;: Include 3-5 correct input-output examples in the prompt. In the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part3/&quot;&gt;Autopilot series&lt;/a&gt;, CrewAI agents use few-shot to maintain style consistency across generated articles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chain-of-thought (CoT)&lt;/strong&gt;: Instruct the model to &quot;think step by step&quot; before giving the final answer. Dramatically improves accuracy in reasoning, calculation, and multi-step analysis tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt chaining&lt;/strong&gt;: Break complex tasks into sequential subtasks, each with its own optimized prompt. This is exactly what CrewAI does with its agent architecture: each agent has a specialized prompt for its role.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cost&lt;/strong&gt;: Virtually zero (only API token cost). A well-designed prompt can take hours of iteration, but operational cost is minimal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fatal limitation&lt;/strong&gt;: The context window has a limit. If you need the model to &quot;know&quot; about 10,000 documents from your knowledge base, you can't inject them all into the prompt. This is where RAG enters.&lt;/p&gt;
&lt;h4 id=&quot;option-2-rag-updatable-proprietary-knowledge&quot;&gt;Option 2: RAG — Updatable Proprietary Knowledge&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; is the right answer when you need the LLM to respond about &lt;strong&gt;your proprietary knowledge&lt;/strong&gt; and that knowledge &lt;strong&gt;updates frequently&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When it's necessary&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product documentation, technical manuals, internal knowledge bases that update weekly or monthly.&lt;/li&gt;
&lt;li&gt;The user can ask unpredictable questions about a broad document corpus (you don't know in advance which fragment the LLM will need).&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;citability&lt;/strong&gt;: the answer must include the sources it draws from (critical for compliance, as we documented in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/eu_ai_act/&quot;&gt;EU AI Act&lt;/a&gt;, Article 13 on transparency).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: When data is structured (SQL tables, APIs with defined schemas) or when you need numerical precision. As I extensively documented in &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/rag_antipatterns/&quot;&gt;Anti-Pattern 7 of the RAG article&lt;/a&gt;, RAG over structured data generates narrative hallucinations where you need exact figures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correct architecture (summarized)&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Semantic chunking&lt;/strong&gt; (not fixed-length — Anti-Pattern 1)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluated embeddings&lt;/strong&gt; with your domain benchmark (Anti-Pattern 2)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reranking&lt;/strong&gt; between retriever and LLM (Anti-Pattern 3)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generous context&lt;/strong&gt; (top-10/15, not top-3 — Anti-Pattern 4)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluation with RAGAS/DeepEval&lt;/strong&gt; before production (Anti-Pattern 6)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Real cost&lt;/strong&gt;: Moderate. The vector store (Pinecone, Weaviate, Algolia) has a monthly cost (€0-100 depending on volume), plus embedding cost (low) and generation cost (API tokens). In the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part8/&quot;&gt;Ops Copilot&lt;/a&gt;, the total RAG cost with Algolia was under &lt;strong&gt;€3/month&lt;/strong&gt; for the blog's ~70 posts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real case at Datalaria&lt;/strong&gt;: The Ops Engineering Copilot (&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part8/&quot;&gt;Autopilot Part 8&lt;/a&gt;) uses RAG with Algolia Agent Studio to answer questions about blog content. Posts are indexed as semantic records (one record per section), and the copilot retrieves relevant fragments before generating the response. Works well for semantic search over free text.&lt;/p&gt;
&lt;h4 id=&quot;option-3-fine-tuning-the-scalpel-not-the-hammer&quot;&gt;Option 3: Fine-Tuning — The Scalpel, Not the Hammer&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Fine-tuning&lt;/strong&gt; is the most powerful technique and the most misused. It involves &lt;strong&gt;partially retraining&lt;/strong&gt; a base model (Gemini, Llama, Mistral) with your own data so the model internalizes specific knowledge, style, or behavior.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When it's essential&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need the model to adopt a &lt;strong&gt;very specific tone or style&lt;/strong&gt; consistently (a brand with strict voice &amp;amp; tone, a domain with very particular technical jargon).&lt;/li&gt;
&lt;li&gt;The task is &lt;strong&gt;highly specialized&lt;/strong&gt; and generalist models don't solve it well even with advanced prompting (industrial defect classification, proprietary nomenclature entity extraction, specialized medical diagnosis).&lt;/li&gt;
&lt;li&gt;You need to &lt;strong&gt;reduce latency and cost&lt;/strong&gt; in production: a fine-tuned smaller model (7B-13B parameters) can match the quality of a large model (70B+) on your specific task, at a fraction of the cost and latency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt; (the most widespread myth):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don't use fine-tuning to &quot;teach the model data.&quot;&lt;/strong&gt; Fine-tuning is not a database. If you need the model to know your product catalog, use RAG. Fine-tuning &quot;burns in&quot; behavioral patterns, not updatable facts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don't use fine-tuning if your knowledge changes frequently.&lt;/strong&gt; Each update requires retraining, which can cost hours and hundreds of euros. RAG is instant: update the document and the retriever finds it immediately.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Modern tools&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LoRA (Low-Rank Adaptation)&lt;/strong&gt;: The standard technique. Instead of retraining the model's billions of parameters, LoRA trains only low-rank matrices &quot;attached&quot; to the model's layers. Reduces training cost by 90%+ and stores the fine-tuned model as a few MB of &quot;adapters.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QLoRA&lt;/strong&gt;: LoRA applied to a 4-bit quantized model. Enables fine-tuning 70B-parameter models on a single consumer GPU (24GB VRAM). Democratized fine-tuning for startups and teams without GPU clusters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vertex AI Tuning / OpenAI Fine-Tuning API&lt;/strong&gt;: Managed services where you upload your training dataset (instruction-response pairs) and the platform runs the fine-tuning without you managing GPU infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Real cost&lt;/strong&gt;: Variable. Fine-tuning with LoRA on a 7B-parameter model with 10,000 examples costs &lt;strong&gt;€5-20&lt;/strong&gt; on cloud (Google Cloud, AWS). A 70B model can cost &lt;strong&gt;€50-200&lt;/strong&gt; per training session. Plus the cost of preparing the dataset (hours of human work). As we analyzed in &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/hidden_economics_ai/&quot;&gt;The Hidden Economics of AI&lt;/a&gt;, fine-tuning's hidden cost isn't compute — it's &lt;strong&gt;training dataset curation&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;option-4-tool-calling-mcp-the-one-nobody-mentions&quot;&gt;Option 4: Tool Calling / MCP — The One Nobody Mentions&lt;/h4&gt;
&lt;p&gt;This is the option I discovered by elimination after RAG failed spectacularly on the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/obs_part5_radar_agent/&quot;&gt;Obsolescence Radar&lt;/a&gt;. &lt;strong&gt;Tool Calling&lt;/strong&gt; means the LLM doesn't try to &quot;know&quot; the answer; instead, it knows &lt;strong&gt;who to ask&lt;/strong&gt; — that is, which tool to execute to get the information with deterministic precision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When it's the right option&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data is &lt;strong&gt;structured&lt;/strong&gt; (SQL databases, REST APIs, spreadsheets with schemas).&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;absolute numerical precision&lt;/strong&gt; (financial calculations, inventory metrics, sensor data).&lt;/li&gt;
&lt;li&gt;The operation requires &lt;strong&gt;actions&lt;/strong&gt;, not just answers (create a ticket, send an email, run a query, call an external API).&lt;/li&gt;
&lt;li&gt;You want to &lt;strong&gt;standardize connections&lt;/strong&gt; between the LLM and tools to avoid vendor lock-in — exactly the problem solved by &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/mcp_protocol/&quot;&gt;MCP (Model Context Protocol)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: The LLM (Gemini 2.5, Claude) acts as a &lt;strong&gt;semantic orchestrator&lt;/strong&gt;: it understands the user's natural language intent, decides which tool(s) to execute, constructs the parameters, executes the tool(s), and interprets results for the user. Tools are deterministic Python functions (decorated with &lt;code&gt;@tool&lt;/code&gt; in CrewAI) that execute precision operations: SQL queries to Supabase, supplier API calls, linear programming calculations with PuLP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost&lt;/strong&gt;: The lowest of all four options. You only pay for LLM tokens (typically few, since the prompt is short) and tool execution (SQL queries, API calls). In the Obsolescence Radar, the cost per complete execution (analyze a component, traverse the BOM graph, calculate financial impact, generate executive report) was under &lt;strong&gt;€0.02 per query&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real case at Datalaria&lt;/strong&gt;: The &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/obs_part5_radar_agent/&quot;&gt;Agentic Obsolescence Radar&lt;/a&gt; uses Tool Calling exclusively. The LLM (Gemini 2.5 via CrewAI) understands the obsolescence alert in natural language, but all data operations — SQL query to the component catalog, BOM graph traversal, P&amp;amp;L calculation, PDF generation — are executed by deterministic Python tools. Result: executive reports in 4 seconds with &lt;strong&gt;0% numerical hallucination&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-decision-matrix&quot;&gt;The Decision Matrix&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Criterion &lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Prompt Engineering &lt;/th&gt;&lt;th align=&quot;center&quot;&gt;RAG &lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Fine-Tuning &lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Tool Calling&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Initial cost&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Minimal &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Low-medium &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ High &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Low&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Operational cost&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Low &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Medium &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Low (small model) &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Minimal&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Precision (free text)&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Medium &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ High &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Very high &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ N/A&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Precision (structured data)&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Low &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Low &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Low &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Exact&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Data freshness&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Instant &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Instant &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Requires retraining &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Real-time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Implementation effort&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Hours &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Days-weeks &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Weeks-months &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Days&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Maintenance&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Minimal &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Medium &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ High (data drift) &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐ Medium&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Traceability (EU AI Act)&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Difficult &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ High (citable sources) &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐ Opaque (black box) &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐ Total (deterministic)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Ideal use case&lt;/strong&gt; &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Generic tasks with clear instructions &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Updatable proprietary text knowledge &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Specific style/tone, ultra-specialized tasks &lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Structured data, numerical precision, actions&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;the-3-question-framework&quot;&gt;The 3-Question Framework&lt;/h4&gt;
&lt;p&gt;If the matrix seems dense, I've distilled a 3-question framework that resolves 90% of decisions:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Question 1: Does the data the LLM needs fit in the prompt?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes → &lt;strong&gt;Prompt Engineering&lt;/strong&gt;. Inject context directly. Simpler, cheaper, faster.&lt;/li&gt;
&lt;li&gt;No → Next question.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Question 2: Is the data free text or structured?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Free text (documentation, manuals, posts) → &lt;strong&gt;RAG&lt;/strong&gt;. Semantic retrieval is superior for searching unstructured text.&lt;/li&gt;
&lt;li&gt;Structured (SQL, APIs, tables, calculations) → &lt;strong&gt;Tool Calling&lt;/strong&gt;. Deterministic tools that execute exact queries.&lt;/li&gt;
&lt;li&gt;Both → &lt;strong&gt;Hybrid architecture&lt;/strong&gt; (RAG for textual context + Tool Calling for structured data, as we proposed in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/rag_antipatterns/&quot;&gt;RAG article&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Question 3: Do you need a behavior or style the base model can't reproduce even with the best prompt?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes (unique brand tone, ultra-specific domain jargon, task that generalist models consistently fail) → &lt;strong&gt;Fine-Tuning&lt;/strong&gt; on a base model.&lt;/li&gt;
&lt;li&gt;No → Go back to Prompt Engineering and refine your prompt before considering more complex techniques.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;what-i-learned-implementing-all-four&quot;&gt;What I Learned Implementing All Four&lt;/h4&gt;
&lt;p&gt;The most valuable lesson from operating these four techniques in production fits in a single sentence: &lt;strong&gt;always start with the simplest technique that could work&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The temptation is to jump straight to RAG or fine-tuning because they're more &quot;sophisticated.&quot; But sophistication doesn't correlate with effectiveness. In the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/ai_agents_part1/&quot;&gt;Autopilot&lt;/a&gt;, the majority of output quality comes from Prompt Engineering — carefully designed system prompts, few-shot examples, and Chain-of-thought. RAG added marginal value in the Ops Copilot for blog search. Fine-tuning wasn't necessary in any case. And Tool Calling was the transformative technique in the Obsolescence Radar, where RAG had failed.&lt;/p&gt;
&lt;p&gt;The evaluation order should always be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prompt Engineering&lt;/strong&gt; (hours, ~€0)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Calling&lt;/strong&gt; if data is structured (days, ~€0)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAG&lt;/strong&gt; if you need access to proprietary text (days-weeks, ~€3-50/month)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fine-Tuning&lt;/strong&gt; only if the previous three consistently fail (weeks, €50-500+)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And in the era of the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/eu_ai_act/&quot;&gt;EU AI Act&lt;/a&gt;, there's a fifth consideration that isn't technical but legal: &lt;strong&gt;traceability&lt;/strong&gt;. Article 10 of the regulation requires that training data for high-risk systems be &quot;relevant, representative, and to the extent possible, free of errors and complete.&quot; This applies directly to fine-tuning: if you fine-tune a model with biased or incorrect data, and that model makes decisions in a regulated domain, you're exposed to sanctions. RAG and Tool Calling, being transparent in their sources, offer traceability that fine-tuning cannot match.&lt;/p&gt;
&lt;p&gt;As we wrote in &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/hidden_economics_ai/&quot;&gt;The Hidden Economics of AI&lt;/a&gt;, the 10x Rule applies: if a more complex technique doesn't give you a result &lt;strong&gt;10 times better&lt;/strong&gt; than the previous one, it probably doesn't justify its added cost and complexity. Start simple. Measure. Scale only when the data demands it.&lt;/p&gt;
&lt;hr&gt;
&lt;h5 id=&quot;sources-of-interest-&quot;&gt;Sources of Interest:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cloud.google.com/vertex-ai/docs/generative-ai/models/tune-models&quot;&gt;&lt;strong&gt;Google Cloud&lt;/strong&gt;: Tuning &amp;amp; Fine-tuning with Vertex AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://huggingface.co/docs/peft/conceptual_guides/lora&quot;&gt;&lt;strong&gt;Hugging Face&lt;/strong&gt;: LoRA — Low-Rank Adaptation of Large Language Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.pinecone.io/learn/rag-vs-fine-tuning/&quot;&gt;&lt;strong&gt;Pinecone&lt;/strong&gt;: RAG vs Fine-Tuning — How to Choose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering&quot;&gt;&lt;strong&gt;Anthropic&lt;/strong&gt;: Prompt Engineering Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/rag_antipatterns/&quot;&gt;&lt;strong&gt;Datalaria&lt;/strong&gt;: RAG in Production — 7 Anti-Patterns That Destroy Precision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/mcp_protocol/&quot;&gt;&lt;strong&gt;Datalaria&lt;/strong&gt;: MCP Protocol — The USB of AI (Standardized Tool Calling)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/obs_part5_radar_agent/&quot;&gt;&lt;strong&gt;Datalaria&lt;/strong&gt;: The Agentic Radar — Tool Calling in Production&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/hidden_economics_ai/&quot;&gt;&lt;strong&gt;Datalaria&lt;/strong&gt;: The Hidden Economics of AI — Real Costs of Each Technique&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/eu_ai_act/&quot;&gt;&lt;strong&gt;Datalaria&lt;/strong&gt;: EU AI Act — Article 10 and Training Data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/24338/fine-tuning-prompt-engineering-vs-rag-when-use-each-and-the-fourth-option-nobody-mentions</guid>
<pubDate>Sun, 09 Aug 2026 14:33:21 +0000</pubDate>
</item>
</channel>
</rss>