agent教程S01-Agent 最小循环教程整理

S01-Agent最小循环教程

第一部分:提出问题:原生大模型只能聊天,无法变成自主干活的Agent

1. 现存现象(原生LLM的天然短板)

大语言模型(LLM)本质是文本生成器,只会根据输入续写文字,天生无法自主落地实操任务,做不到4件关键操作:

  1. 不能自主打开文件、执行终端/程序命令;
  2. 无法查看工具运行后的报错、返回数据;
  3. 不会主动触发外部工具调用;
  4. 拿不到工具执行结果,没办法根据真实结果继续调整思路、推进剩余任务。

2. 我们的目标需求

把「只会打字聊天的大模型」升级为智能体Agent:收到用户复杂指令后,自主判断何时调用工具、执行工具、依据真实运行结果迭代思考,分步完成完整任务。

3. 核心待解决问题

缺少一套中间调度逻辑,打通链路:模型思考输出→工具真实执行→结果反馈回模型→新一轮思考,这是本章节要解决的唯一核心。

关键结论前置:没有循环,就没有真正可用的Agent

第二部分:分析问题:拆解Agent无法落地的底层逻辑与基础概念

1. 问题根源:缺失闭环数据流

如果没有代码搭建循环:

模型输出工具调用指令后,指令不会被真实执行;即便工具运行出数据,运行结果只打印在控制台,无法写入上下文传给模型

模型永远看不到现实世界的真实反馈,每一轮推理都是孤立的,没办法基于上一步结果做下一步决策,永远停留在单次文字生成。

2. 4个核心名词通俗翻译(新手必记)

专业名词 大白话解释
Loop(循环) 不是程序死循环;只要任务没做完,固定重复一套执行步骤,持续迭代
Turn(一轮) 单次完整运行周期:消息入模型→获取回复→按需调用工具→结果存档→准备下一轮
tool_result(工具结果) 不只是终端日志,必须存入对话历史,成为模型下一轮的输入素材
state(运行状态) 循环全程随身带的数据;最小版本=历史消息列表+运行轮次+继续循环的理由

3. Agent核心心智流程图(简化版)

复制代码
用户提问消息 → 送入LLM做推理
├─分支1:模型直接输出最终答案 → 任务结束,循环终止
└─分支2:模型决定调用工具 → 程序执行工具 → 生成tool_result → 结果写入消息历史 → 带着新数据开启新一轮模型调用

灵魂关键点:工具结果必须回写到消息历史,缺这一步,Agent闭环直接断裂。

4. 三类关键数据结构的设计目的(为什么必须这么设计)

(1)Message消息结构体

格式:{"role": "user/assistant", "content": "内容"}

作用:存储全量对话上下文,是模型每一轮推理的原始输入 ,≠前端聊天框展示文案。

坑点:只保存用户消息、丢弃助手回复 → 上下文断层,模型忘记上一轮自己的操作。

(2)Tool Result Block工具结果块
json 复制代码
{"type": "tool_result","tool_use_id":"对应工具ID","content":"工具输出内容"}

作用:依靠tool_use_id绑定「本次结果」和「对应那次工具调用」,避免模型分不清哪条结果对应哪次指令。

(3)LoopState循环状态集合
python 复制代码
state = {"messages": [], "turn_count": 1, "transition_reason": None}

作用:收拢所有循环变量,不用零散定义全局变量;transition_reason标记本轮继续循环的原因,入门只用tool_result(刚跑完工具,需要回传结果继续思考)。

第三部分:解决问题:落地最小可用Agent循环(代码分步+避坑+迭代规划)

1. 单轮Turn分步实现(5步最小流程)

步骤1:初始化消息,存入用户原始提问
python 复制代码
messages = [{"role": "user", "content": 用户输入的查询语句}]
步骤2:调用大模型接口

携带系统提示词(SYSTEM)、工具清单(TOOLS)、全量历史消息,向模型发起请求。

步骤3:强制追加助手回复到messages(新手最高频漏写)

模型返回的assistant内容必须存入消息列表,保存本轮模型思考,否则上下文断裂。

python 复制代码
messages.append({"role": "assistant", "content": response.content})
步骤4:识别并执行工具

遍历模型返回内容,筛选tool_use类型(工具调用指令),逐个运行对应工具,收集全部输出结果。

步骤5:工具结果打包回写消息

