📢gitzw.com上线了,功能陆续更新中,如有问题或反馈请在下方反馈/建议中给我们留言。

hello-agents 使用教程

📌 At a glance

本教程基于 Datawhale 社区开源项目《从零开始构建智能体》,系统讲解 AI Native 智能体的原理与实践。从基础概念到高级技术,涵盖经典范式、低代码平台、框架开发、记忆系统、上下文工程、通信协议、强化学习、性能评估及综合案例,帮助读者从 LLM 使用者成长为智能体构建者。

🎯 进阶📖 10 chapters⏱ ≈137 min read🔄 Updated 2026-06-30
Source:github.com/datawhalechina/hello-agents★ 61,259

1. 项目简介与适用人群

第一章:项目简介与适用人群

欢迎来到《从零开始构建智能体》!在正式开始动手之前,我们得先搞清楚两件事:这个项目到底是干什么的?它适合谁看? 就像你拿到一本新书,总得先看看目录和前言,才知道值不值得花时间读下去,对吧?

这一章的目标很简单——让你在 10 分钟内搞清楚:

  • 这个教程能帮你学到什么
  • 你需要具备什么基础
  • 学完之后你能做什么
  • 以及,为什么你应该选择这个教程而不是其他资料

前置条件

读这一章不需要任何技术基础。你只需要:

  • 对“智能体”或“AI Agent”这个概念有一点点好奇
  • 愿意花几分钟了解这个项目的全貌

如果你已经迫不及待想敲代码了,可以直接跳到下一章。但如果你还在犹豫“我该不该学这个”,那这一章就是为你准备的。


这个项目是什么?

先说说背景。2024 年大家都在比谁家的模型更大、更强,但到了 2025 年,风向变了——大家开始关心:怎么用这些模型做出真正有用的东西? 这就是“智能体”(Agent)的舞台。

但问题来了:市面上关于智能体的教程,要么太理论(讲概念但没法动手),要么太零散(教你用某个工具但不懂原理)。Hello-Agents 项目就是来填补这个空白的。

简单说,这是一个系统性、重实践的智能体学习教程,由 Datawhale 社区发起和维护。它的核心理念是:最好的学习方式就是动手实践。

你可能听说过两种构建智能体的方式:

  1. 软件工程:用 Dify、Coze、n8n 这类平台,本质是流程驱动的开发,LLM 只是后端的一个数据处理模块
  2. AI 原生派:真正以 AI 为核心驱动,智能体自己决定怎么做、用什么工具

这个教程聚焦的是后者——真正的 AI Native Agent。我们会带你穿透各种框架的表象,从核心原理出发,理解智能体到底是怎么工作的,然后亲手把它造出来。

你能学到什么?

读完整个教程,你会经历一个从“使用者”到“构建者”的蜕变。具体来说:

基础篇(第一到三章)

  • 理解智能体到底是什么——不只是“调用 API”,而是真正理解它的定义、类型和经典范式
  • 了解智能体从符号主义到 LLM 驱动的演进历史
  • 掌握大语言模型的基础知识:Transformer 架构、提示工程、主流模型及其局限

实战篇(第四到七章)

  • 手把手实现经典范式:ReAct(思考-行动-观察循环)、Plan-and-Solve(先规划再执行)、Reflection(自我反思)
  • 玩转低代码平台:了解 Coze、Dify、n8n 这些工具怎么用,快速搭建原型
  • 掌握主流框架:AutoGen、AgentScope、LangGraph 等框架的实际应用
  • 自研框架:基于 OpenAI 原生 API,从零构建你自己的智能体框架——这个项目叫 HelloAgents,是教程的配套框架

进阶篇(第八到十二章)

  • 记忆与检索:让智能体记住对话历史,实现 RAG(检索增强生成)
  • 上下文工程:处理长对话中的“情境理解”问题
  • 通信协议:MCP、A2A、ANP 等协议解析
  • Agentic-RL:从监督微调(SFT)到 GRPO 的全流程训练实战
  • 性能评估:如何衡量一个智能体好不好用

综合案例篇(第十三到十五章)

  • 智能旅行助手:MCP 与多智能体协作的真实应用
  • 自动化深度研究智能体:复现 DeepResearch Agent
  • 赛博小镇:Agent 与游戏的结合,模拟社会动态

毕业设计(第十六章)

  • 构建属于你自己的完整多智能体应用

除此之外,社区还贡献了面试题总结、Dify 保姆级教程、上下文工程补充知识等额外内容。

这个教程适合谁?

说实话,这个教程的门槛不高,但天花板不低。我们来拆解一下:

如果你是以下人群,这个教程非常适合你:

1. LLM 使用者想进阶 你已经会用 ChatGPT、调用 API 了,但想知道“怎么让模型自己干活,而不是每次都要我手写提示词”。这个教程会带你从“调 API”升级到“构建智能体”。

2. 学生/研究人员 你想系统学习智能体的原理,而不是零散地看博客。教程从基础到高级,层层递进,适合作为学习路线图。

3. 开发者想转型 AI 应用 你已经是程序员,但还没接触过 AI 应用开发。教程会带你从环境搭建开始,一步步构建完整的智能体应用。

4. 求职者准备面试 社区贡献了专门的面试题总结和答案,覆盖 Agent 岗位的常见问题。

你需要什么基础?

  • 编程基础:至少会 Python 基础语法(变量、函数、类)。如果你完全不会编程,建议先花一周学一下 Python 基础
  • 基本命令行操作:知道怎么打开终端、运行命令
  • 对 LLM 有基本了解:知道什么是提示词、什么是 API 调用。如果你完全没接触过,第三章会帮你补上

这个教程不适合谁?

  • 只想看概念不想动手:教程强调实践,每章都有代码和实验。如果你只想读理论,可能会觉得“太累”
  • 想找“一键部署”的解决方案:教程教的是原理和实现,不是给你一个开箱即用的产品
  • 完全零编程基础:虽然门槛不高,但完全不会编程的话,建议先学 Python 基础

为什么选择这个教程?

你可能在想:“网上那么多教程,为什么偏偏选这个?”

1. 完全免费,开源社区驱动 Datawhale 社区维护,所有内容免费开放。你不仅可以学,还可以贡献——提 issue、提 PR,甚至成为贡献者。

2. 系统性强,不是零散文章 很多教程只讲某个框架怎么用,但你不理解为什么。这个教程从原理到实践,从基础到高级,是一条完整的学习路径。

3. 重实践,有配套框架 教程配套的 HelloAgents 框架 让你从零开始构建自己的智能体,而不是只会用别人的工具。

4. 覆盖面试和求职 社区贡献了面试题总结,学完可以直接去面试 Agent 相关岗位。

如何开始学习?

你有两种方式阅读这个教程:

方式一:在线阅读(推荐)

直接打开浏览器就能看,不需要下载任何东西。

方式二:本地阅读

如果你想在本地阅读或贡献内容,可以参考下一章的安装指南。

常见问题

Q:这个教程需要 GPU 吗? A:大部分内容不需要。你只需要有 OpenAI API 或其他 LLM API 的访问权限。只有第十一章 Agentic-RL 涉及模型训练,才需要 GPU。

Q:教程里的代码能直接跑吗? A:可以。每章的代码都是可运行的,但你需要配置好 API Key 和环境。

Q:学完这个教程能找到工作吗? A:教程覆盖了 Agent 岗位的核心知识,配合社区贡献的面试题,能帮你准备面试。但找工作还需要项目经验和综合能力。

Q:教程会更新吗? A:会的。Datawhale 社区持续维护,你可以在 GitHub 上关注项目更新。


好了,现在你已经知道这个项目是干什么的了。如果你觉得这正是你需要的,那就继续往下走吧——下一章我们会教你如何安装环境、配置 API,为动手实践做好准备。

2. 安装与环境准备

好的,我们开始吧。

第 2 章:安装与环境准备

在开始动手构建智能体之前,我们得先把“工具箱”准备好。想象一下,你要开始做一顿大餐,总得先把锅碗瓢盆、食材调料都备齐了,对吧?这一章的目标就是帮你把电脑环境配置好,让你能顺利运行本书后续所有的代码示例和项目。我们会一起完成三件事:安装 Python、配置一个干净的虚拟环境、以及获取调用大语言模型(LLM)所需的 API 密钥。

前置条件:

  • 一台能正常上网的电脑(Windows、macOS 或 Linux 都可以)。
  • 基本的电脑操作能力,比如打开终端(命令行)、下载文件、解压缩。

第一步:安装 Python

本书的所有代码都基于 Python 3.9 或更高版本。如果你不确定电脑上有没有 Python,或者版本太低,我们先来检查一下。

  1. 打开终端(命令行)

    • Windows:按下 Win + R 键,输入 cmd,然后回车。
    • macOS / Linux:打开“终端”(Terminal)应用。
  2. 检查 Python 版本:在终端里输入以下命令,然后回车:

    python --version

    或者(在某些系统上):

    python3 --version

    预期结果:你会看到类似 Python 3.9.xPython 3.10.x 或更高版本的信息。

    如果遇到问题

    • 提示“python 不是内部或外部命令”:这说明你的电脑还没安装 Python。
    • 版本低于 3.9:比如显示 Python 2.7.xPython 3.8.x,我们需要升级。
  3. 安装或升级 Python

    • 访问 Python 官方网站:https://www.python.org/downloads/
    • 下载适合你操作系统的最新 Python 3.9+ 版本(比如 Python 3.12.x)。
    • 重要:在 Windows 安装时,务必勾选 “Add Python to PATH” 这个选项,否则你之后在命令行里可能找不到 python 命令。
    • 安装完成后,重新打开一个终端,再次运行 python --version 命令,确认安装成功。

第二步:创建虚拟环境

虚拟环境就像是一个独立的“小房间”,每个项目都有自己的房间,里面放着它需要的 Python 库。这样做的好处是,不同项目之间不会互相干扰。比如项目 A 需要 requests 库的 2.0 版本,项目 B 需要 3.0 版本,有了虚拟环境,它们就能和平共处。

我们使用 Python 自带的 venv 模块来创建虚拟环境。

  1. 选择一个目录:在你的电脑上找一个合适的位置,创建一个新文件夹,比如就叫 hello-agents。这个文件夹将用来存放本书的所有代码。

  2. 打开终端并进入该目录

    cd 你的路径/hello-agents

    比如,如果你在桌面上创建了这个文件夹,在 macOS/Linux 上可能是 cd ~/Desktop/hello-agents,在 Windows 上可能是 cd C:\Users\你的用户名\Desktop\hello-agents

  3. 创建虚拟环境:在终端里运行以下命令:

    python -m venv venv
    • 第一个 venv 是 Python 的模块名。
    • 第二个 venv 是你想给这个虚拟环境起的名字,通常就叫 venv,方便记忆。

    预期结果:命令执行后,你的 hello-agents 文件夹里会多出一个名为 venv 的子文件夹,里面就是独立的 Python 环境。

  4. 激活虚拟环境

    • Windows
      .\venv\Scripts\activate
    • macOS / Linux
      source venv/bin/activate

    预期结果:激活后,你会看到终端命令行的最前面多了一个 (venv) 的提示,像这样:

    (venv) C:\Users\你的用户名\Desktop\hello-agents>

    或者

    (venv) yourname@yourcomputer hello-agents %

    看到 (venv) 就说明你已经成功进入虚拟环境了。之后你安装的所有 Python 库,都会被装在这个“小房间”里。

