Skip to content

Instantly share code, notes, and snippets.

@jezzarax
Last active June 17, 2026 23:55
Show Gist options
  • Select an option

  • Save jezzarax/f450885ba4afae3532907a5aeb8fef99 to your computer and use it in GitHub Desktop.

Select an option

Save jezzarax/f450885ba4afae3532907a5aeb8fef99 to your computer and use it in GitHub Desktop.
Example of a simple agentic LLM loop without any agentic frameworks
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = ["openai", "click"]
# ///
import json
import click
from openai import OpenAI
def create_oai_client(api_key: str, base_url: str | None) -> OpenAI:
client_params = {
"api_key": api_key,
}
if base_url:
client_params["base_url"] = base_url
return OpenAI(**client_params)
DEFAULT_SYSTEM_INSTRUCTION = (
"You are a helpful cooking assistant. Use find_recipes to look up what "
"can be made with the ingredients the user has on hand, then call "
"get_recipe_steps to retrieve the detailed steps for a recipe that fits. "
"When you have the steps, respond directly with the recipe name, a short "
"intro, and the steps."
)
DEFAULT_USER_QUERY = (
"I have chicken thighs, lemons, and thyme in the fridge. "
"What should I make for dinner?"
)
# Two tools: find_recipes and get_recipe_steps
TOOLS = [
{
"type": "function",
"function": {
"name": "find_recipes",
"description": (
"Find recipe candidates that match a list of ingredients. "
"Returns a JSON array of recipes with id, name, and short description."
),
"parameters": {
"type": "object",
"properties": {
"ingredients": {
"type": "array",
"items": {"type": "string"},
"description": "The ingredients the user has on hand.",
},
},
"required": ["ingredients"],
},
},
},
{
"type": "function",
"function": {
"name": "get_recipe_steps",
"description": "Get the detailed cooking steps for a recipe by id.",
"parameters": {
"type": "object",
"properties": {
"recipe_id": {
"type": "string",
"description": "The id of the recipe to retrieve.",
},
},
"required": ["recipe_id"],
},
},
},
]
# Fake tool implementations
def run_tool(name: str, arguments) -> str:
if name == "find_recipes":
ingredients = arguments.get("ingredients", [])
main = ingredients[0] if ingredients else "ingredient"
joined = ", ".join(ingredients)
recipes = [
{
"id": "r-001",
"name": f"Pan-seared {main} with citrus",
"description": f"A quick weeknight dish built around {joined}.",
},
{
"id": "r-002",
"name": f"Braised {main} with herbs",
"description": f"Low-and-slow preparation, about 45 minutes.",
},
{
"id": "r-003",
"name": f"Roasted {main} tray bake",
"description": f"One-pan recipe, 35 minutes total.",
},
]
return json.dumps(recipes)
elif name == "get_recipe_steps":
recipe_id = arguments.get("recipe_id", "r-001")
style = {
"r-001": "pan-seared",
"r-002": "braised",
"r-003": "roasted",
}.get(recipe_id, "pan-seared")
steps = [
"Pat the main ingredient dry and season with salt and pepper.",
f"Heat a heavy pan or pot to the right temperature for {style} cooking.",
f"Cook the main ingredient using the {style} method until done.",
"Add aromatics (garlic, thyme) and a finishing squeeze of lemon; baste briefly.",
"Rest for a few minutes, then slice and serve.",
]
return f"Recipe {recipe_id}: " + " ".join(steps)
else:
raise ValueError(f"Unknown tool name: {name}")
def run_agent(
client: OpenAI, model_name: str, system_prompt: str, user_query: str, max_turns=10
):
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_query},
]
for turn in range(max_turns):
resp = client.chat.completions.create(
model=model_name, messages=messages, tools=TOOLS
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(f"\n--- Final answer (turn {turn + 1}) ---")
print(msg.content)
return msg.content
print(f"\n--- Turn {turn + 1} ---")
for tc in msg.tool_calls:
name = tc.function.name
args = json.loads(tc.function.arguments)
print(f" Calling {name}({args})")
result = run_tool(name, args)
print(f" -> {result[:100]}...")
# The update rule: append observation to history
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
print("\n[Max turns reached]")
@click.command()
@click.option(
"--openai-model-name", default="openrouter/free", envvar="OPENAI_MODEL_NAME"
)
@click.option("--openai-api-key", default="sk-none", envvar="OPENAI_API_KEY")
@click.option(
"--openai-base-url",
default="https://openrouter.ai/api/v1",
envvar="OPENAI_BASE_URL",
)
@click.option("--system-instruction", default=DEFAULT_SYSTEM_INSTRUCTION)
@click.option("--user-query", default=DEFAULT_USER_QUERY)
def main(
openai_model_name: str,
openai_api_key: str,
openai_base_url: str | None,
system_instruction: str,
user_query: str,
):
client = create_oai_client(openai_api_key, openai_base_url)
run_agent(client, openai_model_name, system_instruction, user_query)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment