AI agents
Van AWS Bedrock naar Anthropic direct: agent in 4 dagen om
Een dispatch-team van 23 in Antwerpen werd maandag wakker met een AWS Bedrock-rekening die in één weekend verviervoudigd was. Vier dagen later draaide de agent op een directe Anthropic-key.

Maandagochtend, 06:42 Antwerpse tijd. Wim, head of platform bij een logistiek integrator van 23 mensen aan de Plantin en Moretuslei, opent zijn AWS cost-explorer mail nog voor de espresso staat. De dispatch-agent die vorige maand €4,1M aan vrachtorders routeerde, had tussen vrijdagavond en zondagmiddag meer aan inference uitgegeven dan in het hele kwartaal ervoor. De rekening was verviervoudigd. Niemand had een feature gepusht. Niemand had een prompt aangeraakt.
Donderdagmiddag draaide de agent op een directe Anthropic-key, was de Bedrock-client gedegradeerd tot warme fallback, en had de juridische afdeling een nieuw data-processing addendum getekend met Anthropic in plaats van AWS. Zo zagen die vier dagen eruit, en zo zouden we het vandaag opnieuw doen, met een paar dingen anders.
De rekening die de aanname brak
De dispatch-agent was onopvallend. Hij verwerkte een ladingaanvraag uit een klantenportaal, riep een set tools aan die de carrier-database, het tariefblad en de douane-ledger raadpleegden, en gaf een routeringsbeslissing terug met een betrouwbaarheidsmarge. Ongeveer 18.000 calls per dag. De meeste calls waren kort. Het team draaide hem sinds voorjaar 2025 op Claude Sonnet via AWS Bedrock, in de regio Frankfurt, achter een VPC endpoint met PrivateLink. De opzet was bewust saai, en dat is het hoogste compliment dat een operations-team aan infrastructuur geeft.
Wat er in het weekend veranderde, was een combinatie van twee losse knoppen die tegelijk werden omgedraaid. Eerst rolde AWS stilletjes nieuwe data-handling voorwaarden uit voor recentere Anthropic-modellen op Bedrock, inclusief de routing die het bedrijf gebruikte. Die wijziging stond al weken op een roadmap-thread; de echte omschakeling viel op een vrijdag. Daarnaast had een interne aanpassing aan hoe ladingen werden geparsed het gemiddelde aantal input tokens omhoog gedrukt van ongeveer 2.800 naar ongeveer 7.400. Geen van beide veranderingen op zich had een crisis opgeleverd. Samen wel.
De agent factureerde rond €180 per dag. Tegen zondag lag hij op koers voor €740 per dag, zonder zicht op een plafond. Het team had een harde contractuele cap van €25.000 per maand met hun grootste klant voor wat het contract “intelligence services” noemde. Ze zouden er rond de 14e doorheen schieten.
Wat de dispatch-agent eigenlijk doet
Voor we de migratie doorlopen, doet de vorm van de agent ertoe, want die bepaalde welke migratie überhaupt mogelijk was.
De agent is één Claude-gedreven loop met acht tools: find_carriers, get_rate_sheet, check_customs, book_slot, quote_customer, log_anomaly, escalate_to_human en cancel. De system prompt is 1.200 tokens en legt een paar harde regels vast waar de dispatchers niet aan willen tornen. Nooit een klant quoten voordat de douane is gecheckt. Nooit een slot boeken binnen 90 minuten voor cutoff zonder menselijke escalatie. Een gesprek bestaat gemiddeld uit 4 tot 6 tool-calls en eindigt met een gestructureerde JSON-output.
Het team had dit verpakt in hun eigen SDK, zodat prompt, tools en parsing op één plek leefden. Het enige Bedrock-specifieke was het transport: de boto3 Bedrock Runtime-client, een IAM-rol en een PrivateLink endpoint. Die isolatie is de enige reden dat deze migratie vier dagen kostte en geen vier weken.
Waarom Bedrock in 2025 hout sneed, en waarom dat ophield
De oorspronkelijke keuze was niet onnadenkend. Claude draaien via Bedrock in eu-central-1 betekende dat het inference-verkeer binnen de Europese backbone van AWS bleef. Hun bestaande AWS DPA dekte het. Procurement bij hun grootste klant, een Hamburgse verlader met een strakke subprocessor-lijst, tekende in één meeting af. Ze kregen VPC endpoints, IAM-scoped invocaties en CloudWatch-logs out of the box. Bedrock-pricing was prima voor het volume op dat moment.
Wat het team onderschatte, was het tempo waarin Anthropic nieuwe modellen zou uitbrengen, en het tempo waarin AWS de juridische envelop eromheen zou heronderhandelen. Halverwege 2026 liep het model waar de agent op vertrouwde voor tool-use accuratesse een generatie achter op wat direct beschikbaar was. Het kostenverschil per token tussen het Bedrock-oppervlak en de directe Anthropic API was groter geworden. En de nieuwe data-deling voorwaarden zorgden dat hun procurement-verhaal, waar negen maanden inspanning in zat, niet meer met de werkelijkheid strookte.
Als je klantcontracten een specifieke subprocessor bij juridische naam noemen, kan een wijziging in data-handling voorwaarden vanuit de leverancier die contracten breken voordat er één technische wijziging in je stack is gegaan. Hou je subprocessor-verplichtingen bij in dezelfde repository als je IaC, niet op een Notion-pagina die niemand leest.
De migratie, in code
De overstap van Bedrock naar de directe Anthropic API is in code niet moeilijk. De twee SDK's liggen bewust dicht bij elkaar. Het werk zit in het loodgieterswerk eromheen.
Hun Bedrock-call, vereenvoudigd, zag er zo uit:
import boto3, json
bedrock = boto3.client("bedrock-runtime", region_name="eu-central-1")
def invoke_dispatch(messages, tools, system):
resp = bedrock.invoke_model(
modelId="anthropic.claude-sonnet-4-20250514-v1:0",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 1024,
"system": system,
"tools": tools,
"messages": messages,
}),
)
return json.loads(resp["body"].read())
Het directe Anthropic-equivalent dat het team op dag twee schreef:
from anthropic import Anthropic
client = Anthropic() # reads ANTHROPIC_API_KEY
def invoke_dispatch(messages, tools, system):
resp = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=system,
tools=tools,
messages=messages,
)
return resp.model_dump()
Dat is de hele substitutie op de call-site. De moeilijke stukken zaten elders.
Tool-use shape drift
De response-shape is bijna identiek. De oude parser van het team was defensief geschreven tegen de Bedrock-wrapper envelope, en de uitpaklogica liet stilletjes een stop_reason vallen op de directe client. De agent ging vanaf de derde tool-call in elk gesprek in een loop, omdat de loop-terminator op de verkeerde plek werd gelezen. Ze verloren er zes uur aan, vooral omdat het symptoom was “de agent werkt op staging” en de staging-fixture een gesprek van één beurt was.
Rate limits, de echte
De directe Anthropic API werkt met rate limits per organisatie in tokens-per-minuut, niet met per-regio Bedrock-quota. Het burst-patroon van de agent, dat piekt rond de cutoff-tijden van de carriers, raakte dinsdag om 09:30 de default tier-limiet. Ze moesten Anthropic sales bellen voor een tier-verhoging, die nog dezelfde dag binnenkwam maar wel een ochtend handmatig dispatchen kostte. Als je een productie-workload migreert: vraag de limit-bump aan voordat je de wijziging uitrolt, niet erna.
Logging en observability
CloudWatch viel weg. Het team had elke Bedrock-call geïnstrumenteerd met een eigen log group en een metric filter dat afging op token spend. Niets daarvan werkte tegen de directe API. Ze schreven een wrapper van 40 regels die dezelfde metrics naar CloudWatch stuurde via een aparte IAM-scoped rol, zodat de rest van hun dashboards bleef werken. Dat was dag drie.
GDPR, data residency en de EU-vraag
Het juridische stuk kostte langer dan de code. De DPA van hun grootste klant eiste dat alle subprocessors bij naam genoemd én in de EER gevestigd waren. AWS Frankfurt voldeed. Verkeer direct naar Anthropic sturen vroeg een nieuwe DPA, een nieuwe subprocessor-melding met een venster van 30 dagen, en een side letter die zich vastlegde op een specifieke data-retentie houding. Hun jurist had het concept dinsdagochtend klaar en de getekende tegen-handtekening donderdagmiddag, wat snel was naar hun maatstaven en alleen lukte omdat het procurement-team van de klant vanaf maandag in de loop zat.
Het team deed één ding dat enorm hielp, en dat we nu standaard aanbevelen: ze schreven een memo van één pagina, “model substrate”, met daarin de provider, de regio, het retentievenster en het verhaalskanaal voor elk data-incident. Die memo werd het artefact dat procurement-teams opvroegen zodra een nieuwe klant onboardde. Onderhouden kost bijna niets. Hij bespaart hele weken.
De shim die ze hielden
Eén beslissing die het team op dag twee nam, heeft meer opgeleverd dan welke andere ook. Ze gooiden de Bedrock-client niet weg. Ze zetten beide transports achter één interface:
from typing import Protocol
class LLMTransport(Protocol):
def invoke(self, messages, tools, system) -> dict: ...
class AnthropicDirect:
def __init__(self, client): self.client = client
def invoke(self, messages, tools, system):
return self.client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024, system=system,
tools=tools, messages=messages,
).model_dump()
class BedrockFallback:
def __init__(self, client): self.client = client
def invoke(self, messages, tools, system):
# same call as before, kept warm and tested nightly
...
def get_transport() -> LLMTransport:
return AnthropicDirect(...) if FLAGS.use_direct else BedrockFallback(...)
De flag werd op load-balancer niveau omgezet, niet in code. Toen Anthropic twee weken later een incident van 14 minuten had, vloeide het verkeer terug naar Bedrock zonder deploy. De fallback draaide op een ouder model en was iets slechter in tool-selectie, maar de dispatchers haalden hun schouders op en de klanten merkten er niets van.
Dag vier, op het whiteboard
Donderdagavond draaide de agent op de directe API met de nieuwe DPA getekend, het Bedrock-pad in stand-by, en de rekening terug onder €200 per dag. Het team hield vier notities op het whiteboard plakken, die we sindsdien hebben gestolen en op elke migratie gebruiken die we draaien.
Eén: het modeloppervlak en het juridische oppervlak zijn hetzelfde oppervlak. Een wijziging in de één golft door in de ander, en het operations-team hoort het meestal als laatste.
Twee: hou altijd minstens één alternatief transport warm. Inference bij één leverancier is een gok die je niet hoeft te nemen, en de kosten om een fallback warm te houden zijn ongeveer nul vergeleken met de kosten van vier uur uitval tijdens cutoff-uren.
Drie: log token spend per tenant vanaf dag één. Het team had één globale meter, waardoor ze maandagochtend niet konden zien wiens verkeer verantwoordelijk was voor de piek. Ze zijn inmiddels over op per-tenant attributie, en twee maanden later vingen ze een tweede pricing-anomalie in 11 minuten in plaats van 36 uur.
Vier: schrijf de procurement-memo voordat je hem nodig hebt. De teams die het zwaarst lijden in een migratie als deze, zijn de teams wier juridische houding leeft in drie Slack-threads en een doorgestuurde PDF.
Wat je deze week kunt doen
Als je een productie-agent op Bedrock draait en je hebt je DPA al zes maanden niet gelezen, dan is dat de audit van vijf minuten die vandaag de moeite waard is. Open het contract, zet de model-ID's op een rij die je daadwerkelijk aanroept, en bevestig dat de provider-keten waar je klanten op getekend hebben nog overeenkomt met wat er in productie draait. Klopt dat niet, dan heb je nu nog een venster om het te repareren voordat iemand met een klembord het ontdekt.
Toen we vorige maand de routing-laag opnieuw bouwden voor een Rotterdamse vracht-klant, was wat hen verraste niet de inference-kost. Het was hoeveel sneller hun procurement-team door klant-reviews kwam zodra de substrate-memo bestond. Als je een vergelijkbare migratie weegt voor je eigen dispatch- of quoting-stack op AI-agents, is het shim-first patroon hierboven de goedkoopste verzekering die je kunt afsluiten.
Kern
Het modeloppervlak en het juridische oppervlak zijn hetzelfde oppervlak. Verander de één, en de ander golft mee, of je dat nu wilde of niet.
FAQ
Waarom verviervoudigde de Bedrock-rekening van het ene op het andere moment?
Twee losse wijzigingen landden in hetzelfde weekend: AWS herzag de data-handling voorwaarden voor de modeltier van het team, en een interne parser-wijziging duwde het gemiddelde aantal input tokens van 2.800 naar 7.400.
Is de directe Anthropic API goedkoper dan AWS Bedrock?
De per-token lijstprijs van de directe API ligt meestal lager dan het equivalent op Bedrock, maar je verliest VPC endpoints, IAM-scoping en CloudWatch-metrics. Die zul je zelf moeten herbouwen, en dat kost ook iets.
Heb ik een nieuwe DPA nodig bij de overstap van Bedrock naar Anthropic?
Ja, als je klantcontracten AWS bij naam noemen als subprocessor. Je hebt dan een nieuwe DPA met Anthropic nodig, een subprocessor-melding, en meestal een side letter over retentie.
Hoe zwaar is de eigenlijke code-migratie?
De call-sites van de SDK's zijn bijna identiek. Het zware werk zit in parser-drift voor tool-use, andere rate-limit semantiek, en het opnieuw bouwen van de observability-laag die op Bedrock gratis was.
Moet ik de Bedrock-client weggooien na de migratie?
Nee. Zet hem achter een transport-interface en draai hem 's nachts. Als de primaire provider een incident heeft, zet je een flag om op de load balancer in plaats van een deploy uit te rollen.