先看一张总览图会更容易进入状态。它把“调用方 → API Contract → Flask Route → AgentService / AgentEngine”这条链路直接摊开了。你会发现,真正应该先稳定下来的,不是某一段 Flask 代码,而是接口的输入、输出和错误结构。
![图片[1]-小节一:先设计 API Contract——不要一上来就写 Route-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1599.png)
如图可以很直观地看到,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-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1600.png)
响应设计
成功响应:
{
"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-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1601.png)
这张图特别适合配合这里一起理解。左上和右上的几个小块,基本就把为什么要设计 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
这是一种很低成本但非常实用的设计。
















请登录后查看评论内容