第三步:安装项目依赖

本书的代码依赖一些第三方库,比如 openai(用来调用 OpenAI 兼容的 API)、requests(用来发送网络请求)等。我们先把最核心的几个装上。

  1. 确保虚拟环境已激活:确认你的终端前面有 (venv) 标志。

  2. 安装核心库:在终端里运行:

    pip install openai requests

    预期结果:你会看到类似 Successfully installed openai-1.x.x requests-2.x.x 的信息。这表示安装成功。

    如果遇到问题

    • 下载速度慢:可以尝试使用国内的镜像源,比如清华源。在命令后面加上 -i https://pypi.tuna.tsinghua.edu.cn/simple
      pip install openai requests -i https://pypi.tuna.tsinghua.edu.cn/simple

第四步:获取 API 密钥

智能体的“大脑”是大语言模型(LLM),比如 GPT-4、Claude、或者国内的通义千问、DeepSeek 等。要让我们的代码能调用这些模型,需要先获取一个 API 密钥(API Key),它就像一把钥匙,证明你有权限使用这个服务。

本书的示例主要基于 OpenAI 的 API 格式,因为很多国产模型也兼容这种格式,所以非常通用。

方案一:使用 OpenAI 官方 API(需要海外支付方式)

  1. 访问 OpenAI API 官网
  2. 注册或登录账号。
  3. 进入 API Keys 页面,点击 “Create new secret key”。
  4. 复制生成的密钥(以 sk- 开头)。注意:关闭页面后,你就再也看不到这个密钥了,所以一定要先保存好。

方案二:使用国内兼容的 API(推荐初学者)

国内很多大模型厂商也提供兼容 OpenAI 格式的 API,而且通常有免费额度,对新手非常友好。这里以 DeepSeek 为例(因为它速度快、价格便宜、且兼容性好):

  1. 访问 DeepSeek 开放平台
  2. 注册账号并登录。
  3. 在左侧菜单找到 “API Keys”,点击 “创建 API Key”。
  4. 给你的密钥起个名字(比如 hello-agents),然后创建并复制它。

方案三:使用 Datawhale 社区提供的免费 API(如果可用)

在本书的学习过程中,Datawhale 社区有时会提供临时的免费 API 供大家练习。请关注本书的配套社群或项目公告,获取相关信息。

第五步:配置环境变量

把 API 密钥直接写在代码里是非常不安全的,万一不小心把代码传到 GitHub 上,别人就能用你的密钥了。正确的做法是把它存在环境变量里。

  1. 在项目根目录创建 .env 文件:在 hello-agents 文件夹下,创建一个名为 .env 的文件(注意文件名前面有一个点)。

  2. 编辑 .env 文件:用记事本或任何文本编辑器打开它,写入以下内容(如果你用的是 DeepSeek,就填 DeepSeek 的密钥和地址):

    # 你的 API 密钥
    OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    # API 的基础地址(如果是 OpenAI 官方,这行可以不加或注释掉)
    OPENAI_BASE_URL="https://api.deepseek.com"
    • 注意OPENAI_API_KEY 这个变量名是通用的,很多库都默认读取它。OPENAI_BASE_URL 用来指定非 OpenAI 官方的服务地址。如果你用的是 OpenAI 官方,可以不加这一行。
  3. 安装 python-dotenv:这个库能帮我们自动读取 .env 文件里的配置。在终端(确保虚拟环境已激活)运行:

    pip install python-dotenv

第六步:验证环境

现在,我们来写一小段代码,验证整个环境是否配置成功。

  1. hello-agents 文件夹下,创建一个新文件,命名为 test_env.py

  2. 用文本编辑器打开它,写入以下代码:

    import os
    from dotenv import load_dotenv
    from openai import OpenAI
    
    # 1. 加载 .env 文件中的环境变量
    load_dotenv()
    
    # 2. 从环境变量中读取 API 密钥和基础地址
    api_key = os.getenv("OPENAI_API_KEY")
    base_url = os.getenv("OPENAI_BASE_URL")
    
    # 3. 检查密钥是否读取成功
    if not api_key:
        raise ValueError("请先在 .env 文件中设置 OPENAI_API_KEY")
    
    # 4. 创建 OpenAI 客户端
    #    如果 base_url 为空(即没有设置),则默认使用 OpenAI 官方地址
    client = OpenAI(api_key=api_key, base_url=base_url)
    
    # 5. 发送一个简单的请求,测试连接
    try:
        response = client.chat.completions.create(
            model="deepseek-chat",  # 如果你用 OpenAI,可以改成 "gpt-3.5-turbo"
            messages=[
                {"role": "user", "content": "你好,请用一句话介绍你自己。"}
            ]
        )
        print("模型回复:", response.choices[0].message.content)
        print("\n✅ 环境配置成功!一切准备就绪。")
    except Exception as e:
        print(f"❌ 请求失败,请检查你的 API 密钥和网络连接。")
        print(f"错误信息:{e}")
  3. 运行测试脚本:在终端(确保在 hello-agents 目录下,且虚拟环境已激活)运行:

    python test_env.py

    预期结果:如果一切顺利,你会看到类似下面的输出:

    模型回复: 你好!我是 DeepSeek,一个由深度求索公司开发的 AI 助手。我擅长回答问题、提供信息和协助解决问题。有什么我可以帮你的吗?
    
    ✅ 环境配置成功!一切准备就绪。

    如果遇到问题

    • openai.NotFoundError 或类似错误:通常是因为 model 名字填错了,或者 base_url 不对。请检查你的 .env 文件和代码中的模型名。
    • openai.AuthenticationError:说明 API 密钥无效或已过期。请重新检查并复制你的密钥。
    • 网络连接错误:如果你在国内使用 OpenAI 官方 API,可能需要特殊的网络环境。建议先使用 DeepSeek 等国内服务。

小结

到这里,你已经完成了所有准备工作。回顾一下,你做到了:

  1. 安装了 Python 3.9+,为运行代码提供了基础环境。
  2. 创建并激活了虚拟环境,让项目依赖互不干扰。
  3. 安装了 openairequestspython-dotenv 等核心库。
  4. 获取了 API 密钥,拿到了调用大模型的门票。
  5. 配置了环境变量,安全地存储了敏感信息。
  6. 运行了测试脚本,成功让代码和“智能体的大脑”对话了。

现在,你的电脑已经是一个合格的“智能体开发工作站”了。在下一章,我们将正式开始学习如何构建一个最简单的智能体,让它能根据你的指令去思考和行动。准备好了吗?我们出发!

3. 快速上手:在线阅读与本地部署

在线阅读与本地部署

本章的目标很简单:让你在 5 分钟内就能开始阅读《从零开始构建智能体》的全部内容。我们会先走通最省事的在线阅读,再搞定本地部署——后者在你需要离线阅读或修改文档时很有用。

前置条件

  • 一台能联网的电脑(在线阅读不需要任何安装)
  • 本地部署需要安装 GitPython 3.8+

在线阅读(零安装)

项目提供了两个访问入口,选一个就行:

打开浏览器输入上面任意一个地址,你会看到完整的教程页面。左侧是目录树,点击章节标题就能跳转。所有内容都是实时更新的,不需要下载任何东西。

预期结果:浏览器显示教程首页,左侧有完整的章节列表(前言、第一章到第十六章、社区精选等)。

本地部署(离线阅读 + 可修改)

如果你想把整个教程拉到本地,方便离线看或者自己改内容,按下面几步来。

第一步:克隆仓库

打开终端,执行:

git clone https://github.com/datawhalechina/hello-agents.git
cd hello-agents

预期结果:当前目录下多了一个 hello-agents 文件夹,里面包含 docs/README.md 等文件。

常见问题

  • 如果提示 git: command not found,说明你没装 Git。去 git-scm.com 下载安装,或者用 GitHub Desktop 这类图形工具。
  • 网络慢的话,可以试试国内镜像:git clone https://gitee.com/datawhalechina/hello-agents.git

第二步:安装依赖

教程文档是用 MkDocs 构建的,我们需要安装它和推荐的主题:

pip install mkdocs mkdocs-material

预期结果:命令执行完毕,没有报错。可以用 pip list | grep mkdocs 确认安装成功。

常见问题

  • 如果提示 pip: command not found,检查 Python 是否安装,或者用 python -m pip install ... 代替。
  • 建议在虚拟环境里安装,避免污染全局 Python。如果你不熟悉虚拟环境,直接装也行,不影响使用。

第三步:启动本地服务器

在项目根目录(就是 hello-agents 文件夹里)运行:

mkdocs serve

预期结果:终端输出类似 INFO - Building documentation... INFO - Serving on http://127.0.0.1:8000信息。打开浏览器访问 http://127.0.0.1:8000,你会看到和在线阅读一模一样的页面。

实用技巧

  • mkdocs serve 支持热重载——你修改了 docs/ 下的 Markdown 文件,浏览器会自动刷新,不用手动重启。
  • Ctrl+C 可以停止服务器。

常见报错

  • Error: The 'material' theme is not installed:你跳过了第二步,或者安装时网络断了。重新执行 pip install mkdocs-material
  • Address already in use:8000 端口被占用了。换个端口:mkdocs serve -a 0.0.0.0:8080

一个小例子串起来

假设你正在通勤路上,手机信号不好,想离线看第四章的 ReAct 范式。你可以:

  1. 提前在家用 git clone 把仓库拉到电脑上。
  2. 运行 mkdocs serve 启动本地服务器。
  3. 用浏览器打开 http://127.0.0.1:8000,找到第四章开始阅读。
  4. 看到一半想记笔记,直接在 docs/chapter4/第四章 智能体经典范式构建.md 里加注释,浏览器会自动刷新显示修改后的内容。

注意事项

  • 在线阅读的两个地址内容完全一致,选网速快的那个就行。
  • 本地部署后,docs/ 目录下的 Markdown 文件就是教程原文。你可以用任何文本编辑器打开、修改,甚至提交 PR 贡献内容。
  • 如果你只想读不想改,在线阅读是最省事的方案,没必要折腾本地部署。

4. 第一部分:智能体与语言模型基础(概念、历史、LLM 基础)

第一部分:智能体与语言模型基础

