Writing

Agents with opinions: a weekend multi-agent build

In short: I built a small stock analyzer where five agents, each with a fixed investing style, look at the same company and give their own reading. The per-agent outputs are not the interesting part.…

published
read time
5 min
words
961
lang
en
filed under
Engineering

In short: I built a small stock analyzer where five agents, each with a fixed investing style, look at the same company and give their own reading. The per-agent outputs are not the interesting part. The interesting part is what it takes to make several agents disagree usefully.

Not financial adviceThis is an engineering experiment, built for learning. Nothing here or in the tool is a recommendation to buy or sell anything. Do your own research and talk to a licensed professional before you invest.

Most agent demos I see are one assistant with a long list of tools. I wanted to try the opposite: several narrow agents with strong, different opinions, and a way to put their answers side by side. Markets are a good playground for that because there are well known investing philosophies that flatly contradict each other, and the data is free.

What I built

The shape is boring on purpose. A FastAPI backend, a Next.js frontend, market data from yfinance, and either OpenAI or Anthropic models behind the agents. Every analysis is saved to SQLite or PostgreSQL, so I can look back at what the agents said about a ticker last week.

You type a ticker, tick the agents you want, and press analyze. Each agent comes back with its own signal and a confidence score. Three endpoints do the work: POST /api/analyze, GET /api/agents and GET /api/history/{ticker}.

The cast

AgentPhilosophyLooks atTends to worry about
Value styleIntrinsic value against market price, with a margin of safetyEarnings consistency, durable advantages, quantitative fundamentalsPaying too much
Growth styleGrowth from fundamentals and trendsCompany fundamentals, market opportunitiesMissing the run
Technical stylePrice action and indicatorsRSI, MACD, moving averages, Bollinger Bands, volumeMomentum turning
Sentiment styleWhat the crowd thinksNews and social sentiment, analyst ratings, volume surgesMood shifts
Risk managerProtect the portfolioVolatility, VaR, Sharpe ratio, downside deviationPosition size

Four of the agents are investing styles that have been written about for decades: value, growth, technical and sentiment. The fifth is a role rather than a style, and its only job is risk. The mix matters. Styles give you disagreement. The risk manager gives you a check on it.

Why disagreement is the feature

a mid-cap industrial (made up) value growth technical sentiment risk wary keen wary keen neutral hypothetical example, not real output
Same data, five readings, for a company that does not exist. The readings are hypothetical, and the spread is what you look at.

If you blend five agents into one score you get a number with no story. If you show them side by side you get information: when the value and growth agents agree with the risk manager, that says something about the agents' shared assumptions, not about the stock. When only the technical and sentiment agents are excited, that's another pattern worth reading. The spread tells you more than any single answer.

That's the main design choice in the build. Results come back per agent, each with its own confidence, and the interface puts them next to each other. I'd rather read the spread than a blended score.

Design lessons

Narrow agents, written down principles

Each agent has one philosophy and is told what to look at. A prompt that says "be a value investor" gives you a caricature. A prompt that lists what that philosophy actually checks, intrinsic value against price, consistency of earnings, a moat, gives you something you can argue with. A label is not enough. The principles do the work, not the name.

Numbers from code, judgement from the model

My rule for anything numeric: indicators like RSI, volatility or a Sharpe ratio get calculated in Python, and the model reads them. Asking a language model to compute a moving average is asking for a confident wrong number.

One base class

Every agent inherits from BaseAgent and implements analyze(). Adding a sixth is a new class, one line in the analysis service, and one entry in the frontend list. A simplified sketch of the shape, not the repo's exact code:

class BaseAgent:
    name = "base"

    def analyze(self, ticker: str, data: dict) -> dict:
        raise NotImplementedError

class RiskManager(BaseAgent):
    name = "risk"

    def analyze(self, ticker, data):
        metrics = risk_metrics(data["prices"])     # plain Python, no LLM
        text = self.llm.explain(self.principles, metrics)
        return {"agent": self.name, "signal": text.signal,
                "confidence": text.confidence, "reasoning": text.reasoning}

Work without keys

If no API keys are set, the agents return mock responses. That sounds like a small thing. It meant I could build the whole frontend, the database and the API without spending a cent on tokens, and anyone cloning the project can see it run before deciding to plug in a key.

What I'd change next

Right now the agents don't actually talk to each other. They each read the same data and answer on their own. The disagreement is real, but it's parallel, not a conversation. The next step is a second round where the risk manager reads the other four readings and has to respond to them, or where each agent sees the others and can revise once. That's where multi-agent setups get interesting and where they get expensive, so I want to measure whether a second round changes anything before keeping it.

The saved history matters here too. If an agent flips its signal on the same company from one day to the next with no new data, that's a prompt problem, not a market signal.

If you want to try this pattern, start with two agents that are designed to disagree and one that only judges risk. Run them on the same input, print the answers side by side, and see whether the disagreement teaches you anything. If it doesn't, adding four more agents won't help. And whatever comes out is a demonstration of multi-agent design, not something to trade on.

related

Keep reading