*I wrote this post to enter the Google × Devpost All Things Agentic
hackathon (https://allthingsagentichackathon.devpost.com/). The project is SupplyMe,
submitted in the Taskmaster category*
I wanted 500 units of a 50ml fragrance made in Indonesia, on a first-batch
budget.
Five hundred is a small order, and small orders are where the B2B marketplaces
stop being useful to you. The factories I wanted were not listed on any of them.
The ones that were listed sorted by ad spend, and every number on every profile
was a form field somebody filled in once and never opened again.
So I did the job by hand. Three weeks, 41 tabs, three languages. My spreadsheet
had a column for minimum order quantity and nine of its rows said ?
, because
most factories never publish one. I sent the same eight questions to one
supplier at a time and got answers to four of them.
Then two suppliers listed the same major fragrance brand as a customer.
I read both pages twice. They matched in every way that mattered to me: a logo,
a sentence, no date, no contract, nobody else saying it. One of those companies
was lying and I had no way in.
A factory tells you its real minimum inside a negotiation and tells the next
buyer something else. No dataset holds that number. You learn it by asking, and
you learn whether it holds by finding somebody other than the factory saying it.
That is two different jobs. Read what a supplier publishes. Wait days for the
answer to what it does not. A search engine does the first badly and the second
not at all, and a chatbot stops existing the moment you close the tab.
The thing I built is called SupplyMe. You type a product into it — "500 × 50ml EDP, Indonesia, premium packaging, minimise first-batch risk" — and then you
It breaks that product into the supply chain it needs, searches for real
manufacturers of each part, reads what they publish, and emails them what the
web could not answer. Days later, when a factory replies, it notices that the
price in the email is not the price on the website, puts both numbers back to
the supplier in a single follow-up, and ranks whoever survives.
Because a supplier can take three days to answer, nothing in the system waits in
memory for one. Every step is a persisted event, so a reply can arrive long
after the process that sent the email is gone and the mission still picks up
where it left off. That is the part that makes it an agent rather than a
conversation: it keeps working when you are not there.
The first thing I built is the part that answers my week-one question, and it
contains no model at all.
Gemini reads a page and extracts claims, stamping each one with where it came
from. A deterministic function turns those sources into a confidence — noisy-OR
with geometric decay:
CORROBORATION_DECAY, CONFIDENCE_CEILING = 0.55, 0.97
confidence = min(1 - math.prod((1 - w[i] * DECAY**i) for i in range(n)), CEILING)
The weights are the opinionated part:
| Source | Weight |
|---|---|
| The supplier's own email | 0.90 |
| The brand's own website | 0.85 |
| The supplier's website | 0.75 |
| A Maps listing | 0.55 |
| A directory listing | |
| 0.45 | |
| A bare search result | 0.30 |
Decay makes the second corroborating source count for less than the first and
the twentieth count for close to nothing, so twenty directory listings copying
one press release land under the manufacturer's own spec sheet. That 0.45
is
the marketplace problem I started with, written down as a constant.
One rule held the design together. Ask a model how confident it is and you get a
number that moves when you rephrase the prompt. Compute it from source identity
and you get one that moves when the evidence changes.
Ranking follows the same rule: a weighted sum over price, minimum-order fit,
capability, lead time, evidence strength and logistics, at 20/20/20/15/15/10.
Tell a mission to minimise first-batch risk and weight slides off price and onto
order-size fit. The agent that writes the recommendation receives a ranking it
did not compute and cannot reorder — hand it that power and the scores turn into
decoration.
Drawing that line meant I never had to build explainability, because the
explanation is the calculation. MOQ 500 fits an order of 500
.
I started by wrapping everything in an LlmAgent
, because that is what the
framework is for and it felt like cheating not to. Then I read the traces.
Six of them made one call and returned. One prompt, one schema, one response, no
branching, no tool choice. The workflow had already decided what happened next;
the model was filling in a shape.
The seventh looked like this against a real supplier:
read_page https://kemasan-wangi.example.com/
search_web "PT Kemasan Wangi Nusantara Indonesia 50ml glass perfume bottle MOQ"
read_page https://kemasan-wangi.example.com/produk/botol-parfum-50ml
Nobody scripted that sequence. It landed on the homepage, could not find what it
needed, searched for the phrase that would surface a product page, and went back
for it. It returned moq = 500
, quoted from "Minimum order: 500 pcs per desain", and reported price and lead time as missing — which is what later
So research stayed an agent, with search_web
, read_page
and query_maps
,
and the other six became single structured calls. A tool loop standing in for a
structured call gets you a slower and less predictable structured call at
roughly ten times the price. Working out where not to put an agent was the most
useful hour I spent.
Measured from the API's own token counts, eight suppliers researched through to
a full recommendation cost $0.29, across 98 model calls and 562,287 input
tokens. Twelve suppliers costs $0.78, and that is the number I plan against.
Input tokens are nearly the whole bill, because one real supplier website runs
to tens of thousands of tokens and the research agent reads several per
supplier. Spend tracks how many suppliers you look at. How ambitious the brief
is barely moves it.
One saving worth stealing: reasoning tokens bill as output, and extraction does
not need them. Reading a price out of an email gains nothing from a thinking
budget. Capping it took the fast tier from 1,222 output tokens per call to 405.
SupplyMe still cannot tell me which one lied, and I no longer think that was the
right question. It reports one claim as corroborated by the brand's own site and
a trade publication, and the other as the supplier's word with nothing behind
it. Those two things arrive on my screen looking different, and I can click
either one through to the sentence it came from. In week one I would have taken
that over an answer.
MOCK=true docker compose up --build
Built with Google ADK, Gemini 3.5 Flash on Vertex AI, Cloud Run, Firestore,
Pub/Sub, Cloud Tasks, Cloud Scheduler, Secret Manager, Places, Gmail over SMTP
and IMAP, FastAPI, Next.js and OpenTofu.