Skip to content
← 上一章第 1/11 步什么是 Agent →
前置00 全景01 什么是 Agent
自测代码证据未开始

第 0 章:先看全景,再开始写 Agent

← 上一章:教材使用说明 · 下一章:什么是 Agent

这一章先不急着堆代码。你会先跟完一次真实请求,知道模型、上下文、工具和 Harness 各自站在哪里。以后遇到 Memory、Skill、MCP、Hook 或 Goal,就把它放回这张地图,不会再把术语学成一地碎片。

学习成果

完成本章后,你应该能:

  1. 用自己的话解释 Agent = LLM + Context + Tools + Harness
  2. 区分模型“建议调用工具”和系统“真的执行工具”。
  3. 从 Web 请求一路追踪到模型、RAG/MCP、事件流和最终产物。
  4. 看一条运行日志时,指出当前是模型阶段、工具阶段、等待阶段还是终态。
  5. 解释 Skill 为什么是工作方法,而不是新权限。
  6. 说出一个聊天机器人变成可用 Agent 至少还缺哪些工程环节。

先自测一个:一个完整可用的 Agent,四个要素分别是什么?

  • LLM
  • LLM + Context
  • LLM + Context + Tools
  • LLM + Context + Tools + Harness

本章的验收不是“记住四个名词”,而是能够画出一次请求的控制流,并标明每个边界由谁负责。

这个能力有什么用

Agent 相关资料常从一个局部切入:

  • 有的只讲 Prompt;
  • 有的只讲 Tool Calling;
  • 有的把 Memory 当数据库;
  • 有的把 MCP 当 Agent;
  • 有的把多个角色提示当成多 Agent。

局部知识本身没有错,问题是缺少坐标。全景图能帮你做三件事。

第一,定位问题。模型答错,可能是模型能力不足,也可能是上下文缺证据、工具返回错误或 Harness 提前停止。四层原因要分别检查。

第二,控制权限。模型可以提议 create_support_ticket,但 CapabilityPolicy 才决定这个 Skill、这个用户、这个环境是否获准执行。

第三,设计可观察系统。用户不应该只看到“正在思考”。他应该看到检索开始、工具完成、等待批准、引用核验和产物生成等状态。

没有它会发生什么

想象一个客服 Agent 回答:“退款工单已创建。”

如果没有全景视角,你可能只检查最终文字;实际上可能发生了四种不同情况:

  1. 模型凭空声称创建成功,根本没调用工具。
  2. 模型调用了工具,但参数中的订单号错误。
  3. 工具返回失败,Harness 却没有把失败结果送回模型。
  4. 工具已成功,浏览器 SSE 断线后又重复创建一次。

这四种问题的修法完全不同。只调 Prompt 会让问题更隐蔽。

另一个常见失败是权限混淆。Skill 中写了“必要时创建工单”,不代表它获得 ticket:write。MCP Server 暴露了这个 Tool,也不代表所有调用者都有资格使用。

先定位层,再修问题。不要看到 Agent 出错就把所有责任推给模型。

核心机制

先记住这条课程公式:

text
Agent 系统 = LLM + Context + Tools + Harness

LLM:提出下一步

LLM 根据本次请求中可见的信息,生成回答或结构化 Tool Call。它不会天然记住上次进程,也不会天然拥有文件、网络或数据库。

Context:这一次能看见什么

Context 不是“聊天记录”的同义词。它可以包含:

  • 系统规则;
  • 当前用户请求;
  • 经过筛选的历史;
  • Skill 摘要或完整正文;
  • Tool Schema;
  • RAG 证据;
  • Tool Result;
  • 待办项、Goal 和预算状态。

State 是系统保存的全部事实,Context 只是从 State 中为下一次模型调用选出的部分。

Tools:允许做哪些动作

Tool 有名称、描述、输入 Schema、输出约定和实现。模型只生成调用建议,代码负责:

  1. 校验名称与参数;
  2. 检查权限;
  3. 执行或拒绝;
  4. 记录结果;
  5. 把 Observation 放回下一轮 Context。

Harness:让概率模型进入可靠流程

Harness 是模型外围的控制系统,包括:

  • Agent Loop;
  • Context Builder;
  • Tool Registry 与 Capability Policy;
  • 状态和事件;
  • Hook、预算、超时、重试与取消;
  • Skill、记忆与 RAG;
  • 评估、人工批准、发布和回滚;
  • Web/API/MCP 产品界面。

