Agent Canvas/Tools & Integration/ — Tools & Integration

Extensible framework for external integrations and tool calling

ToolBase with validation and error handling; registry for lookup; 24 tools: code_exec (sandboxed Python), tavily (web search), retrieval (RAG), sql_executor, web_crawler, email, api_request, tool_invoke, and 16 more. Each supports max_retries, fallback, and timeout.

N
Classes
N
Files
~N k
Lines
N
Key Metric

📚 What is this & why does it exist?

Tools enable workflows to interact with the outside world: code execution, web search, databases, emails, APIs. Without tools, workflows are isolated. The framework provides sandboxing, error handling, and resource limits. — Replace with 2-4 plain-English sentences explaining what this sub-module does and why it exists. No jargon. Target audience: someone who hasn't read the code.

💡 Real-world analogy

Like stdlib modules: ToolBase = abstract signature; each tool (code_exec, tavily, sql_executor) = implementation; registry = module namespace. Agent calls by name at runtime. — Replace with a vivid, concrete metaphor mapping this sub-module's core concept to everyday life (restaurant, airport, library, highway, etc.). 3-5 sentences.

🤔 Why Is It Designed This Way?

Tools called by name at runtime enable LLMs to decide what to use. Sandboxing (RestrictedPython) isolates untrusted code. Retries with backoff handle transient API failures. Explicit registry (not reflection) avoids footguns. — 150+ words explaining the design choices: what pattern does this follow and why? What constraints shaped the implementation? What trade-offs were made and what was sacrificed?

Design ChoiceWhat Was ChosenWhat Was RejectedWhy
Tool lookupRegistry with factories (explicit)Dynamic import by name (reflection)Explicit registry is safe; reflection risks unintended side effects and circular imports
Code executionRestrictedPython sandboxUnrestricted eval() / exec()Sandbox prevents compromise of host; restricts imports and dangerous builtins
Error handlingRetry + fallback + rerouteFail-fast exception propagationResilience is critical for unreliable external tools; fallback enables graceful degradation
Resource limitsTimeout per tool, memory limit for code_execNo limits (rely on environment)Explicit limits prevent hung workflows and resource exhaustion

Contents

Architecture

