{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigbpuu45mpc4hnzc2u67hiebijc4bspelbb7gpe54nk3w53jguuwa",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mp4ruxwu3o62"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreig3jroko6w5xqo3af7qkz6x4un2feo2kpbjxcz36jpnsq66hfdja4"
    },
    "mimeType": "image/webp",
    "size": 79518
  },
  "path": "/venu_varma/why-do-we-import-100mb-of-frameworks-to-run-a-50-line-llm-reasoning-loop-3afh",
  "publishedAt": "2026-06-25T15:31:08.000Z",
  "site": "https://dev.to",
  "tags": [
    "agents",
    "ai",
    "llm",
    "python"
  ],
  "textContent": "Stop Importing Bloated Frameworks: Build a Python AI Agent from Scratch\n\nYou want to build an AI agent.\n\nSo you head to the docs of a popular orchestration framework, copy the boilerplate, import 20 modules, and spin up an agent. It works—until it doesn't.\n\nSuddenly, you're looking at a 50-line stack trace originating from a library wrapper. You don't know where the query failed, what the exact prompt was, or why the tool call failed to parse.\n\nHere is the truth: **You don't need AutoGen, LangChain, or CrewAI to build a working AI agent.**\n\nYou just need vanilla Python and a basic understanding of the three core pillars of agentic design.\n\n**The Three Pillars of an AI Agent**\n\nAny basic agent can be broken down into three simple components:\n\n  1. **The State (Memory):** A list of message dictionaries (`role` and `content`) passed to and from the LLM.\n  2. **The Schema (Tools):** A dictionary mapping tool names to standard Python functions.\n  3. **The Loop (Reasoning):** A standard `while` loop that calls the LLM, checks if it wants to use a tool, runs the tool if requested, appends the result to the State, and repeats until the LLM returns a final answer.\n\n\n\nLet’s build one.\n\n##  Coding the Agent (under 60 lines of Python)\n\nThis example uses the official `openai` SDK, but the same logic applies to Anthropic, Gemini, or local models running via Ollama.\n\n\n    python\n    import os\n    import json\n    from openai import OpenAI\n\n    # Initialize client\n    client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\"))\n\n    # 1. Define the tools our agent can use\n    def get_weather(location):\n        if \"tokyo\" in location.lower():\n            return \"Tokyo is sunny and 25°C.\"\n        return \"Cool and rainy, 15°C.\"\n\n    # Map the function name to the actual function object\n    tools_map = {\n        \"get_weather\": get_weather\n    }\n\n    # Define the JSON schema so the LLM knows how to call it\n    tool_definition = {\n        \"type\": \"function\",\n        \"function\": {\n            \"name\": \"get_weather\",\n            \"description\": \"Get the current weather for a location\",\n            \"parameters\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"location\": {\"type\": \"string\"}\n                },\n                \"required\": [\"location\"]\n            }\n        }\n    }\n\n    # 2. The Agent reasoning loop\n    def run_agent(user_prompt):\n        # Initialize the State (Memory)\n        messages = [\n            {\"role\": \"system\", \"content\": \"You are a helpful assistant. Call tools when necessary.\"},\n            {\"role\": \"user\", \"content\": user_prompt}\n        ]\n\n        # Run the loop (max 5 turns to prevent infinite runs)\n        for _ in range(5):\n            response = client.chat.completions.create(\n                model=\"gpt-4o-mini\",\n                messages=messages,\n                tools=[tool_definition]\n            )\n\n            message = response.choices[0].message\n            messages.append(message)\n\n            # Check if the model wants to call a tool\n            if message.tool_calls:\n                for tool_call in message.tool_calls:\n                    name = tool_call.function.name\n                    args = json.loads(tool_call.function.arguments)\n\n                    print(f\"[*] Calling tool: {name} with args: {args}\")\n                    tool_output = tools_map[name](**args)\n\n                    # Append tool response back to state\n                    messages.append({\n                        \"role\": \"tool\",\n                        \"tool_call_id\": tool_call.id,\n                        \"name\": name,\n                        \"content\": tool_output\n                    })\n            else:\n                # If no tool was called, this is the final answer\n                return message.content\n\n    # Run it\n    if __name__ == \"__main__\":\n        result = run_agent(\"What is the weather like in Tokyo right now?\")\n        print(f\"\\n[Agent Response]: {result}\")\n\n\n",
  "title": "Why do we import 100MB of frameworks to run a 50-line LLM reasoning loop?"
}