Skip to main content

agentic-function

Turn LLM capabilities into ordinary Python functions with @agentic_function: describe the task in the docstring, constrain the output with a schema; the library handles prompt rendering, validation, retries, caching, tracing, and multi-backend execution.

Languages: English · 中文

  • License: MIT
  • Python: 3.10+
  • Version: 0.0.1 PyPI

Installation

pip install agentic-function

Optional provider SDKs:

pip install "agentic-function[openai]"
pip install "agentic-function[anthropic]"
pip install "agentic-function[openai,anthropic]"

Editable install from source:

pip install -e ".[dev,openai,anthropic]"

Quick start

from agentic_function import agentic_function, AgenticResult, set_default_backend
from agentic_function.backends.mock_backend import MockBackend
from agentic_function.testing import mock_llm

set_default_backend(MockBackend())
mock_llm({"category": "positive", "confidence": 0.94, "reasoning": "..."})

@agentic_function(
    output_schema={
        "category": str,
        "confidence": float,
        "reasoning": str,
    },
)
def classify_sentiment(text: str) -> AgenticResult:
    """Classify the sentiment of ``text``.

    - ``category``: "positive" | "negative" | "neutral"
    - ``confidence``: [0.0, 1.0]
    - ``reasoning``: short explanation
    """

result = classify_sentiment("Amazing launch today!")
print(result.category, result.confidence, result.reasoning)
print(result.metrics.latency_ms, result.metrics.usage.prompt_tokens)

Runnable examples under examples/:

python examples/01_sentiment_classification.py
python examples/02_information_extraction.py
python examples/03_summarization.py
python examples/04_intent_routing.py
python examples/05_composition.py
python examples/06_real_minimax.py   # requires an API key

Examples 0105 use MockBackend and need no API key.


Features

Area Notes
Decorator API @agentic_function; call it like a normal function
Output schema dict, pydantic BaseModel, or Literal[...]
Composition Plain Python calls between functions
Tool export as_openai_tool / as_anthropic_tool, FunctionRegistry
Backends Mock, OpenAI, Anthropic, MiniMax, plus register_backend
Validation & retry pydantic validation; retry on parse / validation failure
Cache InMemoryCache / DiskCache / NullCache
Metrics & cost CallMetrics on every result (latency, tokens, estimated USD, …)
Trace & budget trace, BudgetTracker, Aggregator (incl. Prometheus text)
Diagnostics diagnose / explain_failure / snapshot; debug= / AGENTIC_DEBUG
Testing helpers mock_llm, mock_llm_table, freeze_time, capture_metrics
Async .acall() primary path; sync __call__ available
Errors ValidationError, RetryExhaustedError, BudgetExceededError, …

Usage

Schema and structured output

Declare output_schema as a dict, a BaseModel, or a Literal[...] return annotation. The library injects the JSON schema into the prompt (or uses provider tool / json_schema mode), applies common coercions, and validates with pydantic. On failure it retries according to policy. Callers receive typed fields, not a raw string to parse.

@agentic_function(output_schema={"label": str, "score": float})
def classify(text: str) -> AgenticResult:
    """Classify sentiment of ``text``."""

Composition

topic = extract_topic(article)
summary = make_summary(article, topic.topic, topic.tone)

See examples/05_composition.py.

Tool export

Export a function as OpenAI / Anthropic tool JSON for an external agent or custom tool loop:

from agentic_function import as_openai_tool, as_anthropic_tool, register, get_function

openai_tool = as_openai_tool(make_summary)
anthropic_tool = as_anthropic_tool(make_summary)

register(make_summary)
fn = get_function(make_summary.qualified_name)

Backends

Built-ins: MockBackend, OpenAIBackend, AnthropicBackend, and the MiniMax-CN preset minimax. Register custom backends with register_backend(...).

@agentic_function(backend="mock", output_schema={"label": str})
@agentic_function(backend="openai", model="gpt-4o-mini", output_schema={"label": str})
@agentic_function(backend="anthropic", model="claude-sonnet-4-20250514", output_schema={"label": str})
@agentic_function(backend="minimax", model="MiniMax-M3", output_schema={"label": str})

OpenAI-compatible servers (Ollama, vLLM, LocalAI, …)

Point OpenAIBackend at any Chat Completions–compatible endpoint via base_url. No separate Ollama adapter is required when the server speaks the OpenAI protocol:

from agentic_function import OpenAIBackend, register_backend, set_default_backend

ollama = OpenAIBackend(
    api_key="ollama",                      # required by the client; value often unused locally
    base_url="http://localhost:11434/v1",  # or OPENAI_BASE_URL
    default_model="llama3.2",
)
register_backend("ollama", ollama)
set_default_backend(ollama)

# Equivalent env-based setup with the built-in "openai" backend:
#   export OPENAI_API_KEY=ollama
#   export OPENAI_BASE_URL=http://localhost:11434/v1
@agentic_function(backend="ollama", model="llama3.2", output_schema={"label": str})
def classify(text: str):
    """Classify sentiment of ``text`` as label: positive|negative|neutral."""

