Skip to content

第4章 Agent不是魔法,它只是个聪明点的程序

前三章把 Go 环境和核心语法过了一遍。从这一章开始,我们正式进入 Agent 的世界。很多人觉得 Agent 很玄乎——"自主智能体"、"AI 助理"、"下一代的软件形态"……各种高大上的词往外蹦。这一章,我们把 Agent 从神坛上请下来。它不是什么黑科技,它只是一个聪明点的程序——而且你马上就能用 Eino 跑通一个。


4.1 朋友圈里的"Agent"和真Agent,差在哪?

4.1.1 这个词已经被用烂了

打开任何一个 AI 产品的官网,你大概率会看到"Agent"这个词。自动回复的客服叫 Agent,帮你排日程的插件叫 Agent,连一个定时发邮件的脚本都敢叫自己 Agent。

那到底什么才算真正的 Agent?

我们先说一个最简单的判断标准:

如果你告诉它"做什么",它只会做这一件事——那它不叫 Agent,叫"自动化脚本"。

如果你告诉它"目标",它自己想办法、做决定、调用工具来完成——这才叫 Agent。

举个具体的例子。你有一个"每天早上 8 点给我发今日天气"的需求:

自动化脚本的做法

1. 写一个 cron job
2. 到 8 点,调用天气 API
3. 把返回结果发给你

它只能做你规定好的这一件事。你让它"顺便提醒我今天要带伞",它做不到——你没写这个逻辑。

Agent 的做法

1. 你告诉 Agent 目标:"每天早上提醒我出门要带什么"
2. Agent 自己决定:
   - 需要查天气(调用天气 API)
   - 需要看你的日程(读取日历)
   - 如果下雨 → 提醒带伞
   - 如果有户外会议 → 建议涂防晒
   - 如果降温 → 提醒带外套
3. 它还会根据你的反馈调整——你说"伞的提醒不用了",下次就不提了

Agent 和脚本的核心区别:脚本走的是固定流程,Agent 走的是自主决策


4.1.2 Agent 的四个必备能力

判断一个系统是不是真正的 Agent,看它有没有这四项能力:

能力什么意思没有会怎样
感知能接收输入、理解上下文你跟它说了半天,它当没听见
规划能把大目标拆成小步骤你说"帮我安排出差",它直接懵了
行动能调用工具、执行操作永远只给你建议,从不动手
反思能检查结果、调整策略做错了也不知道改,一直错下去

缺任何一项,都不是完整意义上的 Agent。 市面上很多标榜"AI Agent"的产品,其实只有"感知 + 简单行动",缺了规划和反思。这种我们后面会讲,叫"半吊子 Agent"。


4.2 传统程序走流程,Agent 走"想法"

4.2.1 一个订餐的例子

用传统程序和 Agent 分别实现"帮我订个晚餐",差别一目了然。

传统程序

go
func orderDinner(cuisine string, budget float64, t time.Time) string {
    // 第1步:查可用餐厅
    restaurants := searchRestaurants(cuisine, budget)
    // 第2步:挑第一个
    chosen := restaurants[0]
    // 第3步:下单
    placeOrder(chosen, t)
    return fmt.Sprintf("已为您在%s订餐", chosen)
}

这个程序的逻辑是你写死的。你规定了"挑第一个餐厅"——即使第一个餐厅评分只有 2 星,它也会订。

Agent

你:帮我订个晚餐,要清淡一点的,不用太贵
Agent:
  1. 理解目标:清淡、不贵、晚餐时间
  2. 搜索附近餐厅
  3. 筛选:评分高 + 清淡口味 + 人均合理
  4. 发现三家合适的,根据你的历史偏好(你上周点过粤菜),推荐粤菜馆
  5. 你确认后,自动下单
  6. 发现配送费有点贵,换成了到店自取,省了 15 块

关键区别:传统程序是"把规则写到代码里",Agent 是"理解目标后自己想办法"。


4.2.2 "不确定性"是 Agent 的特性,不是 bug

传统程序追求"确定性"——同样的输入,永远得到同样的输出。

Agent 正好相反——同样的目标,它可能每次走不同的路径

比如同样是"帮我查天气",Agent 可能:

  • 第一次:直接调天气 API
  • 第二次:发现你问的是"明天适不适合跑步",先去查了你的运动偏好,再结合天气和空气质量给了综合建议

这是好事。 说明 Agent 在"思考",在根据上下文调整。你雇一个助理,也不希望他每次都像个机器人一样只做你字面意思上的那件事——你希望他"理解你真正的意图"。


