从 RAG 到 Agent:跑通两个 Demo 后,我终于分清了这两个词

最近接连跑通了两个 LLM 应用的小 Demo:先是一个 RAG 私有文档问答,然后是一个 ReAct 模式的旅行助手 Agent。最大的收获不是代码本身,而是终于搞明白了一件天天被提但一直模模糊糊的事------RAG 和 Agent 到底差在哪

第一站:RAG------让模型"知道"我的文档

第一个 Demo 很经典:让 LLM 回答它训练数据里不可能有的问题------我自己的笔记。

流程两条管线:

ini 复制代码
# 建索引:markdown 文档 → 切成 500 字的块 → 算 embedding → 存进 Chroma
chunks = chunk_text(text, size=500, overlap=50)
embeddings = embedder.encode(chunks)
collection.add(ids=..., documents=chunks, embeddings=embeddings)
ini 复制代码
# 查询:问题 → 向量检索 top3 → 拼进 prompt → 调一次 LLM 生成回答
def answer(question: str) -> str:
    chunks = retrieve(question)          # 检索最相似的 3 块
    prompt = PROMPT_TEMPLATE.format(context=..., question=question)
    response = CLIENT.chat.completions.create(...)
    return response.choices[0].message.content

跑通之后回头看,RAG 的特点非常明显:

  • 流程是代码写死的:检索 → 拼 prompt → 生成,永远这三步,一步不会多
  • LLM 只被调用一次,它自始至终不知道"检索"这件事的存在
  • LLM 的角色是拿着参考资料的答题者------你喂它三段资料,它负责好好回答,答不出就说"文档里没说"

一句话:RAG 解决的是"知道"的问题------把模型不知道的私有知识,现场塞给它。

第二站:Agent------让模型"做事"

第二个 Demo 是一个旅行助手,任务一句话:查北京今天的天气,然后根据天气推荐景点

注意这是个两步任务,而且第二步依赖第一步的结果。如果是普通程序,我们得自己写"先查天气、再搜景点"的调度逻辑。但 Agent 的做法是:只给模型工具,让模型自己决定怎么串

工具就是两个普通 Python 函数,没有任何特殊之处:

python 复制代码
def get_weather(city: str) -> str:
    data = requests.get(f"https://wttr.in/{city}?format=j1", timeout=10).json()
    cur = data["current_condition"][0]
    return f"{city}当前天气:{cur['weatherDesc'][0]['value']},气温{cur['temp_C']}摄氏度"
​
def get_attraction(city: str, weather: str) -> str:
    result = tavily.search(query=f"{city} 适合{weather}天气的旅游景点推荐", max_results=3)
    return "根据搜索,为您找到以下信息:" + ";".join(r["title"] for r in result["results"])

然后在 System Prompt 里告诉模型有哪些工具、按什么格式说话(Thought / Action / Observation 协议),核心循环长这样:

css 复制代码
for i in range(1, MAX_LOOPS + 1):
    # ① 问模型下一步干嘛
    reply = llm.chat.completions.create(model=MODEL, messages=messages).choices[0].message.content
​
    # ② 模型说"信息够了" → 结束
    if "Final Answer" in reply:
        return reply.split("Final Answer:")[-1]
​
    # ③ 抠出工具名和参数,真正执行
    tool_name, args = parse_action(reply)
    observation = TOOLS[tool_name](**args)
​
    # ④ 关键:把工具结果拼成 Observation 喂回对话,进入下一轮
    messages.append({"role": "assistant", "content": reply})
    messages.append({"role": "user", "content": f"Observation: {observation}"})

实际跑起来的输出(真实运行结果节选):

vbnet 复制代码
--- 循环 1 ---
Thought: 用户需要先查询北京今天的天气......第一步先调用天气查询工具。
Action: get_weather(city="北京")
Observation: 北京当前天气:Sunny,气温27摄氏度
​
--- 循环 2 ---
Thought: 北京今天是晴天,气温27摄氏度,适合户外活动。接下来根据这个天气条件调用景点推荐工具。
Action: get_attraction(city="北京", weather="Sunny")
Observation: 根据搜索,为您找到以下信息:北京在sunny天气下最值得去的旅游景点推荐及理由;......
​
--- 循环 3 ---
Thought: 工具返回了景点推荐结果......
Final Answer: 北京今天天气晴朗,气温约27°C,非常适合户外游玩......

执行结果:

看循环 2 那行 Action:weather="Sunny" 这个参数是模型自己填的------它把循环 1 拿到的天气结果,当作循环 2 的输入传了进去。代码里没有任何一行写"先查天气再搜景点",整个流程的编排完全发生在模型的"脑子"里。

这就是 Agent 的本质:LLM 不只是答题者,而是指挥官,工具是它的手脚,那个"问模型 → 干活 → 把结果给模型看"的循环就是它的心脏。

区别,一张表说清

RAG Agent
LLM 被调几次 1 次 N 次(每轮循环一次)
流程谁定的 代码写死 LLM 运行时自己决定
LLM 的角色 拿着参考资料的答题者 调度工具的指挥官
解决什么问题 知道:掌握私有知识 做事:完成多步任务
能否根据中间结果调整 不能,管线是直的 能,下一步取决于上一步

我自己总结的最快判断法:看有没有"循环 + 决策" 。没有循环、模型只出场一次的,是 RAG;有循环、每一步"接下来干嘛"由模型现场判断的,是 Agent。

顺手踩的一个坑

用正则解析模型的 Action: get_weather(city="北京") 后,我最初想用 ast.literal_eval 把参数转成字典------结果直接报 SyntaxError。原因:literal_eval 只认 Python 字典写法 {"city": "北京"},而模型输出的是函数调用写法 city="北京"。最后老老实实用正则逐对提取:

python 复制代码
args = dict(re.findall(r'(\w+)="([^"]*)"', args_str))  # city="北京" → {"city": "北京"}

教训:模型的输出是"协议",解析器必须和 prompt 里约定的格式严丝合缝,差一点都跑不通。

最后

两件事并不冲突:完全可以把"检索知识库"包装成一个工具,放进 Agent 的工具箱------那时 RAG 就成了 Agent 的其中一只手,这也是现在很多落地系统的真实架构(Agent 负责决策,RAG 负责供料)。

下一步计划:给这个 Agent 加第三个工具,试试让它在更多工具里自己选择。


环境:Python 3.12 + DeepSeek(大脑)+ wttr.in(天气)+ Tavily(搜索),全文代码不足 100 行。

相关推荐
ZGi.ai1 小时前
知识库权限变了,怎样避免答错?
agent·权限管理·知识库·工作流·zgi·客服运营
大模型真好玩2 小时前
DeepSeek Harness 入门很简单(四)——DeepSeek Harness接入插件
人工智能·agent·deepseek
掰头战士2 小时前
MCP、Skill、Plugin,都是给agent拓展能力,到底有何区别?
typescript·llm·agent
嘟嘟嘟95273 小时前
AI Agent 的边缘困境
人工智能·架构·agent
HYDtomako3 小时前
Agent checkpoint设计
ai·agent·checkpoint·claude code
梦在远山后4 小时前
从需求到架构:我的企业研发 Agent 整体设计
langchain·agent
DigitalOcean4 小时前
Kimi K3 + Claude:AI Agent 多模型路由实战
llm·agent
掰头战士4 小时前
聊聊 Function Calling,你的模型是否答非所问?
前端·typescript·agent
十正5 小时前
把表变成模型够得着的句柄
人工智能·ai·agent