Concept #114Mediumextended-ai-concepts

How to build or customize an AI agent?

#gen-ai#agents

Answer

How to Build or Customize an AI Agent

Building an AI agent involves choosing a framework, defining the agent's role and tools, managing state, and handling the reasoning loop. Here's a practical guide.

Step 1: Define the Agent's Purpose

Before writing code, answer:

  • What task should the agent accomplish?
  • What tools does it need?
  • Should it be stateful (remember context) or stateless?
  • What are the boundaries (what it should NOT do)?

Step 2: Build a Simple Agent (from scratch)

python
from anthropic import Anthropic
import json

client = Anthropic()

# Define tools the agent can use
tools = [
    {
        "name": "read_file",
        "description": "Read the contents of a file",
        "input_schema": {
            "type": "object",
            "properties": {"path": {"type": "string", "description": "File path"}},
            "required": ["path"]
        }
    },
    {
        "name": "write_file",
        "description": "Write content to a file",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string"},
                "content": {"type": "string"}
            },
            "required": ["path", "content"]
        }
    }
]

def execute_tool(tool_name: str, tool_input: dict) -> str:
    if tool_name == "read_file":
        with open(tool_input["path"]) as f:
            return f.read()
    elif tool_name == "write_file":
        with open(tool_input["path"], "w") as f:
            f.write(tool_input["content"])
        return f"Written to {tool_input['path']}"

def run_agent(task: str, system_prompt: str) -> str:
    messages = [{"role": "user", "content": task}]

    while True:
        response = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=4096,
            system=system_prompt,
            tools=tools,
            messages=messages
        )

        if response.stop_reason == "end_turn":
            return response.content[0].text

        if response.stop_reason == "tool_use":
            # Process tool calls
            messages.append({"role": "assistant", "content": response.content})
            tool_results = []

            for block in response.content:
                if block.type == "tool_use":
                    result = execute_tool(block.name, block.input)
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": result
                    })

            messages.append({"role": "user", "content": tool_results})

# Run the agent
result = run_agent(
    task="Read the file config.json and create a summary.md",
    system_prompt="You are a helpful file management assistant."
)

Step 3: Use a Framework (LangGraph)

python
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool

llm = ChatAnthropic(model="claude-opus-4-6")

@tool
def get_weather(city: str) -> str:
    '''Get weather for a city'''
    return f"Weather in {city}: 22°C, sunny"

@tool
def search_news(topic: str) -> str:
    '''Search recent news on a topic'''
    return f"Recent news about {topic}: [retrieved results]"

# Create agent with tools
agent = create_react_agent(llm, tools=[get_weather, search_news])

# Run
result = agent.invoke({
    "messages": [("user", "What's the weather in Paris and any news about AI today?")]
})

Step 4: Customize Behavior

python
from langgraph.graph import StateGraph, END
from typing import TypedDict

class AgentState(TypedDict):
    messages: list
    task_complete: bool
    attempts: int

def custom_agent_logic(state: AgentState) -> AgentState:
    '''Custom reasoning with guardrails'''
    if state["attempts"] >= 5:
        state["task_complete"] = True  # Stop after 5 attempts
        return state

    # Your custom logic here
    response = llm.invoke(state["messages"])
    state["messages"].append(response)
    state["attempts"] += 1

    if "DONE" in response.content:
        state["task_complete"] = True

    return state

graph = StateGraph(AgentState)
graph.add_node("agent", custom_agent_logic)
graph.add_conditional_edges("agent",
    lambda s: END if s["task_complete"] else "agent")
graph.set_entry_point("agent")
app = graph.compile()

Checklist for Building Agents

  • Define clear task boundaries and stopping conditions
  • Implement max iterations to prevent infinite loops
  • Add error handling for tool failures
  • Log all tool calls for debugging
  • Test with adversarial inputs
  • Add human-in-the-loop for destructive operations
  • Monitor token usage (costs grow fast with agents)