SYNAPSE
RU
Guides

How to Build an AI Agent: A Step-by-Step Guide with Code

A practical guide to creating an AI agent: from choosing a model to launching with RAG and MCP. Python code that you can run right away.

What You'll Need

  • Python 3.9 or newer.
  • An API key from OpenAI (or another provider). You can get one in your account on the provider's platform.
  • Installed libraries: openai, requests, faiss-cpu, numpy.
  • A text editor or IDE.
  • Basic understanding of Python and HTTP requests.

All code examples below assume that you replace YOUR_KEY with the real key. The key can be stored in an environment variable so as not to expose it in the code.

Step 1: Install Dependencies and Set Up the Key

Create a virtual environment and install the packages:

python -m venv agent-env
source agent-env/bin/activate  # for Windows: agent-env\Scripts\activate
pip install openai requests faiss-cpu numpy

Save the key in an environment variable (Linux/macOS):

export OPENAI_API_KEY="YOUR_KEY"

For Windows (cmd):

set OPENAI_API_KEY=YOUR_KEY

Check that the key works:

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hi! Answer with one word."}]
)
print(response.choices[0].message.content)

If you see a response, the key is active.

Step 2: Create a Simple Agent with a Weather Function

An agent differs from a model in that it can call tools. Let's write a function that returns a dummy weather (for demonstration) and teach the model to call it.

Шаг 2: Создайте простого агента с функцией погоды
import json
from openai import OpenAI

client = OpenAI()

def get_weather(city: str) -> str:
    # Stub: in reality, there would be a request to a weather API here.
    return f"In {city} it is currently +15°C, cloudy."

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Returns the current weather in a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name"}
            },
            "required": ["city"]
        }
    }
}]

messages = [{"role": "user", "content": "What is the weather in Moscow?"}]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
)

msg = response.choices[0].message
if msg.tool_calls:
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_weather(args["city"])
        messages.append(msg)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": result
        })
    final = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages
    )
    print(final.choices[0].message.content)
else:
    print(msg.content)

Run it — the agent will call the function and return a response with the weather.

Step 3: Add RAG for Working with Documents

RAG (Retrieval-Augmented Generation) allows the agent to answer questions based on your data. Let's implement a simple search over text fragments.

import numpy as np
import faiss
from openai import OpenAI

client = OpenAI()

# Example knowledge base: list of texts
docs = [
    "Vacation at the company is 28 calendar days.",
    "A vacation request is submitted two weeks before the start.",
    "Sick leave is paid based on average earnings."
]

# Get embeddings for the documents
embeddings = []
for text in docs:
    resp = client.embeddings.create(input=text, model="text-embedding-3-small")
    embeddings.append(resp.data[0].embedding)

# Create a FAISS index
index = faiss.IndexFlatL2(len(embeddings[0]))
index.add(np.array(embeddings).astype('float32'))

def retrieve(query: str, k: int = 2):
    q_emb = client.embeddings.create(input=query, model="text-embedding-3-small").data[0].embedding
    distances, indices = index.search(np.array([q_emb]).astype('float32'), k)
    return [docs[i] for i in indices[0]]



<figure class="post-fig"><img src="/media/inline-1793422159.jpg" alt="Шаг 3: Добавьте RAG для работы с документами" loading="lazy"></figure>



# Example query
question = "How many vacation days?"
context = retrieve(question)
prompt = f"Answer the question using the context:\n{context}\n\nQuestion: {question}"
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}]
)
print(response.choices[0].message.content)

The agent will find the relevant fragment and answer based on it.

Step 4: Connect MCP to Call an External Service

MCP (Model Context Protocol) allows the agent to access external tools through a standardized interface. In the example, we use a simple HTTP service (a stub). In reality, an MCP server can be running locally or remotely.

import requests

def call_mcp_tool(tool_name: str, params: dict) -> dict:
    # Example: calling a local MCP server (stub)
    # In reality, the URL and format depend on the MCP server implementation.
    url = "http://localhost:8000/mcp"
    payload = {"tool": tool_name, "parameters": params}
    try:
        resp = requests.post(url, json=payload, timeout=5)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}

# Usage in the agent: add the tool description to tools and handle the call

This step requires an MCP server to be running. Without it, the call will return a connection error — this is normal for testing.

Step 5: Put Everything Together

Combine the weather function, RAG, and MCP call in a single agent. Logic: first search the knowledge base, then call tools if necessary.

# Pseudocode for the structure
# 1. Get the user request.
# 2. Execute retrieve() to find context.
# 3. Pass the context and request to the model with tool descriptions.
# 4. If the model returned tool_calls — execute the corresponding functions.
# 5. Return the final answer.

The full code can be assembled from the previous steps by adding branching.

Common Mistakes and How to Recognize Them

  • Authentication error (401) — the key is incorrect or not passed. Check the environment variable.
  • The model does not call the tool — the function description lacks clear parameters or the model does not understand the task. Simplify the description, add examples to description.
  • RAG returns irrelevant fragments — too few documents or the embeddings are unsuitable. Increase k or check the quality of the texts.
  • MCP server is unavailable — check whether the server is running and whether the URL is correct. A connection error is a clear sign.
  • The agent loops — limit the number of steps (for example, no more than 5 tool calls).

By following the steps, you will get a working agent that can answer questions based on your data and call external functions.

↗ Primary source: vc.ru