现在怎么用
用 Federation 和 Embassy 跑通一条完整调用链。
如果你想先按仓库里的现成产品体验,入口是:
templates/localfedcli/city
跑通后,你会得到这个调用链:
City Client
↓ Embassy Admin 创建 Bureau / 请求 Federation 签发 user_token
Federation
↓ Embassy User 携带 user_token 调用 service
AIChannel → AIService → handler1. 启动 City
import {
Federation,
AIService,
AIChannel,
type AIChannelStreamInput,
type AIChannelStreamResult,
} from "@downcity/federation";
import { Database } from "@downcity/database-sqlite";
const database = new Database({ filename: "./data.sqlite" });
const base = new Federation({ database });
// 注册一个 echo 模型
class EchoChannel extends AIChannel {
constructor() {
super({ id: "echo" });
}
protected async stream(
input: AIChannelStreamInput,
): Promise<AIChannelStreamResult> {
const input_text = input.call.messages
.flatMap((message) => message.content)
.filter((part) => part.type === "text")
.map((part) => part.text)
.join("\n");
return {
stream: new ReadableStream({
start(controller) {
controller.enqueue({ type: "model_start", request_id: crypto.randomUUID(), model_id: input.model.id });
controller.enqueue({ type: "text_start", content_id: "echo_text" });
controller.enqueue({ type: "text_delta", content_id: "echo_text", delta: `Echo: ${input_text}` });
controller.enqueue({ type: "text_finish", content_id: "echo_text" });
controller.enqueue({
type: "model_usage",
usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 },
});
controller.enqueue({ type: "model_finish", finish_reason: "stop" });
controller.close();
},
}),
};
}
}
const echo = new EchoChannel();
const ai = new AIService();
ai.use(echo.model({ id: "local-echo", upstream_model: "local-echo", name: "Local Echo" }));
base.use(ai);
import { serve } from "@hono/node-server";
await base.health();
serve({ fetch: (request) => base.fetch(request), port: 43127, hostname: "127.0.0.1" });2. 创建 Bureau 并请求签发 token
import { Embassy } from "@downcity/federation";
const embassy = new Embassy({
federation_url: "http://127.0.0.1:43127",
admin_token: administrator_session_token,
});
const token = await embassy.admin.service("accounts").action("tokens/issue").invoke({
bureau_id: "demo",
user_id: "user_123",
metadata: { plan: "pro" },
ttl: "7d",
});3. 产品侧调用
const user_embassy = new Embassy({
federation_url: "http://127.0.0.1:43127",
user_token: token.user_token,
});
const catalog = await user_embassy.user.ai.catalog();
const model = catalog.require("local-echo");
// SDK 通路
const stream = await model.stream({
messages: [{
role: "user",
content: [{ type: "text", text: "你好 Downcity" }],
}],
});
for await (const event of stream) {
if (event.type === "text_delta") process.stdout.write(event.delta);
}4. 你真正复用的是什么
多个产品接入后,复用的是这些东西:
.env中的 provider keyuser_token校验- AIService 的模型路由
- hook 里的套餐、限额、日志和扣费
下一步: