AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

开始学习 Agent 前,需要补齐哪些基础?

我的学习 →

正在读取学习记录…

L0 带你把第一个 Python 程序跑起来,学会收发数据、保存结果、排查报错,再认识大模型怎样处理文字。掌握这些基础后,你就能看懂一个 Agent 程序由哪些部分组成,并开始动手搭自己的助手。

用一个客服小助手理解学习路线

假设你在网上买了一件商品,付款成功了,订单页面却没有显示。你给客服留言:“钱已经扣了,订单怎么没出来?”

客服会把这条留言记成一张工单。可以把工单理解成一张“待处理的问题记录”,里面有问题描述、负责的团队和处理进度。账单团队处理扣款问题,技术团队处理系统故障。

我们的小助手要帮客服做一件具体的事:把已确认的扣款问题交给账单团队。过程很直观:

步骤助手做什么你能看到什么
读取取出这条问题记录用户的留言和当前负责团队
处理把负责团队改成账单团队更新后的记录
确认再查看一次记录负责团队已经变为账单团队

这个例子会用到几种基础能力:Python 执行程序,HTTP 传递请求,数据库保存记录,测试检查结果。后面接入模型时,还会用到文字处理、资料检索和费用计算。先把这些环节学会,再把它们接起来。

各篇也有更小的例子,比如打印查询词、读取一条资料、比较两个向量。你可以先专注当前知识点,学完后再做下面的综合实践。

按这个顺序学习

第一次接触 Agent,可以按表中顺序学习;已有经验,可以先检查每篇的目标,直接补自己的缺口。

顺序文章学完后留下的最小产物或判断
01Python 类型、异常与虚拟环境说明正在使用哪一个解释器,能运行并修改一个独立脚本
02HTTP、REST 与 JSON区分请求、状态码、响应体,以及网络成功与任务成功
03异步、并发与超时给一个请求设置超时,并保留取消或结果未知的状态
04Git、命令行与版本控制提交可复现版本,并能撤回自己的一次改动
05Docker 与可复现环境解释镜像、容器、数据卷边界;具备网络条件时构建并运行
06日志、pytest 与 CI先让一个测试失败,再修复并留下运行记录
07SQL、事务与数据基础重放一次写入与故障回滚,说明单库事务没有覆盖哪些外部动作
08向量、余弦相似度与统计自己计算候选排序,并说明阈值变化后的误检与漏检
09Transformer 与概率生成直觉区分教学版注意力计算和完整语言模型生成
10Token 与上下文窗口为一条请求分配上下文预算,而不是用字数估算真实计费
11Embedding 与 Reranker 入门观察候选数量改变时,相关资料能否进入重排名单
12模型 API、密钥与环境变量用环境变量读取密钥和预算参数,不把密钥提交进仓库
13任务建模、自治边界与成功标准为示例工单写对象、动作、审批、停止状态和成功证据
14Token 计费、吞吐与成本意识分开记录已确认成本和未知预留,拒绝超预算请求

如果时间有限,先完成01、02、03、06、12、13、14:这条路线先备好运行环境和通信,给等待设置上限,用测试检查输入,再补密钥配置、任务边界与成本上限,形成最小闭环。其余篇目继续补版本复现、数据一致性、检索和生成原理;十四篇的学习范围保持完整。

学完后:把基础接成一个小助手

展开综合实践:更新一条客服问题记录
L0 十四篇按运行环境、读取资料、受控决定、回读测试四组能力汇入同一份离线工单助手作品
图 2:按运行环境、数据读取、执行判断和结果确认,把各篇的能力串起来。

例如 Python 和 Git 回答“运行的是哪一版”,HTTP 与 SQL 回答“读到了什么”,任务建模与预算回答“为什么允许下一步”,测试和回读回答“结果有没有发生”。第一次读总览时,先沿上面的目录学习;完成各篇跟做后,再回到这里将这些能力合成一份小作品。

