- Je bouwt een begrensde lus rond een verwisselbare policy en echte lokale functies.
- Je verklaart waarom een final-bericht, eindige lus en geldige JSON nog geen juist of veilig antwoord bewijzen.
Een assistent die een antwoord moet opzoeken, kan na een zoekresultaat besluiten nog iets te berekenen. Die tweede keuze vraagt een nieuwe ronde. Zonder stopregels kan dezelfde opdracht blijven terugkomen, ook wanneer iedere losse toolaanroep geldig is.
Een workflow volgt vooraf vastgelegde codepaden; bij een agent kiest een model tijdens de uitvoering vervolgstappen. Hier vervangen gewone Python-regels dat model, zodat je de lus precies kunt volgen. De lokale optelling rekent echt; onze policy is een deterministische testdubbel.
1. Maak van een wens een klein voorstel
Denk aan een loket: de aanvrager noemt een handeling, maar bedient zelf geen machines. Onze policy mag een tool voorstellen of met final stoppen. Een syntactisch geldig voorstel geeft nog geen uitvoerrecht en garandeert geen juist antwoord.
Schrijf validate_agent_action met de twee exacte vormen uit de opdracht. Toolargumenten zijn maximaal acht JSON-scalars; containers vallen af en gewone getallen blijven eindig binnen ±1e6. Houd bool apart van int en controleer de grootte vóór math.isfinite.
proposal = {
'kind': 'tool', 'call_id': 'c1',
'name': 'add',
'arguments': {'a': 7, 'b': 8}
}
action = validate_agent_action(proposal)
proposal['arguments']['a'] = 99
print(action['arguments']['a'])
# 7
De kopie bewaart de beoordeelde argumenten wanneer het oorspronkelijke voorstel later verandert. Bij deze vlakke scalarargumenten volstaat een nieuwe argumentendictionary. Ongeldige invoervormen geven ValueError.
012. Volg voorstel, uitvoering en observatie
Een observatie beschrijft wat de host werkelijk terugkreeg. De volgende policy vraagt eenmaal de optelling aan en maakt daarna van het resultaat een finaal bericht. Je kunt beide rondes met de hand voorspellen: eerst 15 berekenen, daarna stoppen met tekst 15.
def policy(observations):
if not observations:
return action
data = observations[0]['data']
return {
'kind': 'final',
'text': str(data)
}
tools = {'add': lambda a, b: a + b}
result = run_bounded_agent(
policy, tools)
print(result['status'],
result['answer'])
print(result['tool_attempts'])
# final 15
# 1
Volg in run_bounded_agent steeds dezelfde volgorde: policy en validatie, final, dubbele call-ID, toolbudget, uitvoering en observatie. Final mag dus stoppen als het toolbudget al op is; een herhaalde ID wordt eerder afgewezen dan een nieuwe poging met uitgeput budget. Zonder final eindigt de laatste toegestane ronde met decision-budget als geen andere stopreden optreedt.
Bewaar observaties met call_id, name, ok en data. De tooltrace bevat step, kind, call_id, name, executed en ok; final en rejected hebben hun eigen compacte tracevorm uit de opdracht. Geef de policy een diepe observatiekopie, zodat ook een geneste tooluitkomst het bewaarde log niet kan laten herschrijven.
Stel dat een tool geneste data met count=15 teruggeeft. Verandert de policy haar kopie naar 900, dan moet het eigen log 15 bewaren; alleen de buitenste dictionary kopiëren beschermt die geneste data niet.
Gebruik deze pseudocode voor de lus; de opdracht specificeert de precieze dictionaries:
voor iedere toegestane beslisronde:
vraag en valideer; fout -> policy-error
final -> bewaar finalstap en stop
dubbele ID -> duplicate-call
geen toolpogingen over -> tool-budget
tel poging; voer bekende tool uit
onbekend -> foutobservatie unknown-tool
exception/te groot -> tool-error
bewaar observatie en tooltracestap
na laatste ronde: decision-budget
Vraag: bereken 7 + 8. Kies het beleid en volg elke beslissing. Ook een mislukte poging verbruikt budget.
- 1c1 · add
15
Functie uitgevoerd - 2final
15
Geen functie uitgevoerd
Elke beslissing kost 2, elke uitgevoerde functie 3 fictieve eenheden. Dit is geen tijdmeting. Direct stoppen met 16 is goedkoop én onjuist.
3. Twee budgetten begrenzen verschillend werk
Een onbekende tool of mislukte uitvoering verbruikt wel een toolpoging. Alleen een aangeroepen geregistreerde functie telt als executed, ook wanneer zij een exception gaf. Policyfouten stoppen als policy-error; toolfouten worden de generieke observatie tool-error.
def repeat(observations):
n = len(observations)
return {
'kind': 'tool',
'call_id': 'c'+str(n),
'name': 'add',
'arguments': {'a': 7, 'b': 8}
}
r = run_bounded_agent(
repeat, tools, 3, 1)
print(r['status'], len(r['trace']))
print(r['tool_attempts'])
print(run_bounded_agent(
policy, tools, 1, 4)['status'])
# tool-budget 2
# 1
# decision-budget
Het beslisbudget begrenst het aantal rondes, maar onderbreekt geen hangende callback. Gebruik uitsluitend bekende, begrensde functies; de browserworker heeft daarnaast een eigen uitvoeringstermijn. JSON-conversie maakt willekeurige Python geen veilige sandbox.
De resultaatgrens telt 4096 UTF-8-bytes, niet tekens. Zelfs de JSON-aanhalingstekens tellen mee:
encoded = json.dumps(
'é'*2200, ensure_ascii=False,
separators=(',', ':'))
raw = encoded.encode('utf-8')
print(len(encoded), len(raw))
# 2202 4402
024. Reken de trace na
Eén optelling plus final kost twee beslissingen en één uitvoering. Met twee werkeenheden per beslissing en drie per optelling is dat 2×2+3=7. Dit zijn gekozen oefenkosten, geen europrijzen, tokens of gemeten rekentijd.
Noem het aantal beslissingen D, hun vaste kosten c en het aantal uitgevoerde tools T. Iedere uitvoering i kost t_i; het totale werk W is:
work = trace_work(
result['trace'], 2, {'add': 3})
print(work['decisions'],
work['executed_tools'])
print(work['work_units'])
# 2 1
# 7
Schrijf trace_work voor de opeenvolgende interne tracestappen. Een afgewezen of onbekende toolpoging kost nog steeds een beslissing. Vergelijk bij echte agentproeven ook juistheid en stopreden: minder werk maakt een verkeerd antwoord niet beter.
03Wat neem je mee?
- Voorstel, tooluitvoering en observatie zijn afzonderlijke stappen.
- Beslisbudget en toolbudget voorkomen verschillende herhalingen.
- Een final-bericht zegt dat de lus stopt, niet dat het antwoord klopt.
Hierna voegen we expliciete toestemming en herkenning van herhaalde schrijfacties toe.