Prompt parameters

Parameter Purpose
docstring Task description (system prompt body)
few_shots [(input, output), …] exemplars
prompt_template / system_template Custom {placeholder} templates
include_schema_in_prompt Whether to inject the schema
description Tool-export blurb (defaults to first docstring line)
render_prompt(fn, args, kwargs) Inspect the message list before calling

Async

out = await classify.acall("terrible")

Works as free functions, methods, and classmethods (descriptor protocol).


Metrics, tracing, and cost

Every result includes CallMetrics:

result.metrics.latency_ms
result.metrics.usage.prompt_tokens
result.metrics.usage.completion_tokens
result.metrics.usage.total_tokens
result.metrics.cost_usd
result.metrics.cache_hit
result.metrics.attempts
result.metrics.retries
result.metrics.recovered
result.metrics.attempt_errors
result.metrics.timings
result.metrics.total_cost_usd

Tracing, budgets, and aggregation:

from agentic_function import (
    trace,
    Budget, BudgetTracker, install_budget_tracker,
    Aggregator, install_default_aggregator,
)

with trace("nightly_eval") as ctx:
    out = classify(sample.text)
    ctx.span.set_attribute("sample.id", sample.id)

install_budget_tracker(BudgetTracker(budgets=[
    Budget(metric="cost_usd", limit=5.0),
]))

agg = install_default_aggregator(Aggregator())
print(agg.summary())
print(agg.to_prometheus())

Diagnostics:

from agentic_function import diagnose, explain_failure, snapshot

print(diagnose(result).to_dict())
print(explain_failure(exc))
print(snapshot(result))

Cache keys cover (model, schema, few_shots, prompt_hash). Bound retries with RetryPolicy(max_retries=..., base_delay=..., max_delay=...).

examples/06_real_minimax.py runs against a live backend (API key required).


Errors and retries

A successful call returns a value that matches output_schema. Transient failures are retried according to RetryPolicy; if every attempt fails, the call raises.

call → prompt → cache lookup
                   │ miss
                   ▼
              backend request
                   │
          ┌────────┴────────┐
          │ OK              │ BackendError / ParseError / ValidationError
          ▼                 ▼
     coerce + validate   backoff retry
          │                 │
          │ valid           │ retries exhausted
          ▼                 ▼
       return            RetryExhaustedError
Exception Meaning Retried
BackendError Provider or transport failure Yes
ParseError Response is not usable JSON Yes
ValidationError JSON does not match the schema Yes
RetryExhaustedError All attempts failed No (terminal)
BudgetExceededError Configured budget exceeded No
TimeoutError Request timed out Per retry policy

BackendError.status_code carries the HTTP status when the provider SDK exposes it (for example 429). error_category_of(exc) returns "rate_limit" for status 429, otherwise "backend" for other BackendErrors.

Library errors subclass AgenticFunctionError. On exhaustion, RetryExhaustedError exposes last_exception, metrics, and attempt_errors:

from agentic_function import BackendError, RetryExhaustedError, error_category_of

try:
    result = classify(text)
except RetryExhaustedError as exc:
    cause = exc.last_exception
    status = getattr(cause, "status_code", None)
    if error_category_of(exc) == "rate_limit" or status == 429:
        # apply caller-side backoff / queueing
        ...
    raise

Control retries with max_retries or retry_policy=RetryPolicy(...). Application code may catch failures and apply its own fallback; the library does not substitute default schema fields on failure.


Credentials

Set provider keys via environment variables (for example OPENAI_API_KEY, ANTHROPIC_API_KEY, MINIMAX_CN_API_KEY) or pass them when constructing a backend. Do not place secrets in source files or pass them through configure().


Testing

from agentic_function.testing import mock_llm, mock_llm_table, freeze_time, capture_metrics

mock_llm({"label": "positive", "score": 0.95})
assert classify("amazing").label == "positive"

mock_llm_table([
    {"label": "positive", "score": 0.9},
    {"label": "negative", "score": 0.8},
])

with freeze_time():
    classify("text")

with capture_metrics() as bag:
    classify("a")
    classify("b")
assert len(bag) == 2

You can also use MockBackend, or patch the openai / anthropic clients to assert request shaping (see tests/test_anthropic_backend.py).

pytest tests/ -m "not live_llm"          # offline
pytest tests/ -m live_llm -v             # live MiniMax (API key required)
pytest --cov=agentic_function

Live tests honor AGENTIC_LIVE_LLM_PACE and AGENTIC_LIVE_CALL_GAP (seconds) to space requests.

Isolation points:

Concern Approach
Schema Test the pydantic model directly
Prompt render_prompt(fn, args, kwargs)
Backend request Patch the provider SDK
Backend response Pass a synthetic LLMResponse
Retry Raise synthetic retryable errors
Cache Swap cache implementations
Tool export Assert tool JSON shape
Metrics capture_metrics / aggregator

Decorator parameters

