Hello World Agent

One tool, one question, one file — the same agent in every framework.

View as Markdown

Every example on this page builds the same agent: a get_weather tool wired to an LLM in a ReAct loop. The LLM reasons about what to do, acts by calling the tool, observes the result, then returns a final answer.

The same code works with OpenAI, any OpenAI-compatible endpoint (vLLM, Ollama, RHOAI Model-as-a-Service), or a locally hosted model — just change the environment variables. Pick your framework below to jump to a working example.

How it works

Every framework implements the same loop under different abstractions:

  1. The LLM sees the user message and the list of available tools.
  2. If the LLM decides it needs information, it emits a tool call (e.g. get_weather("Portland")).
  3. The framework executes the tool and feeds the result back to the LLM.
  4. The LLM either calls another tool or returns a final answer.

A tool is any Python function with a docstring. The framework converts it to a function schema automatically — the function name becomes the tool name, the docstring becomes the description, and type hints become the parameter schema.

Running it

Each example reads model connection details from environment variables. Install the framework's dependencies (shown in the requirements.txt tab), set the env vars below, and run python agent.py.

OpenAI

Environment variables
export OPENAI_API_KEY="sk-..."

Local or hosted model

Any OpenAI-compatible API works — vLLM, Ollama, RHOAI Model-as-a-Service, LM Studio, or any other server that implements the /v1/chat/completions endpoint with tool calling support.

Environment variables
# Any OpenAI-compatible endpoint: vLLM, Ollama, RHOAI MaaS, etc.
export OPENAI_BASE_URL="http://maas.apps.my-cluster.example.com/v1"
export OPENAI_MODEL_NAME="gemma4"
export OPENAI_API_KEY="your-token-here"

The model must support tool calling (function calling) for the ReAct loop to work. Models known to work: Gemma 4, Llama 4 Scout, Llama 3.1+, Mistral Instruct v0.3+, Qwen 2.5+.

Sample output
human: What's the weather in Portland?
ai:
tool: The weather in Portland is sunny, 72 F.
ai: The weather in Portland is currently sunny and 72 F.

Agent Frameworks

LangGraph

LangGraph provides create_react_agent — a one-liner that wires tools into the reason → act → observe loop. It uses ChatOpenAI under the hood, which reads OPENAI_API_KEY and OPENAI_BASE_URL from the environment automatically.

create_react_agent() — ReAct loop in one function call
"""Hello World ReAct agent — LangGraph."""

import os
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent


def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny, 72 F."


llm = ChatOpenAI(
    model=os.environ.get("OPENAI_MODEL_NAME", "gpt-4o-mini"),
    base_url=os.environ.get("OPENAI_BASE_URL"),
    api_key=os.environ.get("OPENAI_API_KEY"),
)
agent = create_react_agent(
    llm,
    tools=[get_weather],
    prompt="You are a helpful assistant. When you receive a tool "
           "result, summarize it as a final answer.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What's the weather in Portland?"}]}
)

for msg in result["messages"]:
    print(f"{msg.type}: {msg.content}")

CrewAI

CrewAI models agents as role-playing team members. Even for a single agent, you define a role, goal, and backstory. Tools are decorated with @tool. The LLM wrapper accepts an openai/ model prefix to target any OpenAI-compatible endpoint.

Crew + Agent + Task — Role-based agent with tool use
"""Hello World agent — CrewAI."""

__import__("pysqlite3")
import sys
sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")

import os
from crewai import Agent, Task, Crew, LLM
from crewai.tools import tool


@tool("get_weather")
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny, 72 F."


llm = LLM(
    model=f"openai/{os.environ.get('OPENAI_MODEL_NAME', 'gpt-4o-mini')}",
    base_url=os.environ.get("OPENAI_BASE_URL"),
    api_key=os.environ.get("OPENAI_API_KEY"),
)

agent = Agent(
    role="Weather Reporter",
    goal="Look up weather using the get_weather tool and summarize the result",
    backstory="You are a helpful weather assistant. Always use your tools "
              "to get data, then write a clear summary as your final answer.",
    llm=llm,
    tools=[get_weather],
    max_iter=5,
    max_retry_limit=3,
)

