最近在梳理 LLM 应用开发的学习路径时,发现很多新手容易陷入两个极端:要么只看理论,停留在“大模型能做什么”的层面;要么一上来就啃 LangChain、LlamaIndex 源码,被各种抽象概念绕晕。如果有一个项目能把常见的 LLM 应用场景集中展示,还附带了可运行的代码,学习效率会高很多。
Shubhamsaboo 的awesome-llm-apps正是这样一个仓库。它不是一个“放满论文链接的收藏夹”,而是一组能真正跑起来的 LLM 应用示例,覆盖了 RAG、Agent、MCP、多工具调用等热门方向。本文会从项目结构、核心概念、环境配置、实战运行、常见报错和工程建议几个方面展开,帮助你把它用起来。
1. 背景与核心概念
1.1 awesome-llm-apps 是什么
awesome-llm-apps是一个在 GitHub 上持续维护的开源项目合集,由开发者 Shubhamsaboo 创建。它收集了大量基于 LLM(Large Language Model,大语言模型)构建的应用程序示例,每个示例都带有完整的代码、依赖文件和运行说明。
和普通“awesome 列表”不同,这个仓库里的项目不是单纯放一个 README 或论文链接,而是实打实的 Python 项目。你可以直接克隆到本地,配置好 API Key 后运行起来,看到真实的大模型应用效果。
目前仓库里覆盖的场景包括:
- 基于 RAG(Retrieval-Augmented Generation,检索增强生成)的知识库问答
- 多 Agent 协作系统
- MCP(Model Context Protocol,模型上下文协议)客户端应用
- 金融数据分析助手
- PDF、网页内容问答
- 个人 AI 助手
- Slack、Discord 等平台集成
1.2 它解决什么问题
在 LLM 应用开发中,很多人会遇到这样的困境:
- 官方文档看了不少,但不知道从哪个项目入手。
- 知道 RAG 的大致原理,但遇到“怎么切分文档”“用什么向量库”“怎么处理多轮对话”就卡住了。
- 想做一个 Agent 应用,结果被 ReAct、Function Calling、工具调用这些概念挡住。
- 网上教程很多,但代码版本混乱,跑不起来。
awesome-llm-apps的价值在于:它给出了可以直接运行的最小示例。它不是框架文档,也不是系统教学课程,而是一个“项目脚手架仓库”。你可以把它当作参考实现,也可以基于它改造自己的业务应用。
1.3 常见应用场景
根据仓库中的项目,可以归纳出几类典型应用场景:
| 场景 | 说明 | 对应项目方向 |
|---|---|---|
| 企业知识库问答 | 把内部文档、PDF、网页内容作为知识来源,回答用户问题 | PDF RAG、Web 内容问答 |
| 个人助理 | 管理日程、发邮件、搜索网页信息 | Personal AI Assistant |
| 数据分析 | 通过自然语言查询金融数据、分析股票趋势 | Finance Agent |
| 多 Agent 协作 | 多个角色化的 Agent 分工完成任务 | Multi-Agent System |
| 平台集成 | 在 Slack、Discord 中接入智能聊天机器人 | Slack AI Assistant |
| MCP 应用开发 | 构建支持外部工具和资源接入的 LLM 客户端 | MCP Client |
2. 环境准备与版本说明
在运行awesome-llm-apps中的项目之前,需要先把环境准备好。由于仓库中的项目以 Python 为主,下面以 Python 环境为例说明。
2.1 基础环境要求
建议环境如下,版本需要根据你的项目实际情况调整:
- 操作系统:Windows 10/11、macOS 或主流 Linux 发行版均可。
- Python 版本:3.9 及以上。部分项目可能要求 3.10 或 3.11,建议安装 3.10 或 3.11 作为默认版本。
- 包管理器:pip 或 poetry。仓库部分项目使用
requirements.txt,部分使用pyproject.toml。 - Git:用于克隆仓库。
- API Key:根据项目不同,可能需要 OpenAI API Key、Anthropic API Key、Tavily API Key、Pinecone API Key 等。
- 向量数据库:部分 RAG 项目需要 Chroma、Pinecone、Weaviate 等向量数据库。其中 Chroma 可以本地运行,适合入门。
2.2 克隆仓库
git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git cd awesome-llm-apps仓库目录较大,如果你只想运行某一个项目,也可以使用--depth 1参数进行浅克隆,减少下载体积。
2.3 创建虚拟环境
强烈建议为每个项目创建独立的虚拟环境,避免依赖冲突:
python -m venv venv source venv/bin/activate # Linux / macOS venv\Scripts\activate # Windows激活虚拟环境后,再安装项目依赖。以chat_with_your_pdf这类项目为例:
cd chat_with_your_pdf pip install -r requirements.txt不同项目的依赖差异很大,有的使用 LangChain,有的使用 LlamaIndex,有的使用 CrewAI,建议按每个项目目录下的说明逐个安装。
2.4 环境变量配置
API Key 不要硬编码在代码中,建议通过环境变量或.env文件管理。
在项目根目录创建.env文件:
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx TAVILY_API_KEY=tvly-xxxxxxxxxxxxxxxx PINECONE_API_KEY=xxxxxxxxxxxxxxxx然后在代码中加载:
from dotenv import load_dotenv load_dotenv() import os openai_api_key = os.getenv("OPENAI_API_KEY")这种方式的好处是,代码提交到 GitHub 时不会泄露密钥,也方便在不同环境中切换配置。
3. 核心架构与原理拆解
awesome-llm-apps中的项目看起来五花八门,但拆开来看,核心架构有不少共性。理解这些共性,比跑通某一个项目更重要。
3.1 典型 LLM 应用架构
一个完整 LLM 应用通常包含以下模块:
- 用户交互层:即前端界面,仓库中常用 Streamlit、Gradio 或 FastAPI 实现,负责收集用户输入并展示结果。
- 应用逻辑层:负责调度 LLM、管理对话状态、调用外部工具,这是核心代码所在。
- 外部工具层:包括搜索 API、数据库、向量存储、邮件服务等,扩展 LLM 的能力边界。
- LLM 层:通过 API 调用 GPT、Claude、Llama 等模型,接收 prompt 并返回结果。
3.2 RAG 应用的工作流程
RAG(Retrieval-Augmented Generation,检索增强生成)是awesome-llm-apps中出现频率最高的模式之一。
流程可以简化为:
- 加载文档:读取 PDF、网页或其他格式的文档。
- 文本切分:把长文档切分成固定大小的 chunk,避免超出模型上下文限制。
- 向量化:用 Embedding 模型把每个 chunk 转换成向量。
- 存储:把向量写入向量数据库。
- 检索:用户提问时,把问题向量化,在向量数据库中查找最相似的 chunk。
- 生成:把检索到的上下文和用户问题一起发给 LLM,生成回答。
对应到项目代码中,通常会拆成两个阶段:索引阶段和查询阶段。索引阶段只需要在文档变化时重新执行,查询阶段每次用户提问都会触发。
3.3 Agent 与工具调用
Agent(智能体)是另一种常见模式。在 RAG 中,LLM 主要做“阅读并回答”的工作;而在 Agent 模式中,LLM 变成了一个“决策者”,它根据用户的需求决定调用哪个工具、按什么顺序调用。
例如,在金融分析 Agent 中,LLM 可能会:
- 判断用户需要查询股票数据,于是调用
get_stock_price工具。 - 拿到价格数据后,调用
get_company_news工具获取相关新闻。 - 最后结合两组数据,生成综合分析报告。
这种能力依赖 Function Calling 或 Tool Calling 机制。OpenAI、Anthropic 等都提供了对应的 API,LangChain、CrewAI 等框架则在更高层次上封装了调用逻辑。
3.4 MCP 与外部工具连接
近期热议的 MCP(Model Context Protocol,模型上下文协议)也在仓库中有对应示例。MCP 可以理解为 LLM 和外部工具之间的“USB 接口”标准。它定义了工具、资源和提示词的统一协议格式,开发者只需要实现 MCP Server,任何支持 MCP 的 LLM 客户端都可以直接使用这些工具。
MCP 之所以重要,是因为它改变了工具集成的方式。在没有 MCP 之前,每接入一个工具,都要为 LLM 写一套专门的工具调用代码;有了 MCP 之后,工具提供方只需编写并托管一个 MCP Server,所有兼容 MCP 的客户端都能直接调用。
3.5 为什么需要 LLM 编排框架
很多初学者会问:直接调用 OpenAI API 不是很简单吗?为什么还要用 LangChain、LlamaIndex、CrewAI 这些框架?
原因在于,真实业务场景远比“发送一个请求”复杂:
- 需要管理多轮对话历史。
- 需要对接多种向量数据库。
- 需要封装重试、超时、错误处理。
- 需要支持流式输出。
- 需要在不同模型之间切换。
- 需要编排多个 Agent 的协作流程。
编排框架的价值在于把这些通用能力抽象成现成的模块,让开发者专注于业务逻辑。不过也需要注意,框架的抽象会隐藏底层细节,出现问题时不熟悉原理反而更难排查。因此,建议先通过原生 API 做一个简单 Demo,再引入框架。
4. 完整实战案例:运行一个 RAG 问答应用
下面选择仓库中一个比较经典的项目——PDF 问答聊天机器人来演示完整的运行流程。
4.1 项目功能
这个应用允许用户上传一个 PDF 文件,然后针对 PDF 内容进行多轮提问。实现方式是:
- 读取 PDF 并切分成文本块。
- 使用 OpenAI Embedding API 生成向量。
- 将向量存入本地向量库(本项目使用 Chroma)。
- 用户提问时,检索相关文本块并调用 GPT 生成回答。
4.2 创建项目结构
在awesome-llm-apps仓库中找到对应项目目录。不同版本的项目结构略有差异,通常包含以下文件:
chat_with_your_pdf/ ├── app.py ├── requirements.txt ├── .env ├── README.md └── utils.py4.3 添加依赖
查看requirements.txt,核心依赖通常包括:
streamlit openai langchain langchain-community chromadb pypdf python-dotenv tiktoken安装依赖:
pip install -r requirements.txt如果你是 Apple Silicon Mac,安装chromadb时如果遇到编译问题,可以尝试:
pip install chromadb --no-cache-dir4.4 编写核心代码
下面的代码是一个简化版本的 PDF RAG 应用,用于演示核心逻辑。为了便于理解,我不使用完整框架,而是保留关键链路。
# 文件路径:chat_with_your_pdf/simple_pdf_rag.py import os from dotenv import load_dotenv from pypdf import PdfReader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA load_dotenv() # 1. 读取 PDF def load_pdf_text(pdf_path: str) -> str: reader = PdfReader(pdf_path) texts = [] for page in reader.pages: text = page.extract_text() if text: texts.append(text) return "\n".join(texts) # 2. 切分文本 def split_text(text: str): splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?", " ", ""] ) return splitter.split_text(text) # 3. 构建向量库 def build_vectorstore(chunks): embeddings = OpenAIEmbeddings(model="text-embedding-3-small") vectorstore = Chroma.from_texts( texts=chunks, embedding=embeddings, persist_directory="./chroma_db" ) return vectorstore # 4. 创建问答链 def create_qa_chain(vectorstore): llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever(search_kwargs={"k": 4}) ) return qa_chain if __name__ == "__main__": pdf_path = "sample.pdf" text = load_pdf_text(pdf_path) chunks = split_text(text) print(f"PDF loaded, total {len(chunks)} chunks") vectorstore = build_vectorstore(chunks) qa_chain = create_qa_chain(vectorstore) while True: query = input("请输入问题(输入 exit 退出):") if query.lower() in ("exit", "quit"): break result = qa_chain.invoke(query) print("回答:", result["result"])4.5 运行与验证
运行脚本:
python simple_pdf_rag.py预期输出:
PDF loaded, total 18 chunks 请输入问题(输入 exit 退出):输入一个与 PDF 内容相关的问题后,程序会检索相关文本块并返回模型生成的回答。
需要说明的是,使用RetrievalQA时会有一个隐藏问题:当文本块较多时,stuff方式会把所有检索结果一次性塞进提示词中。如果检索到的文本块超过上下文长度,就会报错。解决方式有两种:
- 减少
k值,例如从 4 改为 2。 - 换用
map_reduce或refine方式处理长文本。
4.6 转换为 Web 应用
如果你希望把脚本变成 Web 应用,可以使用 Streamlit。核心改动是把控制台交互改为 Streamlit 的组件交互:
# 文件路径:chat_with_your_pdf/streamlit_app.py import streamlit as st from simple_pdf_rag import load_pdf_text, split_text, build_vectorstore, create_qa_chain st.set_page_config(page_title="PDF RAG Chatbot", page_icon="📄") st.title("📄 与你的 PDF 对话") uploaded_file = st.file_uploader("上传 PDF 文件", type="pdf") if uploaded_file is not None: with open("temp.pdf", "wb") as f: f.write(uploaded_file.getbuffer()) text = load_pdf_text("temp.pdf") chunks = split_text(text) vectorstore = build_vectorstore(chunks) qa_chain = create_qa_chain(vectorstore) st.success(f"PDF 加载完成,共 {len(chunks)} 个文本块") if "messages" not in st.session_state: st.session_state.messages = [] for message in st.session_state.messages: with st.chat_message(message["role"]): st.markdown(message["content"]) if prompt := st.chat_input("请输入问题"): st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) with st.chat_message("assistant"): result = qa_chain.invoke(prompt) st.markdown(result["result"]) st.session_state.messages.append({"role": "assistant", "content": result["result"]})运行 Streamlit 应用:
streamlit run streamlit_app.py5. 常见问题与排查思路
运行awesome-llm-apps中的项目时,常见的报错和问题可以归纳为以下几类。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
提示ModuleNotFoundError: No module named 'langchain' | 依赖未安装或安装在错误环境中 | 确认当前虚拟环境已激活,执行pip install -r requirements.txt |
提示AuthenticationError或Invalid API Key | API Key 错误或环境变量未加载 | 检查.env文件是否位于当前目录,确认.env中变量名与代码中一致 |
提示ContextWindowExceededError | 检索到的文本块超过模型上下文限制 | 减小chunk_size、减少k值,或换用map_reduce方式 |
| 向量库持久化失败 | 目录权限或 Chroma 版本问题 | 确保persist_directory对应目录可写;升级或固定 chromadb 版本 |
| 中文回答质量差 | 文本切分时把中文句子切断 | 在分隔符中加入中文标点,或在完整代码中使用RecursiveCharacterTextSplitter并添加中文分隔符 |
| 运行 Streamlit 后页面空白 | 浏览器缓存或依赖冲突 | 刷新页面;检查终端是否有报错;确认 openai 与 langchain-openai 版本兼容 |
| 安装 chromadb 时编译报错 | Python 版本或系统依赖问题 | 使用 Python 3.10 或 3.11;尝试安装预编译版本或更新 pip |
除了表中内容,还有一个经常被忽略的问题:Embedding 模型和 Chat 模型不一致。在 RAG 流程中,索引阶段的 Embedding 模型和查询阶段的 Embedding 模型必须是同一个,否则向量空间不一致,检索结果会非常差。如果你在运行时更换了 Embedding 模型,需要删除旧的向量库并重新建立索引。
排查问题时,建议按照以下顺序进行:
- 检查环境变量是否加载成功:在代码中打印
os.getenv("OPENAI_API_KEY"),确认不是None。 - 检查当前使用的是不是正确的 Python 环境:
which python或where python。 - 检查依赖版本是否冲突:使用
pip list查看已安装版本,对照项目requirements.txt中是否有版本要求。 - 检查网络连接:如果使用
httpx或requests访问外部 API,确认所在网络能否正常访问对应服务。 - 查看完整堆栈信息:不要只看最后一行报错,往上翻几行,定位到具体代码位置。
6. 最佳实践与工程建议
6.1 目录与命名规范
awesome-llm-apps中项目很多,如果你要基于它扩展自己的项目,建议遵循以下规范:
- 每个应用一个独立目录,目录名用短横线分隔的小写单词,例如
chat-with-your-pdf。 - 每个目录内包含:
README.md、requirements.txt、.env.example、源码文件和测试文件。 - 在
README.md中说明项目用途、运行步骤、环境变量清单和常见问题。
.env.example很重要,它列出了项目需要的全部环境变量,但不包含真实密钥。提交到 Git 仓库时,确保.env被.gitignore忽略。
6.2 配置管理
LLM 应用的配置项通常包括:
- API Key 和 Base URL
- 模型名称和版本
- Temperature 等生成参数
- 向量数据库连接信息
- 文本切分参数(chunk_size、chunk_overlap)
- 检索参数(k 值)
不要把这些配置散落在代码中。推荐使用 Pydantic Settings 或python-dotenv统一管理:
from pydantic_settings import BaseSettings class Settings(BaseSettings): openai_api_key: str openai_base_url: str = "https://api.openai.com/v1" model_name: str = "gpt-4o-mini" embedding_model: str = "text-embedding-3-small" chunk_size: int = 1000 chunk_overlap: int = 200 retrieval_k: int = 4 class Config: env_file = ".env"6.3 提示词设计与版本管理
提示词(Prompt)是 LLM 应用效果的核心变量。工程化过程中,建议:
- 把系统提示词和用户提示词分离。
- 使用模板而不是字符串拼接。
- 对提示词变更进行版本管理。
- 建立测试集,每次修改提示词后回归验证。
例如:
from langchain_core.prompts import ChatPromptTemplate prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个严谨的技术助手。请基于给定的上下文回答问题。如果上下文中没有相关信息,请明确回答“根据提供的信息无法回答”。"), ("human", "上下文:\n{context}\n\n问题:{question}") ])这个提示词强调了“无法回答时要承认”,能显著减少大模型的幻觉问题。
6.4 异常处理与日志
LLM API 调用可能因为网络波动、限流、超时而失败。生产环境必须做好重试和降级处理:
import time from openai import OpenAI client = OpenAI() def call_llm_with_retry(prompt, max_retries=3, delay=2): for attempt in range(max_retries): try: response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content except Exception as e: if attempt == max_retries - 1: raise e time.sleep(delay * (attempt + 1))日志方面,至少需要记录:
- 每次 LLM 调用的耗时。
- 使用的模型名称和 token 数量。
- 错误类型和重试次数。
- 用户输入的摘要(注意隐私,避免记录完整内容)。
6.5 性能优化
RAG 应用的性能瓶颈通常在检索和生成两个环节。可以考虑以下几点:
- 使用缓存减少重复 LLM 调用。相同问题的结果可以存入 Redis 或数据库中。
- 使用流式输出改善用户体验。
- 对向量数据库建立索引,优化检索速度。
- 引入重排(Rerank)模型提升检索精度。
- 对于超长文档,先做摘要,再做检索。
6.6 生产环境注意事项
如果你要把awesome-llm-apps中的原型改造成生产系统,有几个关键差异需要重视:
- 安全边界:对外提供 API 时,要控制用户输入的注入风险。例如,在提示词中要求模型忽略试图覆盖指令的内容,同时在后端限制用户的 token 数量和调用频率。
- 敏感信息保护:确保日志中不出现 API Key、用户隐私等敏感内容。
- 成本控制:LLM API 按 token 计费,需要监控每个用户或每个会话的 token 消耗。
- 模型版本固定:生产环境应固定模型版本,或使用明确的模型别名,防止模型供应商更新导致行为变化。
- 数据隔离:多租户场景下,要确保每个用户只能访问自己的知识库数据。
6.7 从 awesome-llm-apps 中学习的方法
对于学习型读者,建议不要只是“把项目跑起来”就结束。可以按照以下步骤深入:
- 读代码:找到
app.py或main.py中调用 LLM 的地方,理解输入输出。 - 改参数:调整
chunk_size、temperature、k等参数,观察效果变化。 - 换模型:把 OpenAI 模型换成其他兼容接口的模型,修改 Base URL 和模型名。
- 加功能:在现有项目上增加一个工具调用,或换一个向量数据库。
- 重写:尝试不依赖框架,用原生 API 实现一个最小 RAG。
7. 总结与学习路线
awesome-llm-apps是一个非常适合 LLM 应用开发入门和进阶的参考仓库。通过运行其中的项目,你可以直观地理解 RAG、Agent、MCP 等核心概念的实际应用方式,同时也为业务开发提供了可复用的脚手架。
如果你刚开始接触 LLM 应用开发,可以按照以下路径学习:
- 基础阶段:运行一个最简单的对话应用,理解 API 调用、token、temperature 等基础概念。
- RAG 阶段:从 PDF 问答项目入手,掌握文档切分、向量检索、上下文组装等核心技术。
- Agent 阶段:学习函数调用,尝试构建一个能调用搜索、计算等工具的小型 Agent。
- 工程化阶段:引入编排框架,关注配置管理、异常处理、日志和性能优化。
- MCP 阶段:了解模型上下文协议,尝试编写一个 MCP Server 并接入客户端。
在实际项目中,最重要的不是“跑通 Demo”,而是理解每个环节的原理和边界。跑通只是起点,把项目改造成符合业务需求、能承受真实流量、具备可维护性的系统,才是真正的挑战。
如果文章对你有帮助,可以收藏备用。也欢迎在评论区交流你在运行这些项目时遇到的问题,一起完善这份 LLM 应用开发笔记。