在动手搭建智能体之前,我们需要先搞清楚三个问题:智能体到底是什么?它从哪来?以及驱动它的语言模型是怎么工作的?这一章就是回答这三个问题,帮你建立必要的知识地基。跳过这部分直接写代码,你可能会在后续遇到"为什么我的智能体不按预期行动"这类困惑。

前置条件

  • 已安装 Python 3.8+(后续章节会用到,本章仅需理解概念)
  • 对 AI 有基本认知(知道 ChatGPT 是什么就行)
  • 准备好一个浏览器,用于查阅资料

1. 智能体的定义与核心特征

我们先给"智能体"一个精确的定义。在 AI 领域,智能体(Agent)是指能够感知环境、做出决策并采取行动以实现目标的系统

这个定义包含三个核心要素:

  • 感知:获取环境信息(比如用户输入、传感器数据)
  • 决策:基于感知信息选择下一步行动
  • 行动:执行决策,改变环境状态

一个简单的例子:你问 ChatGPT"今天天气怎么样",它回答了你。这算智能体吗?严格来说不算——因为它只做了一次"感知-决策-行动"循环,没有持续的目标导向行为。

真正的智能体应该是这样的:你让它"帮我规划下周去北京的行程",它先查天气、再查航班、然后订酒店、最后生成行程表——每一步都基于上一步的结果调整下一步行动。

2. 智能体的类型

根据能力复杂度,智能体可以分为四个层次:

类型 特点 例子
反应式 只对当前输入做出反应,无记忆 简单的聊天机器人
基于模型 维护内部状态,能推理 带上下文的对话系统
目标驱动 有明确目标,能规划路径 旅行规划助手
效用驱动 在多个目标间权衡最优解 资源调度系统

目前我们讨论的 LLM 智能体,大多属于目标驱动效用驱动类型。

3. 智能体的经典范式

智能体如何工作?学术界总结了几种经典范式,这里先了解概念,后续章节会手把手实现:

ReAct(Reasoning + Acting) 最常用的范式。智能体先"思考"(推理当前状态),再"行动"(调用工具或回答问题),然后观察结果,继续思考。就像你解数学题:先想用什么公式,再计算,看结果对不对,不对就换方法。

Plan-and-Solve 先制定完整计划,再逐步执行。适合复杂任务,比如"写一篇论文":先规划大纲,再写每个章节。

Reflection 执行后自我反思,改进结果。比如写完代码后,自己检查一遍再提交。

4. 智能体发展简史

了解历史不是为了考试,而是理解为什么今天 LLM 智能体这么火。

1950s-1980s:符号主义时代 智能体基于规则和逻辑推理。代表:Newell 和 Simon 的"通用问题求解器"。问题:规则写不完,遇到新情况就崩。

1990s-2010s:行为主义时代 智能体通过与环境交互学习。代表:强化学习、机器人控制。问题:训练成本高,泛化能力弱。

2020s 至今:LLM 驱动时代 大语言模型让智能体"开窍"了。原因很简单:LLM 能理解自然语言、有常识推理能力、能调用工具。这三点恰好解决了前两个时代的痛点。

5. 大语言模型基础

5.1 Transformer 架构(一句话版)

LLM 的核心是 Transformer,它做了一件事:让模型知道句子中每个词和其他词的关系

比如"他吃了苹果,因为__很饿",Transformer 能算出"他"和"很饿"的关联,从而推断空白处填"他"。

5.2 提示工程(Prompt Engineering)

提示是人和 LLM 沟通的接口。写好提示,智能体才能正确执行任务。

基本原则

  • 明确角色:告诉模型它是谁
  • 明确任务:告诉模型要做什么
  • 明确格式:告诉模型怎么输出
# 好的提示
你是一个旅行规划助手。用户想去北京玩3天,预算5000元。
请生成一个包含景点、交通、住宿的行程表,用Markdown表格输出。

# 差的提示
帮我规划北京旅游。

5.3 主流 LLM 对比

模型 特点 适用场景
GPT-4 综合能力强,支持工具调用 通用智能体
Claude 3 长上下文,安全性好 文档分析、代码生成
Gemini 多模态能力强 图片/视频理解
开源模型(Llama 3, Qwen 2) 可本地部署,可微调 隐私敏感场景

5.4 LLM 的局限性

了解局限比了解能力更重要,因为智能体的很多坑都来自这里:

  • 幻觉:模型会编造事实。解决方案:加入验证机制
  • 上下文窗口:模型能记住的信息有限。解决方案:记忆系统(后续章节)
  • 推理不稳定:同样的输入可能得到不同输出。解决方案:多次采样取多数
  • 工具调用错误:模型可能传错参数。解决方案:参数校验

6. 一个小例子串起来

假设你要做一个"智能客服助手",它需要:

  1. 理解用户问题(感知)
  2. 决定是直接回答还是查知识库(决策)
  3. 执行相应操作(行动)

这个智能体需要:

  • LLM 来理解自然语言(第三章内容)
  • ReAct 范式来循环推理(第四章内容)
  • 记忆系统来记住对话历史(第八章内容)

你现在已经知道它为什么需要这些组件,以及它们各自解决什么问题。

常见坑位与排查

坑1:把 LLM 当成万能的 LLM 不是神,它不知道实时信息、不会精确计算、不能保证事实准确。智能体需要工具来弥补这些短板。

坑2:忽略提示的重要性 同样的 LLM,提示写得好和写得差,效果天差地别。花时间打磨提示,比换模型更有效。

坑3:不理解"智能体"和"聊天机器人"的区别 聊天机器人只做一次问答。智能体有目标、有规划、有循环。如果你只是调 API 问问题,那还不是智能体。

下一步

概念讲完了,接下来我们会进入第二部分:动手实现这些范式。你会看到 ReAct 到底怎么写代码,低代码平台怎么用,以及怎么从零搭建自己的智能体框架。

5. 第二部分:构建你的大语言模型智能体(经典范式、低代码平台、框架开发、自研框架)

第二部分:构建你的大语言模型智能体

这一章是整本书的核心动手环节。前面你理解了智能体是什么、LLM 怎么工作,现在我们要亲手把它造出来。我们会走四条路:先手撸经典范式(ReAct、Plan-and-Solve、Reflection),再体验低代码平台(Coze、Dify、n8n),接着用主流框架(AutoGen、AgentScope、LangGraph)开发,最后从零自研一个框架。每一条路都对应不同的场景——从理解原理到快速落地,再到深度定制。

前置条件:已完成第二章的环境准备(Python 3.10+、OpenAI API Key 或兼容接口、必要的 pip 包)。如果你还没装好,先回去搞定。


4.1 手撸经典范式:ReAct、Plan-and-Solve、Reflection

为什么要手写?框架封装了太多细节,你很难理解智能体到底在"思考"什么。手写一遍,你就能看清每一步:LLM 输出什么、我们怎么解析、怎么决定下一步。

4.1.1 ReAct:思考-行动-观察循环

ReAct 的核心是让 LLM 交替输出"思考"和"行动",然后我们根据行动结果提供"观察",再让 LLM 继续思考。这是最基础的 Agent 模式。

先写一个最小可运行的 ReAct 循环:

import json
from openai import OpenAI

client = OpenAI()  # 确保环境变量 OPENAI_API_KEY 已设置

def call_llm(messages):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        temperature=0
    )
    return response.choices[0].message.content

def search_tool(query):
    # 模拟一个搜索工具,实际可替换为真实 API
    knowledge = {
        "北京人口": "约 2188 万(2023年)",
        "上海人口": "约 2475 万(2023年)"
    }
    return knowledge.get(query, f"未找到关于「{query}」的信息")

# ReAct 系统提示词
system_prompt = """你是一个智能助手,可以通过思考、行动、观察来回答问题。
请按以下格式输出:
思考:你的推理过程
行动:工具名称(参数)
观察:工具返回的结果
...(可重复多轮)
思考:最终结论
答案:你的最终回答

可用工具:
- search_tool(query): 搜索信息"""

messages = [
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": "北京和上海哪个城市人口更多?"}
]

max_steps = 5
for step in range(max_steps):
    response = call_llm(messages)
    print(f"\n=== 第 {step+1} 轮 ===")
    print(response)
    
    if "答案:" in response:
        break
    
    # 解析行动
    if "行动:" in response:
        action_line = [l for l in response.split("\n") if "行动:" in l][0]
        action = action_line.replace("行动:", "").strip()
        # 简单解析:search_tool(北京人口)
        tool_name = action.split("(")[0]
        arg = action.split("(")[1].rstrip(")")
        
        if tool_name == "search_tool":
            result = search_tool(arg)
            messages.append({"role": "user", "content": f"观察:{result}"})

预期结果:你会看到 LLM 先思考需要查人口数据,然后调用 search_tool,拿到结果后比较,最终给出答案。

常见坑

  • LLM 输出格式不稳定:有时不写"行动:"直接写"Action:"。可以在 system prompt 里强调格式,或者用 few-shot 示例。
  • 解析失败:如果 action_line 不存在,程序会报错。加个 try/except 或默认重试。

4.1.2 Plan-and-Solve:先计划再执行

ReAct 是一边想一边做,Plan-and-Solve 则是先制定完整计划,再逐步执行。适合复杂任务。

plan_prompt = """你是一个计划制定者。对于用户的问题,请先制定一个详细的执行计划。
计划格式:
步骤1: 描述
步骤2: 描述
...

然后按计划执行,每步输出:
执行步骤1: 具体操作
观察:结果"""

messages = [
    {"role": "system", "content": plan_prompt},
    {"role": "user", "content": "帮我比较北京和上海的人口、面积、GDP"}
]

# 第一轮:生成计划
response = call_llm(messages)
print("计划:", response)

# 解析步骤并执行(简化版)
steps = [l for l in response.split("\n") if l.startswith("步骤")]
for step_desc in steps:
    # 这里实际需要更复杂的解析,示例略
    print(f"执行:{step_desc}")

4.1.3 Reflection:自我反思修正

Reflection 让 Agent 在得到结果后,自己检查是否正确,必要时修正。

reflection_prompt = """你是一个智能体。完成任务后,请反思你的答案:
1. 答案是否完整?
2. 是否有遗漏信息?
3. 是否需要补充?

如果答案有问题,请输出「需要修正:」并给出修正后的答案。
如果答案正确,请输出「答案正确」。"""

# 在 ReAct 循环结束后,追加反思
messages.append({"role": "user", "content": reflection_prompt})
reflection = call_llm(messages)
print("反思结果:", reflection)

4.2 低代码平台:Coze、Dify、n8n

手写代码理解原理,但实际项目中你可能想快速搭建。低代码平台就是干这个的。

4.2.1 Coze(字节跳动)

Coze 是面向消费者的 Agent 搭建平台,拖拽式操作,内置插件商店。