Parameter Default Meaning
model global default Model id for the backend
output_schema inferred from return annotation dict / BaseModel / Literal[...]
backend set_default_backend(...) Instance or registered name
temperature, top_p, max_tokens, stop global config Sampling params
max_retries global config Retries on parse / validation failure
retry_policy RetryPolicy(...) Backoff and retryable exceptions
cache global default Per-call cache override
timeout global config Request timeout (seconds)
include_schema_in_prompt True Inject JSON schema into the system message
few_shots [] Exemplar pairs
prompt_template / system_template None Custom templates
description first docstring line Tool-export description
debug False / AGENTIC_DEBUG Attach request/response snapshots
executor global default Custom Executor

Environment variables: AGENTIC_FUNCTION_MODEL, AGENTIC_FUNCTION_BACKEND, AGENTIC_FUNCTION_CACHE, AGENTIC_FUNCTION_CACHE_DIR, plus OPENAI_API_KEY, ANTHROPIC_API_KEY, MINIMAX_CN_API_KEY, etc.


Public API

from agentic_function import (
    agentic_function, AgenticFunction, AgenticResult, DynamicResult,
    SchemaSpec, resolve_schema, render_prompt,
    LLMBackend, LLMResponse, StreamChunk,
    MockBackend, OpenAIBackend,
    register_backend, get_backend, get_default_backend, set_default_backend,
    known_backends,
    Executor, GlobalConfig, configure, global_config,
    TraceContext, TraceSpan, TraceRecorder, trace, get_current_trace,
    CallMetrics, TokenUsage, PhaseTimings,
    RetryPolicy, default_retry_policy,
    CacheBackend, InMemoryCache, DiskCache, NullCache,
    get_default_executor, set_default_executor,
    Budget, BudgetTracker, BudgetExceededError,
    install_budget_tracker, get_default_budget_tracker,
    Aggregator, FunctionStats,
    install_default_aggregator, get_default_aggregator,
    Diagnostic, diagnose, diagnose_metrics, explain_failure, snapshot,
    FunctionRegistry, get_global_registry, register, get_function,
    as_openai_tool, as_anthropic_tool,
    testing,
    AgenticFunctionError, BackendError, CacheError, CompositionError,
    ConfigError, ParseError, RegistrationError, RetryExhaustedError,
    SchemaError, TimeoutError_ as TimeoutError, ValidationError,
    error_category_of,
)

AnthropicBackend and MiniMax live under agentic_function.backends and register as "anthropic" / "minimax".


Architecture

@agentic_function(...)
        │
        ▼
  AgenticFunction  (descriptor / call / await)
        │ ExecutionRequest
        ▼
     Executor
   trace → cache → retry → schema → backend
        │
        ├── BudgetTracker
        ├── Aggregator
        └── as_*_tool / Registry

Project layout

agentic-function/
├── agentic_function/
│   ├── core/
│   ├── backends/
│   ├── runtime/
│   ├── composition/
│   ├── validation/
│   ├── utils/
│   └── testing.py
├── tests/
└── examples/

Roadmap

Current release: 0.0.1.

In tree today

  • Decorator API + pydantic / dict / Literal schemas
  • Pluggable backends (Mock, OpenAI, Anthropic, MiniMax)
  • OpenAI-compatible endpoints via OpenAIBackend(base_url=...) (Ollama, vLLM, …)
  • Composition + tool export (as_openai_tool / as_anthropic_tool)
  • Cache, cost estimates, mock_llm test helpers
  • Async, tracing, budget / aggregator / diagnostics
  • HTTP status_code on BackendError (incl. rate-limit categorization)

Next

  • Streaming output as a stable public API
  • Broader CI and typed packaging polish
  • 1.0 — longer-term API stability guarantee

Contributing

See CONTRIBUTING.md.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentic_function-0.0.1.tar.gz (85.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentic_function-0.0.1-py3-none-any.whl (81.3 kB view details)

Uploaded Python 3

File details

Details for the file agentic_function-0.0.1.tar.gz.

File metadata

  • Download URL: agentic_function-0.0.1.tar.gz
  • Upload date:
  • Size: 85.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentic_function-0.0.1.tar.gz
Algorithm Hash digest
SHA256 0633f6b46e22671bbf1336eaa8e19dee2d5e6e914d48651d4502dfb275b3fdef
MD5 fe3c099f2ee45fae61a2488456145c2d
BLAKE2b-256 cfbd285cb648c5eae70ab23351607311e014a70e750ff4c30cfdfa7fa91148ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentic_function-0.0.1.tar.gz:

Publisher: python-publish.yml on loadingvx/agentic-function

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agentic_function-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for agentic_function-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 580329ab7b604d03304befcf658a0c5724f7e9e23028c5ef82f1e90d60d14453
MD5 c4b90bc8ad9fea41c9307a9a43e6cc8d
BLAKE2b-256 502295ea687e9c1498848fd562d61cced792537b1ca4972b2c5b29afc3d13d87

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentic_function-0.0.1-py3-none-any.whl:

Publisher: python-publish.yml on loadingvx/agentic-function

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page