File size: 10,199 Bytes
f74e974
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# πŸ› οΈ Code LLM Toolkit: Fine-tune + RAG + Tool-Calling for Internal Codebases

A complete toolkit for building a Python code generation LLM that can search your internal codebase via RAG, call tools, and reason through multi-step tasks.

## Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Code LLM System                             β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚  Fine-tuned   β”‚   β”‚  RAG Pipeline β”‚   β”‚  Tool Executor       β”‚β”‚
β”‚  β”‚  Qwen2.5-     │◄──│  (AST-aware   β”‚   β”‚  - search_codebase  β”‚β”‚
β”‚  β”‚  Coder-7B     β”‚   β”‚   chunking +  β”‚   β”‚  - execute_python   β”‚β”‚
β”‚  β”‚  + LoRA       β”‚   β”‚   embeddings) β”‚   β”‚  - read_file        β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  - run_tests        β”‚β”‚
β”‚         β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚         β”‚            ReAct Agent Loop              β”‚            β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚
β”‚                            β”‚                                     β”‚
β”‚                     β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”                              β”‚
β”‚                     β”‚   Response   β”‚                              β”‚
β”‚                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

## Research Foundation

Every component is grounded in published research with verified results:

| Component | Paper | Key Result |
|-----------|-------|------------|
| **Base Model** | [Qwen2.5-Coder](https://arxiv.org/abs/2409.12186) | HumanEval 88.4% (7B), SOTA open-source |
| **Tool-Calling Data** | [ToolACE](https://arxiv.org/abs/2409.00920) | Beats GPT-4-turbo on BFCL benchmark |
| **Multi-turn Agent Data** | [APIGen-MT](https://arxiv.org/abs/2504.03601) | 78.19% BFCL v3 (#1, beats o1/GPT-4o) |
| **Code SFT Data** | [Magicoder](https://arxiv.org/abs/2312.02120) | HumanEval 70.7% from 7B with 185K samples |
| **RAG Chunking** | [cAST](https://arxiv.org/abs/2506.15655) | +5.6pp over fixed-size on RepoEval |
| **RAG Strategy** | [AllianceCoder](https://arxiv.org/abs/2503.20589) | API signatures > similar code (+20%) |
| **Retriever-Aware Training** | [Gorilla](https://arxiv.org/abs/2305.15334) | Outperforms GPT-4 on API accuracy |
| **Code Embeddings** | [CodeSage-v2](https://huggingface.co/codesage/codesage-large-v2) | Best open code embedding model |
| **LoRA for Code** | [Astraios](https://arxiv.org/abs/2401.00788) | LoRA matches FFT at β‰₯16B scale |

## Quick Start

### Step 1: Prepare Training Data

Merges 4 verified datasets (ToolACE + APIGen-MT + Magicoder + CodeAct) into a unified ChatML format:

```bash
pip install datasets

# Test with small sample first
python prepare_data.py --max_per_source 100 --dry_run

# Full run β€” pushes merged dataset to Hub
python prepare_data.py --output_repo your-username/code-toolcall-sft-data
```

**Dataset composition (~110K examples):**
| Source | Examples | Purpose |
|--------|----------|---------|
| [Team-ACE/ToolACE](https://huggingface.co/datasets/Team-ACE/ToolACE) | 26K | Tool-calling (single-turn) |
| [Salesforce/APIGen-MT-5k](https://huggingface.co/datasets/Salesforce/APIGen-MT-5k) | 5K | Multi-turn agentic tool use |
| [Magicoder-OSS-Instruct-75K](https://huggingface.co/datasets/ise-uiuc/Magicoder-OSS-Instruct-75K) | ~25K (Python) | Python code generation |
| [xingyaoww/code-act](https://huggingface.co/datasets/xingyaoww/code-act) | 7K | Code-as-action (tools via Python) |

### Step 2: Add Your Internal Codebase Data

**This is the most impactful step.** Use the Gorilla/Magicoder pattern:

1. **OSS-Instruct on your code:** Sample random snippets from your internal repo β†’ use an LLM (GPT-4o, Claude) to generate instruction-solution pairs seeded from that code
2. **Retriever-aware examples:** Include retrieved code context in training prompts so the model learns to use RAG at inference time
3. **Internal API documentation:** Convert your docstrings/README into Q&A pairs

See `prepare_data.py` for the format β€” add your examples as additional sources.

### Step 3: Fine-tune

```bash
# Edit train_sft.py to set your dataset and model repo IDs, then:

# Option A: Run on HF Jobs (recommended for A100/H100 hardware)
# Use the hf_jobs API or CLI

# Option B: Run locally with GPU
pip install trl peft transformers datasets trackio accelerate torch
python train_sft.py
```

**Training configuration (from literature):**
- **Base:** [Qwen/Qwen2.5-Coder-7B-Instruct](https://huggingface.co/Qwen/Qwen2.5-Coder-7B-Instruct) (Apache 2.0)
- **Method:** LoRA (r=32, alpha=64) on all linear layers
- **LR:** 1e-4 with cosine schedule, 10% warmup
- **Epochs:** 2
- **Context:** 8192 tokens
- **Loss:** Assistant-only (masks user/system/tool tokens)
- **Hardware:** 1x A100-80GB (or 2x A10G-24GB)
- **Time:** ~4-6 hours for 110K examples

### Step 4: Index Your Codebase (RAG)

```python
from rag_pipeline import CodebaseIndexer

# Index your internal Python codebase
indexer = CodebaseIndexer(
    "/path/to/your/repo",
    embedding_model="jinaai/jina-embeddings-v2-base-code"  # or codesage-large-v2
)
retriever = indexer.index()

# Save for reuse
retriever.save_index("./my_index")

# Search!
results = retriever.search("authentication token validation", top_k=5)
for chunk, score in results:
    print(f"[{score:.3f}] {chunk.file_path}/{chunk.name}: {chunk.signature}")
```

**RAG pipeline features:**
- **AST-aware chunking** (cAST): Functions, methods, classes stay intact β€” no mid-function cuts
- **Dual embeddings**: Code content + metadata strings (NL descriptions) for hybrid search
- **AllianceCoder context assembly**: API signatures prioritized over full code bodies
- **In-context dependencies**: Automatically extracts imports and class signatures from the current file
- **Embedding models**: Jina-Code-v2 (8K context, 161M) or CodeSage-v2 (best quality, 1.3B)

### Step 5: Run the Agent

```bash
# Interactive mode
python inference.py \
  --model your-username/qwen25-coder-7b-code-toolcall \
  --repo /path/to/your/codebase \
  --index-dir ./my_index

# Single query
python inference.py \
  --model your-username/qwen25-coder-7b-code-toolcall \
  --repo /path/to/your/codebase \
  --query "Add pagination to the product search endpoint"
```

The agent uses a **ReAct loop**:
1. Pre-fetches relevant code via RAG
2. Sends query + context to the LLM
3. If the LLM calls tools β†’ executes them β†’ feeds results back
4. Repeats until the LLM gives a final answer (max 10 turns)

## Recommended Embedding Models

| Model | Size | Context | Best For | HF Link |
|-------|------|---------|----------|---------|
| `codesage/codesage-large-v2` | 1.3B | 2048 tok | Best quality (NL→Code 69.4) | [Link](https://huggingface.co/codesage/codesage-large-v2) |
| `jinaai/jina-embeddings-v2-base-code` | 161M | **8192 tok** | Long files, 30 languages | [Link](https://huggingface.co/jinaai/jina-embeddings-v2-base-code) |
| `codesage/codesage-small-v2` | 130M | 2048 tok | Fast, lightweight | [Link](https://huggingface.co/codesage/codesage-small-v2) |

## Advanced: Full Fine-Tuning (FFT)

For maximum performance, skip LoRA and do full fine-tuning:

```python
# In train_sft.py, remove peft_config and adjust:
LEARNING_RATE = 2e-5    # 10x lower than LoRA
BATCH_SIZE = 1          # Lower to fit in memory
GRAD_ACCUM = 16         # Keep effective batch = 16
# Hardware: 2x A100-80GB minimum for 7B FFT
```

Per [Astraios](https://arxiv.org/abs/2401.00788): FFT slightly outperforms LoRA at 7B scale, but LoRA is within 1% and 30x more parameter-efficient.

## Advanced: GRPO Reinforcement Learning (Stage 2)

After SFT, you can further improve the model with GRPO using execution-based rewards:

```python
from trl import GRPOConfig, GRPOTrainer

# Reward function: does the generated code pass unit tests?
def reward_fn(completions, prompts):
    rewards = []
    for code in completions:
        try:
            exec(code, {})  # Sandbox this properly!
            rewards.append(1.0)
        except:
            rewards.append(0.0)
    return rewards

# Train with GRPO
config = GRPOConfig(
    learning_rate=1e-6,
    num_train_epochs=1,
    per_device_train_batch_size=4,
)
```

## File Structure

```
β”œβ”€β”€ prepare_data.py     # Dataset merging & formatting
β”œβ”€β”€ train_sft.py        # SFT training script (TRL + LoRA)
β”œβ”€β”€ rag_pipeline.py     # AST-aware indexing & retrieval
β”œβ”€β”€ inference.py        # ReAct agent with tool calling
└── README.md           # This file
```

## Requirements

```
transformers>=4.45.0
trl>=1.0.0
peft>=0.12.0
datasets>=3.0.0
accelerate>=1.0.0
trackio>=0.2.0
torch>=2.0.0
sentence-transformers>=3.0.0  # For RAG embeddings
numpy
scikit-learn  # TF-IDF fallback
```

## Citation

If you use this toolkit, please cite the underlying research:

```bibtex
@article{qwen2.5coder,
  title={Qwen2.5-Coder Technical Report},
  author={Hui, Binyuan and others},
  journal={arXiv:2409.12186},
  year={2024}
}
@article{toolace,
  title={ToolACE: Winning the Points of LLM Function Calling},
  author={Liu, Weiwen and others},
  journal={arXiv:2409.00920},
  year={2024}
}
@article{gorilla,
  title={Gorilla: Large Language Model Connected with Massive APIs},
  author={Patil, Shishir G. and others},
  journal={arXiv:2305.15334},
  year={2023}
}
```