站点图标 Liao's blog

5 分钟跑通第一个智能体:从本地 Ollama + gemma4:31b 实战

项目demo地址下载

如果刚开始接触智能体,最容易卡住的地方通常不是“概念听不懂”,而是“看完原理还是不知道怎么自己跑起来”。这篇文章的目标很直接:结合 Datawhale《Hello Agents》第一章 1.3 小节“动手体验:5 分钟实现第一个智能体”的思路,分析我手上的这个 travel_agent_demo 项目,并给出一条适合本地环境的实践路径。

这份项目的价值在于,它没有上来就引入一堆框架,而是保留了 Agent 最核心的闭环:

如果你本地已经安装了 ollama,并且已经拉好了 gemma4:31b,那么这个项目基本就是一份很适合入门的最小可运行样例。

先看理论:1.3 小节到底讲了什么

Datawhale 在 1.3 小节里做了一件很重要的事:它没有先讲复杂框架,而是先带你手写一个最小智能体。这个例子的核心任务是:

先查询天气,再根据天气推荐景点。

这个任务看起来简单,但已经完整覆盖了一个 Agent 的基本能力:

这正是 Thought-Action-Observation 范式最适合演示的地方。Datawhale 1.3 小节把这个过程拆成了三部分:

  1. 定义系统提示词,约束模型输出 ThoughtAction
  2. 定义工具,例如天气查询和景点推荐
  3. 写一个循环,不断把历史上下文和工具观察结果喂给模型

它的重点不在“代码很多”,而在“闭环完整”。这一点,正好和当前这个项目完全对上。

参考链接: Datawhale 原文

这个项目和 1.3 小节是一一对应的

travel_agent_demo 的结构非常克制,只有 4 个核心文件:

如果按 1.3 小节的思路去看,它们的分工非常清晰。

1. config.py:把“提示词”显式写出来

Datawhale 1.3 的第一步是写 AGENT_SYSTEM_PROMPT,告诉模型:

这个项目同样把提示词放在了 config.py 里,并明确要求模型每次只能输出一组:

同时要求 Action 只能是两种形式:

这一步很关键。很多初学者以为“有模型就有 Agent”,其实不对。没有明确的动作协议,模型就无法稳定进入“可执行”的状态。

2. tools.py:把外部世界变成可调用能力

在 Agent 体系里,工具就是模型接触环境的“手”和“眼”。这个项目提供了 3 个工具:

它们背后的实现也非常直白:

这和 1.3 小节的设计是同一种思想:工具不用复杂,但要让模型真的“能做事”。

3. llm_client.py:对接 OpenAI 兼容接口

1.3 小节专门强调了一个现实问题:很多模型服务都走 OpenAI 兼容接口,所以最好封一个通用客户端。这个项目正是这么做的。

llm_client.py 里的 OpenAICompatibleClient 很轻量,核心只有一件事:把 system_promptuser prompt 发送给兼容 OpenAI Chat Completions 的接口。

这也是它能直接接入本地 Ollama 的原因。只要你的 Ollama 开了 OpenAI 兼容入口,配置好:

就可以把本地模型当成 Agent 的“大脑”。

4. agent.py:真正的 Agent 循环

整个项目最像 1.3 小节“原样落地”的部分,就是 agent.py

它做了几件非常典型的事:

  1. 接收用户输入
  2. 拼接历史上下文 prompt_history
  3. 调用大模型生成 Thought + Action
  4. 解析 Action
  5. 如果是工具调用,就执行对应 Python 函数
  6. 把结果写成 Observation
  7. 继续下一轮,直到遇到 Finish[...]

这就是一个标准的最小 Agent 闭环。

如果只用一句话概括这个项目,可以这么说:

它不是“把大模型接到 Python 上”,而是“让大模型在一个受控循环里学会决定何时调用工具”。

为什么这个项目适合写成“第一个智能体”

因为它刚好处在一个很好的平衡点上:

对于博客读者来说,这种项目有三个优点。

第一,代码量小,读者不会在框架封装里迷路。

第二,概念和实现能一一对应。你在书里看到的:

在项目代码里都能找到落点。

第三,容易迁移。你今天做的是旅行助手,明天就能改成:

用本地 Ollama 跑这个项目

你的环境已经具备一个关键前提:本地安装了 ollama,并且已经拉好了 gemma4:31b。这意味着 LLM 侧基本已经准备完成。

这个项目的 README 给出的配置思路如下:

pip install -r requirements.txt

然后准备 .env

TAVILY_API_KEY=你的key
LLM_API_KEY=ollama
LLM_BASE_URL=http://127.0.0.1:11434/v1
LLM_MODEL=gemma4:31b

注意一件事:项目当前 README 里示例地址写的是局域网 IP http://局域网IP:11434/v1。如果你就是在本机运行 Ollama,更常见也更稳妥的写法是:

LLM_BASE_URL=http://127.0.0.1:11434/v1

启动方式很简单:

python agent.py

然后输入类似:

帮我查询今天贵阳的天气,并推荐一个适合现在去的景点

运行前要知道的两个现实问题

这个项目能跑,不代表它已经“产品化”。如果你要写博客,最好把下面两点讲清楚。

1. 没有 TAVILY_API_KEY,景点推荐链路会失败

项目里 get_attraction() 实际上是复用 web_search() 完成的,而 web_search() 依赖 Tavily。

这意味着:

所以如果你想完整复现 Datawhale 1.3 里的“天气 -> 景点推荐 -> 最终总结”三步链路,最好提前准备 Tavily Key。

2. 大模型越大,多轮循环越容易变慢

项目作者已经意识到了这一点,所以在 agent.py 里做了一个很实用的小优化:对 Observation 做摘要截断,避免上下文越来越长。

这件事在本地模型场景下尤其重要。gemma4:31b 的效果会更稳,但如果机器资源一般,多轮推理的等待感会明显上升。博客里可以直接提醒读者:

从“能跑”到“像一个真正的智能体”,这个项目还差什么

如果把标准放在“第一个智能体”,这个项目已经合格。如果把标准放在“更像真实 Agent 系统”,它还可以继续往前走。

1. 记忆

当前 prompt_history 只保存本次会话中的历史,没有用户长期偏好。

如果要增强,可以增加:

这正好对应 Datawhale 习题里提到的“记住用户偏好”方向。

2. 反思与容错

目前如果工具失败,模型只能在错误信息上继续推理,但没有明确的重试策略和回退策略。

更稳一点的做法是增加:

3. 更强的动作协议

现在 parse_action() 通过正则解析参数,足够轻量,但对复杂参数不够稳。

如果后续想扩展更多工具,更建议演进成:

4. 更真实的旅游场景

当前的“景点推荐”本质上还是网页搜索摘要,离真正旅游助手还有距离。下一步可以扩展的能力包括:

从 Datawhale 1.3 小节到这个 travel_agent_demo,最大的体会是:第一个智能体不需要复杂,关键是先把闭环搭起来。只要模型能按照约定输出动作、程序能解析动作、工具能把外部信息带回来,一个真正意义上的 Agent 就已经出现了。

而当这个闭环跑在本地 Ollama + gemma4:31b 上时,学习体验会非常具体。你不再只是“理解概念”,而是真的看见模型如何决定先查天气、再查景点、最后合成答案。对初学者来说,这一步比额外学习十个框架更重要。

参考资料

退出移动版