Zum Inhalt springen
_CORE
KI & Agentensysteme Unternehmensinformationssysteme Cloud & Platform Engineering Datenplattform & Integration Sicherheit & Compliance QA, Testing & Observability IoT, Automatisierung & Robotik Mobile & Digitale Produkte Banken & Finanzen Versicherungen Öffentliche Verwaltung Verteidigung & Sicherheit Gesundheitswesen Energie & Versorgung Telko & Medien Industrie & Fertigung Logistik & E-Commerce Retail & Treueprogramme
Referenzen Technologien Blog Know-how Tools
Über uns Zusammenarbeit Karriere
CS EN DE
Lassen Sie uns sprechen

Tool Use Patterns

10. 06. 2023 4 Min. Lesezeit intermediate

Large language models and AI agents revolutionize how we interact with tools and automate complex tasks. Proper understanding of their usage patterns is key to maximizing efficiency and minimizing errors.

Tool-Use-Patterns: Effektive Werkzeugnutzung in LLM-Agenten

Modern language models have gained the ability to use external tools – from API calls through database queries to complex system operations. The key to success isn’t just technical implementation, but especially proper design patterns that ensure reliability and efficiency of the entire system.

ReAct-Pattern: Grundlegender Baustein

ReAct (Reasoning + Acting) represents a fundamental pattern for tool use. The model proceeds in cycles: analyzes the situation, decides on action, executes it, and evaluates the result. This pattern ensures transparency of decision processes and enables debugging.

class ReActAgent:
    def __init__(self, llm, tools):
        self.llm = llm
        self.tools = {tool.name: tool for tool in tools}

    def run(self, task):
        context = f"Task: {task}\n"
        max_iterations = 10

        for i in range(max_iterations):
            # Reasoning phase
            response = self.llm.generate(
                f"{context}\nWhat should I do next? Think step by step."
            )

            if "FINAL_ANSWER:" in response:
                return self.extract_final_answer(response)

            # Acting phase
            if "ACTION:" in response:
                action, args = self.parse_action(response)
                result = self.tools[action].execute(args)
                context += f"Action: {action}({args})\nResult: {result}\n"

        return "Max iterations reached"

Chain-of-Tools-Pattern

For more complex tasks, we need to chain multiple tools together. Chain of Tools pattern defines explicit operation order and data passing between individual steps.

class ToolChain:
    def __init__(self, steps):
        self.steps = steps

    async def execute(self, initial_data):
        current_data = initial_data

        for step in self.steps:
            try:
                current_data = await step.process(current_data)
                self.log_step(step.name, current_data)
            except Exception as e:
                return self.handle_chain_failure(step, e, current_data)

        return current_data

# Usage for data pipeline
pipeline = ToolChain([
    DatabaseQuery("SELECT * FROM users WHERE active=1"),
    DataTransform("normalize_emails"),
    APICall("send_newsletter"),
    LogResults("newsletter_campaign")
])

result = await pipeline.execute({"campaign_id": "2024-01"})

Tool-Selection-Pattern

When we have multiple tools available for the same task type, we need an intelligent selection mechanism. Tool Selection pattern combines tool metadata with contextual model decision-making.

class ToolSelector:
    def __init__(self, tools):
        self.tools = tools
        self.usage_stats = defaultdict(lambda: {"success": 0, "failure": 0})

    def select_tool(self, task_description, context):
        # Get candidates by capability
        candidates = [t for t in self.tools if t.can_handle(task_description)]

        if len(candidates) == 1:
            return candidates[0]

        # LLM decision with metrics
        tool_info = []
        for tool in candidates:
            stats = self.usage_stats[tool.name]
            success_rate = stats["success"] / (stats["success"] + stats["failure"] + 1)

            tool_info.append({
                "name": tool.name,
                "description": tool.description,
                "success_rate": success_rate,
                "avg_latency": tool.avg_latency
            })

        selection_prompt = f"""
        Task: {task_description}
        Context: {context}

        Available tools:
        {json.dumps(tool_info, indent=2)}

        Select the most appropriate tool and explain why.
        """

        response = self.llm.generate(selection_prompt)
        return self.parse_tool_selection(response, candidates)

