C.W.K.
Stream
Lesson 02 of 05 · published

Before Tool Calling — The Workarounds

~22 min · history, regex, react, scaffolding

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Long before tool calling was a built-in feature of any model, people were already trying to break the LLM out of its room. The early workarounds are worth knowing because they are still alive in older code, and because they explain why today's clean APIs feel like such a relief.

The first family of approaches was prompt-and-parse: ask the model to produce a structured string — JSON, XML, a special <action> tag — and run a regex over its output to detect "I want to call this function." The reliability story was grim. The model would forget the format mid-sentence, wrap the JSON in chatty preamble, switch quote styles, or hallucinate fields. Every team built their own retry-and-repair loop, and every team's loop leaked corner cases.

The second family was ReAct-style scaffolding: prompt the model to interleave Thought / Action / Observation lines, parse the Actions out of the stream, execute them, then feed the Observations back in. ReAct was a real intellectual leap — it taught us that reasoning and acting are interleaved, not sequential — but as an engineering substrate it was paper-thin. The model still had to perfectly format every step, and the parser still had to be defensive against poetry.

The third family was full agent frameworks: LangChain agents, AutoGPT, BabyAGI. They wrapped the prompt-and-parse loop in object-oriented machinery and added planners, memory, and self-critique. They worked when they worked. They failed in spectacular, hard-to-debug ways when they did not, because every layer was still building on the same brittle "ask the model to please format itself" foundation.

The lesson hidden in all of this is the lesson of every protocol we are about to study: the contract has to live below the prose. As long as tool invocation is a thing the model is asked to type out as part of its English answer, you are gambling on the model's mood. The breakthrough was making tool invocation a first-class output of the API itself — not text the model writes, but a structured field the inference engine emits.

Code

ReAct-flavored prompt-and-parse (the old pain)·python
# An LLM is asked to produce a strict format. A regex extracts the call.
# Real systems had to handle: extra whitespace, alternate JSON quoting,
# leaked thoughts, wrapped code fences, mid-stream apologies, etc.
import re, json

prompt = '''You are an assistant with one tool: get_weather(location: str).
When you need it, output exactly:
ACTION: {"tool": "get_weather", "args": {"location": "<city>"}}
Otherwise reply normally.'''

raw = call_model(prompt + "\nUser: weather in Seoul?")
# raw might be:
#   "Sure! ACTION: {\"tool\": \"get_weather\", \"args\": {\"location\":\"Seoul\"}}"
m = re.search(r"ACTION:\s*({.*})", raw)
if m:
    try:
        call = json.loads(m.group(1))
    except json.JSONDecodeError:
        call = repair_json(m.group(1))  # every team had to write this

External links

Exercise

Find an old prompt-and-parse pipeline you wrote (or one in a public repo) and list every defensive measure it takes against malformed model output. Each measure is a place a protocol would let you delete code. The number you produce is, roughly, the value of the breakthrough we're about to study.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.