快速上手

  1. 访问 coze.cn,注册账号
  2. 点击「创建 Bot」
  3. 在「人设与回复」里写系统提示词
  4. 在「技能」里添加插件(搜索、计算器等)
  5. 点击「发布」即可获得 API 或分享链接

最佳实践

  • 提示词要写清楚角色和限制,比如「你是一个旅行助手,只回答旅行相关问题」
  • 插件不要加太多,3-5 个足够,否则 LLM 选择困难
  • 用「知识库」上传文档,让 Agent 能回答私有数据

4.2.2 Dify(开源)

Dify 是开源的低代码平台,可以自部署。

本地部署(Docker 方式):

git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
docker compose up -d

访问 http://localhost:3000,注册后创建应用。

关键区别:Dify 支持工作流编排,你可以把多个 LLM 调用串起来,比如先分类再回答。

4.2.3 n8n(自动化工作流)

n8n 不是专门的 Agent 平台,但可以用它编排 LLM 和外部工具。

最小示例:创建一个工作流,接收 Webhook 请求 -> 调用 OpenAI -> 发送邮件。

适用场景:需要把 Agent 集成到现有业务系统(CRM、ERP)时,n8n 比 Coze/Dify 更灵活。


4.3 框架开发:AutoGen、AgentScope、LangGraph

当低代码平台不够灵活,手写又太繁琐时,框架是折中方案。

4.3.1 AutoGen(微软)

AutoGen 的核心是多 Agent 对话。你定义多个 Agent,它们互相聊天完成任务。

pip install pyautogen
import autogen

# 定义两个 Agent
assistant = autogen.AssistantAgent(
    name="assistant",
    llm_config={"config_list": [{"model": "gpt-4o-mini", "api_key": "..."}]}
)

user_proxy = autogen.UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    code_execution_config={"work_dir": "coding"}
)

# 开始对话
user_proxy.initiate_chat(
    assistant,
    message="写一个 Python 脚本,计算斐波那契数列前 20 项"
)

预期结果:Assistant 会生成代码,UserProxy 自动执行并返回结果,Assistant 再根据结果调整。

常见坑

  • 代码执行默认在本地,注意安全(不要执行 rm -rf /)
  • 如果 Agent 陷入死循环,设置 max_consecutive_auto_reply=3

4.3.2 AgentScope(阿里)

AgentScope 强调分布式和多模态,适合需要视觉、语音的 Agent。

pip install agentscope
import agentscope
from agentscope.agents import DialogAgent

agentscope.init(model_configs={
    "config_name": "my_gpt",
    "model_type": "openai",
    "model_name": "gpt-4o-mini"
})

agent = DialogAgent(
    name="assistant",
    model_config_name="my_gpt",
    sys_prompt="你是一个有帮助的助手。"
)

response = agent("今天天气怎么样?")
print(response)

4.3.3 LangGraph(LangChain)

LangGraph 让你用图结构定义 Agent 流程,节点是 LLM 调用或工具,边是条件跳转。

pip install langgraph langchain-openai
from langgraph.graph import StateGraph, END
from typing import TypedDict, List

class AgentState(TypedDict):
    messages: List

def call_model(state):
    # 调用 LLM
    return {"messages": [llm_response]}

def should_continue(state):
    if "需要工具" in state["messages"][-1]:
        return "tool"
    return END

graph = StateGraph(AgentState)
graph.add_node("agent", call_model)
graph.add_node("tool", call_tool)
graph.add_conditional_edges("agent", should_continue)
graph.set_entry_point("agent")

app = graph.compile()

LangGraph 的优势:你可以精确控制流程,比如「如果 LLM 输出包含代码,先执行再返回结果」。


4.4 自研框架:HelloAgents

前面三种方式各有局限:手写太原始、低代码不够灵活、框架太重。自研框架让你完全掌控。

4.4.1 核心设计

一个最小 Agent 框架只需要三个组件:

  1. LLM 接口:封装 API 调用
  2. 工具注册:让 Agent 知道能用什么工具
  3. 循环引擎:决定何时思考、何时行动、何时结束
# helloagents/core.py
from openai import OpenAI
import json

class Agent:
    def __init__(self, model="gpt-4o-mini"):
        self.client = OpenAI()
        self.model = model
        self.tools = {}
        self.messages = []
    
    def register_tool(self, name, func, description):
        self.tools[name] = {"func": func, "description": description}
    
    def run(self, user_input, max_steps=10):
        self.messages.append({"role": "user", "content": user_input})
        
        for step in range(max_steps):
            response = self.client.chat.completions.create(
                model=self.model,
                messages=self.messages,
                tools=self._build_tool_schema(),
                tool_choice="auto"
            )
            
            msg = response.choices[0].message
            
            if msg.tool_calls:
                for tool_call in msg.tool_calls:
                    func_name = tool_call.function.name
                    args = json.loads(tool_call.function.arguments)
                    result = self.tools[func_name]["func"](**args)
                    self.messages.append({
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": str(result)
                    })
            else:
                return msg.content
        
        return "达到最大步数"
    
    def _build_tool_schema(self):
        return [
            {
                "type": "function",
                "function": {
                    "name": name,
                    "description": info["description"],
                    "parameters": {"type": "object", "properties": {}}
                }
            }
            for name, info in self.tools.items()
        ]

4.4.2 使用示例

from helloagents import Agent

agent = Agent()

def get_weather(city):
    return f"{city} 天气:晴,25°C"

agent.register_tool("get_weather", get_weather, "查询城市天气")

result = agent.run("北京今天天气怎么样?")
print(result)

预期结果:Agent 会调用 get_weather 工具,拿到结果后组织成自然语言回答。

4.4.3 扩展方向

  • 添加记忆系统(保存历史对话)
  • 支持多 Agent 协作(Agent 之间互相调用)
  • 加入错误重试机制

实战串联:做一个旅行规划 Agent

把上面学到的串起来。我们用自研框架,结合 ReAct 范式,做一个能查天气、查航班、推荐景点的旅行助手。

# travel_agent.py
from helloagents import Agent
import datetime

agent = Agent()

def get_weather(city, date=None):
    # 模拟天气 API
    return f"{city} {date or '今天'} 天气:晴,22-28°C"

def search_flights(from_city, to_city, date):
    return f"找到航班:{from_city}->{to_city}{date},价格 ¥800"

def recommend_attractions(city):
    return f"{city} 推荐景点:故宫、长城、颐和园"

agent.register_tool("get_weather", get_weather, "查询城市天气")
agent.register_tool("search_flights", search_flights, "搜索航班")
agent.register_tool("recommend_attractions", recommend_attractions, "推荐景点")

result = agent.run("帮我规划一个北京三日游,包括天气、航班和景点")
print(result)

6. 第三部分:高级知识扩展(记忆与检索、上下文工程、通信协议、Agentic-RL、性能评估)

好的,我们开始吧。

从“能用”到“好用”:为什么需要高级知识扩展?

在上一部分,你已经亲手搭建了自己的智能体框架,让它能调用工具、执行计划,甚至进行简单的反思。恭喜你,你已经迈过了“从无到有”的门槛。但你可能也发现了,这个智能体有点“健忘”——你跟它聊了几句,它就忘了你一开始提的要求;它有时会“断章取义”——只盯着你最后一句话,忽略了整个对话的上下文;它还很“孤独”——只能跟你单聊,没法跟其他智能体协作

这一章,我们就要解决这些问题。我们会一起给智能体装上“记忆”、拓宽它的“视野”、教会它“社交”,甚至让它学会“自我进化”和“自我评估”。这些高级知识,正是把一个“能用”的智能体,打磨成“好用”、“可靠”的智能体的关键。

前置条件:你已经完成了第七章,拥有一个自己编写的、能运行的基础智能体框架(比如 HelloAgent)。你熟悉 Python 和基本的 API 调用。

第八章:记忆与检索——让智能体不再“金鱼脑”

你有没有跟 ChatGPT 聊着聊着,发现它忘了你一开始说的“我叫小明”?这就是因为它没有长期记忆。我们的智能体也一样。默认情况下,每次对话都是“全新”的。要让智能体记住关键信息,我们需要给它装上“记忆系统”。

8.1 记忆的三种形态

智能体的记忆,可以粗略分为三种:

  1. 短期记忆:就像你手里的便签纸,记下当前对话的内容。通常就是对话历史(messages 列表)。
  2. 长期记忆:像你的日记本,记录重要的、需要跨会话保留的信息。比如用户的偏好、关键事实。
  3. 工作记忆:像你的工作台,临时存放当前任务需要的数据。比如工具调用的结果。

我们重点实现长期记忆,因为这是让智能体“成长”的关键。

8.2 动手实现:一个简单的“事实提取”记忆系统

我们不搞复杂的数据库,先用一个最直观的方法:让智能体在每次对话结束时,自己总结出需要记住的“事实”,然后存到一个文件里。下次对话开始时,再把这些事实读出来,塞进系统提示词里。

第一步:编写记忆存储函数

在你的 HelloAgent 框架里,新建一个 memory.py 文件。

# memory.py
import json
import os

MEMORY_FILE = "agent_memory.json"