task = Task(
    description="What is the weather in Portland? Use the get_weather tool "
                "to find out, then respond with a one-sentence summary.",
    expected_output="A single sentence like: The weather in Portland is ...",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
print(result.raw)

AutoGen

AutoGen uses an async-first design. An AssistantAgent wraps a model client and a list of tools — call agent.run() to execute. The OpenAIChatCompletionClient connects to any OpenAI-compatible endpoint.

AssistantAgent + run() — Async agent with tool calling
"""Hello World agent — AutoGen."""

import os
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient


def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny, 72 F."


model_name = os.environ.get("OPENAI_MODEL_NAME", "gpt-4o-mini")
model_client = OpenAIChatCompletionClient(
    model=model_name,
    base_url=os.environ.get("OPENAI_BASE_URL"),
    api_key=os.environ.get("OPENAI_API_KEY"),
    model_info={
        "vision": False,
        "function_calling": True,
        "json_output": True,
        "structured_output": True,
        "family": "unknown",
    },
)

agent = AssistantAgent(
    name="weather_agent",
    model_client=model_client,
    tools=[get_weather],
)


async def main():
    result = await agent.run(task="What's the weather in Portland?")
    print(result.messages[-1].content)


asyncio.run(main())

LlamaIndex

LlamaIndex uses AgentWorkflow with an explicit ReActAgent for text-based tool calling — more reliable than function calling with non-OpenAI models. Use OpenAILike instead of OpenAI for custom model names — it accepts any OpenAI-compatible endpoint via api_base.

ReActAgent + AgentWorkflow — Text-based ReAct loop with OpenAILike
"""Hello World ReAct agent — LlamaIndex."""

import os
import asyncio
from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.openai_like import OpenAILike


def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny, 72 F."


llm = OpenAILike(
    model=os.environ.get("OPENAI_MODEL_NAME", "gpt-4o-mini"),
    api_base=os.environ.get("OPENAI_BASE_URL"),
    api_key=os.environ.get("OPENAI_API_KEY"),
    is_chat_model=True,
    is_function_calling_model=False,
    context_window=128000,
)

react_agent = ReActAgent(
    name="weather_agent",
    description="Looks up the weather",
    tools=[FunctionTool.from_defaults(fn=get_weather)],
    llm=llm,
)

agent = AgentWorkflow(agents=[react_agent], root_agent="weather_agent")


async def main():
    response = await agent.run("What's the weather in Portland?")
    print(response)


asyncio.run(main())

Google ADK

Google Agent Development Kit builds agents using Gemini models natively, but supports any OpenAI-compatible endpoint via its LiteLlm integration. The openai/ model prefix tells LiteLLM to use the OpenAI chat completions API. Tools are plain Python functions passed to the Agent constructor.

Agent + LiteLlm + Runner — Async agent via LiteLLM
"""Hello World agent — Google ADK."""

import os
import asyncio
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types


def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny, 72 F."


model = LiteLlm(
    model=f"openai/{os.environ.get('OPENAI_MODEL_NAME', 'gpt-4o-mini')}",
    api_base=os.environ.get("OPENAI_BASE_URL"),
    api_key=os.environ.get("OPENAI_API_KEY"),
)

agent = Agent(
    name="weather_agent",
    model=model,
    description="A helpful weather assistant",
    instruction="Help users check the weather. "
                "Use the get_weather tool when asked.",
    tools=[get_weather],
)

session_service = InMemorySessionService()
runner = Runner(
    agent=agent, app_name="weather_app",
    session_service=session_service,
)


async def main():
    session = await session_service.create_session(
        app_name="weather_app", user_id="user1",
    )
    message = types.Content(
        role="user",
        parts=[types.Part(text="What's the weather in Portland?")],
    )
    async for event in runner.run_async(
        user_id="user1", session_id=session.id,
        new_message=message,
    ):
        if event.is_final_response():
            print(event.content.parts[0].text)


asyncio.run(main())

Deploy on OpenShift

You can build and run any of the agents above on OpenShift using a UBI 9 Python 3.12 multi-stage build. The Dockerfile uses S2I assemble to install dependencies in a builder stage, then copies the virtual environment into a minimal runtime image.

Build the image

Create the Dockerfile, copy your agent.py and requirements.txt into an app-src/ folder, create a binary BuildConfig, and start the build:

Build steps
# Create the Dockerfile
cat <<'EOF' > Dockerfile
# build
FROM registry.access.redhat.com/ubi9/python-312:latest as builder
USER 0
ADD app-src /tmp/src
RUN /usr/bin/fix-permissions /tmp/src
USER 1001
RUN /usr/libexec/s2i/assemble
# deploy
FROM registry.access.redhat.com/ubi9/python-312-minimal:latest
COPY --from=builder /opt/app-root /opt/app-root
USER 1001
CMD ["python", "agent.py"]
EOF

# Copy source files into app-src/
mkdir app-src
cp agent.py app-src/agent.py
cp requirements.txt app-src/requirements.txt

# Create an OpenShift project (you must be logged in)
oc new-project basic-agents

# Create a binary build config
oc -n basic-agents new-build --binary --name=agent

# Start the build and follow the logs
oc -n basic-agents start-build agent --from-dir=. --follow

Export env vars

Set your model connection details before creating the pod:

Environment variables
export OPENAI_API_KEY=<your-key>
export OPENAI_MODEL_NAME=<your-model>
export OPENAI_BASE_URL=<your-endpoint>

Run the agent

Once the build completes, run the agent as a one-shot pod:

Run the agent
oc -n basic-agents run agent \
  --restart=Never \
  --image=image-registry.openshift-image-registry.svc:5000/basic-agents/agent:latest \
  --env OPENAI_API_KEY=$OPENAI_API_KEY \
  --env OPENAI_MODEL_NAME=$OPENAI_MODEL_NAME \
  --env OPENAI_BASE_URL=$OPENAI_BASE_URL

Check the logs

Pod logs
oc -n basic-agents logs agent

Clean up

Delete build and pod
oc -n basic-agents delete bc,is,pod agent