把所有tool_result以user角色追加进messages,完成单轮闭环,开启下一轮循环。

2. 完整封装:最小agent_loop主循环函数

python 复制代码
def agent_loop(state):
    while True:
        # 1. 携带状态里的上下文调用模型
        response = client.messages.create(model=MODEL,system=SYSTEM,messages=state["messages"],tools=TOOLS,max_tokens=8000)
        # 2. 保存本轮助手回复到消息历史
        state["messages"].append({"role": "assistant", "content": response.content})
        # 3. 模型不调用工具,直接结束循环
        if response.stop_reason != "tool_use":
            state["transition_reason"] = None
            return
        # 4. 执行所有工具调用,收集结果
        results = []
        for block in response.content:
            if block.type == "tool_use":
                output = run_tool(block) # 执行工具
                results.append({"type": "tool_result","tool_use_id": block.id,"content": output})
        # 5. 工具结果写入消息,更新状态,进入下一轮
        state["messages"].append({"role": "user", "content": results})
        state["turn_count"] += 1
        state["transition_reason"] = "tool_result"

逻辑说明 :while True维持循环;stop_reason="tool_use"是入门简化终止条件,只有模型要调用工具时才继续循环。

3. 简化设计说明:为什么入门只用stop_reason做终止判断?

初学阶段优先目标:跑通完整闭环链路 ,不纠结复杂边界。只用单一终止条件可以聚焦三件核心:

① 助手回复写入历史;② tool_result写入历史;③ 循环持续迭代。

复杂终止、异常判断、多分支续行逻辑,放到后续章节补充。

4. 初学者5大致命踩坑清单

  1. 工具结果只打印控制台,不写入messages:模型看不到真实运行数据,无法迭代;
  2. 只存用户消息,丢弃assistant回复:上下文断层,模型丢失自身上一轮思考记录;
  3. tool_result不绑定tool_use_id:模型无法匹配结果与工具调用,指令和结果错乱;
  4. 入门就堆砌流式输出、异常重试、权限管控:基础闭环逻辑被复杂功能掩盖,学不会核心;
  5. 错把messages当成聊天展示数据:messages是Agent的工作记录本、模型的输入上下文,不是前端展示文案。

5. 后续迭代拓展(本章节是Agent底座)

S01只完成最小闭环,后续s系列章节在当前循环基础上叠加能力:

  • s02:接入工具路由管理
  • s03:新增任务规划状态
  • s06:上下文自动压缩
  • s07:工具权限校验
  • s11:工具报错自动恢复

6. 最终一句话总结(牢记Agent本质)

Agent Loop(智能体循环)= 把模型空想的工具指令落地成真实结果,再将结果回喂模型,驱动下一轮持续推理

基于DeepSeek API|3阶入门Agent实战案例(沿用前文Agent循环架构|新手可直接复制运行)

前置准备:

  1. 安装依赖:pip install openai(DeepSeek 兼容OpenAI SDK调用格式)
  2. 前往DeepSeek官网获取API_KEY,替换代码内DEEPSEEK_API_KEY
  3. 接口地址:base_url="https://api.deepseek.com",模型固定:model="deepseek-chat"
    统一代码架构:完全复用上一教程agent_loop循环逻辑,3个案例工具逐个升级,难度循序渐进

公共前置配置(所有案例共用头部代码,放在文件最上方)

python 复制代码
from openai import OpenAI

# 1、DeepSeek全局配置
DEEPSEEK_API_KEY = "你的DeepSeek密钥"
client = OpenAI(
    api_key=DEEPSEEK_API_KEY,
    base_url="https://api.deepseek.com"
)
MODEL = "deepseek-chat"
SYSTEM = "你是具备工具调用能力的AI智能体,遇到数学计算、时间查询、文件操作需求必须调用对应工具,禁止自己编造结果。工具执行完成拿到结果后再汇总答案。"

案例1:Agent自带四则计算器工具【入门:单工具、纯数值运算】

提出问题

用户输入数学计算题(如(25+75)*8/2),大模型容易计算出错;需要让AI自主调用计算器工具,通过程序精准运算,不能AI心算。

分析问题

  1. 模型无法精准做复杂四则运算,依赖自身推理容易出错;
  2. 设计1个calculator工具,接收计算公式字符串,代码运行求值;
  3. 沿用Agent循环:用户提问→模型判断要调用计算器→执行代码计算→结果回填消息→模型整理答案结束循环。

