# How to Contribute to the Qwen-Agent Project: A Developer’s Guide

> Learn how to contribute to the Qwen-Agent project. Explore the repository, install dependencies, and submit pull requests following the four-layer architecture for effective collaboration.

- Repository: [Qwen/Qwen-Agent](https://github.com/qwenlm/Qwen-Agent)
- Tags: how-to-guide
- Published: 2026-03-09

---

**To contribute to the Qwen-Agent project, fork the repository, install full optional dependencies with `pip install -U "qwen-agent[gui,rag,code_interpreter,mcp]"`, and submit a pull request that follows the four-layer architecture by subclassing `BaseTool` with the `@register_tool` decorator or extending `FnCallAgent`, while ensuring all changes pass the `pytest` suite.**

Qwen-Agent is a modular framework for building LLM-driven applications with tool use, planning, and memory. To contribute to the Qwen-Agent project effectively, you must understand its layered architecture and follow the established Git workflow for adding tools, agents, or documentation.

## Understand the Four-Layer Architecture

Qwen-Agent separates concerns into four distinct layers. Understanding these boundaries ensures your contributions integrate cleanly with the existing codebase.

| Layer | Purpose | Key Source |
|-------|---------|------------|
| **LLM Integration** | Provides abstract chat model classes (`BaseChatModel`) and concrete implementations for DashScope, OpenAI-compatible services, and OpenVINO. | [`qwen_agent/llm/base.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/base.py) |
| **Tools** | Define reusable utilities (web search, code interpreter, vector search) that the LLM can call. Tools are registered with the global **TOOL_REGISTRY** via the **@register_tool** decorator. | [`qwen_agent/tools/base.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/tools/base.py) |
| **Memory / Retrieval** | Handles on-the-fly knowledge extraction from uploaded files or external sources, exposing a `mem.run()` API used by agents. | [`qwen_agent/memory/memory.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/memory/memory.py) |
| **Agents** | High-level orchestration components that combine LLMs, tools, and memory to perform complete tasks. The most common entry point is the **Assistant** class, built on top of the function-calling base agent. | [`qwen_agent/agents/assistant.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/assistant.py) |

## Set Up Your Development Environment

Follow these steps to prepare a local workspace that can exercise all modules, including the GUI, RAG, and code interpreter components.

1. **Fork and clone** the repository to your GitHub account.

```bash
git clone https://github.com/<your-username>/Qwen-Agent.git
cd Qwen-Agent

```

2. **Install dependencies** with all optional extras to ensure you can run the full test matrix locally.

```bash
pip install -U "qwen-agent[gui,rag,code_interpreter,mcp]"

```

3. **Run the test suite** with `pytest` to verify that the existing code passes before you begin modifications.

```bash
pytest -q

```

## Implement New Features

Create a feature branch using conventional naming (`feat/<description>` or `fix/<description>`), then implement your changes according to the layer you are extending.

### Adding Custom Tools

Subclass **BaseTool** (or **BaseToolWithFileAccess** when file I/O is required) and decorate the class with `@register_tool('<your-tool-name>')`. Implement the `call` method and optionally override `file_access`. The built-in example in [`qwen_agent/tools/web_search.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/tools/web_search.py) demonstrates how to perform external HTTP queries within this contract.

### Extending Agents

Inherit from **FnCallAgent** or **Agent** and implement `_run` or other lifecycle hooks. The `Assistant` class in [`qwen_agent/agents/assistant.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/assistant.py) shows how to inject RAG knowledge and delegate to the generic function-calling loop defined in [`qwen_agent/agents/fncall_agent.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/fncall_agent.py).

### Updating Documentation

Modify [`README.md`](https://github.com/QwenLM/Qwen-Agent/blob/main/README.md), update the online docs under `qwen-agent-docs/`, and add usage examples to the `examples/` folder, such as [`assistant_rag.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/assistant_rag.py) or [`assistant_qwen3.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/assistant_qwen3.py).

## Validate and Submit Your Changes

Before opening a pull request, ensure your code meets the repository’s quality standards.

- **Lint and type-check** using `ruff` or `black` (if configured) and `mypy` to maintain consistent Python formatting.
- **Commit** with concise messages that reference issues (e.g., `Fix #123 – add vector-search tool`).

```bash
git add .
git commit -m "feat: add custom vector-search tool"
git push origin feat/custom-tool

```

- **Open a Pull Request** targeting the `main` branch, describing the change and linking related issues. The CI pipeline automatically runs `pytest` and lint checks.
- **Iterate** based on reviewer feedback until the PR is approved and merged.

## Code Example: Building a Custom Calculator Tool

The following example demonstrates how to register a new tool and use it with the **Assistant** agent. This pattern mirrors the "Creating a custom tool" section in the README and shows how the framework automatically discovers tools via the **TOOL_REGISTRY**.

```python

# 1️⃣ Define a custom tool (e.g., a simple calculator)

from qwen_agent.tools.base import BaseTool, register_tool
import json5

@register_tool('calc')
class CalcTool(BaseTool):
    description = 'Simple arithmetic calculator.'
    parameters = [{
        'name': 'expression',
        'type': 'string',
        'description': 'A mathematical expression, e.g., "3 * (4 + 5)"',
        'required': True
    }]

    def call(self, params: str, **kwargs):
        args = json5.loads(params)
        expr = args['expression']
        # NOTE: In production, use a safe eval library.

        result = eval(expr, {'__builtins__': {}})
        return json5.dumps({'result': result})

# 2️⃣ Configure the LLM (DashScope example)

llm_cfg = {
    'model': 'qwen-max-latest',
    'model_type': 'qwen_dashscope',
    # API key is read from the DASHSCOPE_API_KEY env var automatically.

    'generate_cfg': {'top_p': 0.8}
}

# 3️⃣ Instantiate the Assistant agent with the custom tool

from qwen_agent.agents import Assistant

assistant = Assistant(
    llm=llm_cfg,
    function_list=['calc'],   # Enable the newly-registered tool

    system_message='You are a helpful calculator bot.'
)

# 4️⃣ Run a chat loop

messages = [{'role': 'user', 'content': 'What is 12 divided by 3?'}]
for response in assistant.run(messages=messages):
    print(response)   # The agent will call `calc` internally and return the answer.

```

## Key Source Files for Contributors

When contributing to the Qwen-Agent project, reference these specific files to understand implementation patterns.

| File | Role |
|------|------|
| [`qwen_agent/agents/assistant.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/assistant.py) | Core agent that injects RAG knowledge and delegates to the generic `FnCallAgent`. |
| [`qwen_agent/agents/fncall_agent.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/fncall_agent.py) | Implements the function-calling loop, tool selection, and streaming output. |
| [`qwen_agent/tools/base.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/tools/base.py) | Global tool registry, `BaseTool` abstraction, and JSON-schema validation. |
| [`qwen_agent/tools/web_search.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/tools/web_search.py) | Example of a built-in tool that performs external HTTP queries. |
| [`qwen_agent/memory/memory.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/memory/memory.py) | Provides retrieval of knowledge from uploaded files or external indices. |
| `qwen_agent/llm/` | Contains adapters for DashScope, OpenAI-compatible services, and OpenVINO. |
| [`qwen_agent/gui/web_ui.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/gui/web_ui.py) | Gradio-based web UI that showcases how to launch an agent interactively. |
| `examples/` | Ready-to-run scripts illustrating typical usage patterns. |
| `tests/` | Unit and integration tests covering agents, tools, and memory. |

## Summary

- **Qwen-Agent** uses a four-layer architecture: LLM Integration, Tools, Memory, and Agents.
- Register new tools by subclassing **BaseTool** and using the **@register_tool** decorator in [`qwen_agent/tools/base.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/tools/base.py).
- Extend agents by inheriting from **FnCallAgent** or **Agent** in `qwen_agent/agents/`.
- Install all optional dependencies (`gui,rag,code_interpreter,mcp`) to ensure your development environment matches CI requirements.
- Always run `pytest -q` and lint checks before submitting a pull request to the `main` branch.

## Frequently Asked Questions

### Do I need to install all optional dependencies to contribute to Qwen-Agent?

While you can contribute with only base dependencies, installing the full suite via `pip install -U "qwen-agent[gui,rag,code_interpreter,mcp]"` ensures you can run the complete test suite and verify that your changes do not break GUI, RAG, or MCP integrations. The CI pipeline tests against all optional extras, so local verification prevents review delays.

### What is the difference between BaseTool and BaseToolWithFileAccess?

**BaseTool** is the standard abstract class for stateless utilities like calculators or API clients. **BaseToolWithFileAccess** extends this interface for tools that must read from or write to the filesystem, providing additional lifecycle hooks for file I/O management. Choose the latter when your tool processes uploaded documents or generates artifacts.

### How do I test my custom tool before submitting a PR?

Create a unit test in the `tests/` directory that instantiates your tool class and calls the `call()` method with valid and invalid JSON parameters. You can also run the tool through the **Assistant** agent in an integration test to verify that the **TOOL_REGISTRY** correctly resolves your tool by name and that the LLM can invoke it during a conversation loop.

### Which agent class should I extend for new functionality?

Extend **FnCallAgent** if your agent requires function-calling capabilities and tool use, as it implements the core loop for selecting and executing tools. Extend the base **Agent** class only if you are building a completely custom orchestration pattern that does not rely on the standard tool-calling protocol defined in [`qwen_agent/agents/fncall_agent.py`](https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/agents/fncall_agent.py).