调用模型
使用 ModelCall、CityModel 和 ModelStreamEvent 调用 Federation 模型。
直接调用 Federation 模型
const catalog = await city.ai.catalog();
const model = catalog.require("deepseek-v4-flash");
const stream = await model.stream({
messages: [{
role: "user",
content: [{ type: "text", text: "解释这个仓库" }],
}],
});
for await (const event of stream) {
if (event.type === "text_delta") process.stdout.write(event.delta);
}model.stream() 返回 ReadableStream<ModelStreamEvent>。成功流以 model_start 开始,在 model_finish 前提供最终 model_usage;协议顺序无效时客户端会直接报错。
作为 Agent 模型
模型目录返回的对象实现 ModelClient,可以直接交给 Agent:
const catalog = await city.ai.catalog();
const model = catalog.require("deepseek-v4-flash");
const agent = new Agent({ id: "reviewer", model });Agent 负责 Session 上下文、工具循环和审批;Federation 负责最终模型选择与计费。
多模态 fallback
Fallback 只检查 ModelCall.messages 中最新一条 role: "user" 消息的 file 内容。最新用户消息只有文本时不会再次触发 fallback;如果最终模型的 fallback 规则不接受某个历史文件,该文件会在本次执行视图中降级为 filename、原始 URL 或 MIME type 文本。Session 保存的原始文件不变。末尾即使存在 assistant 或 tool 消息,也会向前定位最近的 user。
OpenAI-compatible 客户端
需要使用 OpenAI SDK、curl 或现有网关时,调用 /v1/ai/chat/completions。该端点会在边界把 OpenAI 请求转换为同一个 ModelCall,路由、fallback、reasoning、usage 和计费语义保持一致。
调用决策模型
决策模型接收原始状态与带类型的问题,返回带校准概率的判定,不生成文本:
/** 通过当前 Federation 用户身份调用 Jev。 */
import { Embassy } from "@downcity/federation";
const embassy = new Embassy({
federation_url: "http://localhost:3000",
user_token: process.env.FEDERATION_USER_TOKEN,
});
const { answers } = await embassy.user.ai.decision({
model: "teamorouter-jev",
state: { type: "text", text: "客户连续三天未能连接 Stripe。" },
questions: [
{ id: "urgent", type: "boolean", instructions: "这条消息是否表达紧急?" },
{ id: "route", type: "choice", instructions: "应该由哪个队列处理?", options: ["billing", "support"] },
{ id: "churn_risk", type: "score", instructions: "流失风险", min: 1, max: 4 },
],
});
answers[0].value; // true
answers[0].probability; // 0.87
answers[1].distribution; // { billing: 0.72, support: 0.28 }state 为 { type: "text", text } 或 { type: "json", data }。支持三种问题类型,都不产生自由文本:
| 类型 | 答案 | 说明 |
|---|---|---|
boolean | true / false | — |
choice | options 中的一个 | 1 到 255 个不重复候选取值 |
score | 数值 | 需满足 min < max |
问题 ID 必须唯一,且每个问题必须且只能被回答一次。非法输入在任何用量记录产生前返回 422;Channel 返回未覆盖全部问题的结果同样会被拒绝。
embassy.user.ai.decision(input, signal) 支持可选的 AbortSignal,答案通过 question_id 对应问题。Group 可以绑定该方法作为决策客户端,每轮选择并行回复成员;成员保留自己的执行模型。
决策模型不是对话模型:它的 modalities 只有 decision,不能交给 Agent。