O coracao do function calling e a definicao da tool: voce descreve para o modelo qual funcao existe, o que ela faz e quais argumentos ela aceita. O modelo decide quando chama-la e com quais argumentos; o seu backend executa a chamada de verdade e devolve o resultado. No exemplo abaixo, usando a Anthropic Messages API, uma tool consulta o status atual do pedido no seu banco. O modelo nunca inventa o status: ele delega a consulta e so redige a resposta com o dado que voltou.
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
// A tool que expoe a consulta de status ao modelo.
// O modelo NAO executa nada: ele so decide chamar e com quais argumentos.
const tools = [
{
name: 'get_order_status',
description:
'Consulta o status atual de um pedido pelo numero. Use sempre que o usuario perguntar sobre um pedido especifico; nunca invente o status.',
input_schema: {
type: 'object',
properties: {
order_id: { type: 'string', description: 'Numero do pedido, ex: PED-10293' },
},
required: ['order_id'],
},
},
];
// Execucao real da tool no SEU backend: consulta a fonte da verdade.
async function runTool(name, input) {
if (name === 'get_order_status') {
const order = await db.orders.findByPublicId(input.order_id);
if (!order) return { found: false };
return {
found: true,
status: order.status, // 'em_separacao' | 'enviado' | 'entregue'
carrier: order.carrier,
eta: order.estimatedDelivery,
};
}
throw new Error('Tool desconhecida: ' + name);
}
async function ask(question) {
const messages = [{ role: 'user', content: question }];
// 1o turno: o modelo decide se chama a tool.
let res = await client.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 512,
tools,
messages,
});
// Enquanto o modelo pedir tools, executa e devolve o resultado.
while (res.stop_reason === 'tool_use') {
const toolUse = res.content.find((b) => b.type === 'tool_use');
const result = await runTool(toolUse.name, toolUse.input);
messages.push({ role: 'assistant', content: res.content });
messages.push({
role: 'user',
content: [
{
type: 'tool_result',
tool_use_id: toolUse.id,
content: JSON.stringify(result),
},
],
});
res = await client.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 512,
tools,
messages,
});
}
return res.content.find((b) => b.type === 'text')?.text;
}
// O modelo chama get_order_status('PED-10293'), recebe o status FRESCO
// do banco e so entao redige a resposta. Nada e recuperado por similaridade.
await ask('Cade meu pedido PED-10293?');
Repare no ponto que muda tudo: o dado do status nunca passou por embedding nem por vector store. O modelo apenas decidiu chamar a funcao, o seu backend consultou o banco (a fonte da verdade) e o resultado voltou fresco para o modelo redigir. E impossivel o bot responder um status desatualizado, porque ele nao busca uma versao antiga: ele provoca uma consulta nova a cada pergunta.