AI AI树洞

Chapter 01

第一章 初识智能体

这一章解决入门阶段最重要的三个问题:智能体是什么,大语言模型为什么改变了智能体的构建方式,以及如何用一个最小代码示例体验“观察-思考-行动-反馈”的循环。

本章学习目标

概念目标 理解 Agent、环境、目标、状态、观察、行动、工具、反馈和自治度。
代码目标 运行 first_agent.py,理解工具注册、模型决策和行动循环。
判断目标 能区分 Chatbot、Workflow、Copilot 与 Agent,避免把所有 AI 应用都叫智能体。

1.1 什么是智能体?

智能体不是大语言模型时代才出现的概念。更早的人工智能教材会把智能体描述为:处在某个环境中,能够通过传感器感知环境,并通过行动影响环境的系统。这个定义很宽,扫地机器人、游戏角色、交易程序、自动驾驶系统都可以被看作某种智能体。

对开发者来说,可以把智能体理解成一个“有目标的软件执行者”。它不是只回答一句话,而是围绕目标持续读取状态、选择行动、观察结果,并决定是否继续。这个持续循环让它和普通函数、单轮问答、固定工作流拉开距离。

组成 解释 例子
目标 智能体要达成的结果。 整理一份资料摘要、完成一次网页表单填写、生成并验证测试。
环境 智能体能读取和影响的外部世界。 网页、文件系统、数据库、对话上下文、代码仓库。
观察 智能体从环境中获得的新信息。 搜索结果、命令输出、接口响应、用户反馈。
行动 智能体对环境采取的操作。 调用工具、写文件、请求 API、询问用户、结束任务。
入门定义: AI Agent 是一个在给定边界内,为了完成目标而持续感知环境、选择行动并利用反馈调整行为的软件系统。

1.1.2 大语言模型驱动的新范式

传统 Agent 往往依赖人工设计的状态空间、动作空间和规则。大语言模型出现后,很多原本要手写的理解和决策逻辑可以交给模型完成:它可以读懂自然语言任务,解释工具说明,生成计划草稿,选择函数调用参数,并把观察结果转化为下一步判断。

这并不意味着 LLM 本身就是完整 Agent。模型更像一个强大的决策核心,而 Agent 系统还需要工具层、状态层、权限层、执行层、日志层和人工接管层。只把一个聊天模型接到前端,不会自动变成可靠智能体。

Instruction 用户目标、系统规则和任务约束。
LLM 理解任务、生成计划、选择行动。
Tools 搜索、计算、数据库、浏览器、代码执行。
Memory 历史记录、运行状态、长期知识。
Guardrail 权限、预算、校验、人工确认。

1.1.3 智能体的类型

入门阶段可以从决策方式和自治程度给智能体分类。分类不是为了背概念,而是为了帮助你判断应该采用什么实现。

类型 特点 适合任务 实现重点
简单反射型 根据当前输入直接匹配动作。 规则提醒、客服分流、简单分类。 规则库、优先级、兜底回复。
基于状态型 保存历史和当前状态,再决定下一步。 多轮客服、学习助手、表单补全。 状态结构、历史摘要、恢复机制。
目标驱动型 围绕目标规划和执行多个步骤。 资料调研、代码修复、旅行规划。 计划拆解、工具调用、停止条件。
效用驱动型 在多个候选行动中选择收益更高的行动。 推荐、调度、资源分配、策略选择。 评分函数、反馈信号、风险约束。
学习型 根据反馈不断调整策略。 个性化助手、游戏智能体、自动优化系统。 数据闭环、评估、在线或离线学习。

1.2 智能体的构成与运行原理

1.2.1 任务环境定义

设计 Agent 前,先定义任务环境。经典方法会从性能指标、环境、执行器和传感器四个维度分析。换成工程语言,就是先问清楚:怎么判断成功,系统能看见什么,能做什么,做错了有什么后果。

维度 要回答的问题 Agent 项目示例
性能指标 系统怎样算完成得好? 答案准确率、引用完整性、执行耗时、人工接管率。
环境 Agent 与哪些外部对象交互? 浏览器、知识库、代码仓库、数据库、用户会话。
执行器 Agent 能采取哪些动作? 搜索、读取文件、写入草稿、提交表单、调用接口。
传感器 Agent 如何获得反馈? 工具返回值、测试结果、页面文本、用户确认、日志状态。

