Build an AI Agent with Shakti¶
An AI agent — a model that can call functions you define and use the results to answer a question — is a few lines of code with Shakti's built-in Agent. This builds one that can check order status from your own database.
Set up AI¶
from shakti import AI
ai = AI(config) # ai.provider: anthropic in config/settings.yaml
ai.init_app(app)
Agents currently require the Anthropic provider, since they're built on Anthropic's tool-use API — see Agents.
Define a tool¶
A tool is just an async function with a docstring. Shakti generates the tool schema the model needs from the function signature automatically:
from shakti.orm import Database, Repository
from app.models.order import Order
agent = ai.agent(system="You are a helpful order-status assistant.")
@agent.tool(description="Look up an order's status by order ID")
async def get_order_status(order_id: int) -> str:
async with db.session() as session:
order = await session.get(Order, order_id)
if order is None:
return f"No order found with ID {order_id}"
return f"Order {order_id} is {order.status}"
Wire it up as an endpoint¶
@app.post("/support/ask")
async def ask_support(body: dict) -> dict:
result = await agent.run(body["question"])
return {
"answer": result.content,
"tool_calls": [tc.tool_name for tc in result.tool_calls],
}
Try it¶
curl -X POST http://127.0.0.1:8000/support/ask \
-H "Content-Type: application/json" \
-d '{"question": "What is the status of order 42?"}'
The model decides whether it needs to call get_order_status, calls it with the order ID it extracted from the question, and uses the result to answer in natural language — the loop (call the model, run any tool it asks for, feed the result back, repeat) is handled for you, up to max_iterations round-trips.
Multiple tools compose naturally¶
Register more @agent.tool-decorated functions and the model chooses which ones it needs for a given question — you don't have to route the request to the right tool yourself:
@agent.tool(description="Check current inventory for a product SKU")
async def check_inventory(sku: str) -> str:
...
@agent.tool(description="Look up a customer's shipping address")
async def get_shipping_address(customer_id: int) -> str:
...
A question like "is order 42's product in stock, and where is it shipping?" can trigger both tools in one agent.run() call.