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}
}
```
|