graph TB
    BASE["ToolBase
Abstract Base"] REGISTRY["Tool
Registry"] BASE --> REGISTRY CODE["code_exec
Sandbox
RestrictedPython"] --> REGISTRY TAVILY["tavily
Web Search
Tavily API"] --> REGISTRY RETRIEVAL["retrieval
RAG Query
Vector DB"] --> REGISTRY SQL["sql_executor
SQL Query
Database"] --> REGISTRY CRAWLER["web_crawler
HTML Parse
BeautifulSoup"] --> REGISTRY EMAIL["email
SMTP
Send Mail"] --> REGISTRY API["api_request
HTTP
GET/POST"] --> REGISTRY INVOKE["tool_invoke
Recursive
Call Tool"] --> REGISTRY

Tool Execution Lifecycle

flowchart TD
    Lookup["Tool Lookup
By Name"] Init["__init__
Configure"] Validate["Validate
Params"] Execute["_execute()
Run Tool"] Retry{"Transient
Error?"} Success["Success
Return Result"] Fallback["Fallback
exception_default_value"] Lookup --> Init Init --> Validate Validate --> Execute Execute --> Retry Retry -->|Yes| Execute Retry -->|No| Success Retry -->|Exhausted| Fallback style Success fill:#c8e6c9 style Fallback fill:#ffccbc

Key Classes

Class / FunctionFilePurpose
ToolBasetools/base.pyAbstract base with init, validate_params, run; all tools inherit
CodeExecTooltools/code_exec.pyExecutes Python in RestrictedPython sandbox; isolated globals; timeout enforced
TavilyTooltools/tavily.pyWeb search integration; queries Tavily API; returns results with snippets
RetrievalTooltools/retrieval.pyRAG database query; retrieves relevant documents from vector store
SqlExecutorTooltools/sql_executor.pyExecutes SQL with parameterized queries; prevents injection; returns rows as JSON

Data Structures

TypeNameDescription
dictparamsInput parameters for tool (e.g., {query: "python", num_results: 5})
dictoutputTool output: {success: bool, result: any, error: str, duration_ms: int}
dictschema.inputsParameter schema: [{name, type, default, description}]
listretriesRetry history: [{attempt, error, backoff_ms, timestamp}]
inttimeout_secExecution timeout; raises exception if exceeded

Interactions

DirectionPartnerInterfaceDescription
→Agent Componenttool_registry.get(name)Agent looks up tool by name; factory instantiates with args
→External APIsrequests.get/post(), database.query()Tools make outbound calls; failures trigger retry logic
→Code SandboxRestrictedPython.execute(code)code_exec tool runs untrusted Python safely in restricted environment
←CanvasCanvas records tool call in historyCanvas logs all tool calls for audit and performance profiling

Configuration

Knob / ParameterDefaultDescription
max_retries3Retry attempts on transient error (timeout, 5xx, rate limit)
backoff_multiplier2Exponential backoff: wait = base_delay * (multiplier ^ attempt)
timeout_sec30Max execution time; TimeoutError raised if exceeded
exception_default_valuenullReturn this if all retries exhausted

Directory Map

Source tree for Tools & Integration
submod_name/
├── file_a.ext                 ← Role: brief annotation
├── file_b.ext                 ← Role: brief annotation
├── file_c.ext                 ← Role: brief annotation
└── index.ext                  ← Role: entry point

📑 Annotated Code Walkthrough

The most important code in this sub-module, annotated with WHY each piece exists:

run(params) — Execute tool with arguments

// Replace with actual code from the source
void key_function() {
    // ← WHY: Explain the purpose of this line
    // ← WHY: What constraint or requirement drives this?
}

Line-by-line:

  • Line N: What this does and WHY — what would break if removed
  • Line M: The design choice here — why this approach over the obvious alternative

⚠️ Edge Cases & Boundaries

Edge CaseWhat HappensWhere in CodeRisk Level
API rate limit (429)Treated as transient; retry with exponential backoffTavilyTool.run()🔴 High — without backoff, could hammer API; exhausts quota
Code sandbox escape attempt (e.g., eval, __import__)RestrictedPython prevents execution; SyntaxError or NameError raisedCodeExecTool.run()🟢 Low — sandbox prevents harm
SQL injection (e.g., "'; DROP TABLE users; --")Parameterized queries escape input; executed as data, not SQL syntaxSqlExecutorTool.run()🟢 Low — parameterized queries prevent injection
Tool timeout (LLM API slow, network hangs)Timeout exception caught; retry logic applies; if all fail, exception_default_value returnedToolBase.run()🔴 High — timeout prevents hung workflows
Recursive tool_invoke (A → B → A)Call depth tracked; error if depth > max_depth (default 10)ToolInvokeTool.run()🔴 High — prevents stack overflow
Concurrent accessHow it's handledfunction_name:line🔴 High

Deep-Dive Highlights

Core mechanisms from this sub-module have been extracted into dedicated focus pages for in-depth exploration. Each page covers one algorithm, protocol, or subsystem with diagrams, code walks, and configuration details.

Deep-Dive Pages

Code Examples

Example: Typical Usage

// Replace with actual code example
void example() {
    // ...
}

Tool Failure Modes & Recovery Strategies

Tools fail in predictable ways. RAGFlow implements tiered recovery strategies for each failure mode.

Failure Mode Classification

ModeExampleIs Retriable?Recovery Strategy
Transient NetworkConnection timeout, DNS lookup failed, socket reset✓ YesExponential backoff retry; max 5 attempts
Transient ServiceHTTP 503 Service Unavailable, API rate limit (429)✓ YesExponential backoff; may include jitter to avoid thundering herd
Permanent ServiceHTTP 404 Not Found, HTTP 401 Unauthorized, invalid API key✗ NoUse exception_default_value (fallback output) or exception_goto (jump to error handler)
Invalid InputParameter validation failed, malformed request body✗ NoLog error; use exception_default_value or abort
Resource LimitMemory exhausted in code_exec sandbox, query result too large✗ NoUse exception_default_value; increase limits if possible
TimeoutTool execution exceeded timeout duration✓ Yes (maybe)Retry with longer timeout; if still fails, use fallback

Retry Configuration Example

{
  "nodes": [
    {
      "id": "web_search_1",
      "type": "tavily",
      "config": {
        "query": "{{llm_1@output.search_query}}",
        "max_results": 10,
        "timeout": 30,
        "retry_max": 3,
        "retry_backoff_ms": 100,
        "exception_default_value": {
          "results": [],
          "error": "Search service unavailable; using empty results"
        }
      }
    }
  ]
}

Tool Monitoring & Observability

Advanced Tool Patterns & Integration

Beyond basic tool invocation, RAGFlow supports sophisticated patterns for composition, fallbacks, and context passing.

Tool Composition Patterns

Error Handling & Resilience Tiers

TierStrategyWhen to Use
Tier 1: InstantReturn exception_default_value immediately on first failureNon-critical tools; failure is acceptable
Tier 2: Retry with BackoffRetry 3-5 times with exponential backoff (100ms, 200ms, 400ms, 800ms...)Transient failures expected (network glitch, rate limit). Default.
Tier 3: Fallback + PropagateRetry, then try fallback tool, then propagate error to exception handlerCritical path; multiple fallback options (web search → cache → error).
Tier 4: Manual InterventionPause workflow; log for human review; wait for manual tool result injectionHigh-stakes decisions; no good fallback (approve/reject document).

Tool Context & State Management