> ## Documentation Index
> Fetch the complete documentation index at: https://docs.profy.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 对话补全

> POST /v1/chat/completions — OpenAI 兼容的对话补全接口

OpenAI 兼容的对话补全端点。如果你已经在使用 OpenAI SDK，只需更改 `base_url` 和 `api_key` 即可无缝迁移。

```
POST https://api.profy.cn/v1/chat/completions
```

## 认证

支持两种认证方式：

* **API Key**：`Authorization: Bearer sk-pro-xxxx`
* **OAuth Bearer**：`Authorization: Bearer <access_token>`

## 请求体

<ParamField body="model" type="string" required>
  模型标识符。使用 `GET /v1/models` 查询可用模型。
</ParamField>

<ParamField body="messages" type="array" required>
  对话消息数组。每条消息包含 `role` 和 `content` 字段。
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  是否使用 SSE 流式返回。
</ParamField>

<ParamField body="temperature" type="number">
  采样温度，范围 0-2。值越高输出越随机。部分模型不支持此参数（参见模型 capabilities）。
</ParamField>

<ParamField body="max_tokens" type="integer">
  生成的最大 token 数。
</ParamField>

<ParamField body="top_p" type="number">
  Nucleus sampling 参数。
</ParamField>

<ParamField body="frequency_penalty" type="number">
  频率惩罚参数，范围 -2.0 到 2.0。
</ParamField>

<ParamField body="presence_penalty" type="number">
  存在惩罚参数，范围 -2.0 到 2.0。
</ParamField>

<ParamField body="stop" type="string | string[]">
  停止生成的标记。
</ParamField>

<ParamField body="tools" type="array">
  Function Calling 工具定义数组（与 OpenAI 格式一致）。
</ParamField>

<ParamField body="tool_choice" type="string | object">
  工具选择策略：`"auto"`、`"none"` 或指定工具。
</ParamField>

## 非流式请求示例

<CodeGroup>
  ```python Python theme={null}
  from profy import Profy

  async with Profy(api_key="sk-pro-your-key") as client:
      resp = await client.chat.completions.create(
          model="deepseek-v3",
          messages=[
              {"role": "system", "content": "你是一个专业的翻译助手"},
              {"role": "user", "content": "把这句话翻译成英文：今天天气真好"},
          ],
          temperature=0.3,
      )
      print(resp.text)
  ```

  ```typescript TypeScript theme={null}
  import { Profy } from "@profy-ai/sdk";

  const client = new Profy({ apiKey: "sk-pro-your-key" });

  const resp = await client.chat.completions.create({
    model: "deepseek-v3",
    messages: [
      { role: "system", content: "你是一个专业的翻译助手" },
      { role: "user", content: "把这句话翻译成英文：今天天气真好" },
    ],
    temperature: 0.3,
  });

  console.log(resp.text);
  ```

  ```bash curl theme={null}
  curl -X POST https://api.profy.cn/v1/chat/completions \
    -H "Authorization: Bearer sk-pro-your-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek-v3",
      "messages": [
        {"role": "system", "content": "你是一个专业的翻译助手"},
        {"role": "user", "content": "把这句话翻译成英文：今天天气真好"}
      ],
      "temperature": 0.3
    }'
  ```
</CodeGroup>

## 非流式响应

```json theme={null}
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "model": "deepseek-v3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The weather is really nice today."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 28,
    "completion_tokens": 8,
    "total_tokens": 36
  },
  "balance_remaining": 9500
}
```

<Note>
  响应中额外包含 `balance_remaining` 字段，返回调用后的剩余积分余额。这是与 OpenAI 的主要差异之一。
</Note>

## 流式请求示例

