← All Blogs

Building an AI-Powered Function Orchestrator: When AI Becomes Your Code Planner

2 October, 2025

Building an AI-Powered Function Orchestrator: When AI Becomes Your Code Planner blog

As developers, we constantly face a dilemma: how do we make our code flexible enough to handle natural human requests without hardcoding every possible scenario?

While working on various automation projects, I kept running into the same pattern—users would ask for something in plain English, like "Can you calculate 2+25-4^2? or "Process these files and send me a summary", but my code was rigid, expecting specific formats and predefined workflows.

The breakthrough came when I realized: What if AI handled the planning, and I just focused on building solid, reusable functions? Instead of trying to anticipate every user request, let AI interpret the intent and dynamically orchestrate my functions.

This post walks through building a mini AI agent framework that separates what you can do (functions) from how to do it (AI planning). The result? Code that adapts to human intent rather than forcing humans to adapt to your interface.

The Problem: Traditional Code vs. Human Intent

How many times have you written code that looks like this?

def complex_math_solver(expression):
    # Parse expression
    # Apply PEMDAS rules
    # Handle edge cases
    # Return result
    pass

The problem? You're cramming parsing logic, mathematical rules, and execution into one monolithic function. What if we could separate these concerns entirely?

The Solution: AI as a Function Orchestrator

Instead of hardcoding business logic, what if we let AI handle the planning while we focus on building atomic, reusable functions?

Here's the architecture:

Step 1: Define Atomic Functions

First, we create simple, single-purpose functions that do one thing well. Think of these as your building blocks—each function is pure, testable, and completely independent. The key is keeping them atomic so AI can combine them in any order to solve complex problems.

def sum(a, b):
    return a + b

def multiply(a, b):
    return a * b

def power(a, b):
    return a ** b

# Function registry for dynamic execution
FUNCTIONS = {
    "sum": sum,
    "multiply": multiply,
    "power": power,
}

Step 2: Document Your Functions (For AI)

Next, we create clear documentation for each function. This isn't just good practice — it's essential for AI to understand what each function does and how to use it. Think of this as your function's "instruction manual" that AI reads to make smart planning decisions.

DOCS = {
    "sum": {
        "description": "Add two numbers",
        "args": {
            "a": {
                "type": "number",
                "description": "a float or int number",
            },
            "b": {
                "type": "number",
                "description": "a float or int number",
            },
        },
    },
    "multiply": {
        "description": "Multiply two numbers",
        "args": {
            "a": {
                "type": "number",
                "description": "a float or int number",
            },
            "b": {
                "type": "number",
                "description": "a float or int number",
            },
        },
    },
    "power": {
        "description": "Raise a to the power of b",
        "args": {
            "a": {
                "type": "number",
                "description": "a float or int number",
            },
            "b": {
                "type": "number",
                "description": "a float or int number",
            },
        },
    },
}

Step 3: Let AI Generate Execution Plans

Finally, we let AI do the heavy lifting — interpreting natural language requests and creating step-by-step execution plans. The AI uses your function documentation to understand what's possible, then figures out the optimal sequence to achieve the user's goal.

def get_action_plan(user_query):
    prompt = f"""
    You are an AI planner. Convert the user's request into a step-by-step plan.

    Available functions:
    {json.dumps(DOCS, indent=2)}

    User's query: "{user_query}"

    Return a JSON plan with ordered steps.
    """

    response = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        temperature=0
    )
    return json.loads(response.choices[0].message.content)

Real Example: "Solve 2+2*5+4^2"

When a user sends this request to the system, it gets passed to OpenAI along with the function documentation. The AI analyzes the mathematical expression, applies PEMDAS rules, and returns a structured JSON plan that breaks down the calculation into atomic steps using the available functions.

Input: Natural language request
AI Output: Structured execution plan

{
  "steps": [
    { "function": "power", "args": { "a": 4, "b": 2 } },
    { "function": "multiply", "args": { "a": 2, "b": 5 } },
    { "function": "sum", "args": { "a": 2, "b": "<result_of_step_2>" } },
    {
      "function": "sum",
      "args": { "a": "<result_of_step_3>", "b": "<result_of_step_1>" }
    }
  ]
}

Execution Output:

Step 1: power(4, 2) → 16
Step 2: multiply(2, 5) → 10
Step 3: sum(2, 10) → 12
Step 4: sum(12, 16) → 28

