real_agent¶
Level 6 · Real LLM — the first example that talks to an actual model.
Every other curated example runs on MockModelProvider so it's free and
deterministic. real_agent is the one that calls Anthropic's Claude for
real: it reads ANTHROPIC_API_KEY, sends your question, and prints the model's
answer. It's the bridge from "the framework runs" to "the framework answers."
- Prerequisites:
pip install "symfonic-core[anthropic]"+ANTHROPIC_API_KEY - Key concepts:
AnthropicProvider, real LLM integration,.envloading
Get it and run it¶
Installed via pip? Copy it in and run against a real model — no checkout:
pip install "symfonic-core[cli,anthropic]"
export ANTHROPIC_API_KEY=sk-ant-...
symfonic examples add real_agent
python -m real_agent "What is the largest planet in our solar system?"
Or from a source checkout (run from the repo root):
Expected output:
Query: What is the largest planet in our solar system?
---
Response: Jupiter is the largest planet in our solar system.
Nodes: ['react']
Full code¶
"""Real LLM example — runs against Anthropic's Claude API.
Requires:
pip install symfonic-core[anthropic]
cp .env.example .env # then fill in ANTHROPIC_API_KEY
Usage: python -m examples.real_agent
python -m examples.real_agent "Your custom question here"
"""
import asyncio
import os
import sys
from dotenv import load_dotenv
load_dotenv() # loads .env from project root
from symfonic.core import (
AgentConfig,
AgentGraph,
AgentRuntime,
BaseAgentDeps,
)
from symfonic.core.providers import AnthropicProvider
async def main() -> None:
if not os.environ.get("ANTHROPIC_API_KEY"):
print("Error: ANTHROPIC_API_KEY environment variable is required.")
print(" export ANTHROPIC_API_KEY=sk-ant-...")
sys.exit(1)
query = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "What is symfonic? Make up a creative answer in 2 sentences."
config = AgentConfig()
deps = BaseAgentDeps(ModelProvider=AnthropicProvider())
graph = AgentGraph()
runtime = AgentRuntime(graph=graph, deps=deps, config=config)
print(f"Query: {query}")
print("---")
result = await runtime.run(query)
print(f"Response: {result['final_response']}")
print(f"Nodes: {result['node_execution_log']}")
if __name__ == "__main__":
asyncio.run(main())
Step by step¶
1. Load credentials¶
AnthropicProvider reads ANTHROPIC_API_KEY from the environment.
load_dotenv() (shipped with the [anthropic] extra) is a convenience — it
picks the key up from a local .env so you don't have to export it every
shell. Exporting the variable works just as well.
2. Fail fast without a key¶
if not os.environ.get("ANTHROPIC_API_KEY"):
print("Error: ANTHROPIC_API_KEY environment variable is required.")
sys.exit(1)
A real example should tell you why it can't run rather than surfacing a raw auth error from deep in the stack.
3. Wire the real provider¶
This is the only line that differs from minimal_agent:
AnthropicProvider() in place of MockModelProvider. Everything downstream —
graph, runtime, state — is identical. That's the payoff of the ModelProvider
protocol: swapping mock for real is a one-line change.
4. Run and read the answer¶
Same AgentRuntime.run as the mock examples; now final_response carries a
genuine model completion. Pass a question on the command line
(python -m real_agent "...") or it uses a built-in default.
Going further¶
- Swap the provider for another vendor —
OpenRouterProvider,AWSBedrockProvider— the rest of the code is unchanged. See Model Providers. - Add memory so the model reasons over stored context → see
real_agent_with_memoryin the Examples Index. - Ask for a validated object back → Structured Output.
See also¶
- Model Providers
- minimal_agent — the same graph on a mock provider