《深入理解 AI Agent》第 1 章把 Harness 工程视为产品差异的重要来源。来源定位:ai-agent-book@1c18370279f8f0457bf2c44dfa585d08d4d5f281:book/chapter1.md

Skill、MCP 和 Agent 放在哪里

名称它回答的问题是否直接执行
Skill“这类任务应该怎样做?”加载本身不产生副作用
Tool“这一步具体怎样执行?”
MCP“外部能力怎样被统一发现和调用?”协议不执行,Server 实现执行
Agent“根据当前状态,下一步选什么?”由 Harness 驱动
Harness“哪些选择允许落地,怎样继续或停止?”编排和治理执行

完整流程

下面先跟踪课程的目标架构。它说明最终作品应该怎样把 Web Skill 接到统一 Agent Loop,而不是声称当前 v0 已经全部接通。

逐段看目标链路:

  1. POST 创建一次 Run。刷新或重连事件流不应再创建第二次 Run。
  2. Skill Registry 解析固定版本。未批准、隔离或下架版本不能在线运行。
  3. Runner 只向模型暴露 Policy 允许的 Tool Schema。
  4. 模型提出 search_kb,Policy 在副作用前检查。
  5. 检索结果作为 Observation 进入下一次模型调用。
  6. Event Store 保存事实,SSE 负责传输这些事实。
  7. 用户看到的状态来自事件,不来自模型随口编写的“进度说明”。

如果需要创建工单,Policy 还要检查 ticket:write。如果证据不足,成功路径应是拒答或转人工,而不是继续猜。

当前 v0 实现与目标架构的差距

当前 api.py:create_run() 已经能解析已发布 Skill、执行客服 RAG 或 Diff Review、保存 Run,并通过 SSE 按 Last-Event-ID 重放事件。但它还没有把 Web Run 接入 AgentRunner

环节当前 v0本章目标
运行入口create_run() 直接调用 CustomerSupportServiceReviewAgent统一调用 AgentRunner.run_turn()
工具权限业务 Service 自己限制动作所有 Tool 在执行前经过 CapabilityPolicy
事件请求完成后保存 run.started/retrieval.completed/run.completed运行中持续产生 model/tool/turn 事件
SSE对已完成事件做断点重放既能实时订阅,也能断线后重放
返回时机整个 Run 完成后返回 202 与 completed创建 Run 后立即返回,后台继续执行

当前实现的精确入口是 mini-emperor/backend/src/mini_emperor/api.py:create_runstream_run。学习时先跑通 v0,再把这张差距表逐项消掉。这样你不会在教材中看到 AgentRunner,却在 Web 入口里找不到调用链。

如何观察当前状态

一次运行至少需要这些字段:

字段回答的问题示例
run_id是哪一次运行?UUID
event.id / sequence事件顺序是什么?42
event.type当前发生什么?tool.completed
iteration第几次模型决策?2
tool_call_id哪次动作?call_7
skill_version用的哪版方法?1.2.0
policy_decision为什么允许或拒绝?allow: kb:read
status当前生命周期状态?running
artifact_ids产物存在哪里?answer.json
error在哪一层失败?tool_timeout

把事件序列看成状态变化:

text
run.created
→ turn.started
→ model.completed(tool_calls=[search_kb])
→ tool.started
→ tool.completed
→ model.completed(tool_calls=[])
→ turn.completed

如果停在 tool.started,查超时、外部服务和取消;如果出现多个相同 turn.started,查幂等;如果模型最终回答没有引用,查 Context Builder 和引用核验,不要先怪 SSE。

视频内容提炼

视频 1 在 [00:00:15–00:00:47] 用“只能说不能做”引出 Agent,在 [00:02:03–00:02:22] 给出“思考、选择工具、执行、观察”的核心循环。

最值得带走的三点:

  1. LLM 像大脑,Tool 提供行动通道。
  2. 规划、记忆、工具和感知组成自主任务闭环。
  3. 工具不是越多越好,无关 Schema 会增加 Context 和选择负担。

需要修正的地方也很重要:

  • “长期记忆写入向量数据库”只是一种实现,不是定义。
  • “给基础工具,让模型自己创造”必须受沙箱和 Policy 约束。
  • “任务成功后停止”要求有外部可验证的停止条件。

视频证据:video-01,完整笔记见 视频 01 来源笔记

教学仓库代码演进

固定仓库用 12 个累计文件把全景展开:

