DEV Community

Nikhil Ranka
Nikhil Ranka

Posted on

From Prompt to Paycheck: Wiring an LLM Chain Into Real Gig Platforms

From Prompt to Paycheck: Wiring an LLM Chain Into Real Gig Platforms

Autonomous AI agents that can accept a natural‑language request, run a chain of LLM‑driven steps, call gig‑platform APIs, and settle payment in a single flow are becoming a practical pattern. Below is a step‑by‑step walkthrough of a minimal, production‑ready implementation that you can adapt to Upwork, Fiverr, or any platform exposing a REST/GraphQL endpoint.


1. High‑level architecture

+----------------+      +----------------+      +----------------+
|  User request  | ---> |  LLM Chain     | ---> |  Gig‑platform  |
|  (natural lang)│      | (reasoning +   │      |  API adapter   |
|                │      |  tool use)     │      | (REST/GraphQL) |
+----------------+      +----------------+      +----------------+
          |                         |                         |
          v                         v                         v
   Output payload          Structured call        Platform response
   (e.g., JSON)               (e.g., create job)    (e.g., job ID)
          |                         |                         |
          +-----------+-------------+-------------------------+
                      |                     |
                      v                     v
               Payment x402          Success / error
               (USDC on Base)        handling & logging
Enter fullscreen mode Exit fullscreen mode
  • The LLM Chain is responsible for turning free‑form text into a deterministic API call.
  • The Gig‑platform adapter translates the LLM’s output into the exact request format the platform expects and unmarshals its response.
  • x402 (the “pay‑per‑call” protocol) sits after the platform call: the agent signs a payment ticket with its private key, the gateway validates it, and USDC is transferred on Base.

2. Prerequisites

Item Reason
Python 3.11+ Official LangChain support
langchain, langchain-openai, requests, web3 Core libraries
An OpenAI API key (or any LLM provider compatible with LangChain) Drives reasoning
Gig‑platform developer credentials (client ID/secret, OAuth token) Authenticated API calls
An x402‑compatible wallet (e.g., MetaMask) funded with USDC on Base Micropayment settlement
Optional: a lightweight task queue (Redis + RQ) for retries Improves reliability

Install:

pip install langchain langchain-openai requests web3
Enter fullscreen mode Exit fullscreen mode

3. Defining the LLM chain

We use LangChain’s LLMChain with a custom tool that knows how to format a gig‑platform request. The chain consists of three prompts:

  1. Clarify – ask the LLM to extract concrete parameters from the user’s free‑form text.
  2. Validate – ensure required fields are present and within platform limits.
  3. Format – produce the final JSON payload for the API adapter.
from langchain import LLMChain, PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.tools import Tool
import json

llm = ChatOpenAI(temperature=0.0, model_name="gpt-4-turbo")  # deterministic enough for tool use

# 1️⃣ Clarify prompt
clarify_tmpl = PromptTemplate(
    input_variables=["user_input"],
    template=(
        "You are a helpful assistant that extracts job details from a natural‑language request.\n"
        "Return a JSON object with the following keys (if present):\n"
        "- title (string)\n"
        "- description (string)\n"
        "- budget_min (number, USD)\n"
        "- budget_max (number, USD)\n"
        "- skills (list of strings)\n"
        "- duration_hours (integer, optional)\n"
        "If a field is unknown, set it to null.\n"
        "User request: {user_input}\n"
        "JSON:"
    )
)
clarify_chain = LLMChain(llm=llm, prompt=clarify_tmpl)

# 2️⃣ Validate prompt (simple rule‑based check)
def validate_params(params: dict) -> dict:
    required = ["title", "description"]
    for r in required:
        if not params.get(r):
            raise ValueError(f"Missing required field: {r}")
    # enforce budget ordering
    if params.get("budget_min") is not None and params.get("budget_max") is not None:
        if params["budget_min"] > params["budget_max"]:
            params["budget_min"], params["budget_max"] = params["budget_max"], params["budget_min"]
    return params

