The Pain: You spent an afternoon tuning your agent. Next morning, it stares at you blankly — as if yesterday never happened.
What You'll Learn: The 4-stage evolution (Prompt → Context → Harness → Loop), and a runnable 50-line Loop Agent that persists memory.
pip install openai
(openai ≥ 1.0.0)Goal: Copy-paste the code, run it, and see a Loop Agent that doesn't forget.
At 2 AM, you finally got that multi-step workflow working. The agent followed your carefully designed prompt — data fetching, cleaning, analysis, charting. You close your laptop, satisfied.
Next morning, you open the conversation full of hope — and the agent looks at you blankly, as if none of it ever happened.
You check the logs. No errors. No exceptions. The agent regenerated everything — it just "forgot" where it stopped yesterday.
This isn't a joke. It's the nightmare every serious Agent developer experiences. The root cause isn't "the model isn't smart enough." It's a more fundamental fact: your agent was never designed to survive the night.
To understand this, let's use a simple evolution framework:
| Stage | What You Do | Fatal Flaw |
|---|---|---|
| Prompt Engineering | ||
| Write task description, examples, format into prompt | Any unexpected input crashes output | |
| Context Engineering | ||
| Stuff history + intermediate results into context window | Token cost grows linearly, hits window limit | |
| Harness Engineering | ||
| Add tool calling, structured output, error capture | Framework built, but agent is still "one-shot" | |
| Loop Engineering | ||
| Build closed loop: state + memory + feedback + retry + persistence | True engineering — agent starts to "live" |
Loop Engineering isn't a rejection of Prompt Engineering — it's a transcendence. Prompt still matters. But it's the engine, and you can't drive an engine like a car.
Here's the complete, copy-pasteable, runnable Loop Agent. Run it first, then understand it line by line.
import json, os, time
from pathlib import Path
from datetime import datetime
from openai import OpenAI
client = OpenAI() # reads OPENAI_API_KEY from env
STATE_FILE = Path("./agent_state.json")
MEMORY_FILE = Path("./agent_memory.json")
MAX_RETRIES = 3
def load_memory() -> dict:
if MEMORY_FILE.exists():
return json.loads(MEMORY_FILE.read_text())
return {"facts": {}, "errors": []}
def save_memory(mem: dict):
MEMORY_FILE.write_text(json.dumps(mem, indent=2, ensure_ascii=False))
def load_state() -> dict:
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {"state": "idle", "step": 0}
def save_state(state: str, step: int):
STATE_FILE.write_text(json.dumps({
"state": state, "step": step,
"updated_at": datetime.now().isoformat()
}, indent=2, ensure_ascii=False))
def execute(task: str, memory: dict, error_ctx: str = "") -> str:
system = f"You are a task-execution agent. Known facts: {json.dumps(memory.get('facts', {}), ensure_ascii=False)}"
if error_ctx:
system += f"\nLast error: {error_ctx}\nPlease fix."
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": system},
{"role": "user", "content": task}]
)
return resp.choices[0].message.content
def check(output: str, keywords: list[str]) -> tuple[bool, str]:
missing = [kw for kw in keywords if kw not in output]
if missing:
return False, f"Missing: {missing}"
if len(output) < 20:
return False, "Output too short"
return True, ""
def run(task: str, keywords: list[str]):
memory = load_memory()
save_state("running", 0)
for i in range(1, MAX_RETRIES + 1):
error = memory["errors"][-1]["reason"] if memory["errors"] else ""
output = execute(task, memory, error)
ok, reason = check(output, keywords)
if ok:
save_state("done", i)
memory["facts"][task[:30]] = output[:100]
save_memory(memory)
return f"OK on attempt {i}:\n{output}"
else:
save_state("retrying", i)
memory["errors"].append(
{"task": task, "reason": reason, "attempt": i}
)
save_memory(memory)
print(f"Retry {i} failed: {reason}")
time.sleep(1)
save_state("failed", MAX_RETRIES)
return f"All {MAX_RETRIES} attempts failed"
if __name__ == "__main__":
result = run(
task="List 3 Python web frameworks and their features",
keywords=["Flask", "Django", "FastAPI"]
)
print(result)
Copy this to loop_agent.py
and run it.
pip install openai
export OPENAI_API_KEY="sk-..."
python loop_agent.py
Expected output:
OK on attempt 1:
The 3 mainstream Python web frameworks:
1. **Flask**: lightweight micro-framework...
2. **Django**: full-stack, batteries included...
3. **FastAPI**: modern async, auto OpenAPI docs...
Now verify persistence — close the terminal, reopen, run again:
cat agent_state.json
Expected:
{
"state": "done",
"step": 1,
"updated_at": "2026-07-01T12:00:00.000000"
}
cat agent_memory.json
Expected: the facts
dict contains your task and the output.
python loop_agent.py
The agent reads facts
from agent_memory.json
and passes them as known context. That's the "remembers overnight" mechanism.
| Component | Code Location | Description |
|---|---|---|
| Memory Store | ||
load_memory() / save_memory() |
||
| Persist memory to JSON | ||
| State Machine | ||
load_state() / save_state() |
||
| Persist state to JSON | ||
| Executor | execute() |
|
| Call OpenAI API | ||
| Checker | check() |
|
| Verify keywords present | ||
| Task Scheduler | run() |
|
| Retry loop + state transitions | ||
| Guardrails | MAX_RETRIES = 3 |
|
| Retry limit |
Error 1: ModuleNotFoundError: No module named 'openai'
pip install openai
Error 2: openai.AuthenticationError: 401
You didn't set the API key, or it's invalid.
export OPENAI_API_KEY="sk-..."
Error 3: Agent output missing Flask/Django/FastAPI
This is normal! LLMs don't always follow instructions perfectly. That's exactly the Loop Agent's value — the Checker detects missing keywords, rejects the output, and auto-retries. You'll see:
Retry 1 failed: Missing: ['Flask', 'Django', 'FastAPI']
Retry 2 failed: Missing: ['Django']
OK on attempt 3:
...
Error 4: API timeout or rate limit
gpt-4o-mini
is very cheap (~$0.00015/call). If rate-limited, increase time.sleep(1)
or check your OpenAI dashboard.
Now you have a complete runnable Loop Agent. It uses plain JSON files for persistence — which is exactly what lets you touch every component by hand.
Extend it:
Loop Engineering isn't a package you install. It's a shift in architecture thinking. Starting from these 50 lines, you're standing at the threshold of stage 4.
Next article: How Much Memory Does Your Agent Need? — Memory Store Selection Guide
About the author: Wu Ji (无记) — AI & digitalization practitioner focused on Agent engineering, Loop Engineering, and digital transformation. Practical, hands-on tutorials — follow along and it just works.