在电脑上建一个 agentdepth-l0 文件夹,逐篇保存实验源码和运行记录。最后用一个离线工单助手串起来:读取练习工单、检查建议、决定拒绝或执行,再回读本地记录。将 app.py、test_app.py 按下方代码逐个保存到同一个空文件夹。

完整代码:app.py
Python
"""L0 离线工单练习:固定回复只用于检验程序边界。"""

import json
from typing import Callable


def _result(ticket_id: str, status: str, *, suggestion=None, tool_result=None, readback=None, reason="") -> dict:
    return {
        "ticket_id": ticket_id,
        "status": status,
        "suggestion": suggestion,
        "tool_result": tool_result,
        "readback": readback,
        "reason": reason,
    }


def process_ticket(
    ticket: dict,
    suggest: Callable[[dict], str],
    write: Callable[[str, str], str],
    readback: Callable[[str], str],
    *,
    approval_required: bool = False,
) -> dict:
    """验证输入、建议、审批、写入回执与回读;未知写入绝不自动重试。"""
    ticket_id = ticket.get("ticket_id") if isinstance(ticket, dict) else None
    request = ticket.get("request") if isinstance(ticket, dict) else None
    target_team = ticket.get("target_team") if isinstance(ticket, dict) else None
    if not isinstance(ticket_id, str) or not ticket_id.strip() or not isinstance(request, str) or not request.strip() or target_team not in ("Billing", "Technical", "General"):
        return _result(ticket_id if isinstance(ticket_id, str) else "", "rejected", reason="缺少有效的工单编号、请求或目标团队")

    try:
        raw = suggest(ticket)
        suggestion = json.loads(raw)
    except (ValueError, TypeError, TimeoutError):
        return _result(ticket_id, "needs_review", reason="建议不可用,请人工核对")
    if not isinstance(suggestion, dict) or set(suggestion) != {"team"} or suggestion["team"] not in ("Billing", "Technical", "General"):
        return _result(ticket_id, "rejected", reason="建议团队不在允许范围")
    team = suggestion["team"]
    if team != target_team:
        return _result(ticket_id, "needs_review", suggestion=team, reason="建议团队与程序侧目标不一致")

    if approval_required:
        return _result(ticket_id, "needs_approval", suggestion=team, reason="等待人工审批")

    try:
        tool_result = write(ticket_id, team)
    except TimeoutError:
        return _result(ticket_id, "unknown", suggestion=team, reason="写入回执丢失;先核对外部状态,不自动重试")
    if tool_result != "accepted":
        return _result(ticket_id, "needs_review", suggestion=team, tool_result=tool_result, reason="写入未被接受")

    try:
        actual_team = readback(ticket_id)
    except TimeoutError:
        return _result(ticket_id, "unknown", suggestion=team, tool_result=tool_result, reason="回读超时;不能宣布完成")
    if actual_team != team:
        return _result(ticket_id, "needs_review", suggestion=team, tool_result=tool_result, readback=actual_team, reason="回读结果与目标不一致")
    return _result(ticket_id, "confirmed", suggestion=team, tool_result=tool_result, readback=actual_team, reason="回读与目标一致")


