给 Cline 接一个远程 RAG:从 Flask 检索服务到 VS Code 扩展改造

1386 字
7 分钟
给 Cline 接一个远程 RAG:从 Flask 检索服务到 VS Code 扩展改造

Cline 是 VS Code 里常用的 AI 编程助手。默认情况下,用户每次要一个”推箱子""连连看”这类常见小游戏,大模型都会从头生成一遍代码——慢、贵、而且每次结果不一样。

这个项目的目标是:给 Cline 接一个远程 RAG 检索服务,把团队沉淀的可运行代码存进向量库。当用户请求命中库里的代码时,直接返回现成的完整文件,跳过大模型的生成流程;没命中时再走原来的对话生成。

整体分成两部分:一个独立部署的 RAG 检索服务,和对 Cline 扩展本身的改造。

一、RAG 检索服务(Flask + FAISS)#

服务端只做三件事:接收文本入库、生成向量索引、按相似度检索。技术选型是 sentence-transformers 做 embedding、FAISS 做向量索引、Flask 提供 HTTP 接口:

Terminal window
pip install flask sentence-transformers faiss-cpu waitress numpy

核心服务 app.py

from flask import Flask, request, jsonify
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
import pickle
import os
app = Flask(__name__)
model = None
index = None
texts = []
def load_model():
global model
model = SentenceTransformer('all-MiniLM-L6-v2')
def create_or_load_index():
global index, texts
if os.path.exists("faiss_index.bin") and os.path.exists("texts.pkl"):
index = faiss.read_index("faiss_index.bin")
with open("texts.pkl", 'rb') as f:
texts = pickle.load(f)
else:
dim = model.get_sentence_embedding_dimension()
index = faiss.IndexFlatIP(dim) # 内积近似余弦相似度
texts = []
def save_index():
faiss.write_index(index, "faiss_index.bin")
with open("texts.pkl", 'wb') as f:
pickle.dump(texts, f)
@app.route('/health', methods=['GET'])
def health():
return jsonify({"status": "healthy", "total_vectors": index.ntotal})
@app.route('/add', methods=['POST'])
def add_text():
data = request.get_json()
text = data.get('text', '')
if not text.strip():
return jsonify({"error": "Empty text"}), 400
embedding = model.encode([text])
index.add(embedding)
texts.append(text)
save_index()
return jsonify({"status": "success", "total_vectors": index.ntotal})
@app.route('/search', methods=['POST'])
def search():
data = request.get_json()
query = data.get('text', '')
k = data.get('k', 5)
if index.ntotal == 0:
return jsonify({"results": []})
query_embedding = model.encode([query])
scores, indices = index.search(query_embedding, min(k, index.ntotal))
results = []
for score, idx in zip(scores[0], indices[0]):
if idx < len(texts):
results.append({
"index": int(idx),
"text": texts[idx],
"distance": float(score)
})
return jsonify({"results": results})
if __name__ == '__main__':
load_model()
create_or_load_index()
app.run(host='0.0.0.0', port=5050, debug=True)

生产环境用 waitress(Windows)或 gunicorn(Linux)跑:

Terminal window
# Windows
waitress-serve --listen=0.0.0.0:5050 app:app
# Linux
gunicorn -w 4 -b 0.0.0.0:5050 app:app

二、代码入库:带关键词前缀的上传策略#

直接把整个 HTML 文件存进向量库,检索时”推箱子”这种短查询很难和几千行代码算出高相似度。所以入库时给每份代码拼一个关键词前缀,把游戏名、别名、技术栈都写进去:

Terminal window
$content = Get-Content -Path "lianliankan.html" -Raw -Encoding UTF8
$payload = @{
text = "[FORCE_ANSWER] 连连看 完整游戏代码 HTML CSS JavaScript 可直接运行的连连看游戏文件 $content"
} | ConvertTo-Json -Compress
Invoke-RestMethod -Method Post -Uri "http://localhost:5050/add" `
-ContentType "application/json; charset=utf-8" -Body $payload

前缀里的 [FORCE_ANSWER] 是一个约定标记,后面 Cline 端会用到。

三、改造 Cline 扩展#

Cline 端的改造集中在三处:

1. 新增设置项。 在扩展配置里加了开关和服务地址,用户在 VS Code 设置里就能启用:

{
"cline.rag.enabled": true,
"cline.rag.remoteUrl": "http://localhost:5050"
}

2. 请求拦截。 在任务入口(newTask.ts)里对用户输入先做一次 RAG 检索。为了避免所有请求都被拦截,用一个关键词正则做门禁,只有明确命中已入库的游戏名才走 RAG 通道:

const isForceQuery = /推箱子|sokoban|连连看|lianliankan|俄罗斯方块|贪吃蛇/i.test(query)

3. 强制完成短路。 当检索结果带有 [FORCE_ANSWER] 标记时,直接构造 completion_result 发给用户——跳过计划(Plan)和对话流程,用户一按 Act 立刻拿到完整可运行的代码文件。

改造完成后写了个冒烟测试脚本验证链路,从添加向量到三组查询全部通过:

RAG 冒烟测试 3/3 通过
RAG 冒烟测试 3/3 通过

四、实际效果#

在 Cline 里输入”推箱子”,检索命中后直接返回完整代码并在工作区创建文件,输出面板里能看到 RAG primary hitsFORCE_ANSWER hit → short-circuit output 的日志:

RAG 命中后直接返回完整代码
RAG 命中后直接返回完整代码

命中返回代码之后,上下文并没有断——用户可以继续对话,让模型在现成代码的基础上改需求:

返回代码后继续对话完善
返回代码后继续对话完善

通过本地代理观察请求流,可以看到 Cline 侧的健康检查和检索请求都正常打到了 RAG 服务:

RAG 代理日志与文件创建过程
RAG 代理日志与文件创建过程

五、一个踩坑:风格标签的命中优先级#

后来给同一个游戏加了多种风格版本(比如”科技风推箱子”),入库时打上风格标签。结果发现一个 bug:第一次检索只要有结果,代码就直接用了第一条,没有校验结果是否包含正确的风格标签——请求”科技风推箱子”可能返回默认风格的版本。

修复方式是在命中后增加一层标签校验,风格不匹配时继续往后找。修复后请求”科技风推箱子”能准确返回对应版本:

风格标签命中,正确创建科技风版本
风格标签命中,正确创建科技风版本

六、生产部署#

RAG 服务用 Docker 打包:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5050
CMD ["waitress-serve", "--listen=0.0.0.0:5050", "app:app"]

对外通过 Nginx 反向代理暴露:

server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:5050;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

总结#

这套方案的核心思路是**“确定性资产走检索,开放性需求走生成”**:高频、标准化的代码交付用 RAG 直接命中返回,秒级完成且结果稳定;模型的生成能力留给真正需要创造的场景。整个链路涉及向量检索服务搭建、VS Code 扩展二次开发、请求短路设计和检索质量修复,是一次比较完整的 RAG 工程落地。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

给 Cline 接一个远程 RAG:从 Flask 检索服务到 VS Code 扩展改造
https://www.yolof.top/posts/cline-remote-rag-integration/
作者
方静文
发布于
2025-09-05
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
方静文
AI 开发应用工程师 / Fang's Blue Hour
公告
欢迎来到 Fang's Blue Hour!这里记录我的 AI 应用开发实践、开源项目与技术调研。
分类
标签
站点统计
文章
16
分类
5
标签
50
总字数
22,571
运行时长
0
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录