def load_memory():
    """从文件加载长期记忆"""
    if os.path.exists(MEMORY_FILE):
        with open(MEMORY_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    return []

def save_memory(memory_list):
    """将长期记忆列表保存到文件"""
    with open(MEMORY_FILE, "w", encoding="utf-8") as f:
        json.dump(memory_list, f, ensure_ascii=False, indent=2)

第二步:让智能体学会“记笔记”

在智能体处理完一轮对话后,我们额外调用一次 LLM,让它从本轮对话中提取出需要长期记住的事实。

# 在你的 agent.py 中,修改 run 方法
def run(self, user_input):
    # ... 之前的对话逻辑 ...
    
    # 假设 self.messages 已经包含了本轮对话
    # 1. 构造一个“记忆提取”提示
    extract_prompt = {
        "role": "system",
        "content": (
            "请从以下对话中提取出需要长期记住的关键事实。"
            "例如:用户的姓名、偏好、重要日期、项目进展等。"
            "如果没有任何需要记住的信息,请返回一个空列表 []。"
            "请只返回 JSON 格式的列表,例如:[\"用户名叫小明\", \"用户喜欢喝咖啡\"]"
        )
    }
    
    # 2. 调用 LLM 进行提取(复用你的 llm 调用函数)
    extraction_messages = [extract_prompt] + self.messages[-4:]  # 只看最近几轮
    facts_json = self.call_llm(extraction_messages)
    
    # 3. 解析结果并合并到长期记忆
    try:
        new_facts = json.loads(facts_json)
        if isinstance(new_facts, list):
            existing_memory = load_memory()
            # 简单去重(更复杂的可以用语义相似度)
            for fact in new_facts:
                if fact not in existing_memory:
                    existing_memory.append(fact)
            save_memory(existing_memory)
            print(f"[记忆] 新记住: {new_facts}")
    except json.JSONDecodeError:
        print("[记忆] 提取失败,LLM 返回格式不对")

第三步:让智能体学会“回忆”

在每次对话开始时,把长期记忆注入到系统提示词里。

# 在 agent 初始化或每次 run 开始时
def _build_system_prompt(self):
    base_prompt = "你是一个有用的助手。"
    memory = load_memory()
    if memory:
        memory_str = "\n".join([f"- {fact}" for fact in memory])
        base_prompt += f"\n\n## 你记得的关于用户的信息:\n{memory_str}"
    return {"role": "system", "content": base_prompt}

预期结果:现在,你跟智能体说“我叫小明,我喜欢喝冰美式”。它会在本轮回答后,默默记下这两条事实。下次你再启动对话,它就会在系统提示词里看到这些信息,并主动说:“小明你好,今天还要来一杯冰美式吗?”

常见问题

  • 记忆膨胀:如果每次对话都提取,记忆文件会越来越大。解决办法:限制记忆条数(比如最多50条),或者让 LLM 定期“总结”和“遗忘”旧记忆。
  • 格式错误:LLM 返回的 JSON 可能不标准。可以用 try-except 捕获,或者用更宽松的解析方式(比如用正则表达式提取 [...] 部分)。

8.3 进阶:RAG(检索增强生成)

上面的方法只能存“事实”,但存不了“文档”。如果你的智能体需要参考一本手册、一堆论文,就需要 RAG。

RAG 的核心流程是:用户提问 -> 将问题转为向量 -> 在知识库中搜索最相似的文本块 -> 把搜索到的文本块作为上下文,连同问题一起发给 LLM

你可以用 chromadbfaiss 这样的向量数据库。这里不展开,但你可以把 RAG 看作是“记忆”的一种更强大的形式——它让智能体拥有了“查阅资料”的能力。

小结:现在,你的智能体有了“记性”。它不再是一个每次见面都像陌生人的聊天机器人,而是一个能记住你、了解你的伙伴。

第九章:上下文工程——让智能体“看懂”全局

有了记忆,智能体记住了“你是谁”。但在一段很长的对话里,它还是会“迷失”。比如你聊了10分钟A项目,突然问“那个截止日期是什么?”,它可能还在想A项目,但你说的其实是B项目。这就是上下文理解的问题。

上下文工程,就是一系列主动管理对话上下文的技术,确保 LLM 始终“知道”当前在聊什么、目标是什么、已经完成了什么。

9.1 核心问题:窗口有限,信息无限

LLM 的上下文窗口是有限的(比如 128K tokens)。你不能把整个对话历史都塞进去。所以我们需要“取舍”。

9.2 动手实现:上下文压缩与摘要

一个实用的技巧是:当对话历史超过一定长度时,对前面的内容进行“压缩”或“摘要”。

第一步:实现一个上下文管理器

# context_manager.py
class ContextManager:
    def __init__(self, max_tokens=4000):
        self.max_tokens = max_tokens
        self.history = []  # 存储原始消息
        self.summary = ""  # 存储压缩后的摘要

    def add_message(self, message):
        self.history.append(message)
        # 检查是否超限(这里用简单字符数估算,实际应用需用 tokenizer)
        if len(str(self.history)) > self.max_tokens * 4:
            self._compress()

    def _compress(self):
        """调用 LLM 对早期历史进行摘要"""
        # 取最早的一半历史进行压缩
        early_history = self.history[:len(self.history)//2]
        compress_prompt = {
            "role": "system",
            "content": (
                "请将以下对话历史压缩成一个简短的摘要,"
                "保留所有关键信息、决定和用户偏好。"
            )
        }
        # 调用 LLM 生成摘要
        summary_text = call_llm([compress_prompt] + early_history)
        self.summary = summary_text
        # 移除已被压缩的历史
        self.history = self.history[len(self.history)//2:]

    def get_context(self):
        """获取当前上下文,包含摘要和最近历史"""
        context = []
        if self.summary:
            context.append({
                "role": "system",
                "content": f"[对话历史摘要] {self.summary}"
            })
        context.extend(self.history)
        return context

第二步:在智能体中使用上下文管理器

在你的 HelloAgent 中,用 ContextManager 替代原来的 self.messages 列表。

# agent.py
from context_manager import ContextManager

class HelloAgent:
    def __init__(self):
        self.context = ContextManager(max_tokens=4000)
        # ... 其他初始化

    def run(self, user_input):
        self.context.add_message({"role": "user", "content": user_input})
        messages = self.context.get_context()
        # 调用 LLM
        response = self.call_llm(messages)
        self.context.add_message({"role": "assistant", "content": response})
        return response

预期结果:现在,即使你跟智能体聊了上百轮,它也不会“失忆”。它会把早期的内容压缩成一段摘要,然后专注于最近的对话。你问“那个截止日期”,它会先看摘要里有没有提到,再看最近的对话,从而给出准确的回答。

实用技巧

  • 滑动窗口:除了摘要,也可以直接丢弃最早的消息,只保留最近 N 轮。这是最简单的方法。
  • 结构化提示:在系统提示词里明确告诉 LLM 当前任务的状态,比如“你正在完成一个旅行计划,已经确定了目的地是巴黎,正在讨论酒店预订。” 这比让它自己猜要高效得多。

小结:上下文工程让你的智能体有了“大局观”。它不再断章取义,而是能结合整个对话的脉络来理解你的意图。

第十章:智能体通信协议——让智能体学会“社交”

你的智能体现在很“聪明”,但它很孤独。如果能让多个智能体协作,比如一个负责搜索,一个负责总结,一个负责写报告,那威力将成倍增长。这就需要通信协议。

10.1 什么是智能体通信协议?

简单说,就是一套标准化的消息格式和交互规则,让不同的智能体(甚至不同团队开发的智能体)能互相理解、协同工作。

目前比较热门的协议有:

  • MCP (Model Context Protocol):由 Anthropic 提出,侧重于让 LLM 应用(如 Claude Desktop)与外部工具和数据源交互。你可以把它理解为“AI 界的 USB 协议”。
  • A2A (Agent-to-Agent):由 Google 提出,侧重于智能体之间的直接通信和任务协作。
  • ANP (Agent Network Protocol):更通用的智能体网络协议。

10.2 动手实现:用 MCP 让你的智能体“用上”计算器

我们以 MCP 为例,因为它最贴近“工具调用”的概念,而且有现成的 Python SDK。

第一步:安装 MCP SDK

pip install mcp

第二步:创建一个 MCP 服务器(提供计算器工具)

# calculator_server.py
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types

# 创建一个服务器实例
server = Server("calculator")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """声明这个服务器提供的工具"""
    return [
        types.Tool(
            name="calculate",
            description="执行数学计算",
            inputSchema={
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "数学表达式,例如 '2 + 2' 或 'sqrt(16)'",
                    }
                },
                "required": ["expression"],
            },
        )
    ]

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict
) -> list[types.TextContent]:
    """实际执行工具调用"""
    if name == "calculate":
        expression = arguments["expression"]
        try:
            # 安全地计算表达式(生产环境请用更安全的方法)
            result = eval(expression, {"__builtins__": {}}, {})
            return [types.TextContent(type="text", text=str(result))]
        except Exception as e:
            return [types.TextContent(type="text", text=f"计算错误: {e}")]

async def run():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="calculator",
                server_version="0.1.0",
            ),
        )

if __name__ == "__main__":
    import asyncio
    asyncio.run(run())

第三步:让你的智能体连接 MCP 服务器

在你的 HelloAgent 中,添加一个 MCP 客户端,用来发现和调用远程工具。

# agent.py (部分修改)
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

class HelloAgent:
    def __init__(self):
        # ... 其他初始化
        self.mcp_tools = []  # 存储从 MCP 服务器发现的工具

    async def connect_mcp_server(self, command: str, args: list[str]):
        """连接到 MCP 服务器并获取工具列表"""
        server_params = StdioServerParameters(
            command=command,
            args=args

7. 第四部分:综合案例进阶(智能旅行助手、自动化深度研究、赛博小镇)

好的,我们开始吧。

第十三章 智能旅行助手

本章目标

学完前面那么多理论,你肯定手痒了,想用它们做个真正能用的东西。本章我们就来干这件事:MCP 协议和多智能体协作,搭建一个能帮你规划旅行、查天气、订餐厅的智能旅行助手。做完它,你就能理解“协议”和“协作”在真实世界里是怎么落地、怎么解决实际问题的。

前置条件

  • 你已经读完了第十章“智能体通信协议”,知道 MCP 是什么、Client/Server 怎么交互。
  • 你的电脑上已经装好了 Python 3.10+ 和 pip
  • 你有一个可用的 OpenAI API Key(或其他兼容的 LLM API Key),并且知道怎么在环境变量里设置它(比如 export OPENAI_API_KEY="sk-...")。
  • 你已经安装了 hello-agents 项目所需的依赖(如果还没装,可以回到第二章快速过一下)。

第一步:理解我们要做什么

先别急着写代码,我们想清楚目标。

一个旅行助手,至少得能干这几件事:

  1. 查天气:知道目的地未来几天的天气,好决定带什么衣服。
  2. 查景点/餐厅:知道当地有什么好玩的、好吃的。
  3. 规划行程:根据上面查到的信息,生成一个合理的日程安排。

如果让一个智能体自己干所有事,它得内置一大堆 API 调用逻辑,代码会变得又臭又长。更好的方式是:让一个“总指挥”智能体,去调用几个专门的“工具”智能体。每个工具智能体只负责一件事,比如“天气查询专家”、“景点推荐专家”。它们之间通过 MCP 协议通信。

这就是多智能体协作的典型模式。我们这一章,就是要亲手实现这个模式。

第二步:搭建 MCP 服务器(工具提供方)

MCP 服务器就是提供工具的地方。我们先写一个最简单的天气查询服务器。

在你的项目目录下,新建一个文件 weather_server.py

# weather_server.py
import json
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types

# 模拟的天气数据,真实场景下你会调用第三方天气 API
def get_weather(city: str, date: str) -> str:
    """根据城市和日期返回模拟天气"""
    weather_data = {
        "北京": {"2025-07-15": "晴,28-35°C", "2025-07-16": "多云,26-33°C"},
        "上海": {"2025-07-15": "小雨,25-30°C", "2025-07-16": "阴,24-29°C"},
        "杭州": {"2025-07-15": "晴,27-34°C", "2025-07-16": "晴,26-33°C"},
    }
    city_weather = weather_data.get(city, {})
    return city_weather.get(date, f"抱歉,没有{city}{date}的天气数据")

# 创建 MCP 服务器实例
server = Server("weather-server")

# 注册一个工具:查询天气
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="get_weather",
            description="查询指定城市在指定日期的天气情况",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称,如北京"},
                    "date": {"type": "string", "description": "日期,格式 YYYY-MM-DD,如 2025-07-15"},
                },
                "required": ["city", "date"],
            },
        )
    ]