4.3 Agent 是怎么一步步变聪明的?

4.3.1 从 ELIZA 到 GPT-4

Agent 不是一夜之间出现的。它的进化史,就是 AI 一步步获得"感知 → 规划 → 行动 → 反思"能力的过程。

时代代表能做什么缺什么
1960sELIZA模式匹配,假装聊天没有任何真正理解
1990s专家系统按规则推理规则靠人写,换个领域就废了
2010sSiri / Alexa语音识别 + 简单指令只能执行预设命令,不会规划
2020GPT-3能理解自然语言,"很会聊"只会说不会做,没有工具
2022ChatGPT更好的对话 + 一些插件工具调用还很弱
现在AI Agent理解 + 规划 + 行动 + 反思稳定性、安全性还在完善中

4.3.2 三个拐点

Agent 真正走向实用的三个关键拐点:

拐点一:LLM 变聪明了。 以前的 AI 你问它"帮我安排明天的行程",它连你要干嘛都听不懂。现在的 LLM 不仅能听懂,还能帮你拆分步骤、做决策。

拐点二:AI 能调用工具了。 Function Calling 让 AI 不再只能"说",它可以真正去查数据库、调 API、执行代码。这是 Agent 从"聊天玩具"到"能干活的助手"最关键的一步。

拐点三:记忆变长了。 早期模型上下文窗口只有几千 token,聊几句就忘了前面说了什么。现在几十万 token 的上下文,Agent 能记住整个项目的对话历史、你的偏好、之前的决策。


4.3.3 Go 赶上这波了吗?

三个拐点里,Go 在"拐点二"之前确实缺席——训练模型、做推理,那是 Python 和 C++ 的天下。但从拐点二开始,大量 AI 基础设施是用 Go 写的

  • Kubernetes 的 AI 调度器(Go)
  • 向量数据库的查询引擎(Milvus 的 Go SDK)
  • API 网关的智能路由(Go)
  • 字节的 Eino 框架(Go)

Go 在 Agent 时代的角色:不是造发动机的,是用发动机造车的。 别人训好了模型,你用 Go + Eino 把它变成能干活的服务——这恰恰是 Go 最擅长的。


4.4 你的 Agent 适合哪种"工种"?

不是所有 Agent 都是全能的。根据应用场景,Agent 大致分成几类:

4.4.1 对话型 Agent

做什么:跟人聊天、回答问题、提供建议。 典型场景:智能客服、法律咨询助手、教育辅导。 核心能力:感知(理解用户意图)+ 简单行动(查询知识库)。 限制:一般不做复杂任务执行,偏"参谋"角色。

4.4.2 任务型 Agent

做什么:接收目标,自主规划步骤,调用工具完成任务。 典型场景:自动化运维、数据分析、代码生成。 核心能力:规划 + 行动为主,反思能力决定了任务完成质量。 特点:这是本书重点讲的类型——真正能干活的那种。

4.4.3 协作型 Agent

做什么:多个 Agent 分工协作,每人管一块。 典型场景:软件开发团队(一个写代码、一个审代码、一个写测试)、多部门数据整合分析。 核心能力:每个 Agent 有自己的角色和职责,需要通信和协作机制。 特点:这个第 9 章会详细展开。Go 的 goroutine + channel 在这里有天然优势——Agent 之间"说话"就是 channel 通信。

4.4.4 陪伴型 Agent

做什么:记住你的习惯、偏好,提供个性化服务。 典型场景:个人助理、健康管家、学习伴侣。 核心能力:长期记忆 + 情景记忆为主。 特点:不强调复杂的任务执行,强调"懂你"。


4.5 用 Eino 跑通第一个 Agent

理论讲完了,是时候写代码了。我们用 Eino 跑一个极简的 Agent,总共不到 30 行。

4.5.1 准备工作

bash
# 初始化项目
mkdir first-agent && cd first-agent
go mod init first-agent

# 安装 Eino
go get github.com/cloudwego/eino@latest

4.5.2 第一个 Agent:让它说句话

我们先从最简单的开始——一个 Agent,你问它什么,它回答什么。没有工具、没有记忆、没有规划。但它是你第一个真正用 Eino 跑起来的 Agent

go
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/cloudwego/eino/components/model"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"
)

