VISION API · V1

把 Harness 的识图能力
接入你的应用

从第三方后端创建受限会话、提交图片,再通过安全的 Run API 轮询阶段状态和最终文字结果。

BASE URLhttps://agent.example.com
AUTHBearer API Key
POLLING建议 1 秒 / 次
API Key 只放在服务端

不要把 VISION_ONLY_API_KEY 写进网页、App 安装包或公开仓库。你的前端应请求自己的业务后端,再由后端调用本 API。

QUICK START

一次识图任务的完整流程

会话代表一段多轮上下文,Run 代表其中一次业务任务。第三方系统保存两个 ID,就能持续查询任务。

  1. 01
    创建 vision 会话获得 session_id,会话固定绑定 vision-only 能力。
  2. 02
    提交图片和目标获得 run_id,任务先进入 queued 状态。
  3. 03
    按游标轮询每秒查询一次;出现问题时提交回答。
  4. 04
    读取文字结果status 进入 completed 后读取 result.text
AUTHENTICATION

1. 验证访问密钥

向管理员申请 vision-only Key,并在每个请求的 Authorization Header 中携带。管理员可在 /admin/keys 即时签发独立 Key,无需重新部署。可以先调用检查接口确认权限。

GET/v1/auth/check检查 Key 权限
curl https://agent.example.com/v1/auth/check \
  -H "Authorization: Bearer $VISION_AGENT_KEY"
200 RESPONSE{"ok":true,"mode":"api_key","capabilities":["vision"],"user":null}
SESSION

2. 创建识图会话

capability 必须为 visionclient_reference 可用于关联你自己的订单、用户或任务编号,最长 200 个字符。

POST/v1/sessions创建会话
curl -X POST https://agent.example.com/v1/sessions \
  -H "Authorization: Bearer $VISION_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "capability": "vision",
    "client_reference": "order-1001"
  }'
201 RESPONSE
{
  "id": "7a34...",
  "created_at": "2026-08-17T10:00:00.000Z",
  "status": "idle",
  "capability": "vision",
  "legacy": false,
  "client_reference": "order-1001"
}
MESSAGE

3. 提交图片任务

图片内容使用纯 Base64,不要带 data:image/...;base64, 前缀。一次最多 4 张,单张最大 10MB,请求体最大 16MB。

POST/v1/sessions/{session_id}/messages创建 Run
curl -X POST \
  https://agent.example.com/v1/sessions/SESSION_ID/messages \
  -H "Authorization: Bearer $VISION_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "queue",
    "text": "识别商品名称、价格和主要宣传文字",
    "images": [{
      "media_type": "image/jpeg",
      "name": "product.jpg",
      "data": "BASE64_DATA"
    }]
  }'
202 RESPONSE{"accepted":true,"session_id":"...","run_id":"..."}
支持格式image/pngimage/jpegimage/webpimage/gif
RUN POLLING

4. 轮询阶段和最终结果

运行期间建议每秒轮询一次。把响应中的 next_cursor 用作下一次 after,终态后立即停止轮询。

GET/v1/sessions/{session_id}/runs/{run_id}读取 Run
curl "https://agent.example.com/v1/sessions/SESSION_ID/runs/RUN_ID?after=0&limit=50" \
  -H "Authorization: Bearer $VISION_AGENT_KEY"
RUNNING RESPONSE
{
  "session_id": "...",
  "run_id": "...",
  "capability": "vision",
  "status": "running",
  "stage": "analyzing",
  "events": [{
    "id": 3,
    "time": "2026-08-17T10:00:02.000Z",
    "stage": "analyzing",
    "state": "active",
    "message": "正在分析图片内容"
  }],
  "next_cursor": 3,
  "has_more": false,
  "input_required": null,
  "result": null,
  "error": null
}
COMPLETED · 关键字段
{
  "status": "completed",
  "stage": "completed",
  "result": {
    "text": "商品名称为……,标价为……"
  },
  "error": null
}
分页参数after 必须是非负整数;limit 默认 50,最大 100。
HUMAN INPUT

5. 回答补充问题

当 status 为 waiting_input 时,读取 input_required.question_id 和问题数组。提交答案后继续轮询原来的 run_id

WAITING_INPUT · 关键字段
{
  "status": "waiting_input",
  "input_required": {
    "question_id": "...",
    "questions": [{
      "id": "subject",
      "question": "需要识别图片中的哪个商品?",
      "options": ["左侧商品", "右侧商品"]
    }]
  }
}
POST/v1/sessions/{session_id}/questions/{question_id}提交回答
curl -X POST \
  https://agent.example.com/v1/sessions/SESSION_ID/questions/QUESTION_ID \
  -H "Authorization: Bearer $VISION_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "answers": [{
      "id": "subject",
      "selected": ["右侧商品"]
    }]
  }'
