Universal Transformation Framework: Building Cross-Framework AI Agents

Universal Transformation Framework: Building Cross-Framework AI Agents

The AI ecosystem is evolving rapidly, with new frameworks and models emerging constantly. For developers building LLM-powered applications, this presents a challenge: how do you build applications that aren’t tied to a specific framework or vendor? At knify, we’ve developed a Universal Transformation Framework that addresses this challenge head-on, allowing you to define AI agents once and deploy them across multiple frameworks.

The Multi-Framework Challenge

If you’ve worked with LLMs in production, you’ve likely encountered these challenges:

  • You start with one framework (like LangChain) but later need features from another
  • A new model or service emerges that requires a different framework
  • Different parts of your stack use different languages (Python, TypeScript, Go)
  • Costs or performance lead you to switch providers

Traditionally, these transitions require significant rewrites, sometimes from scratch. Our Universal Transformation Framework offers a better way.

The Universal Agent Specification

At the core of our approach is a framework-agnostic specification for AI agents. Here’s a simplified example:

// A universal agent specification in Go
type UniversalAgentSpec struct {
    Name         string
    Model        string
    SystemPrompt string
    Query        string
    Temperature  float64
}

// Example agent definition
myAgent := UniversalAgentSpec{
    Name:         "CustomerSupportAgent",
    Model:        "gpt-4",
    SystemPrompt: "You are a helpful customer support agent for a software company.",
    Query:        "How can I help you today?",
    Temperature:  0.7,
}

This specification is deliberately simple and focuses on the core attributes that define an agent’s behavior rather than the implementation details of how it runs.

Transforming Across Frameworks and Languages

The magic happens in the transformation layer. Using AST (Abstract Syntax Tree) parsing and code generation techniques, our framework can:

  1. Parse a universal specification from source code
  2. Transform it into code for different target frameworks
  3. Generate implementations in different programming languages

For example, our transformation engine can turn the Go specification above into Python code for LangChain:

# Generated Python code for LangChain
from langchain.chat_models import ChatOpenAI
from langchain.schema import SystemMessage, HumanMessage

chat = ChatOpenAI(
    model_name="gpt-4",
    temperature=0.7
)

system_message = SystemMessage(content="You are a helpful customer support agent for a software company.")
human_message = HumanMessage(content="How can I help you today?")

response = chat([system_message, human_message])

Or into TypeScript code for another framework:

// Generated TypeScript code for another framework
import { Agent } from "some-other-framework";

const agent = new Agent({
  name: "CustomerSupportAgent",
  model: "gpt-4",
  systemPrompt:
    "You are a helpful customer support agent for a software company.",
  initialMessage: "How can I help you today?",
  settings: {
    temperature: 0.7,
  },
});

How It Works: AST Parsing and Code Generation

Under the hood, our transformation engine uses several powerful techniques:

1. AST Parsing to Extract Specifications

We use language-specific Abstract Syntax Tree (AST) parsers to read source code and extract the universal specifications. For example, in Go:

func parseAgentSpecFromGoFile(filename string) (UniversalAgentSpec, error) {
    fset := token.NewFileSet()
    node, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
    if err != nil {
        return UniversalAgentSpec{}, err
    }

    var spec UniversalAgentSpec

    ast.Inspect(node, func(n ast.Node) bool {
        // Logic to identify and extract UniversalAgentSpec from the AST
        // ...
        return true
    })

    return spec, nil
}

2. Templating for Code Generation

We use template engines to generate code for target frameworks:

func generatePydanticCode(spec UniversalAgentSpec) (string, error) {
    const tmpl = `
from pydantic import BaseModel
from typing import Optional

class {{.Name}}(BaseModel):
    model: str = "{{.Model}}"
    system_prompt: str = """{{.SystemPrompt}}"""
    temperature: float = {{.Temperature}}

    def run(self, query: str = "{{.Query}}"):
        # Implementation details...
        pass
`
    // Use template engine to render the code
    // ...
}

3. Framework-Specific Adapters

Each target framework has an adapter that handles its specific requirements and best practices:

type FrameworkAdapter interface {
    GenerateCode(spec UniversalAgentSpec) (string, error)
    ValidateSpec(spec UniversalAgentSpec) error
}

type LangChainAdapter struct{}
type PydanticAdapter struct{}
// ...

Practical Applications in knify

In the knify ecosystem, the Universal Transformation Framework enables several powerful capabilities:

Framework Migration

When you need to move from one framework to another:

$ knify transform agent.go --from go --to python --framework langchain

Multi-Framework Deployment

Deploy the same agent definition to multiple frameworks simultaneously:

# In knify's Python API
agent_spec = load_universal_spec("agent.go")
langchain_agent = transform_to_langchain(agent_spec)
llama_index_agent = transform_to_llama_index(agent_spec)

Cross-Language Teams

Enable collaboration between teams using different languages:

# Python team defines agent:
customer_agent.py → universal_spec → typescript_agent.ts
# TypeScript team can use it directly

Beyond Simple Agents: Handling Complex Behavior

The examples so far have been simple, but our framework scales to complex agent behaviors:

  • Tool/Function Calling: Universal specifications for tools and function calling
  • Memory and State: Framework-agnostic definitions for memory systems
  • Custom Workflows: Specifications for multi-step agent interactions
type UniversalTool struct {
    Name        string
    Description string
    Parameters  []ToolParameter
    Handler     string // References function name in host language
}

type UniversalMemory struct {
    Type        string // "buffer", "summary", "vector", etc.
    Capacity    int
    Persistence string // "session", "user", "global"
}

Try It Today

The Universal Transformation Framework is available as part of the knify toolkit. To get started:

  1. Define your agents using our universal specification
  2. Use our CLI tools or APIs to transform them
  3. Deploy across frameworks without rewriting your core logic

In our next article, we’ll dive into PML (Python Markup Language) and how it’s enhancing the Python development experience with advanced compiler and highlighter systems.

Stay tuned for more insights into how knify is reshaping modern web development!