text
step01 单次调用
→ step02 循环
→ step03 history
→ step04 system prompt
→ step05 tool loop
→ step06 Skill
→ step07 memory
→ step08 plan
→ step09 Subagent
→ step10 Agent Team
→ step11 MCP
→ step12 Hooks

不要直接从 1762 行的 step12_hooks.py 第一行读起。先精读 Step 05 的 Loop,再对每一步做能力差分。

来源定位:

  • claude-agent-examples@54a18980334541773f13940aa0c0475728d30ee0:build-agent-example/code/step01_single_call.py
  • claude-agent-examples@54a18980334541773f13940aa0c0475728d30ee0:build-agent-example/code/step05_tool_use.py
  • claude-agent-examples@54a18980334541773f13940aa0c0475728d30ee0:build-agent-example/code/step12_hooks.py

每次阅读只问四个问题:

  1. 上一步用户能看到什么失败?
  2. 本步新增了什么状态?
  3. 新状态在哪个边界被读写?
  4. 用什么测试证明它有效?

《深入理解 AI Agent》工程补充

书第 1 章给出三层核心:

  • LLM 是决策大脑;
  • Context 是当前可见信息;
  • Tool 是动作空间。

课程在此基础上显式加入 Harness,因为工程系统必须回答权限、状态、错误、评估和产品体验。

必做实验 chapter1/context 会对 History、Reasoning、Tool Definitions 和 Tool Results 做消融。重点不是追求最高分,而是观察缺少某类 Context 时出现哪种退化。

bash
cd "$(git rev-parse --show-toplevel)/references/repos/ai-agent-book"
find chapter1/context -maxdepth 2 -type f | sort

先读实验 README,再记录每个变体的输入差异和失败现象。不要把实验中的外部模型配置复制进教材或提交仓库。

进一步来源定位:ai-agent-book@1c18370279f8f0457bf2c44dfa585d08d4d5f281:chapter1/context/README.md

Mini Emperor 对照

Mini Emperor 的最小运行时在:

  • mini-emperor/backend/src/mini_emperor/agent.py
  • mini-emperor/backend/src/mini_emperor/model.py
  • mini-emperor/backend/src/mini_emperor/skills.py
  • mini-emperor/backend/src/mini_emperor/api.py

核心接口与全景的映射:

代码全景角色
ModelClient.complete()LLM
messages / Tool ResultContext
ToolRegistryTools
AgentRunnerLoop
CapabilityPolicy权限边界
AgentEvent可观测性
SkillRegistry方法与版本
FastAPI + SSE产品接口

运行最小验证:

bash
cd "$(git rev-parse --show-toplevel)"
uv run --python 3.12 --extra dev pytest \
  mini-emperor/backend/tests/test_agent.py -v

测试使用脚本化模型,不需要真实 API Key。它能稳定复现 Tool Call、迭代上限和越权阻断。

逐步实现

ModelClient 是 Protocol,不能直接实例化。下面用和测试相同的脚本化模型搭出一个可运行骨架:

python
from mini_emperor.agent import (
    AgentRunner,
    CapabilityPolicy,
    ModelReply,
    ToolCall,
    ToolRegistry,
)

class ScriptedModel:
    def __init__(self, replies: list[ModelReply]) -> None:
        self.replies = iter(replies)

    async def complete(self, messages: list[dict], tools: list[dict]) -> ModelReply:
        return next(self.replies)

def search_kb(query: str) -> str:
    return f"已检索受控知识库:{query}"

model = ScriptedModel([
    ModelReply(tool_calls=[
        ToolCall(id="call-1", name="search_kb", arguments={"query": "退货条件"})
    ]),
    ModelReply(content="请以知识库证据为准。"),
])
tools = ToolRegistry()
tools.register("search_kb", "Search approved support articles", search_kb)
policy = CapabilityPolicy(allowed_tools=frozenset({"search_kb"}))
runner = AgentRunner(model=model, tools=tools, policy=policy)

然后按这个顺序增加能力。

第一步:只输出事件

python
async for event in runner.run_turn("退货需要什么条件?"):
    print(event.type, event.data)

第一眼不要看回答质量,先确认事件顺序稳定。

第二步:替换为真实只读 Tool

python
# search_kb 的实现改为调用 HybridRetriever,但函数名和返回契约不变。

把 Tool 描述写成“做什么、何时用、返回什么”,不要写成隐藏权限指令。

第三步:限制动作空间

python
policy = CapabilityPolicy(
    allowed_tools=frozenset({"search_kb"}),
    network_policy="deny",
)