1.2.2 智能体的运行机制

现代 LLM Agent 的最小运行机制可以抽象为五步:输入目标、构造上下文、模型决策、执行行动、记录反馈。这个过程会反复进行,直到任务完成、预算耗尽、遇到风险或需要人工确认。

Goal 明确用户想达成的目标和限制。
Context 汇总状态、历史、工具说明和观察。
Decision 模型输出下一步行动或结束信号。
Action 调用工具或向用户提问。
Feedback 把工具结果写回状态,进入下一轮。

1.2.3 智能体的感知与行动

“感知”不只是摄像头或传感器。在软件 Agent 里,感知可以是读网页、读文件、读数据库、读命令行输出。行动也不只是机器人运动,它可以是调用函数、生成文件、发送请求、运行测试或把任务交回给人。

生产系统里,行动必须比感知更谨慎。读取网页通常是低风险,删除数据、发邮件、付款、封禁账号就是高风险。高风险行动应该要求人工确认,并记录完整审计信息。

1.3 动手体验:实现第一个智能体

下面的示例是一个最小 Agent。它有两个工具:计算器和笔记保存器。模型决策部分用离线脚本模拟,这样你不用配置 API Key 就能运行;实际接入 LLM 时,只需要替换 call_model 方法。

import json
import re
from dataclasses import dataclass
from typing import Callable


@dataclass
class Tool:
    name: str
    description: str
    handler: Callable[[dict], str]


def calculator(args: dict) -> str:
    expression = str(args.get("expression", ""))
    if not re.fullmatch(r"[0-9+\-*/(). ]+", expression):
        return "表达式包含不允许的字符"
    return str(eval(expression, {"__builtins__": {}}, {}))


def write_note(args: dict) -> str:
    title = str(args.get("title", "untitled"))
    content = str(args.get("content", ""))
    return f"已写入笔记:{title},正文 {len(content)} 字"


TOOLS = {
    "calculator": Tool("calculator", "执行基础数学计算", calculator),
    "write_note": Tool("write_note", "保存一条文本笔记", write_note),
}


class FirstAgent:
    def __init__(self, tools: dict[str, Tool], max_steps: int = 5) -> None:
        self.tools = tools
        self.max_steps = max_steps
        self.observations: list[str] = []

    def build_prompt(self, task: str) -> str:
        tool_text = "\n".join(f"{tool.name}: {tool.description}" for tool in self.tools.values())
        history = "\n".join(self.observations[-3:]) or "暂无观察"
        return (
            f"任务:{task}\n"
            f"可用工具:\n{tool_text}\n"
            f"历史观察:\n{history}\n"
            '请输出 JSON:{"action":"tool","tool":"工具名","args":{}} '
            '或 {"action":"finish","answer":"最终答案"}'
        )

    def call_model(self, prompt: str) -> str:
        if not any("calculator" in item for item in self.observations):
            return json.dumps(
                {"action": "tool", "tool": "calculator", "args": {"expression": "23 * 17 + 8"}},
                ensure_ascii=False,
            )
        if not any("write_note" in item for item in self.observations):
            return json.dumps(
                {
                    "action": "tool",
                    "tool": "write_note",
                    "args": {"title": "第一次 Agent 运行", "content": "先计算,再保存观察结果。"},
                },
                ensure_ascii=False,
            )
        return json.dumps({"action": "finish", "answer": "计算结果为 399,笔记已保存。"}, ensure_ascii=False)

    def parse_action(self, raw: str) -> dict:
        action = json.loads(raw)
        if action.get("action") not in {"tool", "finish"}:
            raise ValueError("action 必须是 tool 或 finish")
        return action

    def run(self, task: str) -> str:
        for step in range(1, self.max_steps + 1):
            prompt = self.build_prompt(task)
            action = self.parse_action(self.call_model(prompt))
            if action["action"] == "finish":
                return action["answer"]

            tool_name = action.get("tool")
            if tool_name not in self.tools:
                return f"停止:未知工具 {tool_name}"

            result = self.tools[tool_name].handler(action.get("args", {}))
            self.observations.append(f"第 {step} 步 {tool_name} 返回:{result}")

        return "停止:超过最大步数"


