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.pyBaseLLM + llms/llm.py:163LLM(更高层,加 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)只调这套统一接口,不关心是哪家。
业务层(一行不改) 合成器 D13 Agent D17 ChatEngine D18 统一 LLM 接口(base/llms + llm.py) chat() complete() stream_chat() metadata ↓ 各家 integration 实现(换模型只换一行) OpenAI() Anthropic() Gemini() Ollama()
业务层只依赖统一接口(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.pyMessageRole: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.pySettings:全局默认——Settings.llmSettings.embed_modelSettings.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 讲起。
← Day 14 Day 16 · Workflow →