架构
Downcity 如何按 Kernel、Capabilities、Interfaces 和 Composition 组织运行时。
理解 Downcity City 最稳的方式,不是先看某一个 API,而是先看它的四层结构:
Interfaces
-> towns 通过 client / Town terminal 接入 City
Composition
-> server / worker 把 City、官方服务、模型组装起来
Kernel
-> City 负责路由、鉴权、上下文、hook 调度
Capabilities
-> AIService 与 accounts / usage / balance / payment 等服务提供真实能力这四层合在一起,形成 Downcity 的运行链路:
产品前端 / App / 内部工具
-> User City / Admin City / Town terminal
-> City
-> Service / AIService
-> Provider / Database多个 client 可以共用一个自部署 City。产品端保持轻量,专注自己的用户体验;City 统一处理鉴权、模型路由、运行时 env、hooks 和官方服务能力。
1. Interfaces:谁来调用 City
Downcity 对外有两类主要入口:
- 产品侧入口:
@downcity/city的User City与Admin City - 运维入口:
downcity
它们都不实现服务端 runtime 本身,只负责把请求送进同一套 City runtime。
2. Composition:谁来把 City 组装起来
Downcity 的运行时不是“new 一个 City 就结束”,中间还有一层面向部署环境的装配:
cities/node负责 Node.js + SQLite 的本地 server 示例cities/edge负责 Cloudflare Workers + D1 的部署示例- 每个 city block 都拥有适配自身运行时的 City 组装逻辑
这一层的职责,是把 City + AIService + 官方服务 + 模型 组装成真正可跑的实例。
3. Kernel:City 本体负责什么
HTTP 请求进入 City 后,City 会先做这些事情:
- 刷新运行时 env 视图
- 校验
user_token或 admin key - 解析
town_id、user_id和身份级别 - 找到目标 Service / Action
- 组装统一
ctx - 执行 hook 和 action
如果 token 无效、过期或 town_id 不匹配,City 会直接返回 401 或 403。
4. Capabilities:Service 与 Action
每个 Service 是一组 Action。Action 是 Service 的一等能力单元。
const translate = new Service({ id: "translate" });
translate.action("zh2en", async (ctx) => {
// ctx.input = { text: "你好" }
// ctx.user = { user_id: "user_1" }
return { translated: await api.translate(ctx.input.text) };
});City 自动为每个 Action 生成路由:
POST /v1/translate/zh2en → translate.action("zh2en")City 本身不关心“翻译”或“支付”是什么业务,它只负责把请求路由到对应 Action。
5. AIService 两条通路
SDK 通路
给 User City 调用:
User City.ai.text({ prompt: "hello", model: "kimi-k2.6" })
-> POST /v1/ai/text
-> Provider text action(ctx)
-> generateText / streamText (ai-sdk)
-> UIMessage / UIMessageStreamOpenAI 兼容通路
给 downcity agent、OpenAI SDK、curl 等第三方工具调用:
POST /v1/ai/chat/completions
{ model: "deepseek-v4-flash", messages: [...], stream: true }
-> Provider openai action(ctx) 或 自动透传
-> 上游 API 原始 Response(SSE 或 JSON)两条通路完全解耦,各自独立运作。
6. 自动透传
当 Provider 有 baseURL + envKey 但没有 openai action 时,AIService 自动生成透传 action。第三方工具发送的 OpenAI body 原样转发到上游 API,Response 原样返回。
不需要任何适配代码。
7. Hook 三层
每个 Action 有独立的 hook。hook 执行顺序从外层到内层:
global.before
→ service.before ← 该 service 下所有 action 共享
→ action.before ← 只这个 action
→ action.run() ← 核心逻辑
→ action.after ← 计费、记录 usage
→ service.after ← 聚合统计
→ global.after ← 全局监控// Action 级 hook
const zh2en = svc.action("zh2en", fn);
zh2en.before(checkBalance).after(deductFee);
// Service 级 hook(所有 action 共享)
svc.hook.after(async (ctx) => {
console.log(`${ctx.user.id} used ${ctx.service.id}.${ctx.action.id}`);
});8. 一句话记住
可以把 Downcity 记成一句话:
Interfaces 负责接入
Composition 负责装配
Kernel 负责运行时规则
Capabilities 负责真实能力