Nikhil RankaFrom Prompt to Paycheck: Wiring an LLM Chain Into Real Gig Platforms Building autonomous...
Building autonomous agents that can actually earn money on freelance marketplaces is less about magic prompts and more about plumbing. Below is a step‑by‑step walkthrough of a minimal, production‑ish pipeline that takes a user request, runs it through an LLM chain, translates the output into a concrete gig‑platform action, and settles payment via the x402 micropayment protocol. The focus is on concrete code, realistic trade‑offs, and what you’ll need to monitor once the agent goes live.
+----------------+ +----------------+ +-----------------+
| Frontend / | HTTP | Agent Service | RPC | Gig‑Platform |
| Trigger (e.g.|------->| (LLM Chain) |------->| API (Upwork, |
| Slack, Web) | +----------------+ | Fiverr…) |
+----------------+ ^
| |
| x402 payment receipt (USDC on Base) |
v |
+----------------+ +----------------+ +-----------------+
| Payment Ledger|<------| x402 Handler |<------| Escrow / Wallet|
+----------------+ +----------------+ +-----------------+
The flow is deliberately synchronous: the user pays before the LLM runs, guaranteeing that compute cost is covered. If you prefer a post‑job payout, you can flip the order, but you’ll need a more complex dispute‑resolution layer.
We’ll use LangChain’s LLMChain with a simple prompt that turns a natural‑language request into a structured gig spec. The example assumes you have an OpenAI API key (replace with any compatible provider).
# agent/llm_chain.py
from langchain import OpenAI, LLMChain, PromptTemplate
from typing import Dict
# Adjust temperature for determinism; lower = more repeatable specs.
llm = OpenAI(temperature=0.2, model_name="gpt-4o-mini")
spec_template = """
You are a helpful assistant that converts a user request into a JSON spec for a freelance gig.
Only output valid JSON, no extra text.
User request: "{request}"
Fields to include:
- title: short, descriptive title (<= 80 chars)
- description: detailed description (<= 500 chars)
- skills: list of required skill strings
- budget_usd: number (optional, if user gave a budget)
- deadline_iso: ISO‑8601 timestamp (optional)
JSON:
"""
prompt = PromptTemplate(input_variables=["request"], template=spec_template)
spec_chain = LLMChain(llm=llm, prompt=prompt)
def build_spec(user_request: str) -> Dict:
"""Run the chain and coerce the output to a dict."""
raw = spec_chain.run(request=user_request)
# LangChain may wrap the JSON in markdown fences; strip them.
cleaned = raw.strip().strip("```
json").strip("
```")
try:
return json.loads(cleaned)
except json.JSONDecodeError as e:
raise ValueError(f"LLM returned invalid JSON: {cleaned}") from e
Trade‑off: Using a small, cheap model (gpt-4o-mini) keeps latency under ~800 ms and cost ≈ $0.0004 per call. If you need richer reasoning (e.g., multi‑step negotiation), swap to a larger model and accept higher latency and cost.
Most platforms expose a REST endpoint for creating a job/post. Below is a generic adapter that you can subclass for Upwork, Fiverr, or a custom marketplace.
# agent/gig_adapter.py
import httpx
from typing import Any, Dict
BASE_URLS = {
"upwork": "https://www.upwork.com/api/v1",
"fiverr": "https://www.fiverr.com/api/v2",
}
class GigAdapter:
def __init__(self, platform: str, token: str):
if platform not in BASE_URLS:
raise ValueError(f"Unsupported platform: {platform}")
self.base = BASE_URLS[platform]
self.client = httpx.AsyncClient(
base_url=self.base,
headers={"Authorization": f"Bearer {token}"},
timeout=httpx.Timeout(10.0, read=30.0),
)
async def create_gig(self, spec: Dict) -> Dict[str, Any]:
"""
Platform‑specific payload mapping lives here.
For demonstration we assume a generic shape:
{
"title": str,
"description": str,
"skills": List[str],
"budget": {"amount": float, "currency": "USD"},
"deadline": str # ISO‑8601
}
"""
payload = {
"title": spec.get("title", ""),
"description": spec.get("description", ""),
"skills": spec.get("skills", []),
"budget": {
"amount": spec.get("budget_usd", 0),
"currency": "USD",
},
}
if spec.get("deadline_iso"):
payload["deadline"] = spec["deadline_iso"]
resp = await self.client.post("/jobs", json=payload)
if resp.status_code >= 400:
# Bubbles up a clean error for the agent layer.
raise httpx.HTTPStatusError(
f"Gig platform error {resp.status_code}",
request=resp.request,
response=resp,
)
return resp.json()
Honest note: Real platforms differ wildly in authentication (OAuth 2.0 vs. personal tokens), rate limits, and required fields. You’ll need to inspect each API’s documentation and handle pagination, webhook confirmations, or escrow steps manually.
x402 is a lightweight HTTP‑based protocol for charging per‑request fees in USDC on Base. The agent service acts as both payer (when calling external APIs) and payee (when receiving user requests).
# agent/x402_handler.py
from fastapi import Header, HTTPException, Request, Response
from x402 import verify_payment, PaymentRequired
import os
# Set your x402 provider’s public key (or use the default testnet).
X402_PUBLIC_KEY = os.getenv("X402_PUBLIC_KEY", "")
async def payment_middleware(request: Request, call_next):
"""
FastAPI middleware that rejects requests without a valid x402 payment.
The client must include the header: `X402-Payment: <signed receipt>`
"""
receipt = request.headers.get("x402-payment")
if not receipt:
raise PaymentRequired(
amount=0.01, # minimum fee in USDC
asset="USDC",
network="base",
payto="0xYourAgentWalletAddress",
)
try:
await verify_payment(
receipt=receipt,
payload=await request.body(),
public_key=X402_PUBLIC_KEY,
)
except Exception as exc:
raise HTTPException(status_code=402, detail=str(exc))
# Payment ok → continue to endpoint
response: Response = await call_next(request)
return response
Add it to your FastAPI app:
# main.py
from fastapi import FastAPI
from .x402_handler import payment_middleware
from .llm_chain import build_spec
from .gig_adapter import GigAdapter
app = FastAPI()
app.middleware("http")(payment_middleware)
@app.post("/run")
async def run_agent(request: Dict):
user_req = request.get("prompt")
if not user_req:
raise HTTPException(status_code=400, detail="Missing prompt")
spec = build_spec(user_req)
# Choose platform based on a simple heuristic or user input.
adapter = GigAdapter(platform="upwork", token=os.getenv("UPWORK_TOKEN"))
gig_resp = await adapter.create_gig(spec)
return {"gig_id": gig_resp.get("id"), "spec": spec}
Cost breakdown (approx.):
Autonomous agents fail in predictable