<CodeGroup>
  ```python Python（流式） theme={null}
  from profy import Profy

  async with Profy(api_key="sk-pro-your-key") as client:
      stream = await client.chat.completions.create(
          model="deepseek-v3",
          messages=[{"role": "user", "content": "讲一个笑话"}],
          stream=True,
      )
      async for chunk in stream:
          if chunk.delta:
              print(chunk.delta, end="", flush=True)
  ```

  ```typescript TypeScript（流式） theme={null}
  import { Profy } from "@profy-ai/sdk";

  const client = new Profy({ apiKey: "sk-pro-your-key" });

  const stream = await client.chat.completions.create({
    model: "deepseek-v3",
    messages: [{ role: "user", content: "讲一个笑话" }],
    stream: true,
  });

  for await (const chunk of stream) {
    if (chunk.delta) {
      process.stdout.write(chunk.delta);
    }
  }
  ```

  ```bash curl（流式） theme={null}
  curl -N -X POST https://api.profy.cn/v1/chat/completions \
    -H "Authorization: Bearer sk-pro-your-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek-v3",
      "messages": [{"role": "user", "content": "讲一个笑话"}],
      "stream": true
    }'
  ```
</CodeGroup>

## 作为 OpenAI 替代

如果你正在使用 OpenAI 的官方 SDK，只需修改 `base_url` 和 `api_key`：

<CodeGroup>
  ```python Python（OpenAI SDK） theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-pro-your-key",
      base_url="https://api.profy.cn/v1",
  )

  response = client.chat.completions.create(
      model="deepseek-v3",
      messages=[{"role": "user", "content": "你好"}],
  )
  print(response.choices[0].message.content)
  ```

  ```typescript TypeScript（OpenAI SDK） theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "sk-pro-your-key",
    baseURL: "https://api.profy.cn/v1",
  });

  const response = await client.chat.completions.create({
    model: "deepseek-v3",
    messages: [{ role: "user", content: "你好" }],
  });
  console.log(response.choices[0].message.content);
  ```
</CodeGroup>

## 调用袋袋专家（Expert-as-Model）

除了直接调用裸模型，你还可以通过 `profy-<identifier>` 格式的模型名调用袋袋平台上已发布的专家（AI Agent）。专家背后是完整的 Agent 能力栈：人格、工具调用、记忆、技能——而你只需像调用普通模型一样使用它。

### 模型命名约定

| 格式                   | 含义              | 示例                        |
| -------------------- | --------------- | ------------------------- |
| `profy-<identifier>` | 调用指定的袋袋专家       | `profy-financial-advisor` |
| 其他模型名                | 直接调用裸 LLM（现有行为） | `deepseek-v3`             |

使用 `GET /v1/models` 可以查询所有可用的专家模型（`type: "expert"`）。

### 请求示例（非流式）

默认行为（`stream` 省略或为 `false`）：Agent 完成全部推理和工具调用后，一次性返回完整 JSON 响应。

<CodeGroup>
  ```python Python（OpenAI SDK） theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-pro-your-key",
      base_url="https://api.profy.cn/v1",
  )

  response = client.chat.completions.create(
      model="profy-financial-advisor",
      messages=[
          {"role": "user", "content": "帮我分析一下特斯拉最近的财报"}
      ],
  )

  print(response.choices[0].message.content)
  ```

  ```typescript TypeScript（OpenAI SDK） theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "sk-pro-your-key",
    baseURL: "https://api.profy.cn/v1",
  });

  const response = await client.chat.completions.create({
    model: "profy-financial-advisor",
    messages: [
      { role: "user", content: "帮我分析一下特斯拉最近的财报" },
    ],
  });

  console.log(response.choices[0].message.content);
  ```

  ```bash curl theme={null}
  curl -X POST https://api.profy.cn/v1/chat/completions \
    -H "Authorization: Bearer sk-pro-your-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "profy-financial-advisor",
      "messages": [
        {"role": "user", "content": "帮我分析一下特斯拉最近的财报"}
      ]
    }'
  ```
</CodeGroup>

### 请求示例（流式）

设置 `stream: true` 可实时接收增量内容，适合需要即时展示文字的场景。

