# How the Tool‑Calling Agent Architecture Works in Open‑Code‑Review

> Discover the tool calling agent architecture in open code review. Learn how LLMs invoke external utilities via schema-driven prompts and JSON function calls for efficient code analysis.

- Repository: [Alibaba/open-code-review](https://github.com/alibaba/open-code-review)
- Tags: internals
- Published: 2026-08-03

---

**The tool‑calling agent in open‑code‑review lets an LLM invoke external utilities during code review by constructing a schema‑driven prompt, parsing JSON function calls from the model, and dispatching execution to concrete tool implementations.**

The open‑code‑review repository implements a **tool‑calling agent** that bridges large language model reasoning with external system capabilities. This architecture enables the agent to perform actions like running git commands, triggering CI pipelines, or querying issue trackers while maintaining a clean separation between LLM decision‑making and tool execution. The design centers on three layers: prompt construction with tool schemas, LLM response parsing, and dynamic tool dispatch.

---

## Architecture Overview

The tool‑calling agent architecture consists of three tightly coupled layers that transform an LLM's intent into executable actions.

### 1. Prompt and Schema Generation

The agent begins by loading **tool descriptors** from [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json). Each descriptor defines:

- Tool name and description
- JSON Schema for parameters
- Implementation class path

In [`open_code_review/agent.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/agent.py), the `ToolCallingAgent` class constructs a system prompt that injects this tool catalog. The LLM receives explicit instructions on which functions it may call and what arguments each requires.

```json
// toolsconfig/tools.json – example entry
{
  "name": "git_diff",
  "description": "Returns the diff between two git refs",
  "parameters": {
    "type": "object",
    "properties": {
      "repo_path": {"type": "string"},
      "base": {"type": "string"},
      "head": {"type": "string"}
    },
    "required": ["repo_path", "base", "head"]
  },
  "implementation": "open_code_review.tools.git_diff.GitDiffTool"
}

```

### 2. LLM Invocation and Function‑Call Parsing

The `invoke()` method in [`open_code_review/agent.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/agent.py) sends the constructed prompt to the configured LLM. The response is inspected for a `function_call` field containing JSON structured data.

When detected, the agent:

1. Validates the JSON against the schema from [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json)
2. Instantiates a `ToolCall` object with the tool name and parsed arguments
3. Proceeds to dispatch rather than returning raw text

```python

# Simplified flow from agent.py

response = llm_client.chat(messages=messages, tools=tool_schemas)

if response.get("function_call"):
    tool_call = ToolCall(
        name=response["function_call"]["name"],
        arguments=json.loads(response["function_call"]["arguments"])
    )
    # Proceed to dispatch layer

else:
    # Return direct LLM text response

    return response["content"]

```

### 3. Tool Dispatch and Execution

The dispatch layer in [`open_code_review/tool_dispatcher.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tool_dispatcher.py) resolves tool names to concrete implementations. Each tool inherits from `BaseTool` defined in [`open_code_review/tools/base_tool.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tools/base_tool.py), which enforces a consistent `run()` interface.

The dispatcher:

- Dynamically imports the class specified in `implementation`
- Instantiates the tool with runtime configuration
- Calls `run()` with validated arguments
- Captures stdout/stderr and returns sanitized output

The tool output is then wrapped into a new message structure and sent back to the LLM, creating a **feedback loop** for multi‑turn reasoning.

---

## Code Implementation Examples

### Creating a Custom Tool

All tools inherit from `BaseTool` and implement the `run()` method with typed parameters matching their JSON schema.

```python

# open_code_review/tools/my_tool.py

from .base_tool import BaseTool

class MyTool(BaseTool):
    """Echoes input text back to the agent."""
    
    def run(self, message: str) -> str:
        """
        Parameters must match the 'parameters' schema 
        in toolsconfig/tools.json exactly.
        """
        return f"Tool output: {message}"

```

Register in [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json):

```json
{
  "name": "my_tool",
  "description": "Echoes the supplied string back",
  "parameters": {
    "type": "object",
    "properties": {
      "message": {
        "type": "string",
        "description": "Text to echo"
      }
    },
    "required": ["message"]
  },
  "implementation": "open_code_review.tools.my_tool.MyTool"
}

```

### Using the Tool‑Calling Agent

```python
from open_code_review.agent import ToolCallingAgent

# Initialize with model configuration

agent = ToolCallingAgent(model="gpt-4o-mini")

review_prompt = """
Review this pull request. If you need additional context 
about file changes, use the git_diff tool. Explain your reasoning.
"""

# Single call handles full loop: prompt → LLM → parse → dispatch → result

response = agent.invoke(review_prompt)

# Response contains final LLM answer after any tool calls complete

print(response.final_answer)

```

### Manual Tool Dispatch (Testing and Debugging)

```python
from open_code_review.tool_dispatcher import ToolDispatcher

dispatcher = ToolDispatcher()

# Execute tool directly without LLM involvement

result = dispatcher.run_tool(
    name="git_diff",
    args={
        "repo_path": "/path/to/repo",
        "base": "main",
        "head": "feature-branch"
    }
)

print(result)  # Raw diff output that would feed back to LLM

```

---

## Core Source Files

| File | Purpose |
|------|---------|
| [`open_code_review/agent.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/agent.py) | `ToolCallingAgent` class — prompt building, LLM interaction, function‑call detection |
| [`open_code_review/tool_dispatcher.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tool_dispatcher.py) | `ToolDispatcher` class — dynamic tool resolution and execution |
| [`open_code_review/tools/base_tool.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tools/base_tool.py) | `BaseTool` abstract class — interface contract for all tools |
| [`open_code_review/tools/git_diff.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tools/git_diff.py) | Reference implementation showing git command execution |
| [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json) | Central registry of available tools with JSON schemas |

---

## Summary

- **Schema‑driven prompts** make tool capabilities explicit to the LLM via [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json)
- **JSON function‑call parsing** extracts structured tool requests from model responses in [`agent.py`](https://github.com/alibaba/open-code-review/blob/main/agent.py)
- **Dynamic dispatch** through [`tool_dispatcher.py`](https://github.com/alibaba/open-code-review/blob/main/tool_dispatcher.py) isolates execution logic from LLM reasoning
- **BaseTool abstraction** in [`open_code_review/tools/base_tool.py`](https://github.com/alibaba/open-code-review/blob/main/open_code_review/tools/base_tool.py) enables consistent tool development
- **Feedback loop architecture** allows multi‑turn tool use where previous results inform subsequent LLM reasoning

---

## Frequently Asked Questions

### How does the agent prevent invalid tool calls?

The `ToolCallingAgent` validates incoming `function_call` JSON against the schema defined in [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json) before dispatch. Missing required parameters or type mismatches trigger an error response that the LLM receives as feedback, allowing it to correct and retry.

### Can tools maintain state between calls?

Tool implementations in `open_code_review/tools/` are designed as **stateless functions**. Any persistence (caching, session data) is handled externally through the `ToolDispatcher` configuration or passed explicitly via arguments in each call.

### What LLM providers are supported?

The `ToolCallingAgent` in [`agent.py`](https://github.com/alibaba/open-code-review/blob/main/agent.py) abstracts provider details through a client interface. The repository supports OpenAI‑compatible APIs and can extend to other providers by implementing the chat completion interface with function‑call response formats.

### How do I add a tool that requires authentication?

Store credentials in environment variables or a secrets manager, then access them within your tool's `run()` method. Never expose secrets in [`toolsconfig/tools.json`](https://github.com/alibaba/open-code-review/blob/main/toolsconfig/tools.json) — that file should only contain schema and implementation metadata, not runtime configuration values.