# 处理工具调用请求
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "get_weather":
        city = arguments.get("city")
        date = arguments.get("date")
        result = get_weather(city, date)
        return [types.TextContent(type="text", text=result)]
    else:
        raise ValueError(f"未知工具: {name}")

# 启动服务器
async def main():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="weather-server",
                server_version="0.1.0",
            ),
        )

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

预期结果:运行 python weather_server.py,你不会看到任何输出,因为它在等待 MCP 客户端连接。这很正常,说明服务器已经跑起来了。

第三步:搭建 MCP 客户端(工具调用方)

现在,我们需要一个“总指挥”智能体,它知道怎么连接天气服务器,并根据用户的问题决定是否调用天气工具。

新建 travel_agent.py

# travel_agent.py
import asyncio
import json
from openai import OpenAI
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

# 初始化 LLM 客户端
client = OpenAI()

# 定义系统提示词,告诉智能体它可以做什么
SYSTEM_PROMPT = """
你是一个智能旅行助手。你可以使用以下工具来帮助用户规划旅行:
- get_weather: 查询天气。调用时需要提供 city 和 date 参数。

当用户提出旅行相关问题时,先思考是否需要使用工具。如果需要,就调用工具获取信息,然后基于信息给出回答。
"""

async def main():
    # 1. 连接到 MCP 服务器
    server_params = StdioServerParameters(
        command="python",
        args=["weather_server.py"]  # 启动天气服务器的命令
    )
    
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # 2. 初始化会话
            await session.initialize()
            
            # 3. 获取服务器提供的工具列表
            tools_result = await session.list_tools()
            # 将 MCP 工具格式转换为 OpenAI 可用的 tool 格式
            tools = [
                {
                    "type": "function",
                    "function": {
                        "name": tool.name,
                        "description": tool.description,
                        "parameters": tool.inputSchema,
                    }
                }
                for tool in tools_result.tools
            ]
            
            print("🤖 智能旅行助手已启动!输入 'quit' 退出。")
            
            # 4. 开始对话循环
            messages = [{"role": "system", "content": SYSTEM_PROMPT}]
            
            while True:
                user_input = input("\n👤 你: ")
                if user_input.lower() == 'quit':
                    break
                
                messages.append({"role": "user", "content": user_input})
                
                # 5. 调用 LLM,并传入可用的工具
                response = client.chat.completions.create(
                    model="gpt-4o",
                    messages=messages,
                    tools=tools,
                    tool_choice="auto"
                )
                
                assistant_message = response.choices[0].message
                messages.append(assistant_message)
                
                # 6. 检查 LLM 是否想要调用工具
                if assistant_message.tool_calls:
                    for tool_call in assistant_message.tool_calls:
                        function_name = tool_call.function.name
                        function_args = json.loads(tool_call.function.arguments)
                        
                        print(f"🔧 调用工具: {function_name}({function_args})")
                        
                        # 通过 MCP 会话调用工具
                        result = await session.call_tool(function_name, function_args)
                        # 提取结果文本
                        result_text = result.content[0].text if result.content else ""
                        
                        print(f"📊 工具返回: {result_text}")
                        
                        # 将工具调用结果返回给 LLM
                        messages.append({
                            "role": "tool",
                            "tool_call_id": tool_call.id,
                            "content": result_text
                        })
                    
                    # 7. 让 LLM 基于工具结果生成最终回答
                    final_response = client.chat.completions.create(
                        model="gpt-4o",
                        messages=messages
                    )
                    final_message = final_response.choices[0].message
                    print(f"🤖 助手: {final_message.content}")
                    messages.append(final_message)
                else:
                    # LLM 直接回答了,没有调用工具
                    print(f"🤖 助手: {assistant_message.content}")

if __name__ == "__main__":
    asyncio.run(main())

预期结果:运行 python travel_agent.py,你会看到启动提示。输入“北京7月15号天气怎么样?”,你会看到类似这样的输出:

🔧 调用工具: get_weather({'city': '北京', 'date': '2025-07-15'})
📊 工具返回: 晴,28-35°C
🤖 助手: 北京7月15号天气晴朗,气温在28到35摄氏度之间,建议穿着轻薄衣物,注意防晒。

常见报错与排查

  • ModuleNotFoundError: No module named 'mcp':说明你没装 mcp 库。运行 pip install mcp
  • 连接被拒绝或工具调用失败:确保 weather_server.pytravel_agent.py 在同一个目录下,并且 weather_server.py 没有语法错误。可以先单独运行 python weather_server.py 看看有没有报错。
  • LLM 不调用工具:检查你的 SYSTEM_PROMPT 是否写清楚了工具的功能和调用时机。有时候模型需要更明确的指示。

第四步:扩展:加入景点推荐服务器

一个工具不够,我们再做一个景点推荐服务器 attraction_server.py

# attraction_server.py
from mcp.server import Server
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types

def get_attractions(city: str, interest: str = "热门") -> str:
    """根据城市和兴趣返回推荐景点"""
    attractions = {
        "北京": {"热门": "故宫、天安门、长城、颐和园", "美食": "王府井小吃街、簋街", "文化": "国家博物馆、798艺术区"},
        "上海": {"热门": "外滩、东方明珠、迪士尼", "美食": "城隍庙、南京路步行街", "文化": "上海博物馆、田子坊"},
        "杭州": {"热门": "西湖、灵隐寺、雷峰塔", "美食": "河坊街、龙井村", "文化": "浙江省博物馆、中国美术学院"},
    }
    city_data = attractions.get(city, {})
    return city_data.get(interest, f"抱歉,没有找到{city}关于{interest}的推荐")

server = Server("attraction-server")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="get_attractions",
            description="查询指定城市的景点推荐,可以指定兴趣类型(热门、美食、文化)",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"},
                    "interest": {"type": "string", "description": "兴趣类型,可选值:热门、美食、文化,默认为热门"},
                },
                "required": ["city"],
            },
        )
    ]

@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "get_attractions":
        city = arguments.get("city")
        interest = arguments.get("interest", "热门")
        result = get_attractions(city, interest)
        return [types.TextContent(type="text", text=result)]
    else:
        raise ValueError(f"未知工具: {name}")

async def main():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="attraction-server",
                server_version="0.1.0",
            ),
        )

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

现在,你需要修改 travel_agent.py,让它同时连接两个服务器。关键改动在 main 函数里:

# 在 travel_agent.py 的 main 函数中,修改连接部分
async def main():
    # 同时启动两个服务器
    server_params_weather = StdioServerParameters(
        command="python",
        args=["weather_server.py"]
    )
    server_params_attraction = StdioServerParameters(
        command="python",
        args=["attraction_server.py"]
    )
    
    # 使用 asyncio.gather 同时管理两个连接
    async with stdio_client(server_params_weather) as (read_w, write_w), \
               stdio_client(server_params_attraction) as (read_a, write_a):
        async with ClientSession(read_w, write_w) as session_w, \
                   ClientSession(read_a, write_a) as session_a:
            await session_w.initialize()
            await session_a.initialize()
            
            # 合并两个服务器的工具列表
            tools_w = await session_w.list_tools()
            tools_a = await session_a.list_tools()
            all_tools = tools_w.tools + tools_a.tools
            
            # ... 后续代码类似,但需要根据工具名称判断调用哪个 session
            # 这里为了简洁,我们只演示思路,实际需要维护一个工具名到 session 的映射

实用技巧:在实际项目中,你通常会用一个工具注册中心或配置文件来管理多个 MCP 服务器,而不是像上面这样硬编码。但作为入门,理解这个“一对多”的模式已经足够了。

第五步:串联一个真实场景

现在,我们来模拟一个完整的旅行规划对话:

  1. 用户:“我打算7月15号去杭州玩两天,帮我规划一下。”
  2. 助手(思考):“我需要先查杭州7月15号和16号的天气,再查杭州有什么好玩的

8. 第五部分:毕业设计与未来展望

第十六章 毕业设计:构建属于你的完整多智能体应用

走到这一步,你已经掌握了从 LLM 基础到高级技术(记忆、上下文工程、通信协议、强化学习、评估)的完整知识体系。本章的目标只有一个:把你学过的所有东西串起来,独立完成一个可运行的多智能体应用。这不是考试,而是你从“学习者”变成“构建者”的毕业作品。

前置条件

  • 已完成前十五章的学习,特别是第七章(自研框架)和第十三至十五章(综合案例)
  • 本地环境已配置好 Python 3.10+、OpenAI API Key(或其他兼容 API)
  • 熟悉 Git 基本操作(clone、commit、push)
  • 准备好一个 GitHub 账号(用于托管你的项目)

第一步:选题与设计

毕业设计不是从零造轮子,而是在已有基础上做有意义的组合与扩展。选题原则:

  • 小而完整:一个核心功能,但端到端跑通
  • 用上至少 3 个你学过的技术:例如 ReAct 范式 + 记忆系统 + MCP 协议
  • 能演示:命令行交互或简单 Web 界面都行

几个参考方向(你也可以自己想):

选题 核心技术点 难度
个人知识助手 RAG + 记忆 + 工具调用 ⭐⭐
代码审查智能体 多智能体协作 + 上下文工程 ⭐⭐⭐
自动化报告生成器 Plan-and-Solve + 评估 ⭐⭐
模拟社交网络 赛博小镇变体 + 通信协议 ⭐⭐⭐⭐

预期结果:一个 README 文档,写清楚你的选题、技术选型、预期功能。

第二步:搭建项目骨架

我们推荐用第七章的自研框架 HelloAgents 作为基础,因为它轻量、无黑盒。如果你更熟悉 LangGraph 或 AutoGen,也可以用它们——但必须能解释清楚每个组件的原理

创建一个新目录并初始化:

mkdir my-agent-graduation
cd my-agent-graduation
git init
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install helloagents openai

创建基本文件结构:

my-agent-graduation/
├── agents/          # 智能体定义
├── tools/           # 工具函数
├── memory/          # 记忆模块
├── config.py        # 配置
├── main.py          # 入口
└── README.md

预期结果:项目目录结构清晰,pip install 无报错,python -c "import helloagents" 能正常执行。

第三步:实现核心逻辑

以“个人知识助手”为例,我们实现一个能记住用户偏好、检索本地文档、调用搜索工具的智能体。

3.1 配置 API

# config.py
import os

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "your-key-here")
OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
MODEL_NAME = "gpt-4o-mini"

3.2 定义工具

# tools/search_tool.py
import requests

def web_search(query: str) -> str:
    """搜索网络并返回摘要"""
    # 这里用 DuckDuckGo 免费 API 做演示
    url = f"https://api.duckduckgo.com/?q={query}&format=json"
    resp = requests.get(url, timeout=10)
    data = resp.json()
    return data.get("AbstractText", "未找到结果")

