--- layout: default --- # Agent Integration Patterns This guide covers common patterns for integrating AI agents with Go Micro services, from single-agent workflows to multi-agent architectures. ## Pattern 1: Single Agent with Multiple Services The simplest and most common pattern. One AI agent has access to multiple microservices as MCP tools. ``` User → AI Agent → MCP Gateway → [Service A, Service B, Service C] ``` ### Setup Run multiple services and expose them all through one MCP gateway: ```go users := micro.NewService("users", micro.Address(":8081")) tasks := micro.NewService("tasks", micro.Address(":8082")) notifications := micro.NewService("notifications", micro.Address(":8083")) // Run all together as a modular monolith g := micro.NewGroup(users, tasks, notifications) g.Run() ``` With `micro run`, all services are discovered automatically via the registry, and the MCP tools endpoint at `/mcp/tools` exposes every endpoint from every service. ### When to Use - Most applications start here - Agent needs to orchestrate across services (e.g., "create a task and notify the assignee") - You want the agent to choose which service to call based on the user's request ## Pattern 2: Scoped Agents Different agents have access to different subsets of tools via scopes. ``` Customer Agent → MCP Gateway → [orders:read, support:write] Internal Agent → MCP Gateway → [orders:*, users:*, billing:*] Admin Agent → MCP Gateway → [*] ``` ### Setup Create tokens with different scopes for each agent: ```go // Gateway with scope enforcement mcp.ListenAndServe(":3000", mcp.Options{ Registry: reg, Auth: authProvider, Scopes: map[string][]string{ "billing.Billing.Charge": {"billing:admin"}, "users.Users.Delete": {"users:admin"}, "orders.Orders.List": {"orders:read"}, "orders.Orders.Create": {"orders:write"}, "support.Support.CreateTicket": {"support:write"}, }, }) ``` Then issue different tokens: - Customer-facing agent token: `scopes=["orders:read", "support:write"]` - Internal agent token: `scopes=["orders:read", "orders:write", "users:read"]` - Admin agent token: `scopes=["*"]` ### When to Use - Different trust levels for different agents - Customer-facing vs internal agents - Compliance requirements (e.g., PCI, HIPAA) ## Pattern 3: Agent as Service Consumer Your Go Micro service itself calls an AI model to process data, using the `ai` package. ``` User → API → Your Service → AI Model (Claude/GPT) → Other Services ``` ### Setup ```go import ( "go-micro.dev/v6/ai" _ "go-micro.dev/v6/ai/anthropic" ) type SummaryService struct { ai ai.Model tasks *TaskClient } func NewSummaryService() *SummaryService { return &SummaryService{ ai: ai.New("anthropic", ai.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")), ai.WithModel("claude-sonnet-4-20250514"), ), } } // Summarize generates an AI summary of a project's tasks. // Returns a natural language summary of task status, blockers, and progress. // // @example {"project_id": "proj-1"} func (s *SummaryService) Summarize(ctx context.Context, req *SummarizeRequest, rsp *SummarizeResponse) error { // Fetch tasks from another service tasks, err := s.tasks.List(ctx, req.ProjectID) if err != nil { return err } // Use AI to summarize resp, err := s.ai.Generate(ctx, &ai.Request{ Prompt: fmt.Sprintf("Summarize these tasks:\n%s", formatTasks(tasks)), SystemPrompt: "You are a concise project manager. Summarize task status in 2-3 sentences.", }) if err != nil { return err } rsp.Summary = resp.Reply return nil } ``` ### When to Use - Your service needs to process natural language - Generating summaries, classifications, or extractions - Enriching data with AI before returning to the caller ## Pattern 4: Agent with Tool Calling An AI model calls your services as tools, with automatic tool execution via the ai package. ``` User → Your App → AI Model ←→ MCP Tools (your services) ``` ### Setup ```go import ( "go-micro.dev/v6/ai" _ "go-micro.dev/v6/ai/anthropic" ) // Define tools from your service endpoints tools := []ai.Tool{ { Name: "create_task", Description: "Create a new task with title and assignee", Properties: map[string]any{ "title": map[string]any{"type": "string", "description": "Task title"}, "assignee": map[string]any{"type": "string", "description": "Username"}, }, }, { Name: "list_tasks", Description: "List tasks filtered by status", Properties: map[string]any{ "status": map[string]any{"type": "string", "description": "Filter: todo, in_progress, done"}, }, }, } // Handle tool calls by routing to your services. The handler mirrors a // go-micro RPC handler: context first, the call in, a result out. toolHandler := func(ctx context.Context, call ai.ToolCall) ai.ToolResult { switch call.Name { case "create_task": var rsp CreateResponse err := client.Call(ctx, "tasks", "TaskService.Create", call.Input, &rsp) if err != nil { return ai.ToolResult{ID: call.ID, Content: fmt.Sprintf(`{"error": "%s"}`, err)} } b, _ := json.Marshal(rsp) return ai.ToolResult{ID: call.ID, Value: rsp, Content: string(b)} case "list_tasks": var rsp ListResponse err := client.Call(ctx, "tasks", "TaskService.List", call.Input, &rsp) if err != nil { return ai.ToolResult{ID: call.ID, Content: fmt.Sprintf(`{"error": "%s"}`, err)} } b, _ := json.Marshal(rsp) return ai.ToolResult{ID: call.ID, Value: rsp, Content: string(b)} } return ai.ToolResult{ID: call.ID, Content: `{"error": "unknown tool"}`} } m := ai.New("anthropic", ai.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")), ai.WithToolHandler(toolHandler), ) // The model will automatically call tools and return the final answer resp, err := m.Generate(ctx, &ai.Request{ Prompt: "Create a task for Alice to review the PR and tell me what tasks she has", SystemPrompt: "You are a helpful project management assistant", Tools: tools, }) fmt.Println(resp.Answer) // "I've created a task for Alice to review the PR. She now has 3 tasks: ..." ``` ### When to Use - Building a chatbot or assistant that manages your services - The agent playground in `micro run` uses this pattern - You want the AI to decide which tools to call and in what order ## Pattern 5: Event-Driven Agent Triggers Services emit events that trigger agent actions via the broker. ``` Service → Broker Event → Agent Handler → AI Model → Action ``` ### Setup ```go // Publisher: emit events from your service broker.Publish("tasks.created", &broker.Message{ Body: taskJSON, }) // Subscriber: agent handler reacts to events broker.Subscribe("tasks.created", func(p broker.Event) error { var task Task json.Unmarshal(p.Message().Body, &task) // Use AI to auto-assign based on task content resp, err := aiModel.Generate(ctx, &ai.Request{ Prompt: fmt.Sprintf("Who should handle this task? Title: %s, Description: %s. Team: alice (frontend), bob (backend), charlie (devops)", task.Title, task.Description), SystemPrompt: "Reply with just the username of the best person to handle this task.", }) // Auto-assign client.Call(ctx, "tasks", "TaskService.Update", map[string]any{ "id": task.ID, "assignee": strings.TrimSpace(resp.Reply), }, nil) return nil }) ``` ### When to Use - Automated workflows triggered by service events - AI-powered routing, classification, or triage - Background processing without user interaction ## Pattern 6: Claude Code Integration Developers use Claude Code with your services as MCP tools for local development workflows. ``` Developer → Claude Code → stdio MCP → [local services] ``` ### Setup ```bash # Start services locally micro run # In another terminal, use Claude Code with your services # Claude Code config (~/.claude/claude_desktop_config.json): ``` ```json { "mcpServers": { "my-project": { "command": "micro", "args": ["mcp", "serve"] } } } ``` Now in Claude Code: ``` "List all tasks that are blocked" "Create a user account for the new hire" "Check the health of all services" ``` ### When to Use - Developer productivity workflows - Managing services during development - Testing and debugging with natural language ## Pattern 7: LangChain / LlamaIndex Integration Use the official Python SDKs to connect agent frameworks directly to your services. ### LangChain ```python from langchain_go_micro import GoMicroToolkit # Connect to MCP gateway toolkit = GoMicroToolkit( base_url="http://localhost:3000", token="Bearer ", ) # Get LangChain tools automatically tools = toolkit.get_tools() # Use with any LangChain agent from langchain.agents import AgentExecutor, create_tool_calling_agent agent = create_tool_calling_agent(llm, tools, prompt) executor = AgentExecutor(agent=agent, tools=tools) executor.invoke({"input": "Create a task for Alice"}) ``` ### LlamaIndex ```python from go_micro_llamaindex import GoMicroToolkit toolkit = GoMicroToolkit( base_url="http://localhost:3000", token="Bearer ", ) # Use as LlamaIndex tools tools = toolkit.to_tool_list() # Use with a LlamaIndex agent from llama_index.core.agent import ReActAgent agent = ReActAgent.from_tools(tools, llm=llm) agent.chat("What tasks are assigned to Bob?") ``` ### When to Use - Python-based agent pipelines - RAG (Retrieval-Augmented Generation) workflows with LlamaIndex - Multi-step LangChain chains that orchestrate your services - Teams that prefer Python for AI/ML work ## Pattern 8: Standalone Gateway for Production Run the MCP gateway as a separate, horizontally scalable process. ``` ┌──────────────────┐ Claude/GPT/Agent ──→│ micro-mcp-gateway │──→ Service A (consul) │ (standalone) │──→ Service B (consul) └──────────────────┘──→ Service C (consul) ``` ### Setup ```bash micro-mcp-gateway \ --registry consul \ --registry-address consul:8500 \ --address :3000 \ --auth jwt \ --rate-limit 10 \ --rate-burst 20 \ --audit ``` Or via Docker: ```bash docker run -p 3000:3000 ghcr.io/micro/micro-mcp-gateway \ --registry consul \ --registry-address consul:8500 ``` ### When to Use - Production deployments where you want the gateway to scale independently - Multiple teams deploying services but sharing one MCP endpoint - Enterprise environments needing centralized auth and audit ## Pattern 9: Planning and Delegation Built into the `Agent` abstraction. Every agent gets two harness tools — `plan` and `delegate` — with no extra setup. They are plain tools, not a separate graph runtime. ``` Conductor ──plan──→ (records ordered steps in memory) ──delegate──→ registered agent (RPC) or ephemeral sub-agent ``` ### Setup Nothing to wire — the tools are added to every agent automatically. Guide their use with the prompt: ```go conductor := micro.NewAgent("conductor", micro.AgentServices("task"), micro.AgentPrompt( "For multi-step requests, call the plan tool first to record your steps. "+ "For notifications, delegate to the \"comms\" agent (to: \"comms\")."), micro.AgentProvider("anthropic"), ) ``` - **`plan`** records an ordered list of steps (`task` + `status`) in the agent's store-backed memory, surfaced back on later turns so it stays oriented. - **`delegate`** hands a self-contained subtask to another agent. **Delegate-first**: if the target is a registered agent it's reached over RPC; otherwise a focused, short-lived sub-agent is created with a fresh, isolated context. A sub-agent is just an agent — created with `New`, talked to with `Ask`; there's no separate "spawn"/"fork" concept. Full example: [examples/agent-plan-delegate](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate). ### When to Use - Multi-step tasks where an explicit plan keeps the agent on track - Multi-agent systems where domain experts own their own services and you want hand-offs to stay distributed (not one agent doing everything) ## Choosing a Pattern | Pattern | Complexity | Best For | |---------|-----------|----------| | Single Agent | Low | Most applications, getting started | | Scoped Agents | Medium | Multi-tenant, compliance | | Agent as Consumer | Medium | AI-enhanced services | | Tool Calling | Medium | Chatbots, assistants | | Event-Driven | High | Automation, background processing | | Claude Code | Low | Developer workflows | | LangChain/LlamaIndex | Medium | Python agent pipelines, RAG | | Standalone Gateway | Medium | Production, enterprise | | Planning & Delegation | Medium | Multi-step tasks, distributed multi-agent systems | Start with **Pattern 1** (single agent) and add complexity as needed. Most applications don't need multi-agent architectures. ## Anti-Patterns ### Don't: Chain Agents Without Coordination ``` Agent A → Agent B → Agent C (no shared state, no trace IDs) ``` Instead, use a single agent with multiple tools, or share trace IDs via metadata. ### Don't: Give Agents Unrestricted Access ``` Customer Agent → scopes=["*"] (dangerous!) ``` Always use the minimum required scopes. See the [MCP Security Guide](mcp-security.md). ### Don't: Skip Error Documentation If agents don't know what errors are possible, they can't handle them gracefully. Always document error cases in your handler comments. ### Don't: Build Agent Logic into Services Keep services as pure business logic. Let the agent harness handle orchestration, retries, and decision-making. Your service should just do one thing well. ## Next Steps - [Building AI-Native Services](ai-native-services.md) - End-to-end tutorial - [MCP Security Guide](mcp-security.md) - Auth and scopes - [Tool Description Best Practices](tool-descriptions.md) - Better docs for agents - [AI Package](../../ai/README.md) - AI provider interface