Skip to content

Services

LLLM services expose tactics through FastAPI. A service is the network face of a tactic, not a separate execution model.

The portable endpoints are:

Endpoint Use
POST /run Execute one tactic call and return one output.
POST /stream Execute a streaming call as server-sent events.
GET /info Return TacticInfo without running the tactic.

/run accepts the protocol envelope:

{
  "input": {"text": "hello"},
  "context": {"trace_id": "demo"}
}

It can also accept raw app JSON when adapting an existing client shape:

{"text": "hello"}

The envelope is preferred for new integrations because it leaves room for request ids, trace ids, caller metadata, and future routing fields.

Create An App

from lllm.services import create_tactic_app
from demo.tactics import EchoTactic

app = create_tactic_app(EchoTactic())

Run it:

uvicorn demo.app:app --host 127.0.0.1 --port 8000

Then call it:

curl -X POST http://127.0.0.1:8000/run \
  -H 'content-type: application/json' \
  -d '{"input":{"text":"hello"}}'

Errors

Service errors use stable envelopes so callers can inspect type, message, tactic, endpoint, request_id, and metadata without scraping framework text. Validation failures, tactic failures, and endpoint conflicts remain machine-readable across local and remote calls.

Custom endpoints can be mounted beside the portable API, but they must avoid reserved LLLM service routes and keep method/path pairs unique. Endpoint paths, names, and tags are validated as portable text so package metadata and docs can refer to them safely.

Remote Clients

RemoteTactic normalizes a service base URL into /run, /stream, and /info calls. Use:

  • RemoteTactic.arun() for JSON run calls,
  • RemoteTactic.astream() for streamed data chunks,
  • RemoteTactic.aevents() for full event envelopes,
  • RemoteTactic.fetch_info() / afetch_info() for remote metadata.

This lets local tactics and HTTP-backed tactics share the same composition layer.