def demo(*, approval_required: bool = False) -> dict:
    """全离线演示;字典就是本地的假工单库。"""
    database = {"T-17": "General"}

    def local_write(ticket_id: str, team: str) -> str:
        database[ticket_id] = team
        return "accepted"

    return process_ticket(
        {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
        suggest=lambda _: '{"team":"Billing"}',
        write=local_write,
        readback=lambda ticket_id: database[ticket_id],
        approval_required=approval_required,
    )


if __name__ == "__main__":
    import sys

    print(json.dumps(demo(approval_required="--approval" in sys.argv), ensure_ascii=False, indent=2))
完整代码:test_app.py
Python
"""从读者要观察的结果开始:建议不等于已完成。"""

import unittest

from app import process_ticket


class TicketTests(unittest.TestCase):
    def test_normal_case_requires_readback(self):
        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Billing"}',
            write=lambda _ticket, _team: "accepted",
            readback=lambda _: "Billing",
        )
        self.assertEqual(result["status"], "confirmed")
        self.assertEqual(result["readback"], "Billing")

    def test_bad_input_never_calls_external_steps(self):
        calls = []
        result = process_ticket(
            {"ticket_id": "", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: calls.append("suggest"),
            write=lambda *_: calls.append("write"),
            readback=lambda _: calls.append("readback"),
        )
        self.assertEqual(result["status"], "rejected")
        self.assertEqual(calls, [])

    def test_write_timeout_does_not_retry_or_claim_success(self):
        calls = []

        def write(_ticket, _team):
            calls.append("write")
            raise TimeoutError("reply lost")

        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Billing"}',
            write=write,
            readback=lambda _: calls.append("readback"),
        )
        self.assertEqual(result["status"], "unknown")
        self.assertEqual(calls, ["write"])

    def test_approval_gate_stops_before_write(self):
        calls = []
        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Billing"}',
            write=lambda *_: calls.append("write"),
            readback=lambda _: calls.append("readback"),
            approval_required=True,
        )
        self.assertEqual(result["status"], "needs_approval")
        self.assertEqual(calls, [])

    def test_unexpected_team_is_rejected(self):
        calls = []
        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Admin"}',
            write=lambda *_: calls.append("write"),
            readback=lambda _: calls.append("readback"),
        )
        self.assertEqual(result["status"], "rejected")
        self.assertEqual(calls, [])

    def test_readback_mismatch_is_not_confirmed(self):
        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Billing"}',
            write=lambda *_: "accepted",
            readback=lambda _: "General",
        )
        self.assertEqual(result["status"], "needs_review")

    def test_valid_but_wrong_team_does_not_write(self):
        calls = []
        result = process_ticket(
            {"ticket_id": "T-17", "request": "转给账单组", "target_team": "Billing"},
            suggest=lambda _: '{"team":"Technical"}',
            write=lambda *_: calls.append("write"),
            readback=lambda _: calls.append("readback"),
        )
        self.assertEqual(result["status"], "needs_review")
        self.assertEqual(calls, [])


if __name__ == "__main__":
    unittest.main()

在已选择 Python 环境的终端中进入保存两个文件的文件夹,依次运行:

Bash
python -X utf8 app.py
python -X utf8 app.py --approval
python -X utf8 -m unittest -v test_app.py

第一条预期为 confirmed,第二条为 needs_approval;测试应有七项 ok。本例把 target_team=Billing 当作程序侧已确认的任务条件;真实系统应从可信业务流程取得它,不能让模型自己填写。write 返回 accepted 只是回执,最终的 confirmed 还要等 readback 与目标团队一致。先把 demo() 的建议从 Billing 改成 Technical:这是允许的团队名,却与任务目标不符,程序应返回 needs_review 且不写入。再试不存在的 Admin,应得到 rejected。两次都改回原值并复跑测试;真实工单不会受到影响。

先看默认运行与 --approval 的区别:前者完成写入和回读,后者停在审批处。Billing 是账单组,Technical 是技术组,General 是综合客服组;代码用英文值保存团队名称。

这份综合作品把前面的练习连起来:正常建议经过检查和写入,最后读回确认;错误建议在执行前停下;需要审批的任务停在审批处。能顺着输入解释这三条路径,就抓住了 L0 的共同线索。

学完 L0 后继续学什么

L0 先建立程序运行、数据处理和模型基础之间的联系。每篇先理解概念,再运行例子,最后改一个参数观察结果。

读完 L0 后进入 L1:模型交互与结构化输出,把这里的网络、参数、校验与失败处理接到模型接口上。L2 再将工具和协议接进来。

继续阅读时,跟着每篇的操作和结果核对即可。环境问题可查 Python 官方虚拟环境文档,请求问题可查 MDN HTTP 概述;各篇还在对应知识点旁列有更具体的资料。

图片查看器
100%

文章配图 · 按 Esc 关闭