Error-Recovery-Pattern

Robust tool use systems must elegantly handle errors. Error Recovery pattern implements hierarchy of fallback strategies – from simple retry through alternative tools to graceful degradation.

class ResilientToolExecutor:
    def __init__(self, primary_tool, fallback_tools=None):
        self.primary_tool = primary_tool
        self.fallback_tools = fallback_tools or []
        self.retry_config = {"max_attempts": 3, "backoff": 2}

    async def execute_with_recovery(self, args):
        # Attempt with primary tool
        for attempt in range(self.retry_config["max_attempts"]):
            try:
                result = await self.primary_tool.execute(args)
                return {"success": True, "result": result, "tool_used": self.primary_tool.name}

            except RetryableError as e:
                if attempt < self.retry_config["max_attempts"] - 1:
                    await asyncio.sleep(self.retry_config["backoff"] ** attempt)
                    continue

            except NonRetryableError:
                break

        # Fallback tools
        for fallback_tool in self.fallback_tools:
            if fallback_tool.can_substitute(self.primary_tool):
                try:
                    adapted_args = self.adapt_args(args, fallback_tool)
                    result = await fallback_tool.execute(adapted_args)
                    return {
                        "success": True, 
                        "result": result, 
                        "tool_used": fallback_tool.name,
                        "fallback": True
                    }
                except Exception:
                    continue

        return {"success": False, "error": "All recovery attempts failed"}

Parallele Werkzeugausfuehrung

For performance-critical applications, parallelization is key. This pattern enables concurrent execution of independent tools with intelligent resource management and dependency handling.

class ParallelToolManager:
    def __init__(self, max_concurrency=5):
        self.max_concurrency = max_concurrency
        self.semaphore = asyncio.Semaphore(max_concurrency)

    async def execute_parallel(self, tool_tasks):
        # Split by dependencies
        independent_tasks = []
        dependent_tasks = []

        for task in tool_tasks:
            if task.dependencies:
                dependent_tasks.append(task)
            else:
                independent_tasks.append(task)

        # Parallel execution of independent tasks
        results = {}
        independent_results = await asyncio.gather(*[
            self._execute_with_semaphore(task) for task in independent_tasks
        ], return_exceptions=True)

        # Update results
        for task, result in zip(independent_tasks, independent_results):
            results[task.id] = result

        # Sequential processing of dependent tasks
        for task in dependent_tasks:
            if self._dependencies_satisfied(task, results):
                result = await self._execute_with_semaphore(task)
                results[task.id] = result

        return results

    async def _execute_with_semaphore(self, task):
        async with self.semaphore:
            return await task.tool.execute(task.args)

Praktische Implementierungstipps

When implementing tool use patterns, we recommend:

  • Monitoring and logging: Log all tool calls including latency and error rates
  • Tool versioning: Implement versioning for backward compatibility
  • Resource management: Use connection pooling and rate limiting
  • Testing: Mock external tools for unit tests
  • Security: Validate all inputs and implement sandboxing

Zusammenfassung

Tool-Use-Patterns stellen eine kritische Komponente moderner LLM-Anwendungen dar. Das ReAct-Pattern bildet die Grundlage fuer Reasoning, waehrend fortgeschrittene Patterns wie Chain of Tools, Tool Selection und Error Recovery Robustheit und Skalierbarkeit gewaehrleisten. Die korrekte Implementierung dieser Patterns, kombiniert mit gruendlichem Monitoring und Testen, schafft zuverlaessige Systeme, die komplexe reale Aufgaben bewaeltigen koennen. Der Schluessel zum Erfolg ist die Balance zwischen Flexibilitaet und Vorhersagbarkeit sowie immer einen Plan B fuer Situationen zu haben, in denen primaere Werkzeuge versagen.

tool usereactpatterns
Teilen:

CORE SYSTEMS Team

Wir bauen Kernsysteme und KI-Agenten, die den Betrieb am Laufen halten. 15 Jahre Erfahrung mit Enterprise-IT.