首页
/ github-rag:基于 GitIngest + LlamaIndex 的 100% 本地 GitHub 仓库问答 RAG 应用实战

github-rag:基于 GitIngest + LlamaIndex 的 100% 本地 GitHub 仓库问答 RAG 应用实战

2026-09-08 14:18:30作者:冯爽妲Honey

本文将拆解 github-rag/README.md 所描述的「Chat with GitHub」项目:它通过 GitIngest 把任意 GitHub 仓库抓取解析为 Markdown,再交由 LlamaIndex 完成切分、向量化与检索问答,端到端可在本地运行。读完本文,你将掌握从「粘贴仓库 URL」到「对话式查询仓库代码与结构」的完整构建链路,并理解本地 LLM(Ollama)、本地 Embedding 与自定义 Prompt 在实际 RAG 工程中的落点。

一、整体思路:把「仓库」变成可对话的 Markdown 知识库

面向代码仓库的 RAG 与面向 PDF/网页的 RAG 最大的差别在于数据源形态:一个仓库包含几十到上千个不同语言的文件,直接灌入向量库既低效又丢失结构。本项目给出的解法是一条清晰的两段式管线:

  1. GitIngest 解析仓库:调用 gitingestingest() 把远程 GitHub 仓库抓取并归一化为单一 Markdown 文本(含仓库摘要 summary、目录树 tree、正文内容 content);
  2. LlamaIndex 构建 RAG:把这份 Markdown 当作普通文档读取 → 按 Markdown 结构切分为节点 → 用本地 Embedding 模型向量化 → 建索引 → 得到流式查询引擎,最后通过 Streamlit 提供聊天界面。
管线阶段 关键实现 源码位置
仓库抓取与 Markdown 化 gitingest.ingest(github_url) app_local.py
文档读取 SimpleDirectoryReader app_local.py
Markdown 节点切分 MarkdownNodeParser app_local.py
本地向量化 HuggingFaceEmbedding(bge-large-en-v1.5) app_local.py
索引与流式问答 VectorStoreIndex.as_query_engine(streaming=True) app_local.py
界面层 Streamlit 会话/聊天组件 app_local.py

这种「仓库 → 一份 Markdown → 节点 → 向量索引」的降维处理,是本项目最容易迁移复用的核心思想。

二、环境准备与依赖安装

README 要求 Python 3.9 及以上(作者在 Python 3.11.9 下测试通过),并提供两种安装方式。

方式一(推荐):直接安装依赖清单

pip install -r requirements.txt

github-rag/requirements.txt 中声明的内容,按职责可拆成四组:

依赖组 包名 在本项目中的作用
仓库解析 gitingest 抓取 GitHub 仓库并输出 Markdown 摘要/目录/正文
RAG 编排 llama-index 文档加载、节点解析、向量索引与查询引擎
模型集成 llama-index-llms-ollamallama-index-llms-openaillama-index-agent-openaillama-index-embeddings-huggingface 本地 LLM(Ollama)、云端 LLM(OpenAI)、本地 Embedding 三类模型接口
UI 与环境 streamlitpython-dotenvpandashuggingface-hub 聊天界面、.env 读取、依赖声明、首次运行拉取嵌入模型权重

方式二:手动逐个安装

pip install gitingest llama-index llama-index-llms-ollama llama-index-llms-openai llama-index-agent-openai llama-index-embeddings-huggingface streamlit pandas python-dotenv huggingface-hub

两种方式本质等价,方式一更便于锁定依赖版本、减少遗漏。

环境变量配置

如果走 OpenAI 集成的入口(app.py),需要在项目目录下创建 .env 文件并填入密钥:

OPENAI_API_KEY=your_openai_api_key_here

从源码看,app.py 在启动时调用 load_dotenv() 加载该文件,而全程没有像 app_local.py 那样显式把 Settings.llm 绑定到 Ollama,说明它是依靠 LlamaIndex 的默认模型配置去解析 OPENAI_API_KEY——这正是 README 要求先配好环境变量的原因。

三、运行前提:让 Ollama 跑起来(100% 本地链路)

本地版入口 app_local.py 默认使用 Ollama + llama3.2 作为生成模型:

@st.cache_resource
def load_llm():
    llm = Ollama(model="llama3.2", request_timeout=120.0)
    return llm
  • model="llama3.2":会话级模型名,需与你本机 Ollama 已下载的模型一致(通常通过 ollama pull llama3.2 预先拉取);
  • request_timeout=120.0:单次生成请求的超时上限为 120 秒,避免长上下文推理时客户端先行断开;
  • 函数被 @st.cache_resource 装饰,Streamlit 重跑脚本时模型实例会复用,不会反复创建连接。

因此启动应用前,请先确认 Ollama Server 处于运行状态(如执行 ollama serve,或确保系统托盘/后台服务已启动),这是本地链路能够出结果的前提。

