# 使用集成调用 OpenAI 模型｜Creght

> 在 Creght 用 OpenAI 集成调模型：ctx.ai.openai.chat 做翻译与对话，json: true 稳定拿 JSON，tools 做单次工具调用，image 生成图片并返回永久地址，密钥不进沙箱。

[![Creght](https://ugc.talizen.com/_assets/site/2061660904709165056/1780797461299__creght_logo.png)API for AI](/)

[查看 llms.txt](/llms.txt)

概览

- [Creght AI 编程指南](/api.md)

AI 可发现性

- [如何优化 llms.txt](/api/optimize-llms-txt.md)

站点配置

- [配置 talizen.config.ts](/api/talizen-config.md)
- [实现基于域名的多语言路由](/api/domain-locale-routing.md)

后端

- [在服务端调用外部 API 并管理缓存](/api/ssr-external-api-cache.md)
- [使用 Func 构建站点后端能力](/api/func-backend.md)
- [JSON 表：定义、读写与查询](/api/func-json-tables.md)
- [上传文件：直传与 Func 内生成](/api/func-assets-upload.md)
- [超时配置与流式响应](/api/func-timeout-streaming.md)
- [使用 Func 接入支付宝电脑网站支付](/api/func-alipay-payment.md)

集成

- [使用集成发送邮件与验证码](/api/func-email-integration.md)
- [使用集成接入支付宝支付](/api/func-alipay-integration.md)
- [使用集成接入 Stripe 支付](/api/func-stripe-integration.md)
- [使用集成调用 OpenAI 模型](/api/func-ai-integration.md)
- [使用集成接入文字转语音](/api/func-tts-integration.md)

登录与用户

- [注册时验证邮箱](/api/auth-verified-registration.md)
- [实现找回密码与修改密码](/api/auth-password-reset.md)
- [在 Func 里实现登录](/api/auth-func-login.md)
- [在 Func 里查询用户](/api/func-user-directory.md)

本页目录

- [连接 OpenAI](#connect)
- [chat：一次对话](#chat)
- [要 JSON 就传 json: true](#json)
- [单次 tool call](#tools)
- [生成图片](#image)
- [逃生舱：extra 与 call](#extra)
- [多渠道：via(tag)](#via)
- [报错怎么看](#errors)
- [不做的事](#scope)

集成/使用集成调用 OpenAI 模型

# 使用集成调用 OpenAI 模型

连接 OpenAI 集成后在 Func 里用 ctx.ai.openai 调模型：chat 做对话与翻译，json 让模型稳定输出结构化数据，tools 做单次工具调用，image 生成图片并存进项目空间。API Key 只保存在服务端。

复制 Markdown 链接

连接 OpenAI 集成之后，Func 里用 `ctx.ai.openai` 就能调模型：对话、翻译、抽取结构化数据、调用一次工具、生成图片。API Key 只保存在服务端，代码里不会出现。

**本文范围**

单次调用。平台不跑多轮 agent 循环，也不做流式，理由在 [最后一节](#scope)。

接口形状是 OpenAI 的 `/chat/completions`。把集成的接口地址指向任意兼容网关（自建的、聚合服务的、云厂商的），站点代码一个字都不用改。

## 连接 OpenAI

打开编辑器的 **后端 → 集成**，点 **OpenAI**，按下表填写。保存时平台会真的打一次上游，密钥不对当场报错，而不是等到有人用到这个功能才发现。

| 字段 | 填什么 | 必填 |
| --- | --- | --- |
| API Key | `sk-` 开头的密钥，在 [OpenAI 后台](https://platform.openai.com/api-keys) 创建 | 是 |
| 默认模型 | 调用没指定模型时用它，比如 `gpt-4o-mini` | 建议 |
| 接口地址 | 留空就是 `https://api.openai.com/v1`。填别家兼容地址即可换供应商 | 否 |
| 渠道标签 | 同一个项目可以接多份配置，用标签区分，见 [多渠道](#via) | 否 |

**接口地址怎么填**

填到 `/v1` 为止就行，末尾的斜杠和 `/chat/completions` 都会被自动去掉。常见的填法是 `https://api.openai.com/v1`、 `https://your-gateway.com/v1`。

## chat：一次对话

`ctx.ai.openai.chat(params)` 发一次调用并返回完整结果。

```ts
export function translate(input, ctx) {
  const r = ctx.ai.openai.chat({
    messages: [
      { role: 'system', content: '把用户输入翻译成英文，只输出译文' },
      { role: 'user', content: input.text },
    ],
    model: 'gpt-4o-mini',   // 不传就用集成里配的默认模型
    temperature: 0.2,
    maxTokens: 512,
  })
  return { text: r.content, tokens: r.totalTokens }
}
```

| 参数 | 说明 |
| --- | --- |
| `messages` | 必填。 `{ role, content }` 数组， `role` 取 `system` / `user` / `assistant` / `developer` / `tool` |
| `model` | 留空取集成里配的默认模型 |
| `temperature` | 不传就不发这个字段 |
| `maxTokens` | 不传就不发这个字段 |
| `json` | `true` 时平台剥代码块并解析，结果放进 `data`，见 [要 JSON](#json) |
| `tools` / `toolChoice` | 工具定义，见 [单次 tool call](#tools) |
| `extra` | 逃生舱，原样并进请求体，见 [逃生舱](#extra) |

返回：

| 字段 | 说明 |
| --- | --- |
| `content` | 模型回复的文本。只要求调用工具时它是空的，这不是错误 |
| `model` | 实际用到的模型 |
| `finishReason` | `stop` / `length` / `tool_calls` 等 |
| `promptTokens` / `completionTokens` / `totalTokens` | 用量，方便自己记账 |
| `data` | 只有 `json: true` 时才有 |
| `toolCalls` | 只有模型要求调用工具时才有 |

## 要 JSON 就传 json: true

让模型输出 JSON 是这个能力最常见的用法：翻译、抽取、分类全是。 `json: true` 时平台会剥掉模型爱包的代码块再解析，结果放在 `data` 里。

```ts
export function extract(input, ctx) {
  const r = ctx.ai.openai.chat({
    messages: [{ role: 'user', content: `从这段话里抽出姓名和城市，返回 JSON：${input.text}` }],
    json: true,
  })
  return { name: r.data.name, city: r.data.city }
}
```

**为什么这一步值得交给平台**

模型回不回代码块取决于模型和当天心情。站点自己写 `JSON.parse` 而忘了剥壳，表现是 **偶发** 解析失败：今天好用明天不好用，最难查。

`json: true` 只管我们这边怎么解析， **不会** 往请求里加 `response_format`：不同网关对这个字段的支持不一致，多传一个不认识的字段就是 400。让模型输出 JSON 仍然要靠提示词写清楚。

## 单次 tool call

传 `tools`，模型要调工具时 `toolCalls` 里就有东西。典型用法是一轮：把用户的自然语言变成一次结构化的函数调用，站点自己执行，然后直接回话。

```ts
export function assistant(input, ctx) {
  const r = ctx.ai.openai.chat({
    messages: [{ role: 'user', content: input.text }],
    tools: [{
      type: 'function',
      function: {
        name: 'reschedule',
        description: '把一个会议改期',
        parameters: {
          type: 'object',
          properties: { meetingId: { type: 'string' }, date: { type: 'string' } },
          required: ['meetingId', 'date'],
        },
      },
    }],
    toolChoice: 'auto',
  })

  if (r.toolCalls?.length) {
    const c = r.toolCalls[0]
    // c.arguments 已经是对象
    ctx.db.update('meetings', c.arguments.meetingId, { date: c.arguments.date })
    return { done: true }
  }
  return { reply: r.content }
}
```

| `toolCalls[i]` | 说明 |
| --- | --- |
| `id` | 这次调用的 id。要跑第二轮的话得把它带回去 |
| `name` | 模型要调的函数名 |
| `arguments` | **已经解析好的对象**。模型吐出坏 JSON 时它是 `undefined` |
| `argumentsRaw` | 参数原文，永远都在 |

**arguments 为什么由平台解析**

OpenAI 原始返回里 `arguments` 是一个 **JSON 字符串** 而不是对象。忘了 `JSON.parse` 的表现不是报错，而是 `args.city` 静默变成 `undefined`，然后代码拿着 undefined 一路往下走。这类「写错了不报错」的坑正是集成要替你堵的。

想跑第二轮（执行完工具再让模型总结）也可以，把工具结果拼回 `messages` 再调一次即可：

```ts
const r2 = ctx.ai.openai.chat({
  messages: [
    { role: 'user', content: input.text },
    { role: 'assistant', toolCalls: r.toolCalls },              // 回放模型上一轮的要求
    { role: 'tool', toolCallId: r.toolCalls[0].id, content: JSON.stringify(result) },
  ],
})
```

平台不替你跑这个循环：几轮停、工具能不能读数据库、超时怎么算，只有站点自己知道。

## 生成图片

`ctx.ai.openai.image(params)`。 **强烈建议带 `upload: true`**，图片会直接存进项目自己的空间并返回永久地址。

```ts
export const config = { timeoutMs: 120000 }   // 生图慢，几十秒是常态

export function cover(input, ctx) {
  const r = ctx.ai.openai.image({
    prompt: input.prompt,
    size: '1024x1024',
    quality: 'high',
    upload: true,
  })
  return { url: r.images[0].fileUrl }
}
```

| 参数 | 说明 |
| --- | --- |
| `prompt` | 必填。只传一个字符串也行： `image('一只雪地里的红狐狸，水彩')` |
| `model` | 默认 `gpt-image-1`。 **不会** 用集成里配的对话模型，那是两回事 |
| `size` | 如 `1024x1024`、 `1536x1024` |
| `quality` | `low` / `medium` / `high`；dall-e-3 是 `standard` / `hd` |
| `style` | dall-e-3 专有： `vivid` / `natural` |
| `background` | gpt-image-1 专有： `transparent` / `opaque` / `auto` |
| `n` | 张数，最多 4 |
| `upload` | `true` 时存进项目空间并返回 `fileUrl`；不传则返回 `imageBase64` |
| `filename` | 只在 `upload` 时有用。默认按内容哈希命名 |

返回 `{ model, images: [...] }`，每张图是 `{ fileUrl | imageBase64, mimeType, bytes, revisedPrompt? }`。

**为什么生图要走集成，而不是自己调接口**

OpenAI 直接返回的图片地址是 **临时的，大约一小时后失效**。自己调接口、把那个地址存进数据库、渲染到页面上，测试时一切正常，上线之后图片会慢慢变成 404，而且不报任何错、日志里也看不出来。

平台永远向上游要图片 **字节** 而不是地址，所以你手里拿不到会过期的东西：要么是自己空间里的永久地址，要么是 base64。

## 逃生舱：extra 与 call

想传平台没暴露的字段，用 `extra`。它原样并进请求体，但改不坏 `messages`：

```ts
ctx.ai.openai.chat({
  messages,
  extra: { top_p: 0.9, seed: 42, response_format: { type: 'json_object' } },
})
```

想调 `/chat/completions` 之外的接口，用 `call(path, body)`。请求体原样发出，上游返回的 JSON 原样交回，密钥同样不进沙箱：

```ts
const r = ctx.ai.openai.call('/embeddings', {
  model: 'text-embedding-3-small',
  input: input.text,
})
const vector = r.data[0].embedding
```

## 多渠道：via(tag)

一个项目可以接多份 OpenAI 配置，比如分类用便宜模型、写作用强模型，或者一份官方一份自建网关。给每份配置写上渠道标签，代码里用 `via()` 选：

```ts
ctx.ai.openai.via('cheap').chat({ messages })
ctx.ai.openai.via('strong').chat({ messages })
```

不写 `via()` 时用标签为 `default` 的那份。

## 报错怎么看

| 报错 | 该改哪一项 |
| --- | --- |
| `ai integration has no api key` | 集成没连，或密钥被清空了 |
| `model is required` | 调用没传 `model`，集成里也没配默认模型 |
| `message at index N has empty content` | 有一条消息的 `content` 是空的 |
| `message at index N has role tool but no toolCallId` | 跑第二轮时忘了带 `toolCallId` |
| `ai response is not valid json` | 用了 `json: true` 但模型没给 JSON。报错里带原文片段，先看是提示词没说清楚还是模型跑偏 |
| `the image provider returned a temporary url` | 网关没按要求返回图片字节。改用 `call()` 自己处理，或换一个支持 `b64_json` 的网关 |
| `invalid n` | 一次最多 4 张 |

上游自己的报错（额度用完、模型不存在、速率限制）会原样带上文案转成 400 或 502。 **不会** 把上游的 401 直接抛给前端，那会让页面误以为是没登录。

## 不做的事

| 不做 | 为什么 |
| --- | --- |
| 多轮 agent 循环 | 停机条件、轮数预算、工具权限只有站点自己知道。单次 tool call 有，循环自己写 |
| 流式输出 | Func 的返回值本来就是一次性的。要打字机效果用 `ctx.sse` 自己推 |
| 缓存与去重 | 「什么算同一次请求」只有站点知道。要缓存自己建一张表 |
| 并入平台积分 | 这是你自己的 API Key、你自己的账单，平台不插手计费 |

相关文档： [更多集成](/docs/ai/more-integrations.md)、 [语音合成集成](/api/func-tts-integration.md)、 [Func 后端能力](/api/func-backend.md)。

![Creght](https://ugc.talizen.com/_assets/site/2061660904709165056/1780797461299__creght_logo.png)

此网站使用 [Creght](/) 创建

![微信客服](https://fsu.creght.com/site/2066727200882692096/1785119134612__image.png?w=3072&fmt=webp)

微信客服

## 链接

- [SaaS 官网生成器](/saas-website-builder.md)
- [价格](/price.md)
- [解决方案](/solution.md)
- [客户案例](/customers.md)
- [AI 模型对比](/ai-models.md)
- [帮助中心](/help.md)
- [联系我们](/contact.md)
- [更新记录 & 博客](/blogs.md)
- [退款说明](/tuikuan.md)

## 资源

- [全部资源](/resources.md)
- [模板](/templates.md)
- [组件库](https://creghtlib.site.creght.com)
- [动效库](/design/effects.md)
- [Figma to Creght](/figma2creght.md)
- [API](/api.md)

## 产品对比

- [对比上线了](/creght-vs-sxl.md)
- [对比凡科建站](/creght-vs-fkw.md)
- [Creght vs 自己写代码](/compare/self-coding.md)
- [Creght vs 外包](/compare/outsourcing.md)
- [Creght vs Framer](/compare/framer.md)
- [Creght vs WordPress](/compare/wordpress.md)

## 协议

- [用户协议](/legal/terms.md)
- [隐私政策](/legal/privacy.md)
- [可接受使用政策](/legal/acceptable-use.md)

## 社交媒体

- [小红书](https://www.xiaohongshu.com/user/profile/5a38606811be10715f4895b6)
- [哔哩哔哩](https://space.bilibili.com/513308095)

[蜀ICP备2023038192号-2](https://beian.miit.gov.cn)

免费方案评估

> 全站页面清单：[/llms.txt](/llms.txt)
