Agents: usage guide¶
Overview¶
This guide shows how to configure and run an agent using zeroth.runtime.agents — the layer described in the agents concept page. Agents are the LLM-powered nodes in a graph; the runtime handles prompt assembly, provider invocation, tool binding, output validation, retries, and thread state. You normally create an AgentRunner per deployment and hand it to the orchestrator, which calls runner.run() each time an AgentNode is visited.
Minimal example¶
import asyncio
from zeroth.runtime.agents import (
AgentConfig,
AgentRunner,
LiteLLMProviderAdapter,
ModelParams,
PromptConfig,
PromptMessage,
)
async def main() -> None:
config = AgentConfig(
agent_id="greeter",
prompt=PromptConfig(
messages=[
PromptMessage(role="system", content="You are a terse assistant."),
PromptMessage(role="user", content="{{ message }}"),
],
),
model_params=ModelParams(model="openai/gpt-4o-mini", temperature=0.0),
)
runner = AgentRunner(
config=config,
provider=LiteLLMProviderAdapter(),
)
result = await runner.run({"message": "Say hi in five words."}, thread_id=None)
print(result.output_data)
asyncio.run(main())
Common patterns¶
- Provider swap — use
DeterministicProviderAdapterin tests (canned responses, no network) andLiteLLMProviderAdapterin dev/prod (OpenAI, Anthropic, local models via one interface). - Structured output — declare an
output_contract_refon the agent node and register it;OutputValidatorwill coerce and validate the model response. - Retry policy — set
RetryPolicy(max_attempts=..., backoff_seconds=...)on theAgentConfigto survive transient provider errors. - Tool attachment — bind callables to declared tool refs through
ToolAttachmentRegistryso the model can only call explicitly declared tools.
Pitfalls¶
- Calling a provider without credentials —
LiteLLMProviderAdapterwill raiseAgentProviderError; gate your example with an env check likeexamples/01_first_graph.pydoes. - Unvalidated model output — skipping
OutputValidatorlets malformed LLM responses propagate into downstream nodes, where they will fail mapping or contract checks far away from the cause. - Thread state leakage — reusing the same
thread_idacross unrelated runs bleeds history between them; mint a fresh thread per logical conversation. - Declaring tools the runtime can't bind — undeclared refs raise
UndeclaredToolError. Register every tool in theToolAttachmentRegistrybefore starting the run. - Infinite retry loops — always set a finite
max_attemptsinRetryPolicy;AgentRetryExhaustedErroris far easier to debug than a stuck run.