Wire the Central Bank indicators into an LLM via function calling
A SGS API foi desenhada para ser uma tool de IA: slugs amigáveis, busca por nome (PT/EN), saída normalizada e padrão enxuto (12 observações) que não estoura o contexto. Este guia mostra como expor a API como duas funções e deixar o modelo descobrir e ler indicadores sozinho.
The SGS API is built to be an AI tool: friendly slugs, name search (PT/EN), normalized output, and a lean default (12 observations) that won't blow up the context window. This guide exposes the API as two functions and lets the model discover and read indicators on its own.
Base: https://sgs.api.insyde.one — aberta, sem autenticação / open, no auth.
O modelo raramente sabe o código SGS de cabeça. Dê a ele duas ferramentas e ele encadeia sozinho: buscar a série, depois ler os dados.
The model rarely knows the SGS code by heart. Give it two tools and it chains them: search for the series, then read the data.
// 1. Usuário: "qual a inflação dos últimos 6 meses?"
// 2. Modelo chama: sgs_search({ q: "inflação" }) → descobre slug "ipca"
// 3. Modelo chama: sgs_series({ id: "ipca", last: 6 })
// 4. Modelo responde com os números + unidade ("% a.m.")
OpenAI (tools / function calling):
[
{
"type": "function",
"function": {
"name": "sgs_search",
"description": "Search the Banco Central (SGS) catalog for an economic indicator by name. Returns matching series with their slug, code and unit.",
"parameters": {
"type": "object",
"properties": {
"q": { "type": "string", "description": "Term in PT or EN, e.g. 'inflação', 'selic', 'dollar'" }
},
"required": ["q"]
}
}
},
{
"type": "function",
"function": {
"name": "sgs_series",
"description": "Read observations for a Banco Central series by slug (e.g. 'ipca') or numeric SGS code. Returns ISO dates and numeric values with unit and frequency.",
"parameters": {
"type": "object",
"properties": {
"id": { "type": "string", "description": "Series slug or SGS code" },
"last": { "type": "integer", "description": "Last N observations (default 12)" },
"start": { "type": "string", "description": "Range start, YYYY-MM-DD" },
"end": { "type": "string", "description": "Range end, YYYY-MM-DD" }
},
"required": ["id"]
}
}
}
]
Anthropic (tools): mesma ideia — o campo input_schema recebe o mesmo objeto de parameters acima. / same idea — input_schema takes the same object as parameters above.
{
"name": "sgs_series",
"description": "Read observations for a Banco Central series by slug or SGS code.",
"input_schema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"last": { "type": "integer" }
},
"required": ["id"]
}
}
As duas funções são apenas fetch na SGS API. Sem estado, sem chave:
Both functions are just a fetch against the SGS API. Stateless, keyless:
const BASE = 'https://sgs.api.insyde.one';
async function runTool(name, args) {
if (name === 'sgs_search') {
const r = await fetch(`${BASE}/series?q=${encodeURIComponent(args.q)}`);
return r.json(); // [{ code, slug, name, unit, frequency, aliases }]
}
if (name === 'sgs_series') {
const qs = new URLSearchParams();
if (args.last) qs.set('last', args.last);
if (args.start) qs.set('start', args.start);
if (args.end) qs.set('end', args.end);
const r = await fetch(`${BASE}/series/${encodeURIComponent(args.id)}?${qs}`);
if (!r.ok) return { error: (await r.json()).error };
return r.json(); // { code, slug, name, unit, frequency, count, observations }
}
}
import OpenAI from 'openai';
const client = new OpenAI();
const messages = [{ role: 'user', content: 'A Selic subiu ou caiu no último ano? E a inflação?' }];
while (true) {
const res = await client.chat.completions.create({
model: 'gpt-4o', messages, tools: SGS_TOOLS,
});
const msg = res.choices[0].message;
messages.push(msg);
if (!msg.tool_calls) { console.log(msg.content); break; }
for (const call of msg.tool_calls) {
const out = await runTool(call.function.name, JSON.parse(call.function.arguments));
messages.push({ role: 'tool', tool_call_id: call.id, content: JSON.stringify(out) });
}
}
type=ai já traz name,
unit e frequency — o modelo interpreta 0.21 como
"0,21% ao mês" sem contexto extra.
type=ai response carries name,
unit and frequency, so the model reads 0.21 as
"0.21% per month" with no extra context.
last maior ou um start/end quando o usuário pedir histórico. / Let the 12-observation default do its job. Only raise last or pass a range when the user asks for history.unit na resposta final — evita confundir "% a.m." com "% a.a.". / Always echo the unit in the final answer — avoids mixing "% per month" with "% per year".