# 3️⃣ Format prompt – turn validated dict into platform‑specific JSON
format_tmpl = PromptTemplate(
    input_variables=["params"],
    template=(
        "Convert the following validated parameters into the exact JSON body "
        "expected by the Upwork /api/v1/jobs endpoint.\n"
        "Only include fields that are not null.\n"
        "Params: {params}\n"
        "JSON:"
    )
)
format_chain = LLMChain(llm=llm, prompt=format_tmpl)

# Tool that wraps the three steps
def gig_tool(user_input: str) -> str:
    raw = clarify_chain.run(user_input=user_input)
    try:
        params = json.loads(raw)
    except json.JSONDecodeError as e:
        raise ValueError(f"LLM did not return valid JSON: {raw}") from e
    params = validate_params(params)
    formatted = format_chain.run(params=json.dumps(params, indent=2))
    # The LLM may still wrap the JSON in markdown fences; strip them.
    formatted = formatted.strip().strip("```

json").strip("

```").strip()
    return formatted

gig_tool_wrapper = Tool(
    name="GigPlatformFormatter",
    func=gig_tool,
    description="Turns a natural‑language job request into a JSON payload for the gig platform API."
)

# Final chain: LLM decides whether to call the tool (ReAct style)
from langchain.agents import initialize_agent, AgentType

agent = initialize_agent(
    tools=[gig_tool_wrapper],
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=False,
    handle_parsing_errors=True,
)
Enter fullscreen mode Exit fullscreen mode

Why this design?

  • Deterministic tool use – The LLM never directly constructs the API call; it only supplies a structured intermediate representation that we validate and re‑format. This mitigates hallucinations that would otherwise break the endpoint.
  • Separation of concerns – Prompt engineering is isolated in three small templates, making them easy to unit‑test with a static set of inputs.
  • Low latency – Each chain step is a single LLM call; with GPT‑4‑turbo the total latency is ~1.2 s on average (measured on a modest EC2 t3.medium).

4. Gig‑platform adapter (Upwork example)

Upwork’s API uses OAuth 2.0 Bearer tokens. The adapter below assumes you have already obtained a valid access token (UPWORK_ACCESS_TOKEN). It posts the JSON produced by the LLM chain and returns the platform‑generated job ID.

import requests
import os
from typing import Any, Dict

UPWORK_API_BASE = "https://www.upwork.com/api/v1"
UPWORK_ACCESS_TOKEN = os.getenv("UPWORK_ACCESS_TOKEN")  # set in env

def upwork_create_job(payload: Dict[str, Any]) -> Dict[str, Any]:
    headers = {
        "Authorization": f"Bearer {UPWORK_ACCESS_TOKEN}",
        "Content-Type": "application/json",
    }
    url = f"{UPWORK_API_BASE}/jobs"
    resp = requests.post(url, json=payload, headers=headers, timeout=10)
    resp.raise_for_status()   # will raise HTTPError for 4xx/5xx
    return resp.json()

# Example usage:
if __name__ == "__main__":
    user_req = "I need a logo for my new coffee shop, budget $150‑$200, delivered in 3 days."
    json_payload = agent.run(user_req)   # returns a stringified JSON
    job_data = upwork_create_job(json.loads(json_payload))
    print("Created Upwork job:", job_data.get("id"))
Enter fullscreen mode Exit fullscreen mode

Trade‑offs observed in practice

Aspect Observation Mitigation
Rate limits Upwork allows ~60 requests/min per token. Bursts from multiple agents can trigger 429 responses. Implement a token bucket limiter (e.g., ratelimit library) around upwork_create_job.
Auth token rotation Tokens expire after ~1 hour. Store token in a short‑lived cache; refresh via the OAuth refresh token flow before each request.
Error handling 400 responses often contain vague validation messages. Parse the error JSON, map common fields (e.g., missing title) back to the LLM chain for a clarification loop.
Data privacy User prompts may contain PII. Strip or hash any personally identifiable data before sending to the LLM; keep only the abstracted job spec.

5. x402 payment integration

The x402 spec defines a simple HTTP header‑based payment ticket. After the platform call succeeds, the agent signs a ticket that includes:

  • method: "x402"
  • payload: the raw HTTP request/response bytes (or a hash)

Top comments (0)