cd /news/ai-agents/i-spent-three-weeks-sourcing-500-per… · home topics ai-agents article
[ARTICLE · art-117141] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

I spent three weeks sourcing 500 perfume bottles by hand. Then I built an agent to do the job.

A developer built SupplyMe, an agent that automates B2B supplier sourcing for small manufacturing orders, after spending three weeks manually sourcing 500 perfume bottles. The agent uses Gemini to extract claims from supplier pages and a deterministic confidence-scoring function to rank suppliers, and it persists every step as an event so it can continue working after the user closes the tab.

read6 min views1 publishedAug 31, 2026

*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.

── more in #ai-agents 4 stories · sorted by recency
── more on @supplyme 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-spent-three-weeks-…] indexed:0 read:6min 2026-08-31 ·