Handleidingen
Agents en tools
Oloproof stuurt geen agent aan. Je agent draait zijn eigen lus, roept zijn eigen tools aan, en legt vast wat er gebeurde als een agent_trajectory/v1-artefact. Elke agentmetriek wordt uit dat record gelezen, dus het record is de hele integratie.
examples/support_agent/ is het project dat deze pagina draait: veertig terugbetalingsverzoeken, een deterministische agent, en geen providergegevens.
Een traject vastleggen
Bouw binnen het systeem de stappen op terwijl ze gebeuren en geef ze aan de caserecorder:
from oloproof import AgentConstraintCheck, AgentStep, AgentTrajectory, current_case, system
@system(name="support-agent", version="slice-e-example", records=("agent_trajectory/v1",))
def run(case):
steps = []
for name, arguments in plan(case):
steps.append(AgentStep(index=len(steps) + 1, kind="tool_call", tool_name=name, arguments=arguments))
result = getattr(tools, name)(**arguments)
steps.append(AgentStep(index=len(steps) + 1, kind="tool_result", tool_name=name, result=result))
current_case().agent_trajectory(
AgentTrajectory(
steps=tuple(steps),
terminal_status="success" if refunded else "failure",
truncated=truncated,
step_limit=STEP_LIMIT if truncated else None,
constraints=(
AgentConstraintCheck(name="no_deletion", passed=deletion is None, step_index=...),
),
)
)
return {"answer": "refunded" if refunded else "unresolved"}Waar elk deel voor dient:
| Veld | Wat het vastlegt |
|---|---|
| AgentStep.kind | message, tool_call, tool_result, observation, decision of final |
| AgentStep.tool_name, arguments, result | de aanroep en wat er terugkwam |
| terminal_status | success, failure of unknown |
| truncated, step_limit | dat de agent zijn grens bereikte en het spoor voortijdig stopt |
| constraints | controles die je omgeving uitvoerde, elk met de stap die ze observeerde |
| checkpoints | punten waarvandaan een herhaling kan hervatten, als AgentCheckpoint |
Het systeem declareert dat het het traject vastlegt, op de decorator en in oloproof.yaml:
system:
name: support-agent
version: slice-e-example
callable: app:run
records: [agent_trajectory/v1]Zonder records: weigeren de agentevaluators te draaien in plaats van elke case als ontbrekend te tellen.
Wat een case declareert
Een case die bepaalde tools in een bepaalde volgorde zou moeten aanroepen, zegt dat onder expected.tools:
{"id": "case_001", "input": {"order_id": "ord-002", "behaviour": "clean"}, "expected": {"answer": "refunded", "tools": ["lookup_order", "issue_refund"]}, "metadata": {"surface": "chat", "behaviour": "clean"}}expected.tools: [] zegt dat de case helemaal geen toolaanroepen verwacht, en wordt daarop beoordeeld. De sleutel weglaten zegt dat toolkeuze niet op de case van toepassing is: agent_tool_sequence en agent_no_undeclared_tool sluiten haar uit met no_declared_tools. Ze verlaat de noemer in plaats van als geslaagd te tellen, omdat een percentage dat is opgeblazen met cases die nooit zijn gemeten geen percentage is. Een waarde die geen lijst van toolnamen is, wordt voor de run geweigerd.
De evaluators
evaluators:
- {type: contains, criterion: answer_correct, field: answer, expected_field: answer}
- {type: agent_tool_called, tool_name: lookup_order}
- {type: agent_no_tool_loop, max_repeats: 2}
- {type: agent_tool_sequence}
- {type: agent_constraints_satisfied, constraints: [no_deletion]}
- {type: agent_max_steps, max_steps: 10}
metrics:
- {id: steps_p95, type: quantile, source: agent_steps, quantile: 0.95}
- {id: tool_calls_p50, type: quantile, source: agent_tool_calls, quantile: 0.5}
slices: [metadata.surface, first_tool, repeated_action, "trajectory_length:4,8"]
min_slice_support: 3| Type | Slaagt wanneer | Neemt |
|---|---|---|
| agent_tool_called | de tool minstens min_calls keer werd aangeroepen | tool_name, min_calls (standaard 1) |
| agent_no_tool_loop | geen identieke aanroep, zelfde tool en argumenten, zich meer dan max_repeats keer achter elkaar herhaalt | max_repeats (standaard 2) |
| agent_tool_sequence | de aangeroepen tools overeenkomen met expected.tools | ordered (standaard true) |
| agent_no_undeclared_tool | geen tool buiten expected.tools werd aangeroepen | niets |
| agent_constraints_satisfied | elke genoemde beperking die de omgeving vastlegde, slaagde | constraints |
| agent_max_steps | het spoor hoogstens max_steps stappen nam | max_steps |
agent_steps en agent_tool_calls zijn de verdelingen achter de laatste, als kwantielmetrieken.
oloproof run│ answer_correct │ 82.5% │ [67.2%, 92.7%] │ 33 / 40 observed · 0 missing · 0 excluded │
│ agent_tool_lookup_order_called │ 100.0% │ [86.8%, 100.0%] │ 39 / 39 observed · 1 missing · 0 excluded │
│ agent_no_tool_loop │ 74.4% │ [56.1%, 87.4%] │ 29 / 39 observed · 1 missing · 0 excluded │
│ agent_tool_sequence │ 60.0% │ [43.3%, 75.2%] │ 24 / 40 observed · 0 missing · 0 excluded │
│ agent_constraints_satisfied │ 92.5% │ [79.6%, 98.5%] │ 37 / 40 observed · 0 missing · 0 excluded │
│ agent_steps_le_10 │ 97.5% │ [86.8%, 100.0%] │ 39 / 40 observed · 0 missing · 0 excluded │
│ steps_p95 │ 10 steps │ [10, no bound] steps │ p95 of 39 observed · 1 missing · 0 excluded │
│ tool_calls_p50 │ 2 calls │ [2, 3] calls │ p50 of 39 observed · 1 missing · 0 excluded ││ no-deletion │ agent_constraints_satisfied │ FAIL │ observed_failures_exceed_limit │Een beperking gatet zoals elk ander criterium. no-deletion is een regel op een geobserveerd aantal met max_failures: 0: drie cases riepen delete_customer aan, en "dit mag niet gebeuren in de suite die we draaiden" heeft geen interval nodig om te beslissen.
Een spoor dat voortijdig stopt
Eén case bereikt de stappenlimiet van de agent, dus zijn spoor wordt vastgelegd als truncated. Elk aantal over een afgekapt spoor is een ondergrens, en een ondergrens beslecht sommige vragen en andere niet:
| Criterium | De afgekapte case | Waarom |
|---|---|---|
| agent_steps_le_10 | faalt | de vastgelegde stappen bewijzen al dat een limiet van tien werd overschreden |
| agent_tool_lookup_order_called | ontbreekt | de aanroep kan in het deel zitten dat niet werd vastgelegd |
| agent_no_tool_loop | ontbreekt | een herhaling die het einde van het spoor bereikt, kan daarna doorgaan |
| steps_p95, tool_calls_p50 | ontbreekt | een kwantiel over ondergrenzen is geen kwantiel |
Ontbrekend in plaats van uitgesloten: de case blijft ongeobserveerd in de noemer, en het interval laat toe dat ze beide kanten op is gegaan. Daarom leest agent_tool_lookup_order_called [86.8%, 100.0%] over 39 geobserveerde cases in plaats van het smallere interval dat 39 cases alleen zouden geven.
Slices over trajecten
first_tool groepeert cases op de tool waarnaar de agent als eerste greep, welke tools de run ook aanriep. repeated_action scheidt cases die een identieke aanroep herhaalden van cases die dat niet deden. trajectory_length:4,8 deelt cases in op 1-4, 5-8 en 9 of meer stappen, op grenzen die je declareert omdat een bakgrens verandert wat een slice zegt.
│ first_tool=search │ agent_no_tool_loop │ 0.0% │ [0.0%, 57.9%] │ 0 / 6 observed · 1 missing · 0 excluded · │
│ first_tool=search │ agent_tool_sequence │ 0.0% │ [0.0%, 41.0%] │ 0 / 7 observed · 0 missing · 0 excluded · │
│ repeated_action=false │ answer_correct │ 93.1% │ [77.2%, 99.2%] │ 27 / 29 observed · 0 missing · 0 excluded · │
│ repeated_action=true │ answer_correct │ 60.0% │ [26.2%, 87.9%] │ 6 / 10 observed · 0 missing · 0 excluded · │Een lus is een signaal, geen verklaring. Niets in de output zegt dat een herhaalde aanroep de reden is dat een case faalde; alleen een herhaling die haar verwijderde, zou dat kunnen.
Meerdere agents
examples/triage_agents/ draait een team van drie: triage geeft elk verzoek door aan billing of tech, en een terugbetaling die billing niet mag uitvoeren, wordt aan een persoon doorgegeven. In een systeem van meerdere agents noemt elke stap de agent die haar zette, en een overdracht van de controle is een handoff-stap:
steps.append(AgentStep(index=1, kind="message", agent="triage", arguments={"request": request}))
steps.append(AgentStep(index=2, kind="handoff", agent="triage", to_agent="billing"))
steps.append(AgentStep(index=3, kind="tool_call", agent="billing", tool_name="lookup_order"))Een traject noemt de agent van elke stap of van geen enkele. Een opname die er maar enkele noemt, wordt geweigerd, en een die er geen noemt, ontbreekt voor elk criterium hieronder in plaats van ervoor te slagen. Een overdrachtsstap is optioneel, omdat de controle ook van hand wisselt wanneer de volgende stap door een andere agent wordt gezet. Het is hoe een spoor een overdracht vastlegt naar een agent die geen stap zet, zoals een persoon.
Een case declareert de agents waar ze doorheen zou moeten gaan onder expected.route:
{"id": "case_012", "input": {"topic": "billing", "request": "I was charged twice for order ord-012", "order_id": "ord-012", "behaviour": "escalated"}, "expected": {"answer": "escalated", "route": ["triage", "billing", "person"]}, "metadata": {"topic": "billing", "behaviour": "escalated"}}evaluators:
- {type: contains, criterion: answer_correct, field: answer, expected_field: answer}
- {type: agent_route}
- type: agent_tool_permissions
permissions:
triage: []
billing: [lookup_order, issue_refund]
tech: [search_kb]
- {type: agent_max_handoffs, max_handoffs: 2}
slices: [route]| Type | Slaagt wanneer | Neemt |
|---|---|---|
| agent_route | de agents die de controle hadden, met herhalingen samengevoegd, de expected.route van de case zijn | niets |
| agent_tool_permissions | elke toolaanroep werd gedaan door een agent die volgens de map die tool mag aanroepen | permissions |
| agent_max_handoffs | de controle hoogstens max_handoffs keer van hand wisselde | max_handoffs |
De route omvat de ontvanger van een overdracht, dus een spoor dat eindigt met een escalatie naar een persoon, routeert naar die persoon. Een case zonder expected.route wordt niet meegeteld door agent_route. De permissiemap is gesloten: een agent die ze niet noemt, mag geen enkele tool aanroepen.
│ answer_correct │ 96.7% │ [82.7%, 100.0%] │ 29 / 30 observed · 0 missing · 0 excluded │
│ agent_route │ 86.7% │ [69.2%, 96.3%] │ 26 / 30 observed · 0 missing · 0 excluded │
│ agent_tool_permissions │ 93.1% │ [73.4%, 99.2%] │ 27 / 29 observed · 1 missing · 0 excluded │
│ agent_handoffs_le_2 │ 86.7% │ [69.2%, 96.3%] │ 26 / 30 observed · 0 missing · 0 excluded │In twee verzoeken voerde tech een terugbetaling uit. Beide slagen voor answer_correct en falen voor agent_tool_permissions: de klant kreeg het juiste antwoord van een systeem dat zijn eigen permissies schond. Eén verzoek wordt heen en weer gegeven tussen billing en tech tot aan de grens van de lus. Zijn spoor is afgekapt, dus het faalt voor de route en de overdrachtsgrens, die zijn begin al beslecht, en ontbreekt voor permissies, die het niet beslecht.
route groepeert cases op de route die hun agents namen, geschreven als triage>billing. Een afgekapt spoor sluit zich bij geen enkele routegroep aan, omdat zijn route een begin is van waar zijn agents daarna ook heen gingen.
Niets in de output zegt welke agent de schuld heeft. Een routeafwijking zegt waar twee routes uiteengaan. Dat een agent een mislukking veroorzaakte, is een bewering over wat er zou zijn gebeurd als hij anders had gehandeld, wat alleen een herhaling die die agent vervangt zou kunnen aantonen, en Oloproof draait er geen.
Verder lezen
- Vastleggen wat een systeem deed behandelt de andere getypeerde artefacten.
- Slices behandelt slice-ondersteuning en waarom slices nooit gaten.