四、一键启动与界面操作

本地入口直接使用 Streamlit 启动:

streamlit run app_local.py

浏览器会自动打开聊天页,使用流程是典型的「加载 → 缓存 → 问答」三步:

  1. 在左侧边栏输入 GitHub 仓库 URL(如 https://github.com/用户名/仓库名),点击 Load Repository
  2. 系统调用 GitIngest 拉取并解析仓库,随后执行切分、向量化、建索引,界面出现 "Ready to Chat!" 提示;
  3. 在底部输入框提问,答案以流式逐字渲染(代码中用 光标模拟打字效果),右侧 Clear ↺ 按钮可清空会话历史并触发 gc.collect() 释放内存。

值得注意的是,会话采用两层缓存:st.session_state.file_cache"{session_id}-{repo_name}" 为 key 保存已构建的查询引擎(app_local.py),重复加载同一仓库不会重建索引;同一浏览器会话内、切换仓库后再提问,也会因为该 key 策略自动路由到对应的引擎。

五、核心链路源码拆解

5.1 GitIngest:把仓库拍平为 Markdown

summary, tree, content = ingest(github_url)

ingest() 一次返回三个结构化结果:仓库级摘要 summary、文件目录树 tree、按目录组织的全部文件正文 content(Markdown 格式)。app_local.py 会把 content 同时写入当前目录的 content.md 与临时目录下的 {repo_name}_content.md,后者作为 LlamaIndex 的输入文档。这意味着整个 RAG 的知识来源就是这一份自包含的 Markdown 文本,链路简单且可复现。

5.2 Markdown 节点切分:保留标题层级语义

索引构建不是把整份 Markdown 当作一个大文本,而是先经过两个关键环节(app_local.py):

docs = loader.load_data()
node_parser = MarkdownNodeParser()
index = VectorStoreIndex.from_documents(
    documents=docs,
    transformations=[node_parser],
    show_progress=True,
)
  • SimpleDirectoryReader 读取临时目录中的 Markdown 文件;
  • MarkdownNodeParser 依据 Markdown 的标题层级(###、代码块等)把长文档切分为结构语义更完整的节点,使「某个函数在哪个文件中、属于哪个模块」这类位置信息能被下游检索利用;
  • transformations=[node_parser] 表示在建索引前应用该变换,show_progress=True 便于在长时间解析时观察进度。

5.3 本地 Embedding:全程不出本机

embed_model = HuggingFaceEmbedding(
    model_name="BAAI/bge-large-en-v1.5", trust_remote_code=True
)
Settings.embed_model = embed_model

项目选择 BAAI/bge-large-en-v1.5 作为默认嵌入模型,并通过 Settings.embed_model 全局注入。对英文代码与英文技术文档的语义匹配效果较好;trust_remote_code=True 允许从 HuggingFace 加载其自定义代码。该模型权重会在首次运行时自动下载并缓存到本机 HuggingFace 目录,因此只有首次加载需要联网,之后整条问答链路都可离线运行

5.4 流式查询引擎

Settings.llm = llm
query_engine = index.as_query_engine(streaming=True)

先由第 2 步的 Ollama 覆盖全局 LLM 设置,再以流式模式创建查询引擎。后续聊天时对 response 做「流式探测」(app_local.py):

if hasattr(response, 'response_gen'):
    for chunk in response.response_gen:
        if isinstance(chunk, str):      # 只拼接字符串类型的流块
            full_response += chunk
            message_placeholder.markdown(full_response + "▌")
else:
    full_response = str(response)

这段防御式代码同时兼容两种后端:当响应对象带有 response_gen 生成器时按流式逐块渲染;否则回退为一次性文本,保证换用不同 LLM 后端时 UI 不会崩。

5.5 定制 QA Prompt:约束回答风格与兜底话术

默认的 LlamaIndex 问答模板通常不带「仓库分析」的语义约束,因此两个入口都重写了 response_synthesizer:text_qa_template。以本地版为例(app_local.py):

qa_prompt_tmpl_str = (
    "Context information is below.\n"
    "---------------------\n"
    "{context_str}\n"
    "---------------------\n"
    "Given the context information above I want you to think step by step to answer "
    "the query in a highly precise and crisp manner focused on the final answer, "
    "incase case you don't know the answer say 'I don't know!'.\n"
    "Query: {query_str}\n"
    "Answer: "
)
qa_prompt_tmpl = PromptTemplate(qa_prompt_tmpl_str)
query_engine.update_prompts(
    {"response_synthesizer:text_qa_template": qa_prompt_tmpl}
)

这段模板清晰地体现了三条工程原则:上下文与问题隔离呈现{context_str} / {query_str})、要求逐步推理并给出精准结论检索不到答案时明确输出 "I don't know!" 而不是编造。通过 update_prompts() 配合 LlamaIndex 约定的模板 key(response_synthesizer:text_qa_template)即可在不改检索逻辑的情况下整体替换问答行为。

5.6 小结:本地问答的运行时内存画像

从代码调用链可以看出一次完整问答的资源消耗集中在三处:GitIngest 生成的仓库 Markdown、bge-large-en-v1.5 的向量索引、常驻内存的 Ollama 模型。对中小型仓库(纯文本源码、文档类仓库)本地运行毫无压力;仓库很大时,README 虽未展开,但可预期首次解析与向量化的耗时与磁盘占用会明显上升(详见下文增强版入口对仓库规模的防御性处理)。

六、增强版入口 app.py:校验、日志与结构上下文

除本地入口外,仓库还提供了面向 OpenAI / 生产化改造的 app.py。它把同一套管线整理得更工程化,直接可读作「从 demo 到可用服务」的升级范本:

1. 输入校验与仓库名清洗

MAX_REPO_SIZE = 100 * 1024 * 1024  # 100MB
SUPPORTED_REPO_TYPES = ['.py', '.md', '.ipynb', '.js', '.ts', '.json']

def validate_github_url(url: str) -> bool:
    return url.startswith(('https://github.com/', 'http://github.com/'))

def get_repo_name(url: str) -> str:
    return url.split('/')[-1].replace('.git', '')

URL 必须命中 github.com 前缀,仓库名自动剥离 .git 后缀,并预设了 100MB 的规模上限常量与关注的文件类型白名单(从源码结构看,这些常量用于约束后续扩展处理逻辑,体现对超大/二进制仓库的防御意识)。

2. 统一异常体系与结构化日志

GitHubRAGError 作为自定义业务异常(app.py)贯穿「抓取失败 → 建索引失败 → 问答失败」各环节;logging 在加载仓库、重置会话等关键路径输出 INFO 级日志(app.py),排查问题时可直接按日志回溯。

3. 提示词注入仓库目录树

增强版的 QA 模板(app.py)在上下文之外额外预留 {tree}(仓库目录树)占位符,引导模型「结合仓库结构与正文上下文」作答,并在信息不足时给出比 "I don't know!" 更温和的兜底文案:I don't have enough information about that aspect of the repository.

七、两个入口怎么选

维度 app_local.py(本地版) app.py(增强版)
生成模型 Ollama + llama3.2(显式 Settings.llm 依赖 .envOPENAI_API_KEY 默认配置
数据隐私 全程本地,仅首次拉取嵌入模型权重需联网 代码与查询会上送云端 API
工程健壮性 基础 try/except URL 白名单校验、自定义异常、结构化日志
提示词特色 step-by-step + "I don't know!" 兜底 注入仓库目录树 + 更完整的兜底话术
适合场景 快速体验、私有代码、离线环境 生产化改造参照、依赖云端模型的团队

README 默认推荐运行本地入口 streamlit run app_local.py,并提示「确保 Ollama Server 正在运行」;若要体验 OpenAI 集成,则先配置 .env 再运行 app.py。两者共享同一套 GitIngest + LlamaIndex 核心管线,模型层(Ollama vs OpenAI)通过 LlamaIndex 的集成包解耦,这正是把 llama-index-llms-ollamallama-index-llms-openai 同时列入依赖清单的原因。

八、常见问题排查(基于仓库实现)

  • 报 Ollama 连接类错误:多为 Ollama Server 未启动或端口不可达。先确认服务在线,再确认 llama3.2 模型已在本地拉取(模型名与 app_local.pymodel 参数一致)。
  • 首次加载仓库很慢 / 卡在解析阶段:包含首次下载 BAAI/bge-large-en-v1.5 权重与 GitIngest 全量拉取两个环节,耐心等待 show_progress=True 的进度条完成即可。
  • 回答超时中断:若仓库极大、单次生成超过 120 秒,可适当调高 app_local.pyrequest_timeout 的值。
  • 问答出现 "I don't know!":这是定制提示词的预期兜底行为,说明检索上下文未命中;可换一种更贴合仓库内命名/术语的提问方式再试。
  • 切换 OpenAI 集成后结果流式失效:增强版在 app.py 同样实现了 response_gen 探测逻辑,若更换到不支持流式的模型会自动回退为一次性文本,属正常兼容路径。

写在最后

本项目的价值不在于发明新算法,而在于把「解析 → 切分 → 向量化 → 流式问答 → 界面」这条代码仓库 RAG 的最小可行链路,用不到两百行代码完整落地,并同时给出本地(Ollama)与云端(OpenAI)两套模型后端。读者可以以此为骨架,替换成自己的 Embedding、自己的提示词,甚至接入多仓库索引,快速扩展成专属的「代码助手」。相关实现与依赖清单均可直接查看 github-rag/app.pygithub-rag/app_local.pygithub-rag/requirements.txt 继续深入。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389