Skip to content
AM
← All posts

Building a personal AI agent on n8n: four workflows, one bot

Published · 5 min read

Most of my work is data platforms: pipelines, lakehouses, the plumbing that analytics and ML sit on. So when School 21 handed me a project to build a personal AI agent, I treated it the way I treat any pipeline. Where does the data come from, what transforms it, what can go wrong, and what does it cost per run?

This post walks through what I built, the decisions behind it, and the parts I would rebuild before trusting it with anything that matters.

The problem

A student at School 21 faces the same handful of questions over and over. Which track should I take? What is happening in my field this week? Which skills are employers actually asking for? What should I study next, and in what order?

Each of those is a small research task. Done by hand, each one means opening a chat with an LLM, explaining your situation again, copying results from one place to another and checking everything yourself. The goal was to replace that with an agent that already knows the context, runs on a schedule where it makes sense, and delivers results to one place: Telegram.

The stack

  • n8n, self-hosted in Docker on Cloud.ru Container Apps. Hosting it myself instead of using n8n Cloud was part of the brief, and it is the right instinct anyway: you learn where the moving parts are when you have to deploy them.
  • GigaChat 2 Max through Cloud.ru Foundation Models, wired into n8n's OpenAI Chat Model node. The API is OpenAI-compatible, with one catch: the Responses API toggle has to be off.
  • Telegram as the only interface: a bot for conversations and a private channel for digests.
  • Tavily for web search, the HH.ru API for job postings, and RSS as a bridge to public Telegram channels.

Four workflows

1. The adviser

A conversational bot that helps choose a track: data science, DevOps, QA, analytics, security, UX/UI, project management, bioinformatics or software development.

Telegram Trigger → AI Agent (GigaChat 2) → Send message
                      ↑
               Simple Memory (keyed by chat ID)

The agent lives in its system prompt. It has one role (a career consultant for School 21 students), one goal (a recommendation), and a fixed script: eight questions, one at a time, waiting for each answer. Interests, prior experience, preferred pace, remote or office, strengths and weaknesses, and so on. After the last answer it writes the recommendation.

Two details matter more than they look:

  • Memory is keyed by the Telegram chat ID. Without that, every user would share one conversation.
  • The script is strict on purpose. An open-ended "help me choose a career" prompt produces a friendly chat that never ends. A numbered list of questions produces a decision.

2. The daily news digest

Every morning at 9:00 the workflow pulls the latest posts from three public Telegram channels, summarises them and posts one digest to my private channel.

Schedule (09:00) → RSS × 3 → Limit 5 each → Merge → Aggregate → AI Agent → Telegram channel

A bot can't read a public channel it doesn't administer, so each channel goes through an RSS service first. The Limit nodes are the cost control: five posts per channel, at most, no matter how chatty a channel was overnight. One aggregated call to the model is cheaper and more coherent than fifteen separate ones.

The output has a fixed shape: a one-paragraph summary of everything, then each channel with its post count and a one-line description and link per post.

3. The weekly job-market digest

Every Saturday the workflow queries the HH.ru API for fresh ML engineer postings in Moscow, asks the model to extract and normalise the requirements, and posts the fifteen most frequent ones.

Schedule (Sat 09:00) → HTTP Request (HH.ru) → AI Agent → Telegram channel

During development I capped it at three postings per run. Every posting is tokens, and you debug a prompt many times before it behaves.

This is the workflow I trust least, and the next post is entirely about why: an LLM is a bad counter, and the output showed it.

4. The mentor

The most involved one. You tell the bot what you want to learn and at what level. It builds a plan of five to eight topics with three to six concepts each, asks you to confirm, and then sends one short lesson at a time, never repeating a concept, using web search to keep the material current.

Telegram Trigger → AI Agent (+ Tavily, + memory) → Code (state machine) → Send message

The interesting part is the Code node. Instead of trusting the conversation history to remember where the user is, it keeps an explicit state per chat in n8n's workflow static data: asking for the goal, asking for the level, waiting for the plan, sending lessons, done. The LLM writes content; the code decides what happens next. I wrote that part up separately because the pattern is useful far beyond this bot.

Decisions worth explaining

Self-hosting over n8n Cloud. For a toy, Cloud is faster. For anything you'll run for months, owning the container means you control versions, secrets and where the data goes.

Telegram as the only interface. No web app to build, notifications for free, and it is where I already read things.

Fixed output formats in every prompt. Every workflow ends in a message a human reads, so every prompt specifies the exact shape of the answer. Free-form output is fine in a chat; in a scheduled digest it is a bug.

Small limits everywhere. Posts per channel, postings per run, users kept in state. An agent that runs on a schedule spends money while you sleep, so the limits are part of the design.

Anonymise before you send. Everything goes to an external API and may be logged there, so nothing identifying goes into a prompt. "My time on the platform is in the top 5%" works as well as a name and a rank.

What I would change for production

  • Take counting away from the model. Extract skills per posting as structured JSON, normalise them with a dictionary, and count in code. The model writes the sentence at the end, nothing more.
  • Move state out of workflow static data. It works for one user and a handful of friends. For more, it belongs in Postgres or Redis with an expiry, not in a blob that a redeploy can wipe.
  • Validate every model output before it reaches Telegram: parse it, check the format, retry or fall back if it is wrong.
  • Log runs and costs. Tokens per run, failures per week. If it isn't measured, it will quietly get expensive or quietly stop working.
  • Pin the model version. A provider update can change behaviour overnight; a pinned version plus a few saved test prompts catches that before users do.

What I took away

An agent is mostly ordinary engineering around a language model: triggers, limits, state, output contracts and monitoring. The model is the one component you can't fully predict, so the job is to make everything around it as predictable as possible.

Next in this series: why I'll never let an LLM count again, and the small state machine that keeps a chat bot from losing its place.