func main() {
    ctx := context.Background()

    // 第一步:创建 ChatModel(决定用哪个大模型)
    chatModel, err := model.NewChatModel(ctx, &model.ChatModelConfig{
        Model:  "gpt-3.5-turbo",
        APIKey: os.Getenv("OPENAI_API_KEY"),
    })
    if err != nil {
        panic(err)
    }

    // 第二步:创建一个 Chain(把模型包起来)
    chain := compose.NewChain[[]*schema.Message, *schema.Message]().
        AppendChatModel(chatModel)

    // 第三步:编译 Chain
    runnable, err := chain.Compile(ctx)
    if err != nil {
        panic(err)
    }

    // 第四步:发送消息
    input := []*schema.Message{
        schema.UserMessage("你好,请用一句话介绍你自己"),
    }

    output, err := runnable.Invoke(ctx, input)
    if err != nil {
        panic(err)
    }

    fmt.Println(output.Content)
}

没有 API Key?用 Mock 模式(还记得第 2 章讲的吧):

go
// 用 Mock ChatModel 替代真实模型
type MockChatModel struct{}

func (m *MockChatModel) Generate(ctx context.Context, 
    input []*schema.Message, opts ...model.Option) (*schema.Message, error) {
    return schema.AssistantMessage(
        "你好!我是你的 AI Agent 助手(Mock 模式)。准备好了吗?",
    ), nil
}

4.5.3 再加点料:让它能汇报时间

刚才的 Agent 只会聊天,不算真正的 Agent——因为它没有"行动"能力。我们给它加一个工具:获取当前时间。

go
import (
    "context"
    "fmt"
    "time"
    
    "github.com/cloudwego/eino/components/tool"
)

// 定义一个获取时间的工具
type GetTimeTool struct{}

func (t *GetTimeTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
    return &schema.ToolInfo{
        Name: "get_current_time",
        Desc: "获取当前的日期和时间",
    }, nil
}

func (t *GetTimeTool) InvokableRun(ctx context.Context, 
    params string) (string, error) {
    now := time.Now()
    return now.Format("2006-01-02 15:04:05"), nil
}

func main() {
    // ... 创建 ChatModel 的代码同上 ...

    // 创建工具
    timeTool := &GetTimeTool{}

    // 把模型和工具组合成 Agent
    agent, err := compose.NewAgent[[]*schema.Message, *schema.Message]().
        WithChatModel(chatModel).
        WithTools([]tool.InvokableTool{timeTool}).
        Compile(ctx)

    if err != nil {
        panic(err)
    }

    // 问它时间——它会自己决定调用工具
    input := []*schema.Message{
        schema.UserMessage("现在几点了?"),
    }

    output, err := agent.Invoke(ctx, input)
    if err != nil {
        panic(err)
    }

    fmt.Println(output.Content)
    // 输出:"现在是 2025-03-15 14:30:22"
}

这就是一个完整 Agent 的最小骨架——理解意图 + 调用工具 + 生成回答。后面的章节会在这个骨架上,一步步加上记忆、规划、多工具编排。


4.6 本章小结

这一章我们给 Agent"祛魅"了,还顺便跑通了第一个:

  1. Agent 不是什么魔法:它只是同时具备了感知、规划、行动、反思四项能力的程序。缺了规划和反思的,最多算半吊子。
  2. Agent 和传统程序完全不同:传统程序走固定流程,Agent 根据目标自主决策。不确定性不是缺陷,是特性。
  3. Agent 是进化来的:从 ELIZA 到 GPT-4,三大拐点让 Agent 从玩具变成了生产力。Go 在拐点二之后找到了自己的位置——用发动机造车。
  4. Agent 也分"工种":对话型、任务型、协作型、陪伴型。本书重点讲任务型,用 goroutine + channel 做协作型。
  5. 你用 Eino 跑通了第一个 Agent:一个能理解问题、调用工具、生成回答的完整 Agent 骨架。

✅ 知识点检查

学完这一章,试试回答这几个问题:

  • [ ] 一个真正的 Agent 必须具备哪四项能力?缺了哪一项就不算完整?
  • [ ] 传统程序和 Agent 的核心区别是什么?用订餐的例子说明。
  • [ ] Agent 进化史上三个关键拐点分别是什么?Go 在哪一阶段开始发力?
  • [ ] 任务型 Agent 和对话型 Agent 最大的不同在哪?
  • [ ] 用 Eino 创建一个 Agent 需要哪几个步骤?

📚 延伸阅读


🎯 下一章预告

第 5 章,我们给 Agent 装一个大脑——

"LLM 是怎么想事情的?看完这一章,你就知道 Agent 的'思考'到底是怎么回事——以及怎么用 Eino 的 ChatModel 让它'想'得更好。"