<CodeGroup>
  ```python Python（OpenAI SDK，流式） theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-pro-your-key",
      base_url="https://api.profy.cn/v1",
  )

  response = client.chat.completions.create(
      model="profy-financial-advisor",
      messages=[
          {"role": "user", "content": "帮我分析一下特斯拉最近的财报"}
      ],
      stream=True,
  )

  for chunk in response:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

  ```typescript TypeScript（OpenAI SDK，流式） theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "sk-pro-your-key",
    baseURL: "https://api.profy.cn/v1",
  });

  const stream = await client.chat.completions.create({
    model: "profy-financial-advisor",
    messages: [
      { role: "user", content: "帮我分析一下特斯拉最近的财报" },
    ],
    stream: true,
  });

  for await (const chunk of stream) {
    const content = chunk.choices[0]?.delta?.content;
    if (content) process.stdout.write(content);
  }
  ```

  ```bash curl（流式） theme={null}
  curl -N -X POST https://api.profy.cn/v1/chat/completions \
    -H "Authorization: Bearer sk-pro-your-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "profy-financial-advisor",
      "messages": [
        {"role": "user", "content": "帮我分析一下特斯拉最近的财报"}
      ],
      "stream": true
    }'
  ```
</CodeGroup>

### 多轮对话（Session）

首次调用时系统自动创建 session，session ID 通过响应头 `X-Session-Id` 返回。后续调用通过以下任一方式传入 session ID 来续接对话：

* 请求体 `session_id` 字段（推荐，OpenAI SDK 通过 `extra_body` 传递）
* 请求头 `X-Session-Id`

```python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="sk-pro-your-key",
    base_url="https://api.profy.cn/v1",
)

# 第一轮
r1 = client.chat.completions.create(
    model="profy-financial-advisor",
    messages=[{"role": "user", "content": "我叫小明，帮我做个投资计划"}],
    extra_body={}
)
session_id = r1._headers.get("x-session-id")

# 第二轮 — 专家记得你的名字和上下文
r2 = client.chat.completions.create(
    model="profy-financial-advisor",
    messages=[{"role": "user", "content": "你还记得我叫什么吗？"}],
    extra_body={"session_id": session_id}
)
```

### Expert-as-Model 与 Agents Run 的对比

| 特性       | `/v1/chat/completions` + `profy-*` | `/v1/agents/run`  |
| -------- | ---------------------------------- | ----------------- |
| SDK 兼容性  | OpenAI SDK 直接使用                    | 需要 Profy SDK      |
| 响应格式     | OpenAI Chat Completions 标准格式       | Profy 自定义 SSE 事件  |
| 流式 / 非流式 | 均支持（`stream` 默认 `false`）           | 仅流式               |
| 工具调用过程   | 静默（Agent 内部消化）                     | 16 种事件全量暴露        |
| 适用场景     | drop-in 替换、LangChain 集成、快速接入       | 需要工具可观测性、构建自定义 UI |

<Tip>
  如果你需要观测 Agent 的完整工具调用过程（如展示"正在搜索..."、"正在分析数据..."等中间状态），请使用 `/v1/agents/run` 端点配合 Profy SDK。
</Tip>

## 与 OpenAI 的差异

| 特性               | 袋袋                        | OpenAI     |
| ---------------- | ------------------------- | ---------- |
| 模型名称             | 袋袋平台模型标识符                 | OpenAI 模型名 |
| 额外返回字段           | `balance_remaining`（剩余积分） | 无          |
| Function Calling | 支持（部分模型）                  | 全量支持       |
| Vision           | 支持（部分模型）                  | 支持         |
| 计费方式             | 袋袋积分                      | 美元         |

<Tip>
  使用 `GET /v1/models` 查询每个模型的 `capabilities`，了解该模型是否支持 temperature、tools、vision 等功能。
</Tip>

## 错误码

| HTTP 状态码 | 说明                             |
| -------- | ------------------------------ |
| `400`    | 缺少 `model` 或 `messages`，或模型不可用 |
| `401`    | 认证失败                           |
| `502`    | 上游模型提供商返回错误                    |

## 下一步

<CardGroup cols={2}>
  <Card title="模型列表" icon="list" href="/zh/developers/api/models">
    查询可用模型及其能力
  </Card>

  <Card title="上报计费事件" icon="bolt" href="/zh/developers/api/events">
    上报自定义计费事件
  </Card>
</CardGroup>
