own-rag-cli 0.0.1-snapshot
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MCP_USAGE.md +315 -0
- package/README.md +133 -0
- package/bin/docker-compose.yml +21 -0
- package/bin/download_model_from_hugginface.py +219 -0
- package/bin/download_model_from_modelscope.py +26 -0
- package/bin/indexer_full.py +1426 -0
- package/bin/mcp_server.py +1433 -0
- package/bin/postinstall.sh +102 -0
- package/bin/rag-remove.sh +198 -0
- package/bin/rag-wrapper.sh +186 -0
- package/bin/requirements.txt +21 -0
- package/chroma_monitor.sh +857 -0
- package/how-its-work.md +285 -0
- package/package.json +49 -0
- package/rag-setup-macos.run +1129 -0
- package/rag-setup.run +1179 -0
package/how-its-work.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# How It Works — RAG Local + Claude Code
|
|
2
|
+
|
|
3
|
+
## Por que BGE-M3?
|
|
4
|
+
|
|
5
|
+
Foram avaliados dois modelos para este RAG:
|
|
6
|
+
|
|
7
|
+
| Modelo | Dims | Context | Foco | Status |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| `all-MiniLM-L6-v2` | 384D | 256 tokens | Geral | Substituído |
|
|
10
|
+
| `jinaai/jina-embeddings-v2-base-code` | 768D | 8192 tokens | Código | Incompatível com transformers ≥4.40 |
|
|
11
|
+
| `BAAI/bge-m3` | 1024D | 8192 tokens | Multilingual | **Escolhido** |
|
|
12
|
+
|
|
13
|
+
O `jina-embeddings-v2-base-code` seria ideal para código puro, mas seu código customizado referencia `find_pruneable_heads_and_indices`, função removida do `transformers` na versão 4.40 e o modelo não foi atualizado. O BGE-M3 funciona com transformers 5.x, tem 1024D (representação mais rica) e contexto de 8192 tokens.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## O que é o BGE-M3
|
|
18
|
+
|
|
19
|
+
O `BAAI/bge-m3` (Beijing Academy of AI) é um modelo de **sentence embeddings** de última geração. Ele converte qualquer texto em um vetor de **1024 dimensões** que representa o significado semântico do conteúdo.
|
|
20
|
+
|
|
21
|
+
Textos semanticamente similares ficam próximos no espaço vetorial:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
"função que valida e-mail" → [0.04, -0.21, 0.67, ...] (1024 números)
|
|
25
|
+
"verificar formato de email" → [0.05, -0.20, 0.65, ...] (muito próximo!)
|
|
26
|
+
"conexão com banco de dados" → [0.81, 0.33, -0.12, ...] (distante)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Vantagens sobre all-MiniLM-L6-v2:**
|
|
30
|
+
- **8192 tokens** de contexto (era 256) — funções inteiras cabem em um chunk
|
|
31
|
+
- **1024 dimensões** (era 384) — representação muito mais rica e precisa
|
|
32
|
+
- **State-of-the-art** no MTEB benchmark (maior benchmark de retrieval)
|
|
33
|
+
- **Chunks maiores**: 6000 chars/chunk (era 2400) — menos fragmentação de código
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Visão Geral da Solução
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart TD
|
|
41
|
+
subgraph SETUP["Fase 1 — Setup (uma vez)"]
|
|
42
|
+
A[rag-setup.run] --> B[Instala dependências Python em ~/.rag_venv]
|
|
43
|
+
B --> C[Sobe ChromaDB Docker localhost:8000]
|
|
44
|
+
C --> D[Instala mcp-rag-server em ~/.local/bin/]
|
|
45
|
+
D --> E[Configura ~/.claude.json com mcpServers]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
subgraph INDEX["Fase 2 — Indexação"]
|
|
49
|
+
F[indexer_full.py /projeto] --> G[Varre arquivos .py .js .ts .md ...]
|
|
50
|
+
G --> H[Divide em chunks 6000 chars, overlap 800]
|
|
51
|
+
H --> I[BAAI/bge-m3 encode chunks → vetores 1024D]
|
|
52
|
+
I --> J[(ChromaDB coleção: codebase HNSW cosine index)]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subgraph QUERY["Fase 3 — Busca em tempo real"]
|
|
56
|
+
K[Claude Code CLI] -->|stdio| L[mcp-rag-server]
|
|
57
|
+
L --> M[BAAI/bge-m3 encode query → vetor 1024D]
|
|
58
|
+
M --> N{ChromaDB HNSW search cosine distance}
|
|
59
|
+
N --> O[Top-K chunks mais similares]
|
|
60
|
+
O --> L
|
|
61
|
+
L -->|resultados formatados| K
|
|
62
|
+
K --> P[Claude usa o contexto para responder]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
SETUP --> INDEX
|
|
66
|
+
INDEX --> QUERY
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Diagrama de Sequencia — Busca Semantica
|
|
72
|
+
|
|
73
|
+
```mermaid
|
|
74
|
+
sequenceDiagram
|
|
75
|
+
actor User as Usuario
|
|
76
|
+
participant CC as Claude Code CLI
|
|
77
|
+
participant MCP as mcp-rag-server<br/>(stdio)
|
|
78
|
+
participant Model as BAAI/bge-m3<br/>(em memoria)
|
|
79
|
+
participant DB as ChromaDB<br/>(Docker :8000)
|
|
80
|
+
|
|
81
|
+
User->>CC: Pergunta sobre o codigo
|
|
82
|
+
CC->>CC: Decide chamar semantic_search_code
|
|
83
|
+
CC->>MCP: {tool: "semantic_search_code",<br/>query: "funcao de autenticacao", top_k: 7}
|
|
84
|
+
|
|
85
|
+
MCP->>Model: encode(["funcao de autenticacao"])
|
|
86
|
+
Model-->>MCP: vetor [0.04, -0.21, ...] (1024D)
|
|
87
|
+
|
|
88
|
+
MCP->>DB: POST /api/v2/collections/codebase/query<br/>{query_embeddings: [...], n_results: 7}
|
|
89
|
+
DB->>DB: HNSW search<br/>cosine distance entre<br/>query e todos os chunks
|
|
90
|
+
DB-->>MCP: [{doc, metadata, distance}, ...]
|
|
91
|
+
|
|
92
|
+
MCP->>MCP: Formata resultado<br/>similarity = (1 - distance) * 100
|
|
93
|
+
|
|
94
|
+
MCP-->>CC: "## [1] /projeto/src/auth.py\nSimilaridade: 91.2%\n..."
|
|
95
|
+
CC->>CC: Injeta resultado no contexto
|
|
96
|
+
CC-->>User: Resposta usando o codigo encontrado
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Diagrama de Sequencia — Indexacao
|
|
102
|
+
|
|
103
|
+
```mermaid
|
|
104
|
+
sequenceDiagram
|
|
105
|
+
actor Dev as Desenvolvedor
|
|
106
|
+
participant IDX as indexer_full.py
|
|
107
|
+
participant FS as Sistema de Arquivos
|
|
108
|
+
participant Model as BAAI/bge-m3
|
|
109
|
+
participant DB as ChromaDB
|
|
110
|
+
|
|
111
|
+
Dev->>IDX: python3 indexer_full.py /meu-projeto
|
|
112
|
+
|
|
113
|
+
IDX->>DB: heartbeat() — valida conexao
|
|
114
|
+
DB-->>IDX: OK
|
|
115
|
+
|
|
116
|
+
IDX->>Model: SentenceTransformer("BAAI/bge-m3", device="cpu")
|
|
117
|
+
Model-->>IDX: modelo carregado (~570MB)
|
|
118
|
+
|
|
119
|
+
IDX->>DB: get_or_create_collection("codebase", hnsw:space=cosine)
|
|
120
|
+
DB-->>IDX: collection handle
|
|
121
|
+
|
|
122
|
+
IDX->>FS: os.walk(root_path)
|
|
123
|
+
FS-->>IDX: lista de arquivos (ignora .git, node_modules, binarios...)
|
|
124
|
+
|
|
125
|
+
loop Para cada arquivo
|
|
126
|
+
IDX->>FS: read_text(encoding=utf-8)
|
|
127
|
+
FS-->>IDX: conteudo do arquivo
|
|
128
|
+
|
|
129
|
+
IDX->>IDX: RecursiveCharacterTextSplitter<br/>chunk_size=6000, overlap=800<br/>separators=["\n\n", "\n", " ", ""]
|
|
130
|
+
|
|
131
|
+
IDX->>Model: encode(chunks) → batch
|
|
132
|
+
Model-->>IDX: [[...1024 floats...], ...]
|
|
133
|
+
|
|
134
|
+
IDX->>IDX: make_chunk_id = MD5(file_path::chunk::index)
|
|
135
|
+
|
|
136
|
+
IDX->>DB: collection.upsert(<br/>ids=[md5...], embeddings=[...],<br/>documents=[chunks], metadatas=[...]<br/>)
|
|
137
|
+
DB-->>IDX: OK
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
IDX-->>Dev: "Indexacao concluida! N arquivos, M chunks"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Como o Modelo Funciona Internamente
|
|
146
|
+
|
|
147
|
+
O `BGE-M3` e baseado em arquitetura XLM-RoBERTa com camadas de attention empilhadas:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Texto de entrada
|
|
151
|
+
|
|
|
152
|
+
[Tokenizacao SentencePiece — multilingual]
|
|
153
|
+
|
|
|
154
|
+
[N x Transformer Layers com Multi-Head Self-Attention]
|
|
155
|
+
|
|
|
156
|
+
[Mean Pooling sobre tokens nao-padding]
|
|
157
|
+
|
|
|
158
|
+
[Normalizacao L2]
|
|
159
|
+
|
|
|
160
|
+
Vetor de 1024 dimensoes (embedding normalizado)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Por que distancia cosseno?**
|
|
164
|
+
|
|
165
|
+
A distancia cosseno mede o angulo entre dois vetores, ignorando a magnitude. Ideal para embeddings normalizados porque:
|
|
166
|
+
- Textos curtos e longos sobre o mesmo topico ficam proximos
|
|
167
|
+
- A normalizacao L2 do BGE-M3 torna cosine = dot product (mais rapido)
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
similarity = 1 - cosine_distance
|
|
171
|
+
= dot(A, B) # quando ambos sao vetores L2-normalizados
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Fluxo de Dados Detalhado
|
|
177
|
+
|
|
178
|
+
```mermaid
|
|
179
|
+
flowchart LR
|
|
180
|
+
subgraph INPUT["Entrada"]
|
|
181
|
+
Q["Query do usuario
|
|
182
|
+
'funcao de login'"]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
subgraph EMBED["Embedding BGE-M3"]
|
|
186
|
+
T1["Tokenizacao SentencePiece
|
|
187
|
+
tokens multilinguals"]
|
|
188
|
+
T2["Transformer Layers
|
|
189
|
+
Multi-Head Attention"]
|
|
190
|
+
T3["Mean Pooling + L2 Norm
|
|
191
|
+
→ vetor 1024D"]
|
|
192
|
+
T1 --> T2 --> T3
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
subgraph SEARCH["Busca Vetorial HNSW"]
|
|
196
|
+
V1["Vetor da query
|
|
197
|
+
1024 dimensoes"]
|
|
198
|
+
V2["HNSW Index
|
|
199
|
+
~N vetores indexados"]
|
|
200
|
+
V3["Top-K vizinhos
|
|
201
|
+
por cosine similarity"]
|
|
202
|
+
V1 --> V2 --> V3
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
subgraph OUTPUT["Saida"]
|
|
206
|
+
R1["[1] auth.py — 91%
|
|
207
|
+
def login(user, pwd)..."]
|
|
208
|
+
R2["[2] session.py — 87%
|
|
209
|
+
def create_session()..."]
|
|
210
|
+
R3["[3] middleware.py — 82%
|
|
211
|
+
def require_auth()..."]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
INPUT --> EMBED
|
|
215
|
+
EMBED --> SEARCH
|
|
216
|
+
SEARCH --> OUTPUT
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Estrutura dos Chunks no ChromaDB
|
|
222
|
+
|
|
223
|
+
Cada chunk armazenado tem:
|
|
224
|
+
|
|
225
|
+
| Campo | Tipo | Exemplo |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| `id` | string | `MD5("src/auth.py::chunk::0")` |
|
|
228
|
+
| `embedding` | float[1024] | `[0.04, -0.21, ...]` |
|
|
229
|
+
| `document` | string | `"def login(user, pwd):\n ..."` |
|
|
230
|
+
| `file_path` | metadata | `/home/<usuario>/projeto/src/auth.py` |
|
|
231
|
+
| `chunk_index` | metadata | `0` |
|
|
232
|
+
| `file_name` | metadata | `auth.py` |
|
|
233
|
+
| `relative_path` | metadata | `src/auth.py` |
|
|
234
|
+
|
|
235
|
+
O ID e deterministico: o mesmo arquivo + mesmo indice sempre gera o mesmo MD5. Isso permite **upsert idempotente** — reindexar um arquivo nao cria duplicatas.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Parametros e seus Impactos
|
|
240
|
+
|
|
241
|
+
| Parametro | Valor anterior | Valor atual | Impacto |
|
|
242
|
+
|---|---|---|---|
|
|
243
|
+
| `EMBEDDING_MODEL` | all-MiniLM-L6-v2 | BAAI/bge-m3 | Melhor qualidade, mais dimensoes |
|
|
244
|
+
| `CHUNK_SIZE` | 2400 chars | 6000 chars | Funcoes inteiras cabem em 1 chunk |
|
|
245
|
+
| `CHUNK_OVERLAP` | 400 chars | 800 chars | Mais continuidade entre chunks |
|
|
246
|
+
| `embedding dims` | 384D | 1024D | Representacao muito mais rica |
|
|
247
|
+
| `context window` | 256 tokens | 8192 tokens | Nao trunca mais codigo longo |
|
|
248
|
+
| `top_k` | 7 (padrao) | 7 (padrao) | Quantidade de chunks por busca |
|
|
249
|
+
| `MAX_FILE_SIZE` | 500KB | 500KB | Limite de tamanho de arquivo |
|
|
250
|
+
| `hnsw:space` | cosine | cosine | Melhor para embeddings normalizados |
|
|
251
|
+
| `device` | cpu | cpu | Sem dependencia de GPU |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Integracao com Claude Code
|
|
256
|
+
|
|
257
|
+
O Claude Code se conecta ao `mcp-rag-server` via **stdio** (protocolo MCP). O servidor e iniciado como subprocesso quando o Claude Code carrega:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
claude (processo principal)
|
|
261
|
+
└── mcp-rag-server (subprocesso, stdio)
|
|
262
|
+
├── carrega BAAI/bge-m3 em memoria (~570MB)
|
|
263
|
+
└── mantem conexao HTTP com ChromaDB
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
A comunicacao e JSON-RPC sobre stdin/stdout. O Claude envia uma chamada de ferramenta e recebe o resultado formatado de volta — tudo sem expor portas ou APIs externas.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Migracao do modelo antigo
|
|
271
|
+
|
|
272
|
+
Ao trocar de modelo, a colecao ChromaDB precisa ser recriada — as dimensoes sao incompativeis (384D vs 1024D). O procedimento:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# 1. Deletar a colecao antiga
|
|
276
|
+
python3 -c "
|
|
277
|
+
import chromadb
|
|
278
|
+
c = chromadb.HttpClient(host='localhost', port=8000)
|
|
279
|
+
c.delete_collection('codebase')
|
|
280
|
+
print('Colecao deletada')
|
|
281
|
+
"
|
|
282
|
+
|
|
283
|
+
# 2. Reindexar o projeto com o novo modelo
|
|
284
|
+
python3 indexer_full.py /caminho/do/projeto
|
|
285
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "own-rag-cli",
|
|
3
|
+
"version": "0.0.1-snapshot",
|
|
4
|
+
"description": "Local RAG setup with ChromaDB + MCP server (Jina/BGE hybrid support).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/JocsaPB/own-rag.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/JocsaPB/own-rag/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/JocsaPB/own-rag#readme",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"rag",
|
|
17
|
+
"mcp",
|
|
18
|
+
"chromadb",
|
|
19
|
+
"embeddings",
|
|
20
|
+
"claude",
|
|
21
|
+
"cursor"
|
|
22
|
+
],
|
|
23
|
+
"bin": {
|
|
24
|
+
"rag": "./bin/rag-wrapper.sh"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"postinstall": "bash ./bin/postinstall.sh"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"README.md",
|
|
31
|
+
"MCP_USAGE.md",
|
|
32
|
+
"how-its-work.md",
|
|
33
|
+
"chroma_monitor.sh",
|
|
34
|
+
"rag-setup.run",
|
|
35
|
+
"rag-setup-macos.run",
|
|
36
|
+
"bin/docker-compose.yml",
|
|
37
|
+
"bin/requirements.txt",
|
|
38
|
+
"bin/rag-wrapper.sh",
|
|
39
|
+
"bin/rag-remove.sh",
|
|
40
|
+
"bin/postinstall.sh",
|
|
41
|
+
"bin/indexer_full.py",
|
|
42
|
+
"bin/mcp_server.py",
|
|
43
|
+
"bin/download_model_from_hugginface.py",
|
|
44
|
+
"bin/download_model_from_modelscope.py"
|
|
45
|
+
],
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
}
|
|
49
|
+
}
|