if __name__ == "__main__":
    agent = FirstAgent(TOOLS)
    print(agent.run("计算 23 * 17 + 8,并保存运行记录"))
    print("\n执行轨迹:")
    for observation in agent.observations:
        print("-", observation)

配套文件:first_agent.py。如果你想看更短的版本,也可以打开 pocket_agent.py

1.3.2 接入大语言模型

把离线脚本换成真实模型时,推荐保持同一个接口:输入 messages,输出严格 JSON。不要让工具层直接执行模型生成的自然语言;先解析、校验、确认工具存在,再调用工具。

def call_model_with_api(messages: list[dict]) -> str:
    """
    伪代码:把这里替换成你使用的模型 SDK。
    关键要求是让模型只返回 JSON,不要夹带解释。
    """
    response = client.chat.completions.create(
        model="your-model",
        messages=messages,
        temperature=0.1,
    )
    return response.choices[0].message.content

实际项目还要加入超时、重试、限流、日志脱敏和成本统计。这些不是“工程洁癖”,而是 Agent 能否稳定运行的基础。

1.3.4 运行案例分析

运行示例时,你会看到 Agent 先调用计算器,再保存笔记,最后返回结果。这个流程虽然简单,但已经具备智能体骨架:目标来自用户,工具来自系统,模型决定下一步,观察写回状态,循环直到完成。

步骤 发生了什么 为什么重要
构造 Prompt 把目标、工具和历史观察交给模型。 模型只能基于它看到的信息决策。
解析 JSON 把模型文本转成结构化行动。 防止自然语言直接进入工具层。
调用工具 执行计算或写笔记。 Agent 通过工具影响环境。
记录观察 把工具返回值写入历史。 下一轮决策需要基于反馈调整。

1.4 智能体应用的协作模式

1.4.1 作为开发者工具的智能体

开发者工具类 Agent 常见于代码编辑器、测试修复、文档生成和运维排障。它们通常拥有读写文件、运行命令、检查错误的工具,但权限应该受目录、命令白名单和人工确认限制。

1.4.2 作为自主协作者的智能体

自主协作者类 Agent 更接近“你给它一个目标,它自己推进”。例如调研助手会搜索资料、筛选来源、生成报告、补引用。它的价值在于处理开放路径任务,但也更需要预算、日志和接管机制。

1.4.3 Workflow 和 Agent 的差异

维度 Workflow Agent
执行路径 预先定义,节点顺序固定。 根据观察动态选择下一步。
适合任务 稳定流程、审批、格式转换。 调研、排障、复杂问答、多工具任务。
可控性 高,行为容易预测。 需要额外边界和评估。
失败处理 按固定分支处理。 需要根据失败原因重试、改计划或交给人。
实践建议: 能用 Workflow 稳定解决的问题,不要强行做成 Agent;只有当路径不确定、需要多轮观察和工具选择时,Agent 才真正有优势。

1.5 本章小结

本章从传统 Agent 定义讲到 LLM Agent 新范式,再用代码实现了一个最小智能体。你应该已经能看出:Agent 的关键不是“会聊天”,而是能围绕目标在环境中行动,并用反馈调整下一步。

下一章会回到历史:为什么早期 AI 如此重视符号和规则,专家系统解决了什么问题,ELIZA 这类规则聊天机器人为什么重要,以及这些思想如何影响今天的大语言模型智能体。

习题

  1. 练习 1.1:概念判断。 分别判断“自动生成 10 个标题”“根据搜索结果写调研报告”“自动删除违规内容”更适合 Chatbot、Workflow、Copilot 还是 Agent,并说明理由。
  2. 练习 1.2:新增工具。FirstAgent 增加 get_time 工具,并让模型在写笔记前先读取当前时间。
  3. 练习 1.3:加入工具白名单。 修改 parse_action,当模型请求未授权工具时抛出错误,而不是直接返回字符串。
  4. 练习 1.4:接入真实模型。call_model 替换为你熟悉的模型 API,并保证模型只输出 JSON。
  5. 练习 1.5:写任务环境分析。 选一个你想做的 Agent,按性能指标、环境、执行器、传感器四项写成表格。

参考文献