STEERING

6. 给当前任务追加指令

mode: "steer" 不创建新业务 Run,而是关联当前正在执行的 Run,响应会返回相同的 run_id

curl -X POST \
  https://agent.example.com/v1/sessions/SESSION_ID/messages \
  -H "Authorization: Bearer $VISION_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "steer",
    "text": "重点识别图片右下角的小字"
  }'
CANCELLATION

7. 取消任务

取消请求接受后 Run 会先进入 cancelling,随后变为 cancelled。进入终态后停止轮询。

POST/v1/sessions/{session_id}/cancel取消当前任务
curl -X POST \
  https://agent.example.com/v1/sessions/SESSION_ID/cancel \
  -H "Authorization: Bearer $VISION_AGENT_KEY"
NODE.JS EXAMPLE

可直接改造的完整后端示例

这段 Node.js 代码可直接从本地文件读取图片并执行一次完整任务。生产代码应设置请求超时,并把 session_idrun_id 与你的业务记录一起保存。

import { readFile } from 'node:fs/promises'

const BASE_URL = process.env.IMAGE_AGENT_URL
const API_KEY = process.env.VISION_ONLY_API_KEY
const imageBase64 = (await readFile('./product.jpg')).toString('base64')

async function request(path, options = {}) {
  const response = await fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  })
  const body = await response.json()
  if (!response.ok) throw new Error(body.error?.code || 'api_error')
  return body
}

const session = await request('/v1/sessions', {
  method: 'POST',
  body: JSON.stringify({
    capability: 'vision',
    client_reference: 'order-1001',
  }),
})

const accepted = await request(`/v1/sessions/${session.id}/messages`, {
  method: 'POST',
  body: JSON.stringify({
    mode: 'queue',
    text: '提取图片中的商品名称、价格和文案',
    images: [{
      media_type: 'image/jpeg',
      name: 'product.jpg',
      data: imageBase64,
    }],
  }),
})

let cursor = 0
while (true) {
  const run = await request(
    `/v1/sessions/${session.id}/runs/${accepted.run_id}` +
    `?after=${cursor}&limit=50`
  )
  cursor = run.next_cursor

  for (const event of run.events) console.log(event.message)

  if (run.status === 'completed') {
    console.log(run.result.text)
    break
  }
  if (run.status === 'waiting_input') {
    console.log('需要回答:', run.input_required)
    break
  }
  if (['failed', 'cancelled'].includes(run.status)) {
    throw new Error(run.error?.code || run.status)
  }
  await new Promise(resolve => setTimeout(resolve, 1000))
}
RUN STATUS

状态说明

状态含义调用方动作
queued已接受,等待执行继续轮询
running正在规划、识图或整理结果继续轮询
waiting_input需要调用方回答问题提交 answers
cancelling正在处理中断请求继续轮询
completed任务完成读取 result.text 并停止
failed任务失败读取 error.code 并停止
cancelled任务已取消停止轮询
ERRORS

常见错误码

HTTP 错误统一使用 { "error": { "code": "...", "message": "..." }, "request_id": "..." },同一个 ID 也会出现在 X-Request-Id 响应头。运行时 Agent 错误位于 Run 的 error 字段,并带可供服务端查日志的 incident_id

unauthorizedKey 缺失或无效
invalid_capabilitycapability 不是 image 或 vision
unsupported_field调用方传入了 agent_preset
capability_forbiddenvision-only Key 请求了 image
invalid_image_input图片格式、数量、Base64 或大小无效
worker_busy单 Worker 正在处理其他会话
steer_unavailable当前没有可追加指令的 Run
legacy_session旧会话只读,需要创建新会话
run_not_foundRun 不存在或不属于此会话
invalid_cursorafter 不是非负整数
invalid_limitlimit 不在 1 到 100 之间
transport_forbiddenvision-only Key 请求原始 SSE
model_not_configured服务端模型凭据缺失,联系管理员处理
agent_errorAgent 异步失败,向管理员提供 incident_id
service_restarted任务被 Gateway 重启中断
SECURITY BOUNDARY

vision-only 返回什么,不返回什么

允许
  • 受控阶段状态
  • 需要回答的问题
  • 最终文字结果
  • 安全错误码
不返回
  • 隐藏思维链
  • 工具参数
  • 工具原始输出
  • Shell、文件或 Web 能力

vision-only Key 不能创建 image 会话,也不能访问原始 /events SSE。识图工具只能读取当前会话目录中的本地图片。最终文本最多 16,000 字符。