Agentic integrations
Build AI agents with DynamoDB as the data layer. pydynox makes it easy to create tools that agents can use to read and write data.
Why pydynox for agents?
AI agents need fast, reliable data access. pydynox gives you:
- Speed - Rust core means fast serialization and queries
- Type safety - Models catch errors before they reach DynamoDB
- Async support - Non-blocking operations for async agent frameworks
- Rich features - Encryption, S3 storage, compression out of the box
Use case: Customer support agent
A support agent that can look up customers and orders:
User: "What's the status of John's last order?"
Agent:
1. Calls get_customer_by_email("john@example.com") → gets customer_id
2. Calls get_recent_orders(customer_id, limit=1) → gets order
3. Returns: "John's last order (#12345) is 'shipped', tracking: XYZ123"
All backed by DynamoDB via pydynox.
Supported frameworks
| Framework | Best for | Key feature |
|---|---|---|
| Strands | AWS-native apps | Simple @tool decorator |
| Pydantic AI | Async apps | Full async support |
| Smolagents | HuggingFace ecosystem | Code generation |
Quick example
"""Quick example of a pydynox tool for agents."""
from pydynox import Model, ModelConfig
from pydynox.attributes import StringAttribute
from strands import tool
class Customer(Model):
model_config = ModelConfig(table="customers")
pk = StringAttribute(hash_key=True)
sk = StringAttribute(range_key=True)
email = StringAttribute()
name = StringAttribute()
@tool
def get_customer(customer_id: str) -> dict:
"""Get customer by ID."""
customer = Customer.get(pk=f"CUSTOMER#{customer_id}", sk="PROFILE")
if not customer:
return {"error": "Not found"}
return {"name": customer.name, "email": customer.email}
Feature examples
Each framework guide shows different pydynox features:
| Guide | Features shown |
|---|---|
| Strands | Queries, NumberAttribute, customer support use case |
| Pydantic AI | S3Attribute, async methods, document management |
| Smolagents | EncryptedAttribute, HR data with sensitive fields |
Best practices
"""Best practices for agentic tools."""
from pydynox import Model, ModelConfig
from pydynox.attributes import EncryptedAttribute, NumberAttribute, StringAttribute
from strands import tool
class Order(Model):
model_config = ModelConfig(table="orders")
pk = StringAttribute(hash_key=True)
sk = StringAttribute(range_key=True)
order_id = StringAttribute()
status = StringAttribute()
total = NumberAttribute()
class Customer(Model):
model_config = ModelConfig(table="customers")
pk = StringAttribute(hash_key=True)
sk = StringAttribute(range_key=True)
name = StringAttribute()
email = StringAttribute()
class Employee(Model):
model_config = ModelConfig(table="employees")
pk = StringAttribute(hash_key=True)
sk = StringAttribute(range_key=True)
name = StringAttribute()
department = StringAttribute()
ssn = EncryptedAttribute(key_id="alias/hr-key")
# Return structured data
@tool
def get_order(order_id: str) -> dict:
"""Get order details."""
order = Order.get(pk=order_id, sk="DETAILS")
if not order:
return {"found": False, "error": "Order not found"}
return {
"found": True,
"order_id": order.order_id,
"status": order.status,
"total": order.total,
}
# Handle errors gracefully
@tool
def delete_customer(customer_id: str) -> dict:
"""Delete a customer."""
customer = Customer.get(pk=f"CUSTOMER#{customer_id}", sk="PROFILE")
if not customer:
return {"success": False, "error": "Not found"}
customer.delete()
return {"success": True}
# Write good docstrings
@tool
def search_orders(customer_id: str, status: str = None) -> list:
"""Search orders for a customer.
Use this when a customer asks about their orders,
order history, or wants to find a specific order.
Args:
customer_id: The customer's unique ID.
status: Filter by status (shipped, pending, delivered).
Returns:
List of orders with order_id, status, and total.
"""
query_params = {
"key_condition": "pk = :pk",
"expression_values": {":pk": f"CUSTOMER#{customer_id}"},
}
if status:
query_params["filter_condition"] = "status = :status"
query_params["expression_values"][":status"] = status
orders = Order.query(**query_params)
return [{"order_id": o.order_id, "status": o.status, "total": o.total} for o in orders]
# Bad - exposes sensitive data
@tool
def get_employee_bad(employee_id: str) -> dict:
"""Get employee (BAD - exposes SSN)."""
emp = Employee.get(pk=f"EMP#{employee_id}", sk="PROFILE")
if not emp:
return {"error": "Not found"}
return {"name": emp.name, "ssn": emp.ssn} # Don't expose SSN!
# Good - protects sensitive data
@tool
def get_employee_good(employee_id: str) -> dict:
"""Get employee (GOOD - no sensitive data)."""
emp = Employee.get(pk=f"EMP#{employee_id}", sk="PROFILE")
if not emp:
return {"error": "Not found"}
return {"name": emp.name, "department": emp.department}
Next steps
Pick a framework and get started:
- Strands - Best for AWS-native applications
- Pydantic AI - Best for async applications
- Smolagents - Best for HuggingFace ecosystem