Inspiration
Modern procurement is painfully manual. A buyer emails a vendor, the vendor replies with a quote, the buyer counters, and after days of back-and-forth a deal is struck — or isn't. We asked: what if two AI agents could handle the entire negotiation loop in seconds, and then execute the payment without a human ever touching the keyboard?
The idea of autonomous economic agents — entities that hold preferences, reason under constraints, and transact — felt like the right problem to push at a hackathon. Not a chatbot that assists a negotiator, but one that is the negotiator.
## What We Built
An end-to-end agentic negotiation and procurement platform:
- VendorAgent and BuyerAgent — two LLM-powered agents with hard price constraints — negotiate over a product in natural language, each driven by a fine-tuned Qwen3-8B model hosted on Pioneer.ai.
- A LangGraph state machine orchestrates the conversation: agents take
turns, a guardrail node validates every offer against each side's floor/
ceiling, and the graph routes to payment once both sides say
ACCEPT. - On agreement, a Stripe-shaped PaymentIntent lifecycle fires automatically — the Vendor creates a payment request, the Buyer confirms it, and an invoice is generated.
- Every agent message and tool execution is logged to ClickHouse for telemetry and replay.
- A React + Vite frontend streams the negotiation live, showing the message log, status badge, invoice block, and a deal-zone price bar sourced from the live backend config.
## How We Built It
### Negotiation Protocol
Each agent's message must end with a structured tag:
[OFFER price=X.XX quantity=N action=ACCEPT|COUNTER|REJECT]
This makes LLM output machine-parseable without a separate extraction step. The guardrail validator enforces constraints: if the VendorAgent ever offers below its floor $f_v$, or the BuyerAgent accepts above its ceiling $c_b$, the negotiation terminates immediately.
Formally, a deal is valid iff the agreed price $p^*$ satisfies:
$$f_v \leq p^* \leq c_b$$
With our default config ($f_v = \$8.00$, $c_b = \$10.00$), the deal zone is $[8.00,\ 10.00]$ — a $\$2.00$ overlap the agents converge into.
### Fine-Tuning on Pioneer.ai
Rather than prompting a general-purpose model, we generated a synthetic
dataset of negotiation dialogues (eval/pioneer_mlops.py) and fine-tuned
Qwen/Qwen3-8B with LoRA via Pioneer's /felix/training-jobs API. The
resulting adapter (negotiation-agent-evals-20260612211958) uses ~120 tokens
per turn — noticeably cheaper and more on-task than a general model.
### Stack
| Layer | Technology | |---|---| | Orchestration | LangGraph (StateGraph) | | LLM | Pioneer.ai — fine-tuned Qwen3-8B | | API | FastAPI + uvicorn | | Payments | Mock Stripe PaymentIntent lifecycle | | Telemetry | ClickHouse (clickhouse-connect) | | Frontend | React + Vite | | Deployment | Render |
## Challenges
Getting LLMs to follow a strict output format. A general-purpose model
would occasionally forget the [OFFER ...] tag or emit it mid-sentence,
breaking the parser. Fine-tuning on structured negotiation examples fixed
this — the adapted model produces well-formed tags on every turn.
LangGraph state threading. The graph runs in a FastAPI background task
while the frontend polls for updates. Getting the in-memory state store to
reflect incremental graph emissions (via stream_mode="values") without race
conditions required careful lock-free design.
Linking payment intents across agent turns. The Vendor creates a
PaymentIntent; the Buyer must confirm the same one. Early versions
generated a fresh ID on authorization (a silent correctness bug). The fix was
an in-memory PaymentIntent store keyed by ID, with amount validation before
confirmation.
Render port binding. Uvicorn defaults to 127.0.0.1, which Render's
port scanner can't see. Took longer than it should have to trace the CORS
errors back to a dead-simple --host 0.0.0.0 flag.
## What We Learned
- Fine-tuning a small model on a narrow task beats prompting a large one — faster, cheaper, and more reliable output structure.
- LangGraph's explicit state machine is the right abstraction for multi-agent protocols: routing logic stays readable, and adding new nodes (payment, guardrails) doesn't touch existing ones.
- ClickHouse is genuinely fast for append-only event logs, and its
MergeTreeengine withPARTITION BY toYYYYMM(timestamp)makes replay queries trivial. - Autonomous agents transacting money — even in mock form — forces you to
think carefully about failure modes: what happens when authorization fails?
(Answer:
TERMINATED, notFULFILLED.)
Log in or sign up for Devpost to join the conversation.