把 SDK 包成 HTTP 服务,是「给别人用」最省事的形态。 骨架只有三步:收请求、跑一次、把结论序列化回去。 实测缺参数那份直接返回 400,一次模型调用都没发生。这一步能省掉大量无意义的开销。
前面九节都是零件,这一节把它们拼成一个能给别人用的东西。 这一节有真跑:处理函数直接调,以及真的起了一个 HTTP 服务、发了一次请求。
一、服务的三步
收:解析请求,校验必填。缺参数直接 400,别往下跑。 跑:调一次,拿到结果。这是唯一慢的地方。 回:序列化成 JSON。状态码要能表达失败。
三步里最容易被跳过的是第一步的校验——而它恰好是最省钱的一步。
二、真跑:处理函数直接调
演示里两个请求:给 path 的返回 200 和一份结论,不给 path 的直接 400。 400 那份一次模型调用都没发生。这就是「先校验再干活」的价值。 反过来说,如果先调模型再校验,你会为每一个错误请求付一次钱。
这个顺序在任何「包一层服务」的场景里都一样:便宜的先做。
三、真跑:包一层 HTTP
同一份处理函数挂到一个端口上,POST 一次,回 200 和同一份 JSON。 从函数到服务,加的东西只有三样:解析请求体、设置响应头、写回字节。 所以「先写函数再包壳」是更省事的顺序:函数能直接调、能单测,壳随时能换。
反过来先写壳,逻辑和 HTTP 细节会缠在一起,测都没法测。
四、服务化以后多出来的四件事
并发:同时来十个请求怎么办。限并发,或者排队。 超时:一次跑五分钟,客户端早断了。服务端也要有自己的超时。 重试:客户端重试会跑两遍。要么加幂等键,要么让重复执行无害。
配额:一个人把额度用完。按调用方限额。 四件事都不难,但都得做。不做的话,服务会在第一个热门需求上垮掉。
五、一条部署建议
把「跑一次」的逻辑留在纯函数里,HTTP 那层只做解析和序列化。 这样本地能直接调、能写单测、能换框架——壳可以换,逻辑不用动。 还要给每次请求生成一个标识,日志里带上它。出问题时能按标识把整条链路串起来。
这两条加起来,就是这个服务以后能不能维护的分界线。
六、动手 Demo:一个最小的 Web 服务:请求进来,结论出去
把 SDK 包成 HTTP 服务,是所有「给别人用」的形态里最省事的一种。 这里真跑两层:处理函数直接调,以及真的起一个服务、发一次请求。
def _handle(req, calls=3):
path = req.get(u"path", u"")
if not path:
return {"status": 400, "body": {"error": u"缺 path"}}
return {"status": 200, "body": {...}}
实跑输出:
--------------------------------------------------------------------
一个最小的 Web 服务:请求进来,结论出去
--------------------------------------------------------------------
把 SDK 包成 HTTP 服务,是所有「给别人用」的形态里最省事的一种。
它的骨架只有三步:收请求、跑一次、把结论序列化回去。
① 服务的三步
--------------------------------------------------------------------
| 步 | 做什么 | 注意什么 |
|---|---|---|
| 收 | 解析请求,校验必填 | 缺参数直接 400,别往下跑 |
| 跑 | 调一次,拿到结果 | 这一步是唯一慢的地方 |
| 回 | 序列化成 JSON | 状态码要能表达失败 |
② 真跑:处理函数直接调
--------------------------------------------------------------------
请求 {"path": "src"} → 状态码 200,
返回 {"path": "src", "steps": ["列出文件", "读入口", "数函数"], "turns": 3, "cost_usd": 0.012}
请求 {} → 状态码 400,返回 {"error": "缺 path"}
缺参数那份直接 400,一次模型调用都没发生——这一步能省掉大量无意义的开销。
③ 真跑:包一层 HTTP
--------------------------------------------------------------------
POST 到 127.0.0.1:60182 → 状态码 200
{"path": "src", "steps": ["列出文件", "读入口", "数函数"], "turns": 3, "cost_usd": 0.012}
同一份处理函数,既能在本地直接调,也能挂到端口上。这就是「先写函数再包壳」的好处。
④ 服务化以后多出来的四件事
--------------------------------------------------------------------
| 多出来什么 | 具体问题 | 至少要做一样 |
|---|---|---|
| 并发 | 同时来十个请求怎么办 | 限并发,或者排队 |
| 超时 | 一次跑五分钟,客户端早断了 | 服务端也要有超时 |
| 重试 | 客户端重试会跑两遍 | 加幂等键 |
| 配额 | 一个人把额度用完 | 按调用方限额 |
这四件事都不难,但都得做。不做的话,服务会在第一个热门需求上垮掉。
⑤ 一条部署建议
--------------------------------------------------------------------
把「跑一次」的逻辑留在纯函数里,HTTP 那层只做解析和序列化。
这样本地能直接调、能写单测、能换框架——壳可以换,逻辑不用动。
! 这里的服务是最小可跑实现:单线程、无认证、无并发控制,只用于演示形状。
①三步:收(解析并校验)、跑(唯一慢的地方)、回(序列化,状态码要能表达失败)。 ②缺参数那份直接 400,一次模型调用都没发生。先校验再干活,能省掉大量无意义的开销; 反过来先调模型再校验,你会为每一个错误请求付一次钱。 ③从函数到服务,加的东西只有三样:解析请求体、设置响应头、写回字节。 所以「先写函数再包壳」更省事——函数能直接调、能单测,壳随时能换。 ④服务化多出四件事:并发、超时、重试(加幂等键)、配额。都不难,但不做会在第一个热门需求上垮掉。
30 秒实验
- 把「先校验」改成「先调模型再校验」,重跑一遍。缺参数那个请求会发生什么?成本差多少?
- 给服务加一个「同一个 path 一分钟内只跑一次」的缓存,重跑一遍。它解决的是四件事里的哪一件?
- 把处理函数里的模型调用换成一个会抛异常的版本,重跑一遍。现在的代码会返回什么状态码? 该返回什么?
常见误区
- 先调模型再校验参数。每个错误请求都要付一次钱。
- 逻辑和 HTTP 细节写在一起。没法单测,也没法换框架。
- 不设服务端超时。客户端断了,服务还在跑,白花钱。
- 重试不做幂等。同一个请求跑两遍,可能改两次文件。
- 日志里没有请求标识。出问题时串不起整条链路。
自测三问(点开对答案)
1. 服务的三步是什么? —— 收(解析并校验)、跑(调一次)、回(序列化成 JSON,状态码表达失败)。 2. 为什么校验要放在最前面? —— 因为它是唯一不花钱的一步。先调模型再校验,每个错误请求都要付一次钱。 3. 服务化之后要多处理哪四件事? —— 并发、超时、重试(幂等)、配额。服务能跑了,最后一节收口:CLI 和 SDK 到底怎么选。
- ☐ (本篇完,下一篇 8.11 Agent SDK 与 Headless CLI:如何选型)
相关笔记
- 4 道安全防线:四道防线在服务里同样适用
- Agent SDK 与 Headless CLI:怎么选型
- Claude Code 橙皮书 · 索引
- 🐎 Claude Code 实战 · 索引