章末自测

题目 1:为什么 agent.run("分析这个项目") 适合作为开发入口,却不适合作为真实 Web 产品唯一入口?

请从调用环境、协议、多调用方、长任务与多用户五个角度解释。

agent.run() 默认调用方已经进入同一个 Python 环境,因此浏览器、App、飞书和其他语言服务无法直接调用;它也没有稳定 Request/Response 协议。真实 Agent 还会面对多个客户端、多用户并发、Session 关联和几十秒长任务。更合理的是保留 agent.run() 作为 AgentEngine 内部接口,在外面增加 AgentService 和 HTTP API。

题目 2:Flask Route、AgentService、AgentEngine 应该分别负责什么?

请说明为什么不应该让 Route 直接承担 Main Loop。

Flask Route 负责 HTTP 请求解析、参数校验、状态码和 JSON Response;AgentService 负责 Session、后续 Run、业务协调和调用 Engine;AgentEngine 负责 ContextBuilder、Provider、Main Loop、Tool Calling 和 State Update。如果 Route 直接承担 Main Loop,网络协议与 Agent Runtime 会强耦合,导致 CLI、飞书、单元测试等入口无法复用同一套核心逻辑。

题目 3:编程实现——写一个最小 Flask Agent API

要求 POST /api/v1/demo 接收 message,缺失时返回 400,成功调用独立 AgentEngine 并返回 JSON。

from flask import (
    Flask,
    jsonify,
    request,
)


class AgentEngine:

    def run(
        self,
        task: str,
    ) -> str:
        return (
            "processed: "
            + task
        )


app = Flask(__name__)

engine = AgentEngine()


@app.post("/api/v1/demo")
def demo():
    payload = (
        request.get_json(
            silent=True
        )
        or {}
    )

    message = str(
        payload.get(
            "message",
            ""
        )
    ).strip()

    if not message:
        return jsonify({
            "error": (
                "message is required"
            )
        }), 400

    answer = engine.run(
        message
    )

    return jsonify({
        "status": "COMPLETED",
        "answer": answer,
    })


if __name__ == "__main__":
    app.run(
        host="127.0.0.1",
        port=5000,
        debug=False,
    )

题目 4:为什么同一个 AgentEngine 应该同时被 CLI、Web、飞书复用?

请从一致性、维护和测试说明。

如果不同入口各维护一份 Agent,会逐渐出现 Prompt、Tool、Memory 和安全规则版本不一致。统一 AgentEngine 后,各入口只负责把自己的输入转换成标准业务调用,核心 Main Loop、ContextBuilder 和 Tool Registry 只维护一份。这样行为一致、测试集中,后续增加新渠道也只需要实现 Adapter,而不是复制 Agent。

题目 5:HTTP API 相比直接 Python 函数调用,多解决了哪些问题?

至少说明语言解耦、部署解耦、版本化和错误标准化。

HTTP API 让 JavaScript、Java、Go、Python 等不同客户端都能通过同一协议调用 Agent,解决语言解耦;Agent Server 可以独立部署,客户端只依赖网络地址,解决部署解耦;通过 /api/v1 等路径可以进行接口版本管理;服务端还可以把内部异常统一转换成 HTTP Status 与结构化 Error Response,而不是暴露 Python Exception。

题目 6:为什么 Agent 服务化以后会自然需要 Run 和 Streaming?

请用一个执行 60 秒、期间调用 8 个 Tool 的任务解释。

60 秒的 Agent 任务不能像普通毫秒级接口一样只等待最终响应。系统需要一个 run_id 标识具体任务,并保存 READY、RUNNING、COMPLETED、FAILED 等生命周期状态;同时用户希望看到“正在读文件”“正在运行测试”“正在重试”等中间进度,因此需要 Streaming 或事件流。Run 和 Streaming 都来自 Agent 长执行和多步骤特性。

题目 7:为什么说 Flask 负责网络层,而不是替代 Agent Harness?

请结合前面已经实现的 ContextBuilder、Session、Memory、Tool Registry 回答。

ContextBuilder、Session、Working/Long-term Memory、Tool Registry 和 Main Loop 都属于 Agent Harness,它们决定 Agent 如何运行。Flask 只负责把这些能力暴露为 HTTP 服务:读取请求、调用 Service、返回响应。健康架构是 Flask → AgentService → AgentEngine → Harness,而不是把 Harness 重写成 Flask Route。这样核心 Agent 才能脱离具体 Web Framework 继续复用。

题目 8:客户端超时后重试,为什么可能创建两个 Agent Run?

请区分请求超时与执行失败,并说明 request_id、idempotency_key、run_id 分别解决什么问题。

响应超时不代表服务器没有收到请求。第一次调用可能已经创建并启动 Run,客户端再次提交就会生成第二个任务。request_id 用于关联一次网络请求及其日志;idempotency_key 表示客户端眼中的同一次业务提交,服务端据此返回第一次创建的结果;run_id 标识实际 Agent 任务,用于查询、订阅或取消。三者用途不同。

题目 9:为什么进程内 Session 在单机测试通过,多 Worker 部署后仍可能失效?

每个 Worker 都有独立内存。第一次请求写入 Worker A 的 Session,第二次请求可能落到 Worker B,B 看不到 A 的状态;Worker 重启后内存也会丢失。需要跨请求、跨进程和跨重启保留的 Session、Run、Trace 应进入共享存储,进程内对象只能作为临时状态或缓存。

进一步阅读

  • HTTP / REST 基础:理解 Method、Path、JSON、Status Code 与 API Contract。
  • Flask 官方文档:下一节会正式实现第一个 Agent API。
  • WSGI / Production Server:了解 Flask 开发服务器与生产运行方式的区别。
  • Service Layer Pattern:理解为什么业务协调层不应该和 Web Route 混在一起。
  • API Versioning:真实系统为什么常使用 /api/v1/...。
  • SSE / Streaming HTTP:为后面的 Agent 实时进度输出做准备。
  • Stateless HTTP 与 Stateful Session:理解为什么请求本身无状态,而 Agent 必须额外管理 Session。
  • Backend Architecture:继续理解 Client → Flask → Service → Engine 的分层思想。

术语表

  • 服务化(Serviceization):把本地函数或脚本能力包装成可被其他进程、设备或系统稳定访问的服务接口,使调用方与内部实现解耦。
  • HTTP API:通过 URL、HTTP Method、Request 和 Response 定义的网络调用协议,是 Web、App、飞书和其他后端服务访问 Agent 的主要入口之一。
  • Agent Server:承载 Agent API、业务 Service、Session/Run 协调并调用 AgentEngine 的后端服务。
  • Flask Route:Flask 中接收特定 HTTP Path 请求的入口,适合负责请求解析、参数检查和 Response 转换,不应该承载完整 Main Loop。
  • AgentService:位于 HTTP 层与 AgentEngine 之间的业务协调层,后续会负责 Session、Run、持久化等逻辑。
  • AgentEngine:负责 Agent Main Loop、Context、Provider、Tool、State 等核心运行逻辑的组件,应尽量与具体 Web Framework 解耦。
  • Client:调用 Agent 服务的外部程序,例如浏览器、App、飞书机器人、内部服务或 CLI Adapter。
  • API Contract:服务端与客户端共同遵守的请求字段、响应字段、状态码和错误格式,允许内部实现独立演进。
  • 请求标识(Request ID):标识一次 HTTP 请求并串联访问日志、错误和 Trace 的 ID,不代表业务操作只执行一次。
  • 幂等键(Idempotency Key):由调用方为一次业务提交提供的稳定标识,用于避免超时重试重复创建 Run。
  • 应用工厂(Application Factory):通过 create_app() 创建并配置 Flask 应用的方式,便于测试时注入依赖,也避免模块导入时启动服务。
  • 共享状态(Shared State):多个请求、Worker 或服务实例都需要访问的 Session、Run、Memory 等数据,通常由数据库、缓存或消息系统承载。

本章总结

这一节,我们正式跨过整门课程一个重要分水岭。

前面所有工作主要解决,Agent 自己怎么运行。

从现在开始,我们开始解决,别人怎么稳定地使用这个 Agent。

最开始,我们只有:

agent.run(
    "分析这个项目"
)

这非常适合开发和调试。

但真实系统里的调用方会越来越多:

Frontend
App
飞书
其他服务

它们不能直接进入你的 Python 进程调用方法。

因此需要:

Frontend
App
飞书
其他服务
    ↓
HTTP API
    ↓
Agent Server

我们正式引入 Flask,不是为了“顺便学一个 Web 框架”,而是因为 Agent 已经从一个本地脚本能力,开始变成一个需要被网络访问的后端能力。

这一节最重要的第一点是,Python Script 没有错,它只是不能成为所有外部系统的唯一入口。

CLI 以后仍然可以保留。

真正改变的是:

AgentEngine

从只被本地脚本调用,变成可以被多个 Adapter 复用。

第二个重点是三层结构:

Flask Route
  ↓
AgentService
  ↓
AgentEngine

Flask Route 负责 HTTP。

AgentService 负责业务协调。

AgentEngine 继续负责:

Main Loop
Context
Provider
Tool
State
Memory

如果因为引入 Flask,就把所有前面做好的 Harness 逻辑塞进 Route,反而说明服务边界没有设计好。

第三个重点是,HTTP API 不只是给网页用。

它真正提供的是跨语言、跨进程、跨部署环境的统一访问协议。

以后:

Web
App
Feishu
Cron
告警平台
数据平台

都可以访问同一个 Agent Server。

第四个重点是,服务化会自然暴露 Agent 原本就存在的复杂性。

因为 Agent 不是普通 CRUD。

它可能:

跑几十步
执行几十秒
持续产生 Tool Result
需要 Session
需要恢复
需要实时进度

网络边界还会带来几件脚本里不明显的事:输入输出必须可序列化,身份和资源权限必须分开校验,请求可能超时和重试,多 Worker 也不会自动共享内存。HTTP 解决的是“大家如何调用”,Run、幂等、持久化和执行器解决的是“任务如何可靠完成”。

所以接下来我们会自然进入:

第一个 Agent API
Run 生命周期
Streaming
SQLite 持久化

这些章节不是额外附加,而是 Agent 真正成为后端服务以后必然面对的问题。

到这里,我们的架构已经从:

Python Script
 ↓
Agent

升级成:

Client
 ↓
Flask
 ↓
AgentService
 ↓
AgentEngine
 ↓
Context / Memory / Session
 ↓
Main Loop
 ↓
Provider / Tools

如果你现在能够清楚解释,“为什么一个已经能 agent.run() 的 Agent,还需要 Flask?”

那么这一章的核心目标就完成了。

下一节,我们会正式实现,用 Flask 封装第一个 Agent API。

也就是:

POST /api/v1/chat

请求里开始真正带:

message
session_id

响应里逐步返回:

answer
run_id
status

从下一节开始,这个 Agent 就真正从本地程序,变成一个可以被其他系统调用的 Agent Backend。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容