Skip to main content

A backend-agnostic, modular AI orchestration framework for building LLM-powered pipelines with functional building blocks

Project description

DeepMCPAgent Logo

🤖 Functional AI

A backend-agnostic, modular AI orchestration framework for building LLM-powered pipelines with functional building blocks.

Python License Status

Features

  • 🧩 Composable Agents – Every unit of logic is a callable class with clearly defined inputs and outputs
  • 🔁 Looping, Caching, Sequencing – Functional-style orchestration with built-in blocks
  • 🎯 Guardrails and Validation – Input/output validation, retry logic, and error handling
  • 🚀 Parallel Execution – Run independent steps concurrently to speed up pipelines
  • 🧪 Isolated Testing – Each step is easy to test with predictable inputs, no side effects
  • 🛠 Tool Support – Built-in support for tools and MCP extensions with no boilerplate
  • 📦 Backend-agnostic – Compatible with any LLM backend supporting agent-style execution

Example Usage

Using the library requires only a minimal setup. You define your pipeline using simple functional components, then invoke it with a request:

import src.fai as fai

def cat_file(file_path: str, page: int) -> dict:
    ...

def query_wiki(query: str) -> dict:
    ...

def sub_agent_template(question: str, chat_history: List[str]) -> str:
    return (PromptBuilder()
            .file('static/agent_prompt').dash()
            .text("Available files in ../operators").tab()
            .text(', '.join(file_list_operators)).back().dash()
            .text("Available backends in ../backends").tab()
            .text(', '.join(file_list_backends)).back().dash()
            .chat(chat_history).dash()
            .text(f"Question: {question}").dash()
            .prompt)

def main_agent_template(chat_history: List[str],
                        file_agent: str, backend_agent: str, general_agent: str) -> str:
    return (PromptBuilder()
            .file('static/agent_prompt').dash()
            .text("Available files in ../operators").tab()
            .text(', '.join(file_list_operators)).back().dash()
            .text("Available backends in ../backends").tab()
            .text(', '.join(file_list_backends)).back().dash()
            .text(f"File agent response:\n{file_agent}").dash()
            .text(f"Backend agent response:\n{backend_agent}").dash()
            .text(f"General agent response:\n{general_agent}").dash()
            .chat(chat_history)
            .prompt)

def create_sub_agent(question: str, key: str) -> fai.Agent:
    return fai.retry(  # Retry on failure up to 3 times by default
        fai.ai_agent(  # Create a Re-Act style AI agent with tools
            template=lambda chat_history: sub_agent_template(question, chat_history),
            tools=[cat_file, query_wiki],
            key=key))

fai_agent = fai.ai_parallel(  # Run parallel research with multiple agents
    template=main_agent_template,  # Combine the results from subagents
    agents=[
        create_sub_agent("Find the file related to users' question", key="file_agent"),
        create_sub_agent("Find the backend related to users' question", key="backend_agent"),
        create_sub_agent("Find general information related to user's question", key="general_agent")
    ])

fai_chat = fai.cache(  # Cache and reuse the result of this chat
    fai.ai_summarize(  # Summarize the chat at the end
        fai.ai_chat(  # Chat with the user until they say '!done'
            agent=fai_agent, output_llm=print_llm_blue, input_user=input)))

fai_german = fai.ai_transform(  # Transform the cached result
    template=lambda it: f"Translate to German:\n\n{it}", agent=fai_chat)
fai_chinese = fai.ai_transform(
    template=lambda it: f"Translate to Chinese:\n\n{it}", agent=fai_chat)
fai_russian = fai.ai_transform(
    template=lambda it: f"Translate to Russian:\n\n{it}", agent=fai_chat)

if __name__ == '__main__':
    print_success_green(f"German: {fai_german()}")
    print_success_green(f"Chinese: {fai_chinese()}")
    print_success_green(f"Russian: {fai_russian()}")

Architecture Overview

At the core of the library is the concept of an Agent: a minimal ReAct-style component that defines a callable unit of computation. Every block — from single prompt calls to multi-step chains — extends this base. It provides a consistent interface for execution while remaining lightweight and composable.

Each Agent has a unique key, which determines where its result is stored in the pipeline’s shared state. When a component runs, its output is inserted into the kwargs dictionary under this key. This mechanism allows downstream targets to reference the output of upstream ones by name, keeping state passing explicit and traceable.

State is passed between all these components through keyword arguments (**kwargs). Each step reads what it needs and adds its own result, keeping everything side-effect-free and easy to follow.

Rather than relying on a graph or node-based model, the architecture favors flat, functional composition. This choice makes it easier to reason about flow, debug intermediate outputs, and write unit tests. Since targets are pure functions, they can be reused freely across pipelines without worrying about shared state or lifecycle side effects.

The result is a system where each block does one thing well, and all parts — from prompt execution to synthesis — are modular, testable, and extensible.

Backend Support

A backend in this library provides the runtime environment for LLM execution. It is responsible for setting up sessions, managing tool access, configuring the model, and executing prompts.

The default backend is GoogleAdkBackend, which wraps a ReAct-style agent using the Google Assistant Developer Kit (ADK). It supports streaming output, tool usage, and agent configuration (e.g., instructions, description, tool restrictions).

However, the system is backend-agnostic by design. You can support OpenAI, Anthropic, or even local LLMs by implementing your own backend class and swapping it in:

def get_backend():
    return MyCustomBackend()

As long as the backend exposes create_runner() and call_agent(), it can be plugged into the rest of the system without modifying any functional components. This makes it easy to port the entire agent pipeline across platforms or environments.

Contributions Welcome

Community contributions are welcome — especially around tool extensions, backend integrations, and improving developer ergonomics. Pull requests, feature suggestions, and experiments are all encouraged. If you're building your own research or agent pipelines, feel free to fork and adapt.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fun_ai_lib-0.2.0.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fun_ai_lib-0.2.0-py3-none-any.whl (18.7 kB view details)

Uploaded Python 3

File details

Details for the file fun_ai_lib-0.2.0.tar.gz.

File metadata

  • Download URL: fun_ai_lib-0.2.0.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.12

File hashes

Hashes for fun_ai_lib-0.2.0.tar.gz
Algorithm Hash digest
SHA256 699c03d371e4bb4de804ba25a8fb14ccf0b66068fd6b357927b5f1ce68cffc18
MD5 f84ee55ba731b5e0f1dab981e6c4b7fa
BLAKE2b-256 cbb8ed971a5b246569ffe1c0b0ce6670220b0439ff449043a99e5bb0ed220f34

See more details on using hashes here.

File details

Details for the file fun_ai_lib-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fun_ai_lib-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.12

File hashes

Hashes for fun_ai_lib-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b0ba31fa0b66fa789c3aeca2005fde90f0835b7c1ea8513cbcdd4ed3fc3ad79a
MD5 0102b56e15191b773eed2a5f7ce6d90e
BLAKE2b-256 3d56a0d97d2e456ecace6749b57bcdccd6dd2da8a54a684d1e7b48dfc6735119

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page