Agent Kit 简介
Agent Kit 是 OpenAI 推出的一个基于 Agent 的工作流编排工具,可以一条龙搞定「编排 → 发布 → 集成 →评估」的 AI 工作流平台。
如果你正在寻找把 AI 工作流从原型拉到生产的稳妥方式,Agent Kit 值得优先试用。它把可视化编排、前端嵌入、数据连接与效果评估串成一个闭环,降低实施成本、提升上线速度。
核心组件一览
- Agent Builder:拖拽式可视化编排,所见即所得地搭流程。
- ChatKit:将已发布的工作流一键嵌入前端页面,开箱即用的聊天组件。
- Evals:自动化评估与优化,支持自定义指标和评估模型。
- Connector Registry:统一管理数据源与工具接入,规范化配置与权限。
为什么选 Agent Kit
- 输出到自定义组件:工作流的结果可直达你的前端组件,可在 Widgets Studio 设计并复用渲染逻辑。
- 前端快速接入:通过 ChatKit 将工作流发布为组件,几行代码接入对话能力。
- 内置评估闭环:使用 Evaluation 评估与优化工作流,支持自定义指标,持续提升效果。
使用限制与注意事项
- MCP 工具生态仍在扩充,当前数量有限。
- 深度绑定 OpenAI 生态。
- 付费与企业认证:使用 Agent Builder 等功能需要付费账号;GPT‑5 系列与高级优化需完成企业认证。
实战上手路径
我们将基于官方 Starter 项目 演示入门,并扩展用 Python FastAPI + React 集成一个小型 Demo。
准备工作
- 获取
OPENAI_API_KEY
:在 OpenAI 平台 创建密钥。后端创建会话时将使用该密钥,以校验调用归属并防止workflow_ID
泄露被滥用。 - 配置域名白名单:在 域名白名单设置 添加你的前端站点域名,确保 ChatKit 组件安全可用。
在 Agent Builder 创建与发布工作流
创建工作流
在 Agent Builder 选择模板或从零开始搭建。若未通过 企业认证,请将模型切换为可用的 GPT‑4 系列。 可在 Agent Builder 使用 Evals 评估工作流效果,支持自定义指标和评估模型。
发布工作流
发布后获取 workflow_ID
,用于在 ChatKit 前端组件中进行绑定与调用。
官方示例项目
下载项目并安装依赖及环境
bash
# 下载项目
git clone https://github.com/openai/openai-chatkit-starter-app.git
# 安装依赖项
npm install
# 复制环境变量文件
cp .env.example .env.local
将 .env.local 中的 OPENAI_API_KEY 及 NEXT_PUBLIC_CHATKIT_WORKFLOW_ID 替换为你自己的 OPENAI_API_KEY 及 workflow_ID
启动项目
bash
# 打包项目
npm run build
# 启动项目
npm run dev
自定义调整
可在 lib/config.ts 调整 初始提示、问候文本、ChatKit 主题 可在 components/.tsx 调整事件触发逻辑,以集成您的分析及存储
想第一时间掌握 OpenAI AgentKit 的实战用法,以及更多 MCP、Agent、RAG、多模态 应用落地案例 来 赋范空间大模型社区 ,这里不仅有 AgentKit 全流程实操拆解,还有持续更新的 Agent / RAG / 多模态 应用落地实战案例,带你深入学习。
工作流集成项目Demo
此项目基于 Python FastAPI + React 实现使用 Agent Kit 的工作流集成项目Demo。
可加 小助理 领取项目源码
服务端
由于 CDN 限制,我们可以在服务端返回本地的 chatkit.js 脚本。
python
@app.get("/cdn/chatkit.js")
async def proxy_chatkit_js():
"""返回本地 chatkit.js """
base_dir = os.path.dirname(__file__)
local_candidates = [
os.path.abspath(os.path.join(base_dir, "../frontend/public/chatkit.js")),
]
for local_path in local_candidates:
with open(local_path, "rb") as f:
content = f.read()
logger.info(f"使用本地 ChatKit 脚本: {local_path}")
return Response(
content=content,
media_type="application/javascript",
headers={
"Cache-Control": "public, max-age=3600",
"Access-Control-Allow-Origin": "*"
}
)
解析工作流配置文件 workflows.json,加载工作流列表及默认工作流。
python
def load_workflow_config():
base_dir = os.path.dirname(__file__)
data_dir = os.path.abspath(os.path.join(base_dir, "..", "data"))
candidates = [
os.path.abspath(os.path.join(data_dir, "workflows.json")),
]
for path in candidates:
if os.path.exists(path):
with open(path, "r", encoding="utf-8") as f:
try:
return json.load(f)
except Exception as e:
logger.error(f"读取工作流配置失败: {e}")
break
logger.warning("请配置工作流")
return {
"workflows": [],
"default": None,
}
WORKFLOW_CONFIG = load_workflow_config()
@app.get("/api/workflows")
async def get_workflows():
"""返回工作流列表"""
return WORKFLOW_CONFIG
创建 ChatKit 会话
python
def _create_chatkit_session(workflow_type: str, workflow_id: str, stable_user_id: str):
"""调用 OpenAI ChatKit 创建会话并返回 session_id 与 client_secret。"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}",
"OpenAI-Beta": "chatkit_beta=v1",
}
payload = {"workflow": {"id": workflow_id}, "user": stable_user_id}
response = requests.post(
"https://api.openai.com/v1/chatkit/sessions",
headers=headers,
json=payload,
timeout=30,
)
if response.status_code != 200:
logger.error(f"ChatKit API 错误: {response.status_code} {response.text}")
raise Exception(f"OpenAI API Error ({response.status_code}): {response.text}")
session = response.json()
return session.get("id"), session.get("client_secret")
@app.post("/api/chatkit/session")
async def create_chatkit_session(workflow_type: str | None = None):
"""
创建 ChatKit 会话
1. 前端请求这个接口
2. 服务端使用 OpenAI API Key 创建 session
3. 返回 client_secret、session_id、workflow_id 给前端
4. 前端使用 client_secret 连接 ChatKit
"""
try:
# 解析工作流:优先前端传入,其次使用 workflows.json 的 default
selected_type = workflow_type or WORKFLOW_CONFIG.get("default")
workflow_id = WORKFLOWS_MAP.get(selected_type or "")
if not selected_type or not workflow_id:
raise HTTPException(status_code=400, detail="工作流识别错误请确认配置")
workflow_type = selected_type
logger.info(f"创建 ChatKit Session for workflow: {workflow_type} ({workflow_id})")
# 为该工作流维持稳定 user_id
stable_user_id = _get_or_create_user_id(workflow_type)
sid, csec = _create_chatkit_session(workflow_type, workflow_id, stable_user_id)
logger.info(f"ChatKit Session 创建成功: {sid} (workflow: {workflow_type})")
# 持久化最新密钥到本地 JSON
if sid and csec:
_set_latest_secret(sid, csec, workflow_type, workflow_id)
return {
"client_secret": csec,
"session_id": sid,
"workflow_type": workflow_type,
"workflow_id": workflow_id
}
except Exception as e:
logger.error(f"创建 ChatKit Session 失败: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to create ChatKit session: {str(e)}"
)
前端有 session_id 时,可通过该接口获取最新的 client_secret 以恢复历史会话。
python
@app.get("/api/chatkit/session")
async def get_latest_client_secret(session_id: str | None = None):
"""
前端仅存储 session_id,通过该接口获取密钥以恢复历史。
"""
try:
if not session_id:
raise HTTPException(status_code=400, detail="缺少 session_id")
info = _get_latest_secret(session_id)
if not info:
raise HTTPException(status_code=404, detail="未找到该会话")
return {
"client_secret": info["client_secret"],
"session_id": session_id,
"workflow_type": info.get("workflow_type"),
"workflow_id": info.get("workflow_id"),
"updated_at": info.get("updated_at")
}
except HTTPException:
raise
except Exception as e:
logger.error(f"查询最新密钥失败: {e}")
raise HTTPException(status_code=500, detail=f"查询失败: {e}")
挂载前端页面
python
app.mount("/", StaticFiles(directory=frontend_dist_path, html=True), name="static")
想第一时间掌握 OpenAI AgentKit 的实战用法,以及更多 MCP、Agent、RAG、多模态 应用落地案例 来 赋范空间大模型社区 ,这里不仅有 AgentKit 全流程实操拆解,还有持续更新的 Agent / RAG / 多模态 应用落地实战案例,带你深入学习。
前端
主页面
jsx
import { useChatKit } from '@openai/chatkit-react';
import { useEffect, useState } from 'react';
import './App.css';
import WorkflowSelector from './components/WorkflowSelector';
import ChatPane from './components/ChatPane';
function App() {
const [errorMsg, setErrorMsg] = useState(null);
// 工作流配置从后端加载
const [flows, setFlows] = useState([]);
const [activeFlow, setActiveFlow] = useState(null);
const [flowsLoading, setFlowsLoading] = useState(true);
// 仅在前端保存每个工作流的 session_id,由后端映射并返回最新 client_secret
const storageKey = 'chatkit.flowSessions';
const readSessions = () => {
try {
return JSON.parse(localStorage.getItem(storageKey) || '{}');
} catch {
return {};
}
};
const writeSessions = (map) => {
try {
localStorage.setItem(storageKey, JSON.stringify(map));
} catch {
// 忽略存储错误
}
};
const getSavedSessionId = (flow) => {
const m = readSessions();
return m[flow || 'default'] || null;
};
const setSavedSessionId = (flow, sid) => {
const m = readSessions();
m[flow || 'default'] = sid;
writeSessions(m);
};
const { control: kitCtrl } = useChatKit({
api: {
// 会话续期或网络重试时调用
async getClientSecret(currentClientSecret) {
const flowKey = activeFlow || 'default';
const savedSid = getSavedSessionId(flowKey);
// 1) 初次挂载或切回工作流:若有 session_id,向后端查询最新密钥
if (!currentClientSecret && savedSid) {
try {
const resp = await fetch(`/api/chatkit/session?session_id=${encodeURIComponent(savedSid)}`);
if (resp.ok) {
const info = await resp.json();
return info.client_secret;
}
} catch (e) {
}
}
// 2) 无有效 session_id 或刷新失败:创建新会话,并保存 session_id
try {
const response = await fetch(`/api/chatkit/session${activeFlow ? `?workflow_type=${encodeURIComponent(activeFlow)}` : ''}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
setSavedSessionId(flowKey, data.session_id);
return data.client_secret;
} catch (error) {
setErrorMsg(error.message);
throw error;
}
},
},
// 输入框配置
composer: {
placeholder: '输入消息',
},
onError: (error) => {
const emsg = error.message || JSON.stringify(error);
setErrorMsg(emsg);
},
});
useEffect(() => {
// 从后端加载工作流配置
(async () => {
try {
const resp = await fetch('/api/workflows');
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const cfg = await resp.json();
const options = (cfg.workflows || []).map(w => ({ id: w.id, name: w.name, workflow_id: w.workflow_id }));
setFlows(options);
const defaultType = cfg.default || (options[0]?.id ?? null);
setActiveFlow(defaultType);
setFlowsLoading(false);
} catch (e) {
setFlowsLoading(false);
}
})();
}, []);
return (
<div className="app">
<div className="header">
<p>AgentKit:Agent Builder + Chat Kit Demo</p>
</div>
{/* 主内容区域 */}
<div className="main-content">
<div className="left-column">
<WorkflowSelector
flows={flows}
activeFlow={activeFlow}
flowsLoading={flowsLoading}
onChange={(newFlow) => {
setActiveFlow(newFlow);
}}
/>
<ChatPane
errorMsg={errorMsg}
activeFlow={activeFlow}
kitCtrl={kitCtrl}
/>
</div>
</div>
</div>
);
}
export default App;
chatkit组件
jsx
import { ChatKit } from '@openai/chatkit-react';
export default function ChatPane({ width, errorMsg, activeFlow, kitCtrl }) {
return (
<div className="chat-container" style={{ width: `${width}px` }}>
{errorMsg ? (
<div className="error-state">
<h3>加载失败</h3>
<p>{errorMsg}</p>
<button onClick={() => window.location.reload()} className="reload-btn">
重新加载
</button>
</div>
) : (
<ChatKit key={activeFlow || 'default'} control={kitCtrl} className="chatkit-widget" />
)}
</div>
);
}
工作流选择器组件
jsx
export default function WorkflowSelector({ flows, activeFlow, flowsLoading, onChange }) {
return (
<div className="workflow-selector">
<label htmlFor="workflow-select">选择工作流:</label>
<select
id="workflow-select"
value={activeFlow ?? ''}
onChange={(e) => onChange?.(e.target.value)}
className="workflow-select"
disabled={flowsLoading}
>
{flowsLoading ? (
<option value="">加载中...</option>
) : (
(flows?.length ?? 0) > 0 ? (
flows.map(opt => (
<option key={opt.id} value={opt.id}>{opt.name || opt.id}</option>
))
) : (
<option value="">未配置工作流</option>
)
)}
</select>
</div>
);
}
详情参考 OpenAI AgentKit 介绍 OpenAI AgentKit 文档 ChatKit 示例项目 ChatKit 高级示例项目 ChatKit Studio