即使模型请求 create_support_ticket,Handler 也不会执行。

第四步:让 Web 只订阅事件

创建 Run 和订阅 Event 必须分开。SSE 断线重连只重放事件,不能重新调用 run_turn()

第五步:添加完成证据

对客服回答,证据是文档 ID、标题和引用片段;对代码任务,证据是测试结果;对 Skill 发布,证据是评估与人工批准。

失败实验与调试

失败实验:Tool 成功,任务仍失败

把用户问题设为“查看桌面文件”,但 Tool Handler 固定返回当前工作目录。

预期现象:

  • tool.completed 正常出现;
  • 模型可以写出流畅总结;
  • 用户目标仍没有完成。

这证明“调用成功”只说明执行层无异常,不说明语义目标满足。

调试顺序:

  1. 查 Tool Arguments 是否表达“桌面”。
  2. 查 Handler 是否使用正确路径。
  3. 查 Tool Result 是否包含可验证路径。
  4. 查结束门禁是否真的验证了目标。

再做一次越权实验:

bash
cd "$(git rev-parse --show-toplevel)"
uv run --python 3.12 --extra dev pytest \
  mini-emperor/backend/tests/test_agent.py \
  -k capability_policy -v

预期是危险 Handler 从未被调用,事件记录 tool.failed。如果模型随后声称成功,那是回答验证问题,不是 Policy 问题。

本章练习

  1. 画出“在线运行 customer-support”和“下载 Skill 到本地 Agent”两条不同链路。
  2. 给每条链路标出最少三个信任边界。
  3. AgentEvent 事件表扩展一个 policy.denied 事件,说明与 tool.failed 的差别。
  4. 解释为什么 Tool Result 是数据,不应覆盖 System Prompt。
  5. 找出一次真实运行中最适合用确定性检查而不是 LLM Judge 的环节。
  6. 用 80 字解释 MCP Server 为什么不是 Agent。

完成标准:你的答案必须出现“谁做决定、谁执行、证据在哪里”,不能只列术语。

无资料复述

合上资料,用三分钟回答:

  1. Agent 与单次 LLM 调用的分界是什么?
  2. Context 和 State 有什么不同?
  3. 模型能看到 Tool,为什么仍可能没有执行权限?
  4. Skill、Tool、MCP、Harness 各自负责什么?
  5. 一条 SSE 事件能证明什么,不能证明什么?
  6. 如果客服 Agent 声称工单已创建,你如何逐层核验?

能画出 用户 → Web → API → Runner → Model → Policy → Tool → Event → 用户,并讲清每条箭头,才算通过。

深入学习导航

视频P012 分钟 · 视频 01 [00:00:15–00:02:22]
预计
12 分钟
位置
视频 01 [00:00:15–00:02:22]
阅读任务
只看痛点、四要素和核心循环;画出哪些是模型、哪些是外部动作。
完成证据
提交一张带 LLM、Context、Tool、Harness 标签的图。
教学仓库P035 分钟 · claude-agent-examples Step 01、05、12
预计
35 分钟
位置
claude-agent-examples Step 01、05、12
阅读任务
比较单次调用、工具循环和 Hook 后的新增边界,不线性阅读大文件。
完成证据
写出三步各新增的状态与失败模式。
书与实验P050 分钟 · ai-agent-book 第 1 章 + chapter1/context
预计
50 分钟
位置
ai-agent-book 第 1 章 + chapter1/context
阅读任务
读公式、ReAct、Harness,并对 Context 元素做一次消融。
完成证据
保存一张四列消融表:移除项、现象、原因、修复层。
论文P050 分钟 · ReAct Figure 1 与 Section 3
预计
50 分钟
位置
ReAct Figure 1 与 Section 3
阅读任务
把 Thought/Action/Observation 映射到 Step 05 和 AgentEvent。
完成证据
指出哪些推理内容不应直接暴露给最终用户。
官方文档P145 分钟 · DeepSeek Chat Completion + FastAPI Streaming + WHATWG SSE
预计
45 分钟
位置
DeepSeek Chat Completion + FastAPI Streaming + WHATWG SSE
阅读任务
分清模型流式输出、服务器流和浏览器 EventSource 三个层。
完成证据
写出一次断线重连为何不会重复执行 Tool。

← 上一章:教材使用说明 · 下一章:什么是 Agent

Markdown 是唯一内容源,HTML 由构建流程生成。