解决问题:完整可运行代码

python 复制代码
# ==========案例1:计算器工具定义==========
def run_tool(tool_info):
    """工具分发函数,匹配工具名称执行对应逻辑"""
    if tool_info.name == "calculator":
        expr = tool_info.parameters["expr"]
        try:
            res = eval(expr)
            return f"算式{expr}的计算结果:{res}"
        except Exception as e:
            return f"计算失败,错误:{str(e)}"

# 工具描述:告诉模型可用的工具
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "calculator",
            "description": "用于四则数学运算,传入数学表达式字符串,返回计算结果",
            "parameters": {
                "type": "object",
                "properties": {
                    "expr": {"type": "string", "description": "数学计算公式,例如:(12+38)*5"}
                },
                "required": ["expr"]
            }
        }
    }
]

# 智能体主循环(和教程原版逻辑完全一致)
def agent_loop(user_input):
    state = {
        "messages": [{"role": "user", "content": user_input}],
        "turn_count": 1,
        "transition_reason": None
    }
    while True:
        resp = client.chat.completions.create(
            model=MODEL,
            messages=state["messages"],
            tools=TOOLS
        )
        choice = resp.choices[0]
        msg = choice.message
        # 保存模型本轮回答到上下文
        state["messages"].append(msg.model_dump(exclude_none=True))

        # 没有工具调用,循环结束,输出答案
        if not msg.tool_calls:
            print("【最终回答】", msg.content)
            return

        # 执行所有工具
        tool_returns = []
        for tool_call in msg.tool_calls:
            tool_res = run_tool(tool_call.function)
            tool_returns.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": tool_res
            })
        # 工具结果写入消息,开启下一轮思考
        state["messages"].extend(tool_returns)
        state["turn_count"] += 1

# 测试运行
if __name__ == "__main__":
    agent_loop("帮我计算 (125+375)*12/5 - 99")

运行说明

模型识别数学公式→调用calculator→Python代码运算→结果回传给DeepSeek→AI整理结果输出。


案例2:系统时间查询工具【进阶:调用Python内置库获取真实环境数据】

提出问题

大模型知识库时间固定,不知道本机当前年月日时分,无法回答「现在几点、今天日期」;需要调用Python datetime获取本机真实时间。

分析问题

  1. LLM没有实时系统时间,不能凭空生成当前时间;
  2. 新增get_current_time工具,使用datetime获取系统时间;
  3. 循环逻辑不变,仅修改TOOLS和run_tool,实现时间查询。

解决问题:完整可运行代码

python 复制代码
from datetime import datetime

# ==========案例2:时间查询工具==========
def run_tool(tool_info):
    if tool_info.name == "get_current_time":
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        return f"当前系统时间:{now}"

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_current_time",
            "description": "获取服务器/本机当前的年月日、时分秒实时时间,无入参",
            "parameters": {"type": "object", "properties": {}, "required": []}
        }
    }
]

# agent_loop函数和案例1完全一模一样,无需改动直接复用
def agent_loop(user_input):
    state = {
        "messages": [{"role": "user", "content": user_input}],
        "turn_count": 1,
        "transition_reason": None
    }
    while True:
        resp = client.chat.completions.create(
            model=MODEL,
            messages=state["messages"],
            tools=TOOLS
        )
        choice = resp.choices[0]
        msg = choice.message
        state["messages"].append(msg.model_dump(exclude_none=True))

        if not msg.tool_calls:
            print("【最终回答】", msg.content)
            return

        tool_returns = []
        for tool_call in msg.tool_calls:
            tool_res = run_tool(tool_call.function)
            tool_returns.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": tool_res
            })
        state["messages"].extend(tool_returns)
        state["turn_count"] += 1

# 测试
if __name__ == "__main__":
    agent_loop("现在是什么日期和具体时间?")

案例3:本地TXT文件读写工具【实战:贴近真实办公,多参数工具】

提出问题

用户需要AI帮忙把一段话保存到本地txt、读取已有文件内容;模型不能直接操作电脑文件,必须通过文件读写工具实现。

分析问题

  1. LLM无法直接操作系统文件,需要封装write_file(写入)、read_file(读取)两个工具;
  2. 工具入参包含文件名、文本内容,实现多参数传入;
  3. Agent自动判断用户需求是读还是写,自主选择对应工具。