Final Result: 28

The Magic: Dynamic Plan Execution

This function takes the AI-generated plan and executes it step by step. The key insight is result chaining—each step can reference outputs from previous steps using placeholders like <result_of_step_1>. The system automatically resolves these references, creating a dynamic pipeline where complex calculations emerge from simple function compositions.

def execute_plan(plan):
    results = {}
    for idx, step in enumerate(plan["steps"], start=1):
        func_name = step["function"]
        args = step["args"]

        # Replace placeholders with previous results
        for k, v in args.items():
            if isinstance(v, str) and v.startswith("<result_of_step_"):
                step_idx = int(v.split("_")[-1].replace(">", ""))
                args[k] = results[step_idx]

        # Execute function dynamically
        func = FUNCTIONS[func_name]
        result = func(**args)
        results[idx] = result

        print(f"Step {idx}: {func_name}({args}) → {result}")

    return results[len(results)]

Why This Architecture Wins

Separation of Concerns

  • You write: Pure, testable functions

  • AI handles: Complex planning and orchestration

  • System manages: Execution flow and state

Human-in-the-Loop Safety

if "error" in plan:
    print("❌ Error in plan generation:")
    print(plan["error"]["message"])
    sys.exit(1)  # Safe exit on planning failures

For example, if a user asks "Divide 10 by 0 and add 5", the AI can detect this is mathematically impossible and return an error response like:

{
  "error": {
    "message": "Cannot divide by zero - this operation is undefined in mathematics"
  }
}

This prevents dangerous operations from executing and provides clear feedback to users.

Infinite Extensibility

Today, it's math functions:

FUNCTIONS = {
    "sum": sum,
    "multiply": multiply,
    "divide": divide
}

Tomorrow it could be anything:

FUNCTIONS = {
    "read_file": read_file,
    "send_email": send_email,
    "query_database": query_db,
    "fetch_weather": weather_api,
    "analyze_sentiment": sentiment,
}

Real-World Applications

File Operations

"Take all .txt files in /docs, extract headings, and create a summary document"

Required Functions: list_files(), read_file(), extract_headings(), create_document(), write_file()

API Orchestration

"Get weather for New York, if it's raining, send a Slack message to #general"

Required Functions: fetch_weather(), check_condition(), send_slack_message()

Data Pipeline

"Load sales.csv, calculate monthly averages, generate a chart, and email it to the team"

Required Functions: load_csv(), calculate_average(), group_by_month(), generate_chart(), send_email()

MCP Server Integration

"Query our customer database, analyze sentiment of recent feedback, and create a dashboard"

Required Functions: query_database(), analyze_sentiment(), aggregate_data(), create_dashboard(), save_report()

The Bigger Picture

This isn't just a math solver — it's a mini AI agent framework. The system provides:

  1. Function Library: Atomic, reusable components

  2. AI Planner: Intelligent request interpretation

  3. Execution Engine: Safe, traceable function orchestration

  4. Human Oversight: Approval and error handling

What's Next?

  1. Add more function types (file ops, API calls)

  2. Implement approval workflows (show plan before execution)

  3. Add function validation (type checking, parameter validation)

  4. Build a web interface (make it accessible to non-developers)

  5. Integrate with MCP servers (extend to complex business logic)

The bottom line: Stop hardcoding business logic. Let AI handle the planning, you handle the implementation. The result? More flexible, maintainable, and extensible code that adapts to user intent rather than forcing users to adapt to your interface.

🚀 Come Join my Newsletter

I share tips on how to get started with freelancing, remote jobs, developer-related stuff, startup ecosystem, and lots of insider secrets with my subscribers.

Subscribe →
🧠 More Interesting Reads
Building a Smart Session Tracker for Your Mac's Menu Bar
How I Learned to Stop Worrying and Love Bash Scripts (While Actually Taking Breaks)
How to enable in-app Notifications using TinyMCE APIs
Notifications add value to an app by helping to build conversations between users. They can also help make an interface less hostile by sharing important information. And it’s because they’re so useful that you’re being flooded by feature requests th...
REST vs SOAP: why we recommend REST APIs for A2P messaging
Many businesses use messaging APIs to simplify communications with stakeholders and customers. Business short message service (SMS) tools enable organizations to implement one-time password (OTP) verification, alerts, reminders, and other types of cu...