Let code handle exact operations

Tools & database lookups

Expose narrow Python functions for exact crosswalk queries and understand how tool calls execute.

Prepared September 14, 2026 · SDK source reviewed at c9e8b34 · Examples are teaching adaptations; authenticated gateway calls were not run for these pages.

Guide library

What this capability does

A tool is a Python function the model can request. The application executes the function and gives the result back to the model. This lets exact work—such as looking up an occupational code—happen in ordinary code rather than being guessed in generated text.

For a résumé translation application, useful tools might look up a military-to-civilian crosswalk, fetch a reviewed occupation description, or search an approved reference collection. Start with a small, explicit set of functions. If every case follows the same steps, call them directly from Python before introducing model-directed tool selection.

QuestionModel proposes tool + argumentsPython validates and executesResult returnedModel explains

Find the implementation

The last example includes a broader scientific-data workflow and extra dependencies. Study its separation of data ingestion and database querying; a simple code lookup can use a much smaller implementation.

Design the database before exposing a tool

A military crosswalk may contain active and historical relationships, missing civilian mappings, and one-to-many matches. Inspect the selected dataset before designing lookup rules. Preserve code strings, source versions, and relevant service/category/code-system fields. Do not assume a military code alone uniquely identifies an occupation.

The example below assumes that a separate import step has produced this illustrative SQLite table. These are proposed normalized column names, not the raw CSV headers or an existing delivered database.

SQL · Example 01
CREATE TABLE crosswalk (
    service TEXT NOT NULL,
    personnel_category TEXT NOT NULL,
    code_system TEXT NOT NULL,
    military_code TEXT NOT NULL,
    status TEXT NOT NULL,
    onet_code TEXT,
    civilian_title TEXT,
    source_version TEXT NOT NULL
);

During import, map the source's actual columns and status values to this schema. Keep historical rows rather than dropping them without review. Retain records lacking an O*NET code and represent that condition explicitly. A query result should be able to return multiple candidate relationships with provenance.

Write a narrow lookup function

This code expects an existing crosswalk.db containing the illustrated schema. It opens the database read-only, uses parameter binding, and limits the number of rows returned. The function exposes occupational fields rather than arbitrary SQL text.

PYTHON · Example 02
import json
import sqlite3
from contextlib import closing
from pathlib import Path
from genai_studio.agents import tool

@tool
def lookup_crosswalk(
    service: str,
    personnel_category: str,
    code_system: str,
    military_code: str,
    source_version: str,
) -> str:
    """Find recorded active civilian mappings for an exact military code.

    Args:
        service: Service label in the normalized database.
        personnel_category: Personnel category in that database.
        code_system: Military code family.
        military_code: Exact code string; preserve leading zeros.
        source_version: Reference version selected by the application.
    """
    db = Path("crosswalk.db").resolve()
    uri = db.as_uri() + "?mode=ro"
    query = """
        SELECT onet_code, civilian_title, source_version
        FROM crosswalk
        WHERE service = ? AND personnel_category = ?
          AND code_system = ? AND military_code = ?
          AND source_version = ? AND status = 'active'
        ORDER BY onet_code, civilian_title
        LIMIT 21
    """
    params = (service, personnel_category, code_system,
              military_code, source_version)
    with closing(sqlite3.connect(uri, uri=True)) as connection:
        connection.row_factory = sqlite3.Row
        rows = connection.execute(query, params).fetchall()
    return json.dumps({
        "matches": [dict(row) for row in rows[:20]],
        "truncated": len(rows) > 20,
    })

Parameter binding keeps values separate from SQL syntax. Read-only mode prevents this connection from writing to the database. Those controls do not validate an imported mapping or resolve an ambiguous code; they constrain how the function accesses data.

The tool description helps the model understand the arguments. Application code should ideally bind the approved source version and authorized case context itself, rather than letting the model freely choose those controls. The version argument is explicit here to make the data dependency visible for teaching.

Test the function before adding an agent

The decorator preserves ordinary Python calls. Test the function using actual labels from the imported database. Include one known match, an ambiguous code, an obsolete-only code, and a nonexistent code. An empty result is a valid lookup outcome; it is not evidence that the person lacks useful civilian skills.

The tool's schema can be inspected without a model call:

PYTHON · Example 03
# Run after the lookup_crosswalk definition above.
print(json.dumps(lookup_crosswalk.spec.parameters, indent=2))

Use the same function directly in a fixed pipeline when the required lookup is already known. An agent is useful only if choosing among several tools adds value.

Give the tool to an agent

This continuation uses the function above and the access settings from the chat guide. Enter a request containing the actual service/category/code/version labels from the imported database.

PYTHON · Example 04
import os
from genai_studio import GenAIStudio
from genai_studio.agents import Agent, GenAIStudioClient, NullTracer

client = GenAIStudioClient(
    GenAIStudio(), default_model=os.environ["GENAI_STUDIO_MODEL"]
)
agent = Agent(
    client=client,
    tools=[lookup_crosswalk],
    max_steps=4,
    force_final_answer=False,
    tracer=NullTracer(),
    system=(
        "Use lookup_crosswalk for occupational mappings. "
        "Ask for missing lookup fields. Do not invent codes or matches. "
        "Report multiple matches and missing mappings explicitly. "
        "A crosswalk relationship is not proof of personal qualification."
    ),
)
result = agent.run(input("Lookup request using imported labels: "))
if result.stopped != "final":
    raise RuntimeError("The lookup workflow did not complete.")
print(result.text)

The model proposes a function name and argument values. The agent wrapper executes a registered function and returns the actual result. The model then explains it. A prompt telling the model to use a tool is not a guarantee that it did so; inspect the run's tool calls or call the function deterministically when the lookup is mandatory.

max_steps bounds the agent loop. With the reviewed default force_final_answer=True, a step-limit exit may also trigger a final text-generation call; the examples disable that fallback to keep an incomplete tool workflow explicit. Network retries and tool-internal work still require their own bounds.

Keep writes and case access explicit

For the first version, let ingestion code populate reference tables and let the review interface save approved edits. Give the model read-only lookup tools. A generic “run any SQL” tool adds parsing, authorization, and query-cost problems that a narrow function avoids.

When tools access personal case data, derive the case identity and permissions from the logged-in application context. A model-supplied case ID must not grant access by itself. Log which reference version and case were used without dumping raw résumé text into general logs.

The SDK includes guards and approval mechanisms. Those can help enforce a chosen policy, but do not replace database permissions or application authorization. Decide the actual allowed operations instead of relying on a prompt such as “be careful.”

Combine SQL with retrieval

Question Sensible operation
Which civilian codes are recorded for this exact military code? Parameterized SQL lookup.
What does this known civilian role require? Fetch its canonical description by ID, then retrieve additional context if needed.
Which references discuss a paraphrased duty? Semantic or hybrid retrieval over reviewed references.
Did the veteran perform that duty? Inspect that case's evidence and ask for confirmation when missing.

Keep the crosswalk result, retrieved reference passages, and personal evidence distinguishable in the prompt and output. The model should not promote a suggested role's requirements into the veteran's work history.

Practical checks

Run a direct lookup first, then the same lookup through the agent. Inspect proposed arguments and returned rows. Check how the system handles missing fields and multiple matches. Validate the relationship’s meaning and source version separately from whether the database query executed successfully.

Further reading