Day 15 / 共 20 天 · 第 3 周 检索与查询
LLM 抽象(RAG 的最后一块)
第 3 周收官。RAG 的最后一环——大模型本身。LlamaIndex 把各家 LLM 统一封装成一套接口,让 OpenAI/Claude/本地模型能互换。今天讲 LLM 抽象、chat/complete、消息角色、全局 Settings。
📍 你在整条链的位置(RAG 全链路即将闭环)
检索 → 后处理 → 合成→
LLM(生成的执行者)→
Agent/Workflow(W4)
L01
为什么要抽象 LLM
🤔 各家 LLM 的 API 五花八门
OpenAI、Claude、Gemini、本地 Ollama——每家 API 参数、返回格式都不同。如果 RAG 代码直接调 OpenAI,想换成 Claude 就要大改。
💡 统一 LLM 接口,换模型只换一行
LlamaIndex 定义统一的
LLM 接口——不管底层是谁,都用 llm.chat(messages) / llm.complete(prompt)。换模型只需换 integration(OpenAI() → Anthropic()),业务代码(建索引、检索、合成)一行不改。回想前面所有组件(Reader/Embedding/VectorStore/Retriever)都是"接口统一、实现可换"——LLM 也不例外。L02
LLM 接口
base/llms/base.py 的 BaseLLM + llms/llm.py:163 的 LLM(更高层,加 prompt 处理)。核心抽象方法:
llm.chat(messages) # 对话(现代)
llm.complete(prompt) # 文本补全(老式)
llm.stream_chat(messages) # 流式对话
# + 异步版 achat / acomplete ...
llm.metadata # 模型信息(上下文窗口大小,PromptHelper D13 用它算装箱)
读法:各家 LLM(
llama-index-llms-openai 等 integration)继承 LLM 实现这几个方法。LlamaIndex 内部(合成器 D13、Agent D17)只调这套统一接口,不关心是哪家。业务层只依赖统一接口(chat/complete/stream);底层 integration 可自由替换,换模型不改业务代码
L03
chat vs complete
📝 两种交互
llm.complete("请续写:从前有座山") # 补全:给文本,续写
llm.chat([ChatMessage(role="user", content="你好")]) # 对话:给消息列表,返回回复💡 现代模型都是 chat 式
complete(补全)是老式接口;chat(对话)是现代接口(ChatGPT 那样,给带角色的消息列表)。LlamaIndex 两个都支持,内部自动转换(chat 模型收到 complete 请求会包装成单条 user 消息)。RAG 合成答案通常用 chat(system 设"你是问答助手"、user 放"资料+问题")。
L04
ChatMessage / 角色
base/llms/types.py:MessageRole(:53:SYSTEM/USER/ASSISTANT/TOOL)、ChatMessage(:1159:role + content)、ChatResponse/CompletionResponse。
📝 一次 RAG 对话的消息
[ ChatMessage(role=SYSTEM, content="你是问答助手,只依据资料回答"),
ChatMessage(role=USER, content="资料:报销上限3000元…\n问题:报销上限?"),
# LLM 返回 →
ChatMessage(role=ASSISTANT, content="报销上限为 3000 元。") ]"消息 + 角色"是现代 LLM 应用的通用语言
SYSTEM(设人设/规则)、USER(用户说的)、ASSISTANT(模型答的)、TOOL(工具返回的,Day 17 Agent 用)。Agent 的多轮推理、记忆(Day 18)都基于这套消息模型。新版 content 还支持多模态(文本/图片块)。
L05
流式
💡 stream_chat 返回生成器,逐块产出 delta
stream_chat/stream_complete 逐 token 返回(每块含增量 delta)。让界面"打字机效果"实时显示(Day 13 合成器的 streaming 就基于它)。统一的流式接口让所有下游(合成器/Agent/chat engine)都能支持流式,不管底层 LLM 是谁。L06
Settings:一处设置,全局生效
settings.py 的 Settings:全局默认——Settings.llm、Settings.embed_model、Settings.node_parser。不显式传时,各组件用它。
📝 全局配置
from llama_index.core import Settings
Settings.llm = OpenAI(model="gpt-4o") # 全局设 LLM
Settings.embed_model = OpenAIEmbedding() # 全局设嵌入
# 之后 VectorStoreIndex / query_engine 不传就用这些这就是"5 行 RAG"能那么短的原因
不用每个组件传 llm/embed_model——设一次 Settings,全局默认用它(或从环境变量读 OpenAI key)。换模型:改
Settings.llm 一行,全应用生效。(旧版叫 ServiceContext,已被更简洁的 Settings 取代。)L07
结构化与工具调用(Agent 的基础)
💡 structured_predict + 工具调用
LLM 还提供 structured_predict(让 LLM 严格返回 Pydantic 对象)和工具调用(function_calling)——这是 Agent(Day 17)能"自主用工具"的底层能力。读法:工具调用:给 LLM 一组工具,它直接返回"我要调 weather('北京')"这样的结构化决策。第 4 周的 Agent 就靠 LLM 的工具调用能力来自主决策。LlamaIndex 把各家 LLM 的工具调用也统一封装了——又是"接口统一"。
L08
今日小结 + 动手(第 3 周收官)
🧠 第 3 周你应该能回答
- 为什么要抽象 LLM?换模型怎么做?
- chat vs complete?ChatMessage 的角色模型(SYSTEM/USER/ASSISTANT/TOOL)?
- 流式接口为什么重要?
- Settings 怎么让"5 行 RAG"成立?工具调用是谁的基础?
✋ 动手
cd /Users/bitmart/work/codes/github/llama_index/llama-index-core/llama_index/core
sed -n '163,200p' llms/llm.py
grep -n "class MessageRole\|class ChatMessage\|class ChatResponse" base/llms/types.py
grep -n "llm\|embed_model" settings.py | head
下周预告 · 第 4 周:超越 RAG——Workflow(事件驱动引擎)、基于它的 Agent(用工具、多步推理)、聊天记忆、可观测评估。Day 16 从 Workflow 讲起。