3.3 实现记忆模块

# memory/simple_memory.py
from typing import List, Dict

class SimpleMemory:
    def __init__(self):
        self.history: List[Dict] = []
        self.preferences: Dict = {}
    
    def add_interaction(self, user_input: str, agent_response: str):
        self.history.append({"user": user_input, "agent": agent_response})
    
    def get_context(self) -> str:
        return "\n".join(
            [f"用户: {h['user']}\n助手: {h['agent']}" for h in self.history[-5:]]
        )
    
    def remember_preference(self, key: str, value: str):
        self.preferences[key] = value

3.4 组装智能体

# main.py
from helloagents import Agent, ReAct
from config import OPENAI_API_KEY, MODEL_NAME
from tools.search_tool import web_search
from memory.simple_memory import SimpleMemory

def main():
    memory = SimpleMemory()
    
    agent = Agent(
        name="知识助手",
        model=MODEL_NAME,
        api_key=OPENAI_API_KEY,
        tools=[web_search],
        system_prompt="你是一个知识助手,帮助用户查找信息并记住他们的偏好。"
    )
    
    print("知识助手已启动(输入 'exit' 退出)")
    while True:
        user_input = input("\n你: ")
        if user_input.lower() == "exit":
            break
        
        # 注入记忆上下文
        context = memory.get_context()
        response = agent.run(user_input, context=context)
        
        print(f"助手: {response}")
        memory.add_interaction(user_input, response)
        
        # 简单偏好提取(演示用)
        if "我喜欢" in user_input or "我的名字" in user_input:
            memory.remember_preference("last_topic", user_input)

if __name__ == "__main__":
    main()

预期结果:运行 python main.py 后,能进行多轮对话,智能体能调用搜索工具并记住上下文。

第四步:添加评估与测试

毕业设计需要证明你的智能体“工作得不错”。用第十二章学到的评估方法,写一个简单的测试脚本:

# test_agent.py
from main import agent

test_cases = [
    {"input": "今天天气怎么样?", "expected_tool_call": True},
    {"input": "你好", "expected_tool_call": False},
]

for case in test_cases:
    result = agent.run(case["input"])
    # 检查是否调用了工具(简单判断)
    tool_used = "搜索" in result or "http" in result
    assert tool_used == case["expected_tool_call"], f"测试失败: {case['input']}"
    
print("所有测试通过!")

预期结果python test_agent.py 输出“所有测试通过!”。

第五步:完善文档与发布

一个没有 README 的项目等于没做。写清楚:

  1. 项目简介:一句话说明做什么
  2. 快速开始:安装、配置、运行命令
  3. 技术架构:用了哪些技术、为什么选它们
  4. 演示截图:终端输出或界面截图
  5. 未来改进:你想到但没时间做的功能

然后提交到 GitHub:

git add .
git commit -m "完成毕业设计:个人知识助手"
git remote add origin https://github.com/你的用户名/my-agent-graduation.git
git push -u origin main

预期结果:一个公开的 GitHub 仓库,README 完整,其他人 clone 后能直接运行。

常见坑位与排查

1. API 调用失败

报错openai.AuthenticationErrorConnectionError
排查:检查 OPENAI_API_KEY 是否有效,OPENAI_BASE_URL 是否正确(国内用户可能需要代理或使用国内 API 中转)。

2. 工具函数不生效

报错:智能体不调用你定义的 web_search
排查:确认工具函数的文档字符串(docstring)写清楚了——LLM 靠它理解工具用途。另外检查 tools 参数是否传入了函数对象而非字符串。

3. 记忆不生效

表现:第二轮对话智能体忘了之前说过什么
排查:检查 context 参数是否传入了 agent.run(),以及 SimpleMemory.get_context() 返回的内容格式是否被 LLM 理解。

4. 依赖冲突

报错pip install 时版本冲突
排查:使用虚拟环境(venv),先 pip install helloagents 再装其他包。如果冲突严重,用 pip install helloagents==0.1.0 指定版本。

一个小例子串起来

假设你想做一个“旅行规划助手”,它需要:

  1. 记住用户的出发城市和偏好(记忆)
  2. 搜索目的地天气和景点(工具调用)
  3. 用 ReAct 范式分步规划行程(推理)
  4. 最后输出一份 Markdown 格式的旅行计划(输出格式化)

你只需要把上面代码中的 system_prompt 改成旅行规划相关,添加一个 get_weather 工具,再调整记忆模块存储用户偏好(比如“我喜欢海边”)。整个过程不超过 100 行代码——这就是你学完所有技术后的能力。

未来展望

毕业设计不是终点。你可以沿着这几个方向继续深入:

  • 接入 MCP 协议:让智能体能调用更多外部服务(日历、邮件、数据库)
  • 加入多智能体协作:让两个智能体分工,一个负责搜索,一个负责总结
  • 用 Agentic-RL 微调模型:针对你的特定任务,用 GRPO 训练一个更高效的模型
  • 部署成 Web 服务:用 FastAPI 包装,让其他人通过浏览器使用你的智能体

现在,打开终端,开始你的毕业设计吧。

9. 社区贡献精选与扩展阅读

社区贡献精选

读完前面十五章,你已经掌握了从基础概念到高级技术、从框架开发到综合案例的全套技能。但智能体领域发展极快,单靠一本书很难覆盖所有方向。本章精选社区贡献的优质内容,帮你拓展视野、查漏补缺,同时告诉你如何参与贡献。

前置条件

  • 已完成前十五章的学习
  • 拥有 GitHub 账号(用于提交 PR 或查看社区项目)

社区精选内容一览

社区成员贡献的内容分为两类:Extra-Chapter(独立于正文的扩展文章)和 Co-creation-projects(社区共创的毕业设计项目)。以下是精选推荐:

1. 面试准备

Agent 面试题总结与答案(Extra01)

如果你正在求职,这两份文档是必读的。它汇总了 Agent 岗位常见的面试问题,涵盖概念理解、框架原理、实战场景等,并附有参考答案。建议先自己思考,再对照答案查漏补缺。

2. 知识点补充

上下文工程内容补充(Extra02)

第九章讲上下文工程时,受篇幅限制只覆盖了核心内容。这篇补充文章深入讲解了更多实用技巧,比如动态上下文压缩、长对话中的记忆管理策略等。如果你在实际项目中遇到上下文溢出问题,这里可能有解决方案。

Dify 智能体创建保姆级教程(Extra03)

第五章介绍了低代码平台,但 Dify 的实操细节很多。这篇教程从注册到部署,每一步都有截图和说明,适合想快速上手 Dify 的读者。

Hello-Agents 课程常见问题(Extra04)

学习过程中遇到的典型问题汇总,包括环境配置、代码运行报错、概念理解等。遇到问题先翻这里,大概率能找到答案。

Agent Skill 相关文章(Extra05)

这篇聚焦 Agent 的技能系统设计,包括技能注册、调用、组合等工程实践。适合想深入理解 Agent 能力边界的读者。

3. 毕业设计项目

社区共创毕业设计(Co-creation-projects)

第十六章要求你构建一个完整的多智能体应用。社区成员已经提交了多个项目,涵盖不同场景和技术栈。你可以:

  • 参考这些项目的架构设计
  • 基于某个项目进行二次开发
  • 提交你自己的毕业设计

如何贡献

看到这里,你可能也想分享自己的学习心得或实践成果。贡献流程很简单:

  1. Fork 仓库:访问 hello-agents,点击右上角 Fork
  2. 创建分支:在本地创建一个新分支,命名如 extra-my-topic
  3. 添加内容
    • 独立文章放到 Extra-Chapter 目录,文件名格式 ExtraXX-你的标题.md
    • 毕业设计放到 Co-creation-projects 目录,建一个以你项目命名的文件夹
  4. 提交 PR:推送到你的 Fork 仓库,然后向主仓库发起 Pull Request

注意事项:

  • 内容必须是原创或已获授权转载
  • 代码示例要可运行,依赖和版本号写清楚
  • 引用外部资料时注明来源

常见问题

Q:我的内容比较短,也能提交吗? A:可以。哪怕是一篇 500 字的技术笔记,只要对他人有帮助,都欢迎提交。

Q:提交后多久会被合并? A:维护者会定期审核 PR,通常 3-7 天内会有反馈。如果长时间未回复,可以在 PR 评论区 @ 维护者。

Q:我想修改正文内容,不是新增章节,怎么办? A:直接提交 PR 修改对应文件即可。如果是修正错误,请在 PR 描述中说明。

实用技巧

  • 先看已有内容:提交前浏览 Extra-Chapter 目录,避免重复
  • 保持风格一致:参考已有文章的 Markdown 格式和代码块写法
  • 写清楚摘要:在 PR 描述中说明你的内容解决了什么问题、适合谁阅读

社区的力量在于分享。你的每一次贡献,都在帮助下一个学习者少走弯路。

10. 常见问题与面试指南

常见问题与面试指南

学完前面十六章,你已经掌握了从理论到实战的全链路知识。但有两个现实问题摆在面前:一是学习过程中踩过的坑怎么排查,二是如何把这些知识转化成面试中的竞争力。本章就专门解决这两件事。

前置条件

  • 已完成前十六章的学习或具备同等知识储备
  • 有至少一个自己动手跑通的 Agent 项目(哪怕是简单的 ReAct 实现)
  • 准备好一份简历,后面会用到

第一部分:学习过程中的高频问题

1. 环境与安装

Q:安装依赖时总是报版本冲突,怎么办?

先确认 Python 版本:python --version,本项目要求 Python 3.10+。推荐用虚拟环境隔离:

python -m venv hello-agents-env
source hello-agents-env/bin/activate  # Linux/Mac
# 或 hello-agents-env\Scripts\activate  # Windows
pip install -r requirements.txt

如果还冲突,大概率是 openailangchain 的版本不兼容。稳妥做法:先装 openai>=1.0.0,再装其他库。

Q:OpenAI API 调用报 401/429 错误?

  • 401:检查 OPENAI_API_KEY 是否设置正确,不要有多余空格或换行
  • 429:触发了速率限制。加 time.sleep() 或用 tenacity 做重试
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def call_llm(prompt):
    # 你的调用代码
    pass

2. 智能体运行问题

Q:Agent 陷入死循环,一直调用同一个工具?

这是 ReAct 模式最常见的坑。原因通常是:工具返回的结果不够明确,LLM 认为需要再试一次。

解决办法:

  1. 给工具输出加明确的"完成"信号,比如返回 {"status": "done", "result": ...}
  2. 设置最大迭代次数,超时强制终止
MAX_ITERATIONS = 10
for i in range(MAX_ITERATIONS):
    # 你的 Agent 循环
    if i == MAX_ITERATIONS - 1:
        return "已达到最大尝试次数,请简化你的请求"

Q:LLM 输出格式不对,解析 JSON 总是失败?