解决问题:完整可运行代码

python 复制代码
# ==========案例3:文件读写双工具==========
def run_tool(tool_info):
    if tool_info.name == "write_file":
        # 解析入参
        file_name = tool_info.parameters["file_name"]
        content = tool_info.parameters["content"]
        try:
            with open(file_name, "w", encoding="utf-8") as f:
                f.write(content)
            return f"成功:内容已写入{file_name}"
        except Exception as e:
            return f"写入失败:{str(e)}"
    elif tool_info.name == "read_file":
        file_name = tool_info.parameters["file_name"]
        try:
            with open(file_name, "r", encoding="utf-8") as f:
                text = f.read()
            return f"文件{file_name}内容:\n{text}"
        except Exception as e:
            return f"读取失败:{str(e)}"

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "将文本内容写入本地txt文件",
            "parameters": {
                "type": "object",
                "properties": {
                    "file_name": {"type": "string", "description": "文件名,如note.txt"},
                    "content": {"type": "string", "description": "需要保存的文本"}
                },
                "required": ["file_name", "content"]
            }
        }
    },
    {
        "type": "function",
        "name": "read_file",
        "description": "读取本地txt文件的全部内容",
        "parameters": {
            "type": "object",
            "properties": {"file_name": {"type": "string", "description": "待读取的文件名"}},
            "required": ["file_name"]
        }
    }
]

# agent_loop代码复用,不用修改
def agent_loop(user_input):
    state = {
        "messages": [{"role": "user", "content": user_input}],
        "turn_count": 1,
        "transition_reason": None
    }
    while True:
        resp = client.chat.completions.create(
            model=MODEL,
            messages=state["messages"],
            tools=TOOLS
        )
        choice = resp.choices[0]
        msg = choice.message
        state["messages"].append(msg.model_dump(exclude_none=True))

        if not msg.tool_calls:
            print("【最终回答】", msg.content)
            return

        tool_returns = []
        for tool_call in msg.tool_calls:
            tool_res = run_tool(tool_call.function)
            tool_returns.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": tool_res
            })
        state["messages"].extend(tool_returns)
        state["turn_count"] += 1

# 测试:先写入再读取
if __name__ == "__main__":
    # 任务1:写入文件
    agent_loop("把'DeepSeek Agent入门学习笔记:智能体循环=思考→调用工具→结果回传'保存到note.txt")
    # 任务2:读取文件
    agent_loop("读取note.txt里面的内容")

新手练习拓展指引

  1. 练手修改1:在案例1新增开方、取余工具;
  2. 练手修改2:案例2新增查询星期几的逻辑;
  3. 练手修改3:案例3新增追加写入(append)工具;
  4. 核心记忆点 :所有Agent万变不离其宗------模型思考→工具执行→结果入上下文→下一轮思考,和前文教程闭环逻辑保持一致。
相关推荐
网络与设备以及操作系统学习使用者1 小时前
多路由设备静态路由配置详解
运维·网络·学习·华为·智能路由器
二哈赛车手1 小时前
新人笔记---继图片搜索功能后续以及AI网络搜索功能一些经验与踩坑点,吐槽一下自己在做这方面的崩溃瞬间
java·网络·人工智能·spring boot·笔记·spring
计算机安禾1 小时前
【算法分析与设计】第44篇:随机化复杂度类:RP、BPP与去随机化猜想
java·数据结构·数据库·算法·机器学习
IT大白鼠1 小时前
GRE协议原理与华为设备配置实践
网络·网络协议·华为
m0_641889291 小时前
2026最新GEO优化效果监测分析工具实测:Top 5平台深度横评
人工智能·大模型·agent·品牌营销·geo·智能营销·geo优化
RD_daoyi1 小时前
Google SEO第四周:深度站内优化——让网站快速收录、稳定排名的硬核技术
大数据·服务器·人工智能·搜索引擎
未若君雅裁1 小时前
Java 线程基础:进程、线程、并发并行、创建方式与生命周期
java·开发语言
未若君雅裁2 小时前
死锁产生条件与诊断:jps、jstack、VisualVM
java·开发语言
再玩一会儿看代码2 小时前
Java抽象类和接口区别_场景理解
java·开发语言·经验分享·笔记·python