传统 RAG 的流程是一条直线:用户查询丢给检索器,取回的片段连同问题塞给模型,模型据此作答。这条直线有两个先天弱点——它只有一次检索机会,第一轮没找到的东西后面就再也没有了;它对齐的是查询的字面语义相似度,用户问法稍有偏差,真正相关的资料就可能落在召回窗口之外 [1]。
Agentic RAG 的思路是把检索过程交给智能体:自主构造搜索查询、批判取回的结果、按需执行多轮检索。检索不再是流水线上的一个固定环节,而成为模型可以规划、可以迭代的一组动作 [1]。
最简版本:联网搜索智能体
用 smolagents 搭一个能联网检索的智能体,只需要一个搜索工具加一个模型:
from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel
# Initialize the search tool
search_tool = DuckDuckGoSearchTool()
# Initialize the model
model = InferenceClientModel()
agent = CodeAgent(
model=model,
tools=[search_tool],
)
# Example usage
response = agent.run(
"Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering."
)
print(response)这个智能体跑起来分四步:先分析请求,从查询里识别出关键要素(豪华风格的超级英雄派对、装饰、娱乐、餐饮);再执行检索,用 DuckDuckGo 拉取最新相关信息;然后综合信息,把零散结果整理成一份完整可执行的计划;最后存档备用,把检索到的信息留存下来,供以后规划同类活动时复用 [1]。
自定义知识库:把检索器包成工具
联网搜索解决的是开放信息,企业场景更常见的是把自有文档做成知识库。做法是把检索器包成一个 smolagents Tool:向量数据库存的是文本经机器学习模型转出的数值表示(嵌入),靠高维空间里「含义相近」来做语义搜索 [1]。示例用 BM25 做检索、RecursiveCharacterTextSplitter 做切分:
from langchain_community.docstore.document import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from smolagents import Tool
from langchain_community.retrievers import BM25Retriever
from smolagents import CodeAgent, InferenceClientModel
class PartyPlanningRetrieverTool(Tool):
name = "party_planning_retriever"
description = "Uses semantic search to retrieve relevant party planning ideas for Alfred’s superhero-themed party at Wayne Manor."
inputs = {
"query": {
"type": "string",
"description": "The query to perform. This should be a query related to party planning or superhero themes.",
}
}
output_type = "string"
def __init__(self, docs, **kwargs):
super().__init__(**kwargs)
self.retriever = BM25Retriever.from_documents(
docs, k=5 # Retrieve the top 5 documents
)
def forward(self, query: str) -> str:
assert isinstance(query, str), "Your search query must be a string"
docs = self.retriever.invoke(
query,
)
return "\nRetrieved ideas:\n" + "".join(
[
f"\n\n===== Idea {str(i)} =====\n" + doc.page_content
for i, doc in enumerate(docs)
]
)工具类是 smolagents 工具机制的典型样板:name 和 description 是给模型看的,模型靠它们决定什么时候调用;inputs 声明参数 schema;真正干活的是 forward 方法——从 BM25 索引取回前 5 条文档,拼成带分隔符的文本返回。然后准备语料、切分、装配:
party_ideas = [
{"text": "A superhero-themed masquerade ball with luxury decor, including gold accents and velvet curtains.", "source": "Party Ideas 1"},
{"text": "Hire a professional DJ who can play themed music for superheroes like Batman and Wonder Woman.", "source": "Entertainment Ideas"},
{"text": "For catering, serve dishes named after superheroes, like 'The Hulk's Green Smoothie' and 'Iron Man's Power Steak.'", "source": "Catering Ideas"},
{"text": "Decorate with iconic superhero logos and projections of Gotham and other superhero cities around the venue.", "source": "Decoration Ideas"},
{"text": "Interactive experiences with VR where guests can engage in superhero simulations or compete in themed games.", "source": "Entertainment Ideas"}
]
source_docs = [
Document(page_content=doc["text"], metadata={"source": doc["source"]})
for doc in party_ideas
]
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
add_start_index=True,
strip_whitespace=True,
separators=["\n\n", "\n", ".", " ", ""],
)
docs_processed = text_splitter.split_documents(source_docs)
# Create the retriever tool
party_planning_retriever = PartyPlanningRetrieverTool(docs_processed)
# Initialize the agent
agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel())
# Example usage
response = agent.run(
"Find ideas for a luxury superhero-themed party, including entertainment, catering, and decoration options."
)
print(response)切分参数值得留意:chunk_size 500、chunk_overlap 50,加了起始索引、去首尾空白,分隔符从段落级一路细到字符级。经验上,块太大稀释检索精度,块太小丢失上下文,50 左右的重叠能保住跨块边界的句子。装配好的智能体先查文档拿相关信息,再结合知识库的洞见,并在内存里维持对话上下文 [1]。
BM25 和向量检索是互补关系:BM25 是词频统计方法,不需要嵌入模型,对术语的精确匹配很强;向量检索捕捉同义改写和语义相近。生产系统常用混合检索把两路召回合并,再统一重排。
让检索更聪明
Agentic RAG 的进阶玩法集中在七类策略:查询重构,不改用户原话而是构造更贴合目标文档的检索词;查询分解,复合问题拆成多个子查询分别检索;查询扩展,同一意图换成多种措辞各查一遍;重排序,用 Cross-Encoder 对「查询-文档」对打更细的相关性分;多步检索,用前一轮结果指导下一轮查询;多源整合,网络搜索和本地文档一起用;结果校验,内容进答案之前先过一遍相关性和准确性审查 [1]。
这些策略在工程上各有位置。Cross-Encoder 打分准但贵——每对查询文档都要过一遍完整模型,所以标准做法是先用便宜的第一阶段召回 top-k,再对短名单重排。查询分解适合多实体多约束的复合问题,子查询独立检索后合并去重。结果校验可以让模型判断检索片段与问题的事实一致性,不一致的片段宁可不用。
系统层面同样有讲究:智能体应按查询类型和上下文在可用工具之间做选择;内存系统维持对话历史、避免重复检索同样的问题;要有回退策略,主检索失效时系统仍能给出有价值的东西;校验步骤兜住最后的质量关 [1]。
本文改编自 Hugging Face agents-course 的 Building Agentic RAG Systems 一节[1],原文以 Apache-2.0 许可发布。
来源
- 1Building Agentic RAG Systems | Hugging Face Agents CourseHugging Face agents-course (Apache-2.0)
引用本页: smolagents 检索智能体. TellWorld, https://www.tellworld.net/zh/practice/practice-smolagents-retrieval. 更新于 2026-11-14