开始学习 Agent 前,需要补齐哪些基础?
正在读取学习记录…
L0 带你把第一个 Python 程序跑起来,学会收发数据、保存结果、排查报错,再认识大模型怎样处理文字。掌握这些基础后,你就能看懂一个 Agent 程序由哪些部分组成,并开始动手搭自己的助手。
用一个客服小助手理解学习路线
假设你在网上买了一件商品,付款成功了,订单页面却没有显示。你给客服留言:“钱已经扣了,订单怎么没出来?”
客服会把这条留言记成一张工单。可以把工单理解成一张“待处理的问题记录”,里面有问题描述、负责的团队和处理进度。账单团队处理扣款问题,技术团队处理系统故障。
我们的小助手要帮客服做一件具体的事:把已确认的扣款问题交给账单团队。过程很直观:
| 步骤 | 助手做什么 | 你能看到什么 |
|---|---|---|
| 读取 | 取出这条问题记录 | 用户的留言和当前负责团队 |
| 处理 | 把负责团队改成账单团队 | 更新后的记录 |
| 确认 | 再查看一次记录 | 负责团队已经变为账单团队 |
这个例子会用到几种基础能力:Python 执行程序,HTTP 传递请求,数据库保存记录,测试检查结果。后面接入模型时,还会用到文字处理、资料检索和费用计算。先把这些环节学会,再把它们接起来。
各篇也有更小的例子,比如打印查询词、读取一条资料、比较两个向量。你可以先专注当前知识点,学完后再做下面的综合实践。
按这个顺序学习
第一次接触 Agent,可以按表中顺序学习;已有经验,可以先检查每篇的目标,直接补自己的缺口。
| 顺序 | 文章 | 学完后留下的最小产物或判断 |
|---|---|---|
| 01 | Python 类型、异常与虚拟环境 | 说明正在使用哪一个解释器,能运行并修改一个独立脚本 |
| 02 | HTTP、REST 与 JSON | 区分请求、状态码、响应体,以及网络成功与任务成功 |
| 03 | 异步、并发与超时 | 给一个请求设置超时,并保留取消或结果未知的状态 |
| 04 | Git、命令行与版本控制 | 提交可复现版本,并能撤回自己的一次改动 |
| 05 | Docker 与可复现环境 | 解释镜像、容器、数据卷边界;具备网络条件时构建并运行 |
| 06 | 日志、pytest 与 CI | 先让一个测试失败,再修复并留下运行记录 |
| 07 | SQL、事务与数据基础 | 重放一次写入与故障回滚,说明单库事务没有覆盖哪些外部动作 |
| 08 | 向量、余弦相似度与统计 | 自己计算候选排序,并说明阈值变化后的误检与漏检 |
| 09 | Transformer 与概率生成直觉 | 区分教学版注意力计算和完整语言模型生成 |
| 10 | Token 与上下文窗口 | 为一条请求分配上下文预算,而不是用字数估算真实计费 |
| 11 | Embedding 与 Reranker 入门 | 观察候选数量改变时,相关资料能否进入重排名单 |
| 12 | 模型 API、密钥与环境变量 | 用环境变量读取密钥和预算参数,不把密钥提交进仓库 |
| 13 | 任务建模、自治边界与成功标准 | 为示例工单写对象、动作、审批、停止状态和成功证据 |
| 14 | Token 计费、吞吐与成本意识 | 分开记录已确认成本和未知预留,拒绝超预算请求 |
如果时间有限,先完成01、02、03、06、12、13、14:这条路线先备好运行环境和通信,给等待设置上限,用测试检查输入,再补密钥配置、任务边界与成本上限,形成最小闭环。其余篇目继续补版本复现、数据一致性、检索和生成原理;十四篇的学习范围保持完整。
学完后:把基础接成一个小助手
展开综合实践:更新一条客服问题记录
例如 Python 和 Git 回答“运行的是哪一版”,HTTP 与 SQL 回答“读到了什么”,任务建模与预算回答“为什么允许下一步”,测试和回读回答“结果有没有发生”。第一次读总览时,先沿上面的目录学习;完成各篇跟做后,再回到这里将这些能力合成一份小作品。
在电脑上建一个 agentdepth-l0 文件夹,逐篇保存实验源码和运行记录。最后用一个离线工单助手串起来:读取练习工单、检查建议、决定拒绝或执行,再回读本地记录。将 app.py、test_app.py 按下方代码逐个保存到同一个空文件夹。
完整代码:app.py
"""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
"""从读者要观察的结果开始:建议不等于已完成。"""
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 环境的终端中进入保存两个文件的文件夹,依次运行:
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 概述;各篇还在对应知识点旁列有更具体的资料。
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。