LLM 输出的 JSON 经常带多余文字或格式错误。不要直接 json.loads(),用正则提取或加一层校验:

import re
import json

def extract_json(text):
    # 匹配第一个 { 到最后一个 } 之间的内容
    match = re.search(r'\{.*\}', text, re.DOTALL)
    if match:
        try:
            return json.loads(match.group())
        except json.JSONDecodeError:
            # 尝试修复常见问题:单引号替换为双引号
            fixed = match.group().replace("'", '"')
            return json.loads(fixed)
    raise ValueError("未找到有效的 JSON")

Q:Memory 越长,Agent 响应越慢,还容易跑偏?

这是上下文窗口的物理限制。不要把所有历史都塞进去,用滑动窗口或摘要策略:

class SlidingWindowMemory:
    def __init__(self, max_messages=20):
        self.max_messages = max_messages
        self.messages = []
    
    def add(self, message):
        self.messages.append(message)
        if len(self.messages) > self.max_messages:
            # 保留系统提示和最近的对话
            self.messages = [self.messages[0]] + self.messages[-(self.max_messages-1):]

3. 框架与平台

Q:Dify 和 Coze 上搭建的 Agent,导出后怎么在本地跑?

低代码平台的导出格式通常是 JSON 或 YAML 描述文件,不是可执行代码。如果你需要本地部署,建议:

  • 用 Dify 的 API 模式,远程调用
  • 或者参考第七章,用导出的工作流逻辑,在自研框架里重写

Q:LangGraph 的 StateGraph 总是画不对?

常见错误:节点之间的边连错了。先画流程图再写代码,每个节点只做一件事。调试时加 print 看 state 变化:

def debug_node(state):
    print(f"当前状态: {state.keys()}")
    # 你的逻辑
    return state

第二部分:面试指南

面试前的准备

先梳理你的项目经验

面试官最常问的不是八股文,而是"你做过什么"。把你跑通的 Agent 项目整理成 STAR 格式:

  • Situation:项目背景,解决什么问题
  • Task:你的具体任务
  • Action:你做了什么(技术选型、架构设计、踩坑解决)
  • Result:效果如何(准确率、响应时间、用户反馈)

一个真实的例子(你可以参考这个结构):

我做了一个智能旅行助手,用 ReAct 模式 + 三个工具(天气查询、酒店预订、路线规划)。一开始 Agent 总是调用错工具,比如用户问天气,它却去查酒店。后来我在工具描述里加了明确的触发条件,比如"仅当用户提到'天气''温度''下雨'等词时才调用此工具",准确率从 62% 提升到 89%。

高频面试题

以下题目按频率排序,每个都附了回答要点。

1. 什么是 AI Agent?和传统程序有什么区别?

回答要点:

  • Agent 是能感知环境、自主决策、执行动作的智能体
  • 传统程序是确定性的:输入 → 固定逻辑 → 输出
  • Agent 是不确定性的:输入 → LLM 推理 → 选择工具 → 观察结果 → 循环直到完成
  • 核心区别:Agent 有"思考"和"适应"的能力

2. ReAct 模式是怎么工作的?

回答要点:

  • ReAct = Reasoning + Acting
  • 循环:思考(Thought) → 行动(Action) → 观察(Observation) → 再思考
  • 每个 Action 调用一个工具,Observation 是工具返回的结果
  • 直到 Thought 认为任务完成,输出 Final Answer

3. 怎么解决 Agent 的幻觉问题?

回答要点(分层次):

  • 提示层:明确告诉 LLM "不知道就说不知道"
  • 工具层:用外部工具(搜索、数据库)获取事实,不依赖模型内部知识
  • 验证层:对输出做二次校验,比如用另一个 LLM 做事实核查
  • 架构层:用 RAG 或 Memory 提供上下文约束

4. 多 Agent 协作怎么保证一致性?

回答要点:

  • 通信协议:定义标准化的消息格式(JSON Schema)
  • 共享记忆:所有 Agent 读写同一个 Memory 实例
  • 仲裁机制:设一个 Coordinator Agent 做决策汇总
  • 容错设计:超时重试、降级策略

5. 怎么评估一个 Agent 的好坏?

回答要点:

  • 任务完成率:给定测试集,看 Agent 能否正确完成
  • 工具调用准确率:是否调对了工具、参数是否正确
  • 响应速度:从输入到输出的总耗时
  • 鲁棒性:输入有噪声或歧义时,表现是否稳定
  • 成本:API 调用次数和 token 消耗

6. 你遇到过最棘手的 Agent 问题是什么?怎么解决的?

这道题考的是你的实战能力。不要编,用你真实踩过的坑。如果你没遇到过特别难的,可以说:

最棘手的是 Agent 在复杂任务中频繁切换上下文,导致前面的推理结果丢失。我通过引入"工作记忆"——把中间结果持久化到 JSON 文件,每次推理前加载——解决了这个问题。虽然增加了 I/O 开销,但任务成功率从 55% 提升到 83%。

面试实战建议

技术面常见环节

  1. 手撕代码:可能会让你现场写一个简单的 ReAct 循环。提前练熟第七章的框架代码,能徒手写出核心逻辑。

  2. 系统设计:给一个场景,让你设计 Agent 架构。比如"设计一个客服 Agent"。注意:不要只堆技术名词,要说清楚为什么选这个方案、有什么 trade-off。

  3. 追问细节:面试官会深挖你简历上的项目。确保你能说清楚每个技术选型的理由,比如"为什么用 LangGraph 而不是 AutoGen"。

反问环节(加分项)

面试最后通常会让你提问。别问"加班多吗"这种,问点有深度的:

  • "贵团队的 Agent 在生产环境里是怎么做错误恢复的?"
  • "你们在 Agent 的 Memory 管理上有什么实践经验?"
  • "如果遇到 LLM 输出格式不稳定,你们是怎么处理的?"

这些问题表明你真正做过、思考过。


实用技巧汇总

调试 Agent 的黄金三招

  1. 加日志:在每个关键节点打印输入输出,特别是 LLM 的原始响应
  2. 降级测试:先用最简单的 prompt 跑通流程,再逐步加复杂度
  3. 人工模拟:把 LLM 调用替换成固定返回值,先验证逻辑正确性

快速定位问题

现象 可能原因 排查方向
Agent 不调用工具 工具描述不清晰 检查 prompt 中的工具定义
调用工具但参数错误 输出格式解析失败 检查 JSON 解析逻辑
响应速度越来越慢 Memory 膨胀 检查上下文窗口大小
结果前后矛盾 缺乏全局记忆 检查 Memory 策略

最后一条建议

面试官看重的不是你知道多少概念,而是你有没有真正动手做过。哪怕只是一个简单的 ReAct Agent,只要你把踩过的坑、怎么解决的、效果如何讲清楚,就比背一百道八股文强。现在就去打开你的项目,把那些调试记录整理成面试素材吧。

FAQ

问题1:安装或运行项目时遇到 Python 版本或依赖冲突怎么办?

项目基于 Python 3.10+ 开发,建议使用虚拟环境(如 condavenv)隔离依赖。首先执行 pip install -r requirements.txt,若遇到版本冲突,可尝试手动升级/降级关键库(如 openailangchain)。如果使用自研框架 HelloAgents,请确保已安装 openai>=1.0.0。推荐使用 pip install --upgrade pip 后再安装依赖。

问题2:为什么我无法访问在线文档?国内用户如何加速?

项目提供了两个在线阅读入口:

  • 国外访问https://datawhalechina.github.io/hello-agents/
  • 国内加速https://hello-agents.datawhale.cc 如果国外链接加载缓慢或被墙,请直接使用国内加速地址。若仍无法访问,可尝试克隆仓库后在本地用 docsifymkdocs 启动本地服务器阅读。

问题3:教程中提到的“AI Native Agent”和“低代码平台 Agent”有什么区别?

  • 低代码平台 Agent(如 Dify、Coze、n8n):本质是流程驱动的软件开发,LLM 作为数据处理的后端,适合快速搭建业务流。
  • AI Native Agent:真正以 AI 驱动的智能体,核心是 LLM 自主决策、规划、调用工具,本教程重点讲解后者。如果你只想快速体验,可先看第五章;若想深入原理,建议从第四章开始。

问题4:运行第四章的 ReAct 或 Plan-and-Solve 示例时,报错“API key not found”或“模型不存在”?

请检查环境变量是否设置正确,例如:

export OPENAI_API_KEY="your-api-key"

如果使用其他模型(如通义千问、DeepSeek),需在代码中修改 base_urlmodel 参数。部分示例默认使用 gpt-4,若你的 API 没有该模型权限,可改为 gpt-3.5-turbo 或兼容模型。

问题5:教程中提到的“HelloAgents”框架和 LangGraph、AutoGen 有什么区别?我需要全部学习吗?

  • HelloAgents:本项目自研的轻量级框架,基于 OpenAI 原生 API,适合理解 Agent 核心原理(如 ReAct、Memory、工具调用)。
  • LangGraph / AutoGen:工业级框架,功能更丰富,但学习曲线较陡。 建议顺序:先学第四章(经典范式)→ 第七章(自研框架)→ 第六章(主流框架对比),这样能由浅入深,避免被框架细节淹没。

问题6:我在学习第十一章 Agentic-RL(从 SFT 到 GRPO)时,训练代码跑不起来,显存不够怎么办?

Agentic-RL 训练需要较高显存(建议 24GB+)。如果显存不足,可以:

  • 减小 batch_sizemax_length 参数。
  • 使用 gradient_accumulation_steps 模拟更大 batch。
  • 尝试使用更小的基座模型(如 Qwen2-1.5B 替代 7B)。
  • 如果本地无法运行,推荐使用 Colab(需 Pro)或 AutoDL 等云 GPU 服务。

问题7:教程中的“赛博小镇”案例需要哪些额外依赖?为什么我运行后没有看到交互界面?

“赛博小镇”是一个多智能体模拟项目,需要安装 pygamestreamlit(具体见第十五章开头)。如果运行后没有界面,请检查:

  • 是否在终端中正确执行了启动命令(如 python main.pystreamlit run app.py)。
  • 是否安装了所有依赖(pip install pygame streamlit)。
  • 如果使用 Jupyter Notebook,部分交互可能无法正常显示,建议在纯 Python 环境中运行。

问题8:我是初学者,应该从哪一章开始?需要先学完所有章节才能做毕业设计吗?

  • 零基础:建议按顺序从第一章到第四章,理解智能体概念和经典范式后,再跳转到第七章(自研框架)或第十三章(综合案例)。
  • 有基础:可以直接从第四章或第六章开始。
  • 毕业设计:第十六章毕业设计是开放性的,你可以结合前几章学到的知识(如 Memory、MCP、多智能体协作)构建自己的应用,不需要学完所有章节。社区也提供了共创毕业设计项目供参考。

🔗 Related