Notes pratiques : Ingénierie en boucle : Création d’agents IA auto-améliorables à l’aide de quatre éléments
Guide pratique détaillé : Ingénierie en boucle : Création d’agents IA auto-améliorables à l’aide de quatre éléments : contrats, vérifications et emplacements pour du code intégrable destinés aux équipes utilisant ce modèle.
Utilisez ceci comme une version révisée destinée aux opérateurs des idées présentées dans « Loop Engineering : Construire des agents d’IA auto-amélioratifs avec quatre boucles imbriquées » : étapes claires, emplacements de code ordonnés et notes de récupération qui survivent au transfert de responsabilités. L’étape « Aperçu » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Conservez les configurations en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système.
Décryptage global : l’ingénierie au-delà des instructions
Pour l’étape d’analyse globale, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’une mise en forme ultérieure. Préférez des sorties structurées avec validation de schéma plutôt que du texte libre lorsque l’étape suivante consiste en du code ou une appel à outil.
Pourquoi c’est important
Pour l’étape « Pourquoi c’est important », définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Faites approuver par un humain les étapes qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas la complétude du processus métier.
L’idée principale : boucles de contrôle imbriquées
Pour l’étape The Core Idea Nested, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute exécution partielle silencieuse. Faites approuver par un humain les cas où de l’argent est dépensé ou où des données de production sont modifiées. La connexion en temps de compilation ne correspond pas à une complétude opérationnelle. Pour l’étape The Core Idea Nested, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système.
┌──────────────────────────────────────────────────────┐
│ Loop 4 — Hill Climbing (self-improvement over time) │
│ ┌────────────────────────────────────────────────┐ │
│ │ Loop 3 — Event Queue Poller (orchestration) │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ Loop 2 — Verification & Retry │ │ │
│ │ │ ┌────────────────────────────────────┐ │ │ │
│ │ │ │ Loop 1 — ReAct Agent │ │ │ │
│ │ │ │ (think → act → observe → think) │ │ │ │
│ │ │ └────────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
Le domaine : Évaluation des risques en assurance
Lors du traitement de l’étape d’évaluation des risques en assurance, notez d’abord le contrat : les données requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez à la fois le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations ultérieures. Créez des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur tente à nouveau un nœud ultérieur.
{
"id": "APP-001",
"applicant_age": 34,
"state": "FL",
"property_type": "residential",
"coverage_amount": 450000,
"claim_history_5yr": 1,
"credit_score_tier": "good",
"flood_zone": true,
"has_flood_rider": false,
"business_use": false
}
"APP-001": {
"split": "train",
"expected_decision": "modify",
"expected_flags": ["flood_rider_required", "windstorm_exclusion"]
}
Boucle 1 : L’agent ReAct
Lorsque vous travaillez sur l’étape Loop 1 The ReAct, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables aux scripts volumineux. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus complexe et embrouillé. Faites un point d’étape après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
Le schéma
Lors de la phase « The Pattern », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez les terminations partielles silencieuses. Faites des points de contrôle après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lors de la phase « The Pattern », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du graphe.
System Prompt
│
▼
[Think] → What information do I need?
│
▼
[Act] → Call tool (lookup_application, retrieve_rules, ...)
│
▼
[Observe] → Tool returns result
│
▼
[Think] → What does this mean? What next?
│
... (repeat until decision is made)
│
▼
[Act] → draft_decision (terminal tool call)
L’implémentation de LangGraph
La phase de mise en œuvre de LangGraph fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript parfait, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours réussi et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Gardez l’état du graphe plat et typé : les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
class UnderwritingState(TypedDict):
application_id: str
messages: Annotated[list[AnyMessage], add_messages] # reducer accumulates
decision: str
rationale: str
flags: list[str]
recommended_premium_adj: float
lessons: list[str]
spend: float
_steps: int
def build_loop1(system_prompt: str, meter: CostMeter):
model = ChatAnthropic(model="claude-sonnet-4-6").bind_tools(TOOLS)
def agent_node(state: UnderwritingState) -> dict:
prompt = system_prompt
if state.get("lessons"):
prompt += "\n\nUnderwriting lessons:\n" + "\n".join(
f"- {l}" for l in state["lessons"]
)
msgs = [SystemMessage(content=prompt)] + list(state["messages"])
response = model.invoke(msgs)
meter.record_from_message(response) # track spend per call
return {
"messages": [response],
"_steps": state.get("_steps", 0) + 1,
"spend": meter.spent,
} def tools_node(state: UnderwritingState) -> dict:
last = state["messages"][-1]
tool_results, updates = _dispatch_tools(last.tool_calls)
return {"messages": tool_results, **updates} # updates captures draft_decision output def should_continue(state) -> Literal["tools", "__end__"]:
if state.get("_steps", 0) >= MAX_STEPS: # hard cap at 8 steps
return END
if getattr(state["messages"][-1], "tool_calls", None):
return "tools"
return END g = StateGraph(UnderwritingState)
g.add_node("agent", agent_node)
g.add_node("tools", tools_node)
g.set_entry_point("agent")
g.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
g.add_edge("tools", "agent")
return g.compile()
Les quatre outils
Le stade des Quatre Outils fonctionne le mieux lorsqu’il est considéré comme une surface mesurable. Capturez un transcript parfait, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit pointer vers une seule responsabilité plutôt que vers un processus embrouillé. Exposez les outils avec des schémas restreints et des étiquettes explicites indiquant les effets secondaires. Les hôtes doivent savoir quels appels modifient l’état avant d’approuver automatiquement.
@tool
def lookup_application(app_id: str) -> dict:
"""Return the full application record for the given application ID."""
# reads from applications.json — deterministic, no LLM call
@tool
def retrieve_rules(risk_factor: str) -> list[str]:
"""Return underwriting rules matching the given risk factor keyword.
Use terms like: flood, claims, credit, coverage, state, business."""
# keyword match against rules_kb.json - forces explicit rule lookup
@tool
def fetch_risk_signal(signal_type: str) -> dict:
# simulated external data pull (credit bureaus, flood maps, etc.)
@tool
def draft_decision(
decision: Literal["accept", "modify", "decline", "refer"],
rationale: str,
flags: list[str],
recommended_premium_adj: float,
) -> dict:
"""Finalize the underwriting decision with structured output."""
# terminal action - structured schema forces the agent to commit explicitly
Pourquoi la limite par étape est importante
La phase Why the Step Cap fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Traitez cette phase comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définites des vérifications de succès et refusez toute complétion partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption. La phase Why the Step Cap fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Boucle 2 : Vérification et tentative de réessai basée sur le correcteur
Pour la phase de vérification et d’achèvement du Loop 2, définissez les entrées, le responsable de l’étape ainsi que les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. Une configuration en temps de compilation ne garantit pas la complétude du fonctionnement commercial.
def run_loop2(
app_id: str,
system_prompt: str,
meter: CostMeter,
max_retries: int = 3,
) -> tuple[dict, bool]:
state = run_loop1(app_id, system_prompt, meter)
for attempt in range(max_retries):
decision = state.get("decision", "ran_out_of_steps")
if decision == "refer":
_write_human_queue(app_id, state) # human-in-the-loop path
return state, True
if is_correct(decision, app_id): # deterministic check
return state, True
if attempt >= max_retries - 1:
return state, False # exhausted retries
# construct targeted feedback for next attempt
expected = load_historical_decisions()[app_id]["expected_decision"]
feedback = HumanMessage(content=(
f"Your decision was '{decision}' but this application requires '{expected}'. "
f"Review the risk factors carefully and call draft_decision again."
))
extra_messages = list(state.get("messages", [])) + [feedback]
state = run_loop1(app_id, system_prompt, meter, extra_messages=extra_messages)
return state, False
Décisions de conception à retenir
Pour l’étape des décisions de conception à retenir, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Faites approuver par un humain les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas la complétude du processus métier.
Boucle 3 : Le polleur de file d’événements
Pour l’étape For the Loop 3 The Event, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses. Faites approuver par un humain les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne correspond pas à une complétude opérationnelle. Pour l’étape For the Loop 3 The Event, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système.
def run_event_loop(
system_prompt: str,
meter: CostMeter,
pending_path: Path = DEFAULT_PENDING,
state_path: Path = DEFAULT_STATE,
once: bool = False,
) -> None:
run_state = load_run_state(state_path)
verify_judge_checksum(run_state.get("judge_checksum", "")) # tamper check
total = len(json.loads(pending_path.read_text(encoding="utf-8-sig"))
if pending_path.exists() else [])
processed = 0
while True:
pending = (json.loads(pending_path.read_text(encoding="utf-8-sig"))
if pending_path.exists() else [])
if not pending:
if once:
print("[loop3] queue empty - done")
break
print("[loop3] queue empty - sleeping...")
time.sleep(POLL_INTERVAL)
continue
app_id = pending[0]
processed += 1
print(f"[loop3] {processed}/{total} {app_id} ...", flush=True)
try:
result_state, passed = run_loop2(app_id, prompt_with_lessons, meter)
except BudgetExhaustedError:
raise # budget exhaustion is fatal
except Exception as exc:
print(f"[loop3] {app_id} ERROR: {exc!r} - skipping")
# remove from queue and continue - one bad app cannot block the rest
remaining = [x for x in pending if x != app_id]
pending_path.write_text(json.dumps(remaining), encoding="utf-8")
continue
# ... update state, distill lesson, trigger hill-climbing
Pourquoi une file d’attente basée sur des fichiers ?
Lors de l’étape « Pourquoi une file d’attente basée sur des fichiers ? », notez d’abord les exigences : entrées requises, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez à la fois le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages échoués font partie intégrante du produit, et non d’améliorations ultérieures. Créez des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
Détectation des modifications non autorisées via un checksum
Lors du traitement de l’étape de détection de modification via le checksum, notez d’abord les exigences : entrées requises, signal de succès, et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité et non un processus embrouillé. Créez des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel au LLM lorsque l’opérateur réessaie un nœud ultérieur.
verify_judge_checksum(run_state.get("judge_checksum", ""))
def compute_judge_checksum() -> str:
content = _HIST.read_bytes() # historical_decisions.json
return hashlib.sha256(content).hexdigest()
def verify_judge_checksum(expected: str) -> None:
actual = compute_judge_checksum()
if actual != expected:
raise RuntimeError(
f"Judge checksum mismatch - historical_decisions.json was tampered with."
)
Sauter vs Planter
Lors de l’étape « Sauter vs Planter », écrivez d’abord le contrat : entrées requises, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez les terminations partielles silencieuses. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lors de l’étape « Sauter vs Planter », écrivez d’abord le contrat : entrées requises, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les flags fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Boucle 4 : Ascension de colline (Auto-amélioration)
La phase de montée en côte Loop 4 fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement réussi, un cas d’échec ainsi que la note de réversion avant d’élargir le périmètre. Documentez en même temps le parcours optimal et celui de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Gardez l’état des graphes simple et de type défini ; les blocs imbriqués masquent l’identité du nœud qui a écrit tel champ et perturbent la reprise après interruption.
seed prompt
│
▼
evaluate on training set → score, failures
│
▼
┌────────────────────────────────┐
│ for each round: │
│ │
│ reflect(current, failures) │ ← LLM analyzes failure patterns
│ │ │
│ ▼ │
│ candidate_prompt │
│ │ │
│ ▼ │
│ evaluate(candidate, train) │ ← full eval run
│ │ │
│ ▼ │
│ audit_prompt(candidate) │ ← anti-cheating check
│ │ │
│ ▼ │
│ if score > best AND clean: │
│ best = candidate │ ← keep
│ else: │
│ discard │ ← revert
└────────────────────────────────┘
│
▼
write best_prompt.txt
Étape de réflexion
L’étape « Reflect Step » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple réussi, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’erreur doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Maintenez l’état du graphe simple et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
REFLECT_TEMPLATE = """You are improving the system prompt of an insurance underwriting agent.CURRENT PROMPT:
{prompt}
The agent got these decisions WRONG on training applications:
{failures}
Look for PATTERNS in the failures. Infer GENERAL underwriting rules that would fix them.
Do NOT memorize specific application IDs or applicant details.
Write an improved system prompt. Reply with ONLY the new prompt text."""
def reflect(current_prompt: str, failures: list[dict]) -> str:
client = anthropic.Anthropic()
failure_text = "\n".join(
f"- APP {f['app_id']}: agent said '{f['got']}', expected '{f['expected']}'. "
f"Application data: {f['application']}"
for f in failures
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1500,
messages=[{"role": "user", "content": REFLECT_TEMPLATE.format(
prompt=current_prompt,
failures=failure_text,
)}],
)
return response.content[0].text.strip()
L’étape d’évaluation
La phase d’évaluation fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemplaire idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définites des vérifications de succès et refusez toute complétion partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
def evaluate_prompt(system_prompt: str, split: str = "train", meter=None):
tasks = load_tasks(split)
failures = []
for task in tasks:
state = run_loop1(task["id"], system_prompt, meter)
decision = state.get("decision", "ran_out_of_steps")
if not is_correct(decision, task["id"]):
failures.append({
"app_id": task["id"],
"got": decision,
"expected": task["expected_decision"],
"application": task["application"],
})
score = (len(tasks) - len(failures)) / len(tasks)
return score, failures
La phase d’évaluation fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemplaire idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les indicateurs fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Le contrôle d’accès : anti-surapprentissage et anti-triche
Pour The Gate Anti-Overfitting et la phase correspondante, définissez les entrées, le responsable de l’étape ainsi que les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations ultérieures. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas la complétude du processus métier.
def improve(seed_prompt: str, lessons: list[str], meter: CostMeter, rounds: int = 5) -> str:
best = with_lessons(seed_prompt, lessons)
best_score, failures = evaluate_prompt(best, split="train", meter=meter)
for r in range(1, rounds + 1):
candidate = reflect(best, failures)
score, cand_failures = evaluate_prompt(candidate, split="train", meter=meter)
verdict = audit_prompt(candidate) # anti-cheat check
if score > best_score and verdict == "VERDICT: CLEAN":
best, best_score, failures = candidate, score, cand_failures
BEST_PROMPT_PATH.write_text(best, encoding="utf-8")
print(f"round {r}: {score:.0%} KEPT ({len(cand_failures)} failures)")
else:
reason = "cheating" if verdict != "VERDICT: CLEAN" else f"{score:.0%} <= {best_score:.0%}"
print(f"round {r}: {score:.0%} REVERTED ({reason})")
return best
L’Auditeur de Prompts
Pour l’étape de l’Auditeur des prompts, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables à des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Préférez des sorties structurées avec validation de schéma à du texte libre lorsque l’étape suivante consiste en du code ou une appel d’outil.
AUDIT_SYSTEM = (
"You are a security auditor for AI systems. "
"Check whether the prompt contains any hardcoded application IDs (e.g. APP-001) "
"or hardcoded decisions for specific applications. "
"These would constitute cheating — memorizing answers instead of learning rules. "
"Reply with exactly one of:\n"
"VERDICT: CLEAN\n"
"VERDICT: CHEATING\n"
"Followed by a one-sentence explanation."
)
def audit_prompt(evolved_prompt: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=200,
system=AUDIT_SYSTEM,
messages=[{"role": "user", "content": f"PROMPT TO AUDIT:\n{evolved_prompt}"}],
)
return response.content[0].text.strip().split("\n")[0] # first line only
Mémoire des leçons : Distillation des connaissances entre sessions
Pour l’étape de connaissance inter-session de la mémoire des leçons, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute complétion partielle silencieuse. Faites approuver par un humain les opérations qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne correspond pas à une complétude opérationnelle. Pour l’étape de connaissance inter-session de la mémoire des leçons, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer.
Il n’est pas nécessaire de lire l’ensemble du graphique.DISTILL_PROMPT = """An insurance underwriting agent made a wrong decision.Application details: {application}
Agent decided: {got}
Correct decision: {expected}
Write ONE short, general underwriting rule that would prevent this mistake.
Do NOT reference this specific application ID or any applicant names/details.
Reply with only the rule, as a single sentence."""
def distill_lesson(application: dict, got: str, expected: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=150,
messages=[{"role": "user", "content": DISTILL_PROMPT.format(...)}],
)
return response.content[0].text.strip()
def with_lessons(base_prompt: str, lessons: list[str]) -> str:
if not lessons:
return base_prompt
lessons_text = "\n".join(f"- {l}" for l in lessons)
return base_prompt + f"\n\nUnderwriting lessons learned:\n{lessons_text}"
def measure_gain(base_prompt: str, lessons: list[str], split: str = "test", meter=None) -> float:
stateless_score, _ = evaluate_prompt(base_prompt, split=split, meter=meter)
augmented = with_lessons(base_prompt, lessons)
stateful_score, _ = evaluate_prompt(augmented, split=split, meter=meter)
return stateful_score - stateless_score # positive = lessons help
Contrôle budgétaire : Le compteur de coûts
Lors du traitement de l’étape de contrôle budgétaire et de suivi des coûts, notez d’abord les éléments requis pour le contrat : les données nécessaires, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Documentez à la fois le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations apportées ultérieurement. Créez des points de contrôle après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel au LLM lorsque l’opérateur tente à nouveau un nœud ultérieur.
BUDGET_USD = 2.00
INPUT_PRICE_PER_TOKEN = 3.00 / 1_000_000
OUTPUT_PRICE_PER_TOKEN = 15.00 / 1_000_000
class CostMeter:
def record(self, input_tokens: int, output_tokens: int) -> None:
if self.spent >= self._budget: # check BEFORE adding
raise BudgetExhaustedError(
f"Budget ${self._budget:.2f} exhausted at ${self.spent:.4f}"
)
self.spent += input_tokens * INPUT_PRICE_PER_TOKEN \
+ output_tokens * OUTPUT_PRICE_PER_TOKEN
État d’exécution : Initialisation idempotente
Lors de la phase d’initialisation idempotente en état d’exécution, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité et non un processus embrouillé. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
def _init_run_state() -> dict:
path = _STATE_DIR / "run_state.json"
state = {}
if path.exists():
try:
content = path.read_text(encoding="utf-8-sig").strip() # handles Windows BOM
if content:
state = json.loads(content)
except (json.JSONDecodeError, UnicodeDecodeError):
pass # corrupt file → start fresh
if not state:
state = dict(_DEFAULT_RUN_STATE)
state["judge_checksum"] = compute_judge_checksum() # always refresh
path.write_text(json.dumps(state, indent=2), encoding="utf-8")
return state
Les trois modes d’exécution
Lors de la phase des Trois modes d’exécution, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez toute exécution partielle silencieuse. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lors de la phase des Trois modes d’exécution, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système.
python -m src.main --mode single --app-id APP-001
python -m src.main --mode event-loop --once
python -m src.main --mode improve --rounds 5
Flux de données : suivi du début à la fin
L’étape de suivi du flux de données du début à la fin fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez l’état du graphe simple et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
pending_applications.json
│
│ [Loop 3 reads APP-009]
▼
run_loop2("APP-009", prompt, meter)
│
│ [Loop 2 calls Loop 1]
▼
run_loop1("APP-009", prompt, meter)
│
│ [LangGraph StateGraph]
▼
agent_node → ChatAnthropic.invoke([SystemMsg, HumanMsg])
│
│ response: tool_call(lookup_application, {"app_id": "APP-009"})
▼
tools_node → lookup_application.invoke({"app_id": "APP-009"})
│
│ returns: {id: APP-009, state: TX, coverage: 1200000, ...}
▼
agent_node → ChatAnthropic.invoke([..., ToolMessage])
│
│ response: tool_call(retrieve_rules, {"risk_factor": "coverage"})
▼
tools_node → retrieve_rules.invoke({"risk_factor": "coverage"})
│
│ returns: ["Coverage > $1M requires mandatory refer. Flag: high_coverage"]
▼
agent_node → ChatAnthropic.invoke([..., ToolMessage])
│
│ response: tool_call(draft_decision, {decision: "refer", ...})
▼
tools_node → draft_decision.invoke({...})
│
│ updates state: {decision: "refer", flags: ["high_coverage"], ...}
▼
should_continue → END (no more tool calls)
│
▼
Loop 2: decision == "refer" → write human_queue.json → return (state, True)
│
▼
Loop 3: passed=True → update run_state.json → remove APP-009 from queue
│
│ [decisions_since_last_improvement becomes 9 >= 8]
▼
Loop 4: improve(seed_prompt, lessons, meter, rounds=5)
│
│ reflect → evaluate → audit → gate → write best_prompt.txt
▼
Loop 3: continue with APP-010 using new best_prompt
Lecons clés d’ingénierie
La phase des leçons clés d’ingénierie fonctionne au mieux lorsqu’elle est considérée comme une surface mesurable. Recueillez un transcript exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit pointer vers une seule responsabilité plutôt que vers un processus embrouillé. Maintenez l’état des graphes simple et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
1. Séparer l’oracle de l’agent
La phase « 1 Separate the oracle » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Traitez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez toute complétion partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption. La phase « 1 Separate the oracle » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
2. Déterminisme à la frontière d’évaluation
Pour le déterminisme à ce stade, il convient de définir les entrées, l’auteur de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas la complétude du processus métier.
3. L’outil draft_decision en tant qu’extraction structurée
Pour la phase 3 du outil de draftdecision, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables à des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Authentifiez au niveau du gateway et réautorisez au niveau du plan de données. Un token porteur seul ne constitue pas une frontière entre les tenants.
4. La lutte contre la triche est indispensable dans les systèmes auto-améliorants
Pour les 4 étapes où la lutte contre la triche est obligatoire, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute exécution partielle silencieuse. Faites approuver manuellement les opérations qui entraînent des dépenses ou modifient des données de production. Une connexion en temps de compilation ne garantit pas la complétude du processus métier. Pour les 4 étapes où la lutte contre la triche est obligatoire, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à le lire.
toute la grille.5. Le BOM et l’encodage sont des bugs de production
Lors du traitement de l’étape 5 concernant le BOM et l’encodage, notez d’abord les exigences : entrées requises, signal de succès, et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez à la fois le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations ultérieures. Faites un point après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel d’LLM lorsque l’opérateur réessaie un nœud ultérieur.
6. Budget avant coût, et non après
Lorsque vous travaillez sur l’étape des 6 budgets avant le calcul des coûts, notez d’abord les éléments requis par le contrat : les données nécessaires, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité et non un processus embrouillé. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel au LLM lorsque l’opérateur réessaie un nœud ultérieur.
# WRONG: allows one overspend before raising
self.spent += cost
if self.spent > self._budget:
raise BudgetExhaustedError(...)
# CORRECT: raises before the overspend registers
if self.spent >= self._budget:
raise BudgetExhaustedError(...)
self.spent += cost
7. flush=True sur les lignes de progression dans des boucles à long exécution
Lorsque vous travaillez sur les 7 étapes nécessitant un résultat « True », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux éléments générés, définez des vérifications de succès et refusez toute exécution partielle silencieuse. Faites des points de contrôle après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
print(f"[loop3] {processed}/{total} {app_id} ...", flush=True)
Lorsque vous travaillez sur les 7 étapes nécessitant un résultat « True », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du graphe.
8. Le budget de montée en pente doit être séparé du budget du cycle d’événements
Le budget de montée en pente fonctionne le mieux lorsqu’il est considéré comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours optimal et les procédures de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
try:
system_prompt = run_hill_climbing(system_prompt, lessons, meter)
run_state["decisions_since_last_improvement"] = 0
except BudgetExhaustedError:
print(f"[loop3] hill-climbing skipped — budget exhausted at ${meter.spent:.4f}")
run_state["decisions_since_last_improvement"] = 0
Étendre ce modèle
La phase d’extension de ce modèle fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple réussi, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’erreur doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
Exécution du système
La phase de « Exécution du système » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définites des vérifications de succès et refusez toute mise en œuvre partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
# 1. Install
cd underwriting_loop
pip install -e ".[dev]"
export ANTHROPIC_API_KEY=sk-ant-...
# 2. Run a single application (debug mode - cheapest)
python -m src.main --mode single --app-id APP-001
# 3. Drain the pending queue with event loop
python -m src.main --mode event-loop --once
# 4. Run standalone hill-climbing (5 rounds)
python -m src.main --mode improve --rounds 5
# 5. Run the full offline test suite (no API key needed)
pytest tests/ -v
La phase de « Exécution du système » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les indicateurs fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
seed score: 44% (9 failures)
round 1: 56% KEPT (7 failures)
round 2: 56% REVERTED (score 56% <= best 56%)
round 3: 69% KEPT (5 failures)
round 4: 75% KEPT (4 failures)
round 5: 69% REVERTED (score 69% <= best 75%)
Final test evaluation...
spend: $1.8342
test score: 75%
gain (vs baseline): +25%
Conclusion
Pour l’étape de conclusion, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’une mise en forme ultérieure. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. La configuration en temps de compilation ne garantit pas l’exhaustivité du fonctionnement commercial.
Avantages et inconvénients de l’ingénierie par boucles
Pour définir les avantages et inconvénients des étapes, il faut préciser les entrées, le responsable de l’étape ainsi que les critères d’achèvement avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité et non un processus embrouillé. Faites approuver par des humains les étapes qui entraînent des dépenses ou modifient des données de production. Une connexion en temps de compilation ne garantit pas la complétude du processus métier.
Avantages
Pour la phase Pros, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminaisons partielles silencieuses. Faites approuver par un humain les cas où de l’argent est dépensé ou où des données de production sont modifiées. La connexion en temps de compilation ne revient pas à une complétude opérationnelle. Pour la phase Pros, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système.
Inconvénients
Lors du traitement de l’étape Cons, notez d’abord le contrat : les entrées requises, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures. Faites un point après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
Quand utiliser l’ingénierie en boucle — et quand ne pas l’utiliser
Lors de l’étape « Quand utiliser une boucle », notez d’abord les exigences : entrées requises, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Faites un point après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel d’LLM lorsque l’opérateur réessaie un nœud ultérieur.
Le test à deux questions
Lors de la phase du Test à Deux Questions, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez les terminations partielles silencieuses. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lors de la phase du Test à Deux Questions, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Utilisez l’ingénierie par boucles lorsque
L’ingénierie par boucles fonctionne le mieux lorsque l’étape est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Gardez l’état des graphes plat et typé ; les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
Ne pas utiliser l’ingénierie par boucles lorsque
La phase « Ne pas utiliser de boucle » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript parfait, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’erreur doit pointer vers une seule responsabilité plutôt que vers un processus embrouillé. Maintenez l’état du graphe simple et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
8 éléments qui permettent à une boucle de fonctionner réellement
Les 8 éléments qui permettent à l’étape de fonctionner au mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Traitez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez toute mise en œuvre partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués cachent le fait que tel nœud a modifié tel champ et perturbent la reprise après interruption. Les 8 éléments qui permettent à l’étape de fonctionner au mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et une note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
1. Un objectif vérifiable
Pour l’étape 1 « Objectif vérifiable », définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’une mise en forme ultérieure. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. La configuration en temps de compilation ne garantit pas l’exhaustivité du fonctionnement commercial.
2. Arrêt définitif
Pour l’étape 2 « A Hard Stop », définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Faites approuver par un humain les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas la complétude du processus métier.
3. De bons outils
Pour l’étape des 3 Bonnes Outils, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute mise à jour partielle silencieuse. Authentifiez-vous au niveau du gateway et réautorisez-vous au niveau du plan de données. Un simple token porteur ne constitue pas une frontière entre les tenants. Pour l’étape des 3 Bonnes Outils, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les flags fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système.
4. Mémoire
Lorsque vous travaillez sur les 4 étapes de la mémoire, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’améliorations apportées ultérieurement. Créez un point de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.
5. Un vérificateur distinct
Lors de la phase 5 « A Separate Checker », notez d’abord les éléments essentiels du contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’erreur doit indiquer une seule responsabilité et non un processus embrouillé. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel d’LLM lorsque l’opérateur réessaie un nœud ultérieur.
6. Planifier avant d’agir sur des tâches complexes
Lors de la phase des 6 étapes « Planifier avant d’agir », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez les terminations partielles silencieuses. Faites des points de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lors de la phase des 6 étapes « Planifier avant d’agir », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle garantit l’honnêteté des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
7. Journalisation
La phase 7 « Journalisation » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez l’état du graphe plat et typé. Les blocs imbriqués cachent le fait que tel nœud a écrit tel champ et perturbent la reprise après interruption.
8. Sens du coût
La phase 8 « Sens du coût » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Préférez des unités petites et testables à des scripts complexes. Lorsqu’une étape échoue, l’échec doit pointer vers une seule responsabilité plutôt que vers un processus embrouillé. Maintenez l’état du graphe plat et typé. Les blocs imbriqués cachent le fait que tel nœud a écrit tel champ et perturbent la reprise après interruption.
# The ordering matters:
if self.spent >= self._budget: # check BEFORE adding
raise BudgetExhaustedError(...)
self.spent += cost # add AFTER the check clears
La liste de contrôle
La phase de la liste de contrôle fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définites des vérifications de succès et refusez toute complétion partielle silencieuse. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption. La phase de la liste de contrôle fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Références :
Pendant l’étape des références, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’une mise en forme ultérieure. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. La connexion en temps de compilation ne garantit pas l’exhaustivité du fonctionnement commercial.
Liste de contrôle opérationnelle
Lorsque vous travaillez sur l’étape de la liste de contrôle opérationnelle, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste garantit que les modifications ultérieures du code restent transparentes.
Enregistrez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce du coût permet d’éviter des factures inattendues lorsque le parcours passe de l’environnement de démonstration à des environnements partagés.
Faites un point d’étape après les étapes coûteuses. La reprise ne doit pas facturer à nouveau la même appel de LLM lorsque l’opérateur réessaie un nœud ultérieur.
Fixez les versions des dépendances et enregistrez le digest de l’image ayant exécuté la démonstration. La reproductibilité vaut mieux que les connaissances empiriques.
Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent se trouver en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe.
Faites un point d’étape après les étapes coûteuses. La reprise ne doit pas facturer à nouveau la même appel de LLM lorsque l’opérateur réessaie un nœud ultérieur.
Au préalable de promouvoir l’ensemble des composants, figez les versions, conservez une transcription exemplaire pour le chemin critique, et vérifiez les étapes de réversion. Les environnements partagés nécessitent des limites de fréquence d’accès, des contrôles de location, ainsi qu’un responsable clair pour la rotation des secrets. Préférez une fiabilité solide à des démonstrations brillantes mais ponctuelles.
Note de batch pour c0f4a1437d4f : gardez les clés du fournisseur en dehors du répertoire, fixez un plafond pour les tokens par session, et stockez les transcriptions à côté des fichiers d’évaluation afin que les remplacements ultérieurs de modèles restent comparables.