The Agent Spec

Agent quality comes mostly from three things, and mixing them is the most common cause of poor answers. Keep them in separate layers, and let tool descriptions do the heavy lifting on routing.

Prerequisite: a strong agent needs a strong semantic view underneath it. If you skipped it, start with Exhibit A.

Start with Three Layers and work through the tabs in order. Next exhibit: Exhibit C, Evaluations.

Exhibit B · Section 1 of 4

The Three-Layer Model

Agent quality comes mostly from three things, and mixing them is the most common cause of poor answers. Keep them in separate layers.

Orchestration

instructions.orchestration

Put here: tool routing, intent defaults (e.g. default time window), scope limits, multi-step workflows, fallback when a tool errors or returns nothing.

Keep out: tone, formatting, SQL-generation rules.

Response

instructions.response

Put here: tone, answer-first structure, tables vs. charts, units/currency, data freshness, handling ambiguity or empty results.

Keep out: tool routing, SQL-generation rules.

Tool description

tools[].tool_spec.description

Put here: what the tool does, what data it accesses, when to use it, when NOT to use it, input guidance.

 

Rule of thumb: if it affects what the agent does or which tool it picks → orchestration. If it affects how the output looks → response. If it describes a tool → the tool's description.
Exhibit B · Section 2 of 4

Tool Descriptions Drive Routing Accuracy

Agents pick tools by name and description alone, not by inspecting your data model. This is the single biggest lever on routing accuracy. Write every description with this formula:

1
What it does
+ what data it accesses (grain, metrics, history, refresh)
+
2
When to use
specific question types, with examples
+
3
When NOT to use
critical: stops overuse for anything remotely related
+
4
Input guidance
units, date formats, key filter values

Give every tool a distinct domain and a non-overlapping "when to use", and always include an explicit "when NOT to use". When you have multiple Analyst tools, the descriptions are what let the agent tell them apart.

The negative case earns its keep: without an explicit "when NOT to use", the agent reaches for a tool on anything remotely related. That one line prevents a whole class of wrong-tool answers.
Exhibit B · Section 3 of 4

Failure Patterns & Fixes

When an agent misbehaves, the cause is usually one of a few things, and the fix is almost always in the tool description.

SymptomLikely causeFix
Wrong tool selectedVague "When to use"Add specific examples + "When NOT to use"
Parameter errorsAmbiguous inputsAdd format, examples, constraints
HallucinationsAgent using the wrong toolTighten negative routing in the description
Consistency matters: use the same terminology across all instructions and descriptions. If orchestration says "customers" but a tool description says "accounts", the agent will misbehave. Keep the total number of tools to 5–10; smaller, focused agents are faster and more reliable.

Diagnosing routing problems is exactly what evaluations are for. See Exhibit C for measuring tool selection and execution accuracy.

Exhibit B · Section 4 of 4

Where the Spec Lives (and How It Deploys)

dbt Projects on Snowflake has no runtime file read, so each agent's spec lives inline in a deploy_<agent> wrapper macro in agents/<agent>.sql. The wrapper passes the spec to create_agent / alter_agent, which substitute the environment tokens with the active target, so the same spec deploys to dev, staging, or prod unchanged.

{% macro deploy_example_agent(alter=false) %}
  {% set spec %}
    models: { orchestration: auto }
    instructions:
      orchestration: "routing + defaults + fallbacks"
      response:      "tone, tables vs charts, units"
      sample_questions: [ ... ]
    tools:
      - tool_spec:
          name: sales_analyst
          description: "what + when + when NOT + inputs"
    tool_resources:
      sales_analyst:
        semantic_view: <<DATABASE>>.<<SCHEMA>>.SV_SALES
        execution_environment: { type: warehouse, warehouse: <<WAREHOUSE>> }
  {% endset %}
  {{ create_agent('example_agent', spec) }}
{% endmacro %}
Required: every cortex_analyst_text_to_sql tool needs an execution_environment under tool_resources (the warehouse its SQL runs in). Use execution_environment: { type: warehouse, warehouse: <name> }, not a top-level warehouse key.

Deploy with dbt run-operation deploy_<agent> (CREATE OR REPLACE). For zero-downtime edits to a live agent, add --args '{alter: true}'.

Visual
Drop an agent trace here (Snowsight AI Observability) showing tool routing, great for illustrating a "when NOT to use" fix before/after.