小节一:先设计 API Contract——不要一上来就写 Route

先看一张总览图会更容易进入状态。它把“调用方 → API Contract → Flask Route → AgentService / AgentEngine”这条链路直接摊开了。你会发现,真正应该先稳定下来的,不是某一段 Flask 代码,而是接口的输入、输出和错误结构。

图片[1]-小节一:先设计 API Contract——不要一上来就写 Route-大赛人网

如图可以很直观地看到,API Contract 更像是服务边界:左边各种调用方只需要遵守约定发请求,Route 只负责把请求正确接住并转给 Service,真正的业务能力还是在后面的 Service 和 Engine 里。这样分开以后,后面无论你用 Web、curl 还是其他服务来接入,思路都会更清楚。

一个稳定接口,第一步不是:

@app.post("/api/v1/chat")
def chat():
    ...

而是先定义,请求长什么样?响应长什么样?失败怎么返回?

这叫 API Contract。

请求设计

本节最小请求:

{
  "message": "检查这个 Python 项目"
}

只要求一个字段:

message

它表示当前用户任务。

为什么现在不加:

session_id
user_id
workspace
stream

不是这些不重要。

而是我们先把第一条服务链路打通。

后面会逐步扩展。

因此当前示例明确是单用户教学链路。真实共享环境不能让客户端在 Body 里自报 user_id 就当成可信身份;用户身份要来自鉴权结果,session_id 和 workspace 还要检查资源归属。我们先不实现这些字段,但要把“尚未支持”和“默认安全”分开。

最小请求合同可以写得更具体:

图片[2]-小节一:先设计 API Contract——不要一上来就写 Route-大赛人网

响应设计

成功响应:

{
  "answer": "...",
  "run_id": "run_abc123",
  "status": "completed"
}

三个字段都很重要。

answer:

Agent 最终结果

run_id:

这一次执行的唯一标识

status:

当前执行状态

这一节同步执行,所以成功时统一:

completed

同步成功使用 HTTP 200。下一节改成“先创建、后台执行”后,更合适的是 HTTP 202,并返回 ready 或 running。不要出现 HTTP 已返回 200、Body 却写着 failed 这种互相打架的合同。

为什么 status 用字符串而不是布尔值?

不要设计:

{
  "success": true
}

作为唯一状态。

因为后面任务会出现:

ready
running
waiting_approval
completed
failed

字符串状态更容易扩展。

错误响应

如果把这一段再往上提一层看,HTTP API 的意义其实不只是“给函数包一个 URL”。它本质上是在系统之间定义一套稳定协议:请求怎么传、响应怎么回、错误怎么表达、版本怎么演进、安全怎么控制。

图片[3]-小节一:先设计 API Contract——不要一上来就写 Route-大赛人网

这张图特别适合配合这里一起理解。左上和右上的几个小块,基本就把为什么要设计 API Contract 说明白了:不同语言要能互调、部署位置要能分离、版本要能平滑升级、错误要能标准化、长任务还要能支持 Streaming。理解到这一层,再回来看 error_code、message、status 这些字段,就不会觉得它们只是“格式问题”了。

比如缺少 message:

{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "message is required"
  }
}

HTTP:

400

内部异常:

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "agent execution failed"
  }
}

HTTP:

500

非法 JSON 或 Body 不是对象,可以使用:

{
  "error": {
    "code": "INVALID_JSON",
    "message": "request body must be a JSON object",
    "request_id": "req_abc123"
  }
}

INVALID_JSON 和 INVALID_REQUEST 值得分开:前者说明协议内容无法按 JSON 对象读取,后者说明 JSON 已经读懂,但字段不满足合同。前端据此能给出更准确提示。

为什么不直接把 Python Exception 返回客户端?

比如:

KeyError: 'messages'
File "/usr/local/..."

这些内部信息:

客户端不需要
可能泄露实现
协议不稳定

所以外部 API 应该返回稳定错误结构。

服务端仍然要用 app.logger.exception(...) 或 Trace 保存完整异常,并附上同一个 request_id。只写一句“失败了”却不留内部证据,确实不会泄露信息,但也会让维护者无从排查。

API 版本路径

我们使用:

/api/v1/chat

而不是:

/chat

原因很简单。

后面协议改动时,可以有:

/api/v2/chat

这是一种很低成本但非常实用的设计。

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

昵称

取消
昵称

    请登录后查看评论内容