AI AgentTechnical Deep Dive

AI Agent 入门:从概念到第一个可运行闭环

发布时间2025/11/01
分类AI Agent
预计阅读9 分钟
作者吴长龙
*

真正的 Agent 不是“会聊天的模型升级版”,而是能围绕目标做规划、调工具、检查结果并决定是否继续的执行系统。

01.为什么很多“Agent 项目”最后只是带工具的聊天流

第一次接触 Agent 时,最容易掉进两个误区:

  • 把 Agent 理解成“更聪明的 ChatGPT”
  • 把任何带工具调用的流程都叫 Agent

这两个理解都不够准确。

如果一个系统只是接收用户输入,然后固定按预设步骤调用几个 API,再把结果返回出来,它更接近“工作流自动化”而不是 Agent。真正有 Agent 特征的系统,至少要具备下面三个能力:

  • 它能围绕目标决定下一步做什么,而不是只能走写死的步骤
  • 它能根据环境反馈调整行为,而不是只执行一次
  • 它能在任务完成、失败或需要人工接管时,明确停下来

所以更贴近工程实践的定义是:

Agent 是一个围绕目标运行的执行系统。它使用模型做判断,调用外部工具完成动作,并根据结果继续规划或结束任务。

这个定义比“像人一样思考的智能体”更有用,因为它直接对应系统设计里的几个核心问题:目标怎么表达、工具怎么暴露、状态怎么保存、循环什么时候停止。

02.Agent、Copilot、工作流,分别解决什么问题

这三个概念经常被混在一起,但它们适合的场景差别很大。

类型输入输出关系是否自主决策典型场景
聊天/Copilot你问我答很弱写作辅助、代码补全、知识问答
工作流固定步骤串联无或极弱表单审批、定时报表、固定 ETL
Agent目标驱动,多步执行较强多工具排障、任务编排、开放式助理

经验上可以这样判断:

  • 如果步骤稳定、规则明确、异常少,优先做工作流
  • 如果主要价值是“理解上下文并给建议”,优先做 Copilot
  • 只有当任务路径不固定、需要动态选择工具或需要在反馈中持续调整时,才值得引入 Agent

这一步判断很重要。很多系统并不是“做不了 Agent”,而是“没必要做 Agent”。

03.一个最小 Agent 闭环应该包含什么

从实现角度看,Agent 不需要一上来就引入复杂框架。一个能跑起来的最小闭环,通常只需要 5 个部分:

1. 目标

目标不是随便一句用户输入,而是系统真正要完成的任务描述。例如:

  • “整理本周告警并生成值班摘要”
  • “根据用户问题查询知识库并返回带引用的答案”
  • “读取日志,判断故障类别并给出下一步排查建议”

目标越清晰,模型越容易做出稳定决策。

2. 状态

状态至少要记录:

  • 当前任务
  • 历史消息
  • 工具调用结果
  • 已执行步数
  • 是否结束

如果没有显式状态,Agent 很容易在多轮里失控,或者重复做同一件事。

3. 工具

工具是 Agent 接触外部世界的方式。常见类型包括:

  • 查询类:搜索、数据库、向量检索、日志检索
  • 操作类:发消息、创建工单、写文件、触发脚本
  • 计算类:代码执行、规则引擎、评分器

工具设计要尽量“小而稳”。一个职责清晰、参数简单的工具,比一个“万能工具”更容易让模型用对。

4. 决策器

通常由 LLM 承担,负责决定:

  • 现在能不能直接回答
  • 该调用哪个工具
  • 工具结果够不够支撑结论
  • 要不要继续下一轮

Agent 的“智能”主要体现在这里,但这里也最容易出错,所以必须配合边界控制和日志记录。

5. 终止条件

这是很多入门文章容易忽略的部分。没有终止条件的 Agent,基本等于一个潜在的死循环。

常见终止条件包括:

  • 任务完成
  • 达到最大步数
  • 关键工具连续失败
  • 命中人工接管规则

04.一个更靠谱的最小实现

下面这个例子不追求框架完整,而是把 Agent 闭环说清楚。它做的事情很简单:如果用户问天气,就调用工具;否则直接回答。

python snippetpython
from __future__ import annotations

import json
from dataclasses import dataclass, field
from typing import Any

from openai import OpenAI

client = OpenAI()


def get_weather(city: str) -> dict[str, str]:
    sample = {
        "北京": {"condition": "晴", "temperature": "25C"},
        "上海": {"condition": "多云", "temperature": "23C"},
    }
    return sample.get(city, {"condition": "未知", "temperature": "未知"})


TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询指定城市天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"}
                },
                "required": ["city"],
            },
        },
    }
]


@dataclass
class AgentState:
    user_query: str
    messages: list[dict[str, Any]] = field(default_factory=list)
    steps: int = 0
    finished: bool = False


def run_agent(query: str, max_steps: int = 4) -> str:
    state = AgentState(
        user_query=query,
        messages=[
            {
                "role": "system",
                "content": (
                    "你是一个任务助手。需要实时信息时调用工具。"
                    "如果信息不足,不要猜。"
                ),
            },
            {"role": "user", "content": query},
        ],
    )

    while not state.finished and state.steps < max_steps:
        state.steps += 1

        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=state.messages,
            tools=TOOLS,
        )
        message = response.choices[0].message

        if not message.tool_calls:
            state.finished = True
            return message.content or "未生成结果"

        state.messages.append(message.model_dump())

        for tool_call in message.tool_calls:
            if tool_call.function.name != "get_weather":
                continue

            args = json.loads(tool_call.function.arguments)
            result = get_weather(args["city"])

            state.messages.append(
                {
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": json.dumps(result, ensure_ascii=False),
                }
            )

    return "任务未在限定步数内完成,请转人工处理。"

这个版本有几个值得保留的点:

  • 有明确状态对象,而不是把所有变量散落在函数里
  • max_steps,避免无限循环
  • 工具返回结构化数据,方便模型继续消费
  • 当任务没完成时,会明确给出“转人工”的出口

这才是一个“能作为工程起点”的最小 Agent,而不是只展示一次工具调用。

05.Agent 最容易出问题的三个地方

决策边界过于模糊

如果系统提示、工具说明和任务目标都写得很泛,模型会在“该不该调用工具”上摇摆,表现就是同一个问题时而直接回答、时而乱调工具。

解决方式不是继续堆提示词,而是把边界写清楚:

  • 什么时候必须调用工具
  • 什么时候禁止臆测
  • 什么结果才算完成

工具设计过粗

比如只提供一个 run_anything 工具,让模型自己拼命令、自己猜参数,这种设计表面灵活,实际上最不稳定。

更好的方式是把工具拆成清晰动作,例如:

  • search_docs
  • get_incident_logs
  • create_ticket
  • send_summary

这样模型更容易选对,日志也更好排查。

没有人工接管点

生产环境里,Agent 不应该对所有问题都“硬做到底”。一旦遇到这些情况,应该及时停下:

  • 工具连续失败
  • 置信度不足
  • 涉及高风险操作
  • 输出会直接影响业务或用户

把“知道什么时候停”设计进去,往往比“多做一步”更重要。

06.什么时候值得做你的第一个 Agent

适合上手的题目通常有两个特点:

  • 工具边界比较清楚
  • 错误成本比较低

比如:

  • 文档问答助手
  • 日报或周报汇总助手
  • 简单的数据分析助理
  • 开发环境里的代码检索和 PR 摘要

不太适合一开始就做的题目包括:

  • 高风险自动执行系统
  • 跨多个内部系统的大编排
  • 需要强 SLA 的外部客服入口

先做一个小闭环,跑通目标、状态、工具和终止条件,再谈多 Agent、长期记忆、复杂工作流,会更稳。

07.总结

Agent 的关键不在“像不像人”,而在它是不是一个可控的执行闭环。只要你能回答清楚这几个问题,项目方向通常就不会跑偏:

  • 目标是什么
  • 模型负责什么判断
  • 工具边界在哪里
  • 状态如何保存
  • 系统何时停止或转人工

把这些基础打稳之后,再去引入 LangGraph、工作流编排、多 Agent 协作,才会真正变成工程能力,而不是概念堆砌。