关于 thesys-generative-ui
用于借助 TheSys C1 构建 AI 界面的开发技能,可将 LLM 回复呈现为流式交互式 React 组件。内容涵盖预置聊天界面、自定义渲染以及前后端集成方式。
主要功能
- 01将回复渲染为交互式 React 界面
- 02流式生成界面
- 03使用预置 C1Chat 或 C1Component
- 04自定义主题和界面操作
- 05集成 JavaScript 与 Python 后端
- 06使用 Zod schema 配置工具调用
适用场景
- 01为聊天界面添加交互式 UI
- 02展示 AI 生成的图表和表格
- 03生成动态表单与工作流
- 04构建结构化搜索结果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill thesys-generative-ui安装后在 Claude Code 中输入/thesys-generative-ui确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdREADME.mdSKILL.json详细介绍
TheSys 生成式 UI 集成
使用 TheSys C1 生成式 UI API 构建 AI 驱动界面的完整技能。将大模型响应转换为流式交互式 React 组件。
什么是 TheSys C1?
TheSys C1 是一种生成式 UI API,可将大语言模型(LLM)的响应转换为实时交互式 React 组件,而不是纯文本。AI 应用无需再显示大段文本,而是可以实时流式呈现表单、图表、表格、搜索结果和自定义 UI 元素。
核心创新
传统的 LLM 应用会返回文本,开发者必须手动将其转换为 UI:
LLM → Text Response → Developer Parses → Manual UI Code → Display
TheSys C1 消除了这一手动步骤:
LLM → C1 API → Interactive React Components → Display
实际影响
- 吸引力提升 83%——用户更喜欢交互式组件,而不是大段文本
- 开发速度提升 10 倍——无需手动将文本转换为 UI
- 成本降低 80%——减少开发时间和维护成本
- 可用于生产环境——已被构建 AI 原生产品的团队采用
何时使用此技能
在构建以下内容时使用此技能:
-
带有丰富 UI 的聊天界面
- 需要呈现文本以外内容的对话界面
- 带有表单和操作的客户支持聊天机器人
- 可展示数据可视化内容的 AI 助手
-
数据可视化应用
- 使用 AI 生成图表的分析仪表板
- 带有动态表格的商业智能工具
- 展示结构化结果的搜索界面
-
动态表单生成
- 电商产品配置器
- 由 AI 驱动的多步骤工作流
- 使用智能表单收集数据
-
AI Copilot 和助手
- 带有代码片段和文档的开发者工具
- 带有交互式课程的教育平台
- 带有引文和参考资料的研究工具
-
搜索与发现
- 展示结构化结果的语义搜索
- 突出显示发现内容的文档分析
- 提供交互式回答的知识库
此技能可避免以下错误
- ❌ 流式设置不正确导致 Agent 响应为空
- ❌ 消息数组问题导致模型忽略系统提示词
- ❌ SDK 与 API 之间的版本兼容性错误
- ❌ 未使用 ThemeProvider 导致主题无法应用
- ❌ 响应转换不当导致流式处理失败
- ❌ Zod 架构无效导致工具调用出错
- ❌ 缺少持久化导致线程状态丢失
- ❌ 导入顺序问题导致 CSS 冲突
- ❌ 类型定义过时导致 TypeScript 错误
- ❌ 缺少标头导致 CORS 失败
- ❌ 未实现重试逻辑导致速率限制时崩溃
- ❌ 环境问题导致身份验证令牌错误
按框架快速入门
Vite + React 设置
最灵活的自定义后端设置(你的首选技术栈)。
1. 安装依赖项
npm install @thesysai/genui-sdk @crayonai/react-ui @crayonai/react-core @crayonai/stream
npm install openai zod
2. 创建聊天组件
文件:src/App.tsx
import "@crayonai/react-ui/styles/index.css";
import { ThemeProvider, C1Component } from "@thesysai/genui-sdk";
import { useState } from "react";
export default function App() {
const [isLoading, setIsLoading] = useState(false);
const [c1Response, setC1Response] = useState("");
const [question, setQuestion] = useState("");
const makeApiCall = async (query: string) => {
setIsLoading(true);
setC1Response("");
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: query }),
});
const data = await response.json();
setC1Response(data.response);
} catch (error) {
console.error("Error:", error);
} finally {
setIsLoading(false);
}
};
return (
<div className="container">
<h1>AI Assistant</h1>
<form onSubmit={(e) => {
e.preventDefault();
makeApiCall(question);
}}>
<input
type="text"
value={question}
onChange={(e) => setQuestion(e.target.value)}
placeholder="Ask me anything..."
/>
<button type="submit" disabled={isLoading}>
{isLoading ? "Processing..." : "Send"}
</button>
</form>
{c1Response && (
<ThemeProvider>
<C1Component
c1Response={c1Response}
isStreaming={isLoading}
updateMessage={(message) => setC1Response(message)}
onAction={({ llmFriendlyMessage }) => {
if (!isLoading) {
makeApiCall(llmFriendlyMessage);
}
}}
/>
</ThemeProvider>
)}
</div>
);
}
3. 配置后端 API(Express 示例)
import express from "express";
import OpenAI from "openai";
import { transformStream } from "@crayonai/stream";
const app = express();
app.use(express.json());
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed",
apiKey: process.env.THESYS_API_KEY,
});
app.post("/api/chat", async (req, res) => {
const { prompt } = req.body;
const stream = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930", // or any C1-compatible model
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: prompt },
],
stream: true,
});
// Transform OpenAI stream to C1 response
const c1Stream = transformStream(stream, (chunk) => {
return chunk.choices[0]?.delta?.content || "";
});
res.json({ response: await streamToString(c1Stream) });
});
async function streamToString(stream: ReadableStream) {
const reader = stream.getReader();
let result = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
result += value;
}
return result;
}
app.listen(3000);
Next.js App Router 设置
最受欢迎的框架,支持通过 API 路由构建全栈应用。
1. 安装依赖项
npm install @thesysai/genui-sdk @crayonai/react-ui @crayonai/react-core
npm install openai
2. 创建聊天页面组件
文件:app/page.tsx
"use client";
import { C1Chat } from "@thesysai/genui-sdk";
import "@crayonai/react-ui/styles/index.css";
export default function Home() {
return (
<div className="min-h-screen">
<C1Chat apiUrl="/api/chat" />
</div>
);
}
3. 创建 API 路由处理程序
文件:app/api/chat/route.ts
import { NextRequest, NextResponse } from "next/server";
import OpenAI from "openai";
import { transformStream } from "@crayonai/stream";
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed",
apiKey: process.env.THESYS_API_KEY,
});
export async function POST(req: NextRequest) {
const { prompt } = await req.json();
const stream = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930",
messages: [
{ role: "system", content: "You are a helpful AI assistant." },
{ role: "user", content: prompt },
],
stream: true,
});
// Transform to C1-compatible stream
const responseStream = transformStream(stream, (chunk) => {
return chunk.choices[0]?.delta?.content || "";
}) as ReadableStream<string>;
return new NextResponse(responseStream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
},
});
}
就是这样! 现在你已经拥有一个可用的生成式 UI 聊天界面。
Cloudflare Workers + 静态资源设置
你的技术栈:Workers 后端搭配 Vite+React 前端。
1. 创建 Worker 后端(Hono)
文件:backend/src/index.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
const app = new Hono();
app.use("/*", cors());
app.post("/api/chat", async (c) => {
const { prompt } = await c.req.json();
// Use Cloudflare Workers AI or proxy to OpenAI
const response = await fetch("https://api.thesys.dev/v1/embed/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${c.env.THESYS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "c1/openai/gpt-5/v-20250930",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: prompt },
],
stream: false, // or handle streaming
}),
});
const data = await response.json();
return c.json(data);
});
export default app;
2. 前端设置(与 Vite+React 相同)
使用上面的 Vite+React 示例,但将 API 调用配置为指向你的 Worker 端点。
3. Wrangler 配置
文件:wrangler.jsonc
{
"name": "thesys-chat-worker",
"compatibility_date": "2025-10-26",
"main": "backend/src/index.ts",
"vars": {
"ENVIRONMENT": "production"
},
"assets": {
"directory": "dist",
"binding": "ASSETS"
}
}
将 THESYS_API_KEY 添加为密钥:
npx wrangler secret put THESYS_API_KEY
核心组件
<C1Chat>——预构建聊天组件
使用场景:以最少的设置构建对话界面。
C1Chat 组件是一款功能齐全的聊天 UI,内置:
- 消息历史记录
- 流式响应
- 线程管理
- 加载状态
- 错误处理
- 响应式设计
基本用法
import { C1Chat } from "@thesysai/genui-sdk";
import "@crayonai/react-ui/styles/index.css";
export default function App() {
return (
<C1Chat
apiUrl="/api/chat"
agentName="My AI Assistant"
logoUrl="https://example.com/logo.png"
/>
);
}
关键属性
apiUrl(必填)- 聊天补全的后端端点agentName- AI Agent 的显示名称logoUrl- Agent 的徽标/头像theme- 自定义主题对象(参见“主题设置”部分)threadManager- 用于支持多会话(高级)threadListManager- 用于会话列表 UI(高级)customizeC1- 自定义组件(页脚、思考状态)
使用主题
import { C1Chat } from "@thesysai/genui-sdk";
import { themePresets } from "@crayonai/react-ui";
<C1Chat
apiUrl="/api/chat"
theme={themePresets.candy} // or 'default', or custom object
/>
<C1Component> - 自定义集成组件
适用场景:需要完全控制状态管理和 UI 布局。
C1Component 是底层渲染器。你需要处理:
- 获取数据
- 管理状态
- 布局结构
- 错误边界
基本用法
import { C1Component, ThemeProvider } from "@thesysai/genui-sdk";
import "@crayonai/react-ui/styles/index.css";
const [c1Response, setC1Response] = useState("");
const [isStreaming, setIsStreaming] = useState(false);
// ... fetch logic
return (
<ThemeProvider>
<C1Component
c1Response={c1Response}
isStreaming={isStreaming}
updateMessage={(message) => setC1Response(message)}
onAction={({ llmFriendlyMessage }) => {
// Handle interactive actions (button clicks, form submissions)
console.log("User action:", llmFriendlyMessage);
// Make new API call with llmFriendlyMessage
}}
/>
</ThemeProvider>
);
关键属性
c1Response(必填)- C1 API 响应字符串isStreaming- 响应是否仍在流式传输(显示加载指示器)updateMessage- 流式传输期间响应更新的回调onAction- 用户与生成的 UI 交互时触发的回调llmFriendlyMessage:要发送回大模型的预格式化消息rawAction:组件中的原始操作数据
重要:必须使用 ThemeProvider 包裹
// ❌ Wrong - theme won't apply
<C1Component c1Response={response} />
// ✅ Correct
<ThemeProvider>
<C1Component c1Response={response} />
</ThemeProvider>
<ThemeProvider> - 主题设置与自定义
适用场景:始终使用它包裹 <C1Component>,或自定义 <C1Chat> 的外观。
主题预设
TheSys 内置了预设主题:
import { themePresets } from "@crayonai/react-ui";
// Available presets:
// - themePresets.default
// - themePresets.candy
// ... (check docs for full list)
<C1Chat theme={themePresets.candy} />
暗色模式支持
import { useSystemTheme } from "./hooks/useSystemTheme"; // custom hook
export default function App() {
const systemTheme = useSystemTheme(); // 'light' | 'dark'
return (
<C1Chat
apiUrl="/api/chat"
theme={{ ...themePresets.default, mode: systemTheme }}
/>
);
}
自定义主题对象
const customTheme = {
mode: "dark", // 'light' | 'dark' | 'system'
colors: {
primary: "#3b82f6",
secondary: "#8b5cf6",
background: "#1f2937",
foreground: "#f9fafb",
// ... more colors
},
fonts: {
body: "Inter, sans-serif",
heading: "Poppins, sans-serif",
},
borderRadius: "12px",
spacing: {
base: "16px",
},
};
<C1Chat theme={customTheme} />
CSS 覆盖
创建 custom.css 文件:
/* Override specific component styles */
.c1-chat-container {
max-width: 900px;
margin: 0 auto;
}
.c1-message-user {
background-color: #3b82f6 !important;
}
.c1-message-assistant {
background-color: #6b7280 !important;
}
然后导入:
import "@crayonai/react-ui/styles/index.css";
import "./custom.css"; // AFTER the default styles
AI 提供商集成
TheSys C1 API 兼容 OpenAI,这意味着它可与任何使用 OpenAI API 格式的大模型提供商配合使用。
OpenAI 集成
设置
npm install openai
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed",
apiKey: process.env.THESYS_API_KEY, // TheSys API key
});
模型选择
TheSys 通过 C1 支持 OpenAI 模型:
// GPT 5 (Stable - Recommended for Production)
model: "c1/openai/gpt-5/v-20250930"
// GPT 4.1 (Experimental)
model: "c1-exp/openai/gpt-4.1/v-20250617"
完整示例
const response = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930",
messages: [
{
role: "system",
content: "You are a helpful assistant that generates interactive UI components.",
},
{
role: "user",
content: "Show me a comparison table of the top 3 project management tools.",
},
],
stream: true, // Enable streaming
temperature: 0.7,
max_tokens: 2000,
});
Anthropic(Claude)集成
设置
TheSys C1 通过兼容 OpenAI 的端点支持 Anthropic 的 Claude 模型:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed",
apiKey: process.env.THESYS_API_KEY,
});
模型选择
// Claude Sonnet 4 (Stable - Recommended for Production)
model: "c1/anthropic/claude-sonnet-4/v-20250930"
// Claude 3.5 Haiku (Experimental)
model: "c1-exp/anthropic/claude-3.5-haiku/v-20250709"
⚠️ 已弃用的模型:不再推荐使用 Claude 3.5 Sonnet 和 Claude 3.7 Sonnet。请使用上方稳定版 Claude Sonnet 4。
Claude 示例
const response = await client.chat.completions.create({
model: "c1/anthropic/claude-sonnet-4/v-20250930",
messages: [
{
role: "system",
content: "You are Claude, an AI assistant that creates interactive interfaces.",
},
{
role: "user",
content: "Create a product comparison chart for electric vehicles.",
},
],
stream: true,
temperature: 0.8,
max_tokens: 4096,
});
模型规格与定价
下表列出了通过 TheSys C1 API 提供的当前稳定版和实验版模型:
| 模型 | 模型 ID | 输入价格 | 输出价格 | 上下文 | 最大输出 |
|---|---|---|---|---|---|
| Claude Sonnet 4 | c1/anthropic/claude-sonnet-4/v-20250930 | $6.00/M | $18.00/M | 180K | 64K |
| GPT 5 | c1/openai/gpt-5/v-20250930 | $2.50/M | $12.50/M | 380K | 128K |
| GPT 4.1(实验版) | c1-exp/openai/gpt-4.1/v-20250617 | $4.00/M | $10.00/M | 1M | 32K |
| Claude 3.5 Haiku(实验版) | c1-exp/anthropic/claude-3.5-haiku/v-20250709 | $1.60/M | $5.00/M | 180K | 8K |
定价说明:
- 费用按每百万个 Token(M)计算
- 定价基于模型名称,与端点类型(嵌入或可视化)无关
- 建议在生产环境中使用稳定版模型(前缀为
c1/) - 实验版模型(前缀为
c1-exp/)用于测试,行为可能有所不同
模型版本:模型标识符包含版本日期(例如
v-20250930)。请始终查看 TheSys Playground 获取最新稳定版本。
Cloudflare Workers AI 集成
使用 Workers AI 绑定进行设置
// In your Cloudflare Worker
export default {
async fetch(request: Request, env: Env) {
// Use Workers AI directly (cheaper for some use cases)
const aiResponse = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Hello!" },
],
});
// Then transform to C1 format and send to frontend
// ...
}
};
混合方案:Workers AI + C1
// Option 1: Use Workers AI for processing, C1 for UI generation
const thinkingResponse = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [{ role: "user", content: "Analyze this data..." }],
});
// Then use C1 to generate UI from the analysis
const c1Response = await fetch("https://api.thesys.dev/v1/embed/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${env.THESYS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "c1/openai/gpt-5/v-20250930",
messages: [
{
role: "system",
content: "Generate a chart visualization for this data.",
},
{
role: "user",
content: thinkingResponse.response,
},
],
}),
});
Python 后端集成
TheSys 提供 Python SDK,用于通过 FastAPI、Flask 或 Django 实现后端。
设置
pip install thesys-genui-sdk openai
FastAPI 示例
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from thesys_genui_sdk import with_c1_response, write_content
import openai
import os
app = FastAPI()
client = openai.OpenAI(
base_url="https://api.thesys.dev/v1/embed",
api_key=os.getenv("THESYS_API_KEY")
)
@app.post("/api/chat")
@with_c1_response # Automatically handles streaming headers
async def chat_endpoint(request: dict):
prompt = request.get("prompt")
stream = client.chat.completions.create(
model="c1/anthropic/claude-sonnet-4/v-20250930",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt}
],
stream=True
)
# Stream chunks to frontend
async def generate():
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
yield write_content(content)
return StreamingResponse(generate(), media_type="text/event-stream")
主要功能
@with_c1_response装饰器:自动设置适用于流式传输的响应头write_content辅助函数:格式化用于 C1Component 渲染的内容块- 与框架无关:适用于 FastAPI、Flask、Django 或任何 Python Web 框架
Flask 示例
from flask import Flask, request, Response
from thesys_genui_sdk import with_c1_response, write_content
import openai
import os
app = Flask(__name__)
client = openai.OpenAI(
base_url="https://api.thesys.dev/v1/embed",
api_key=os.getenv("THESYS_API_KEY")
)
@app.route("/api/chat", methods=["POST"])
@with_c1_response
def chat():
data = request.get_json()
prompt = data.get("prompt")
stream = client.chat.completions.create(
model="c1/openai/gpt-5/v-20250930",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt}
],
stream=True
)
def generate():
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
yield write_content(content)
return Response(generate(), mimetype="text/event-stream")
通用模式(适用于任何提供方)
错误处理
try {
const response = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930",
messages: [...],
stream: true,
});
// Process stream...
} catch (error) {
if (error.status === 429) {
// Rate limit - implement exponential backoff
await new Promise(resolve => setTimeout(resolve, 1000));
// Retry...
} else if (error.status === 401) {
// Invalid API key
console.error("Authentication failed. Check THESYS_API_KEY");
} else {
// Other errors
console.error("API Error:", error);
}
}
使用 transformStream 进行流式传输
import { transformStream } from "@crayonai/stream";
const llmStream = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930",
messages: [...],
stream: true,
});
// Transform OpenAI stream to C1 stream
const c1Stream = transformStream(llmStream, (chunk) => {
return chunk.choices[0]?.delta?.content || "";
}) as ReadableStream<string>;
return new Response(c1Stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
},
});
使用 Zod Schema 调用工具
工具调用允许 AI 调用函数,并显示交互式 UI,以收集数据、调用外部 API 和处理复杂工作流。
1. 使用 Zod 定义工具
import { z } from "zod";
import zodToJsonSchema from "zod-to-json-schema";
// Define the tool schema
const webSearchSchema = z.object({
query: z.string().describe("The search query"),
max_results: z.number().int().min(1).max(10).default(5)
.describe("Maximum number of results to return"),
});
// Convert to OpenAI tool format
export const webSearchTool = {
type: "function" as const,
function: {
name: "web_search",
description: "Search the web for current information",
parameters: zodToJsonSchema(webSearchSchema),
},
};
2. 更复杂的示例:订单管理
import { z } from "zod";
// Discriminated union for different product types
const productOrderSchema = z.discriminatedUnion("type", [
z.object({
type: z.literal("gloves"),
size: z.enum(["S", "M", "L", "XL"]),
color: z.string(),
quantity: z.number().int().min(1),
}),
z.object({
type: z.literal("hat"),
style: z.enum(["beanie", "baseball", "fedora"]),
color: z.string(),
quantity: z.number().int().min(1),
}),
z.object({
type: z.literal("scarf"),
length: z.enum(["short", "medium", "long"]),
material: z.enum(["wool", "cotton", "silk"]),
quantity: z.number().int().min(1),
}),
]);
const createOrderSchema = z.object({
customer_email: z.string().email(),
items: z.array(productOrderSchema).min(1),
shipping_address: z.object({
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.string(),
}),
});
export const createOrderTool = {
type: "function" as const,
function: {
name: "create_order",
description: "Create a new order for products",
parameters: zodToJsonSchema(createOrderSchema),
},
};
3. 实现工具执行
// tools.ts
import { TavilySearchAPIClient } from "@tavily/core";
const tavily = new TavilySearchAPIClient({
apiKey: process.env.TAVILY_API_KEY,
});
export async function executeWebSearch(query: string, max_results: number) {
const results = await tavily.search(query, {
maxResults: max_results,
includeAnswer: true,
});
return {
query,
results: results.results.map((r) => ({
title: r.title,
url: r.url,
snippet: r.content,
})),
answer: results.answer,
};
}
export async function executeCreateOrder(orderData: z.infer<typeof createOrderSchema>) {
// Validate with Zod
const validated = createOrderSchema.parse(orderData);
// Save to database
const orderId = await saveOrderToDatabase(validated);
return {
success: true,
orderId,
message: `Order ${orderId} created successfully`,
};
}
4. 在 API 路由中集成工具
import { NextRequest, NextResponse } from "next/server";
import OpenAI from "openai";
import { transformStream } from "@crayonai/stream";
import { webSearchTool, createOrderTool } from "./tools";
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed",
apiKey: process.env.THESYS_API_KEY,
});
export async function POST(req: NextRequest) {
const { prompt } = await req.json();
const llmStream = await client.beta.chat.completions.runTools({
model: "c1/anthropic/claude-sonnet-4/v-20250930",
messages: [
{
role: "system",
content: "You are a helpful shopping assistant. Use tools to search for products and create orders.",
},
{
role: "user",
content: prompt,
},
],
stream: true,
tools: [webSearchTool, createOrderTool],
toolChoice: "auto", // Let AI decide when to use tools
});
// Handle tool execution
llmStream.on("message", async (event) => {
if (event.tool_calls) {
for (const toolCall of event.tool_calls) {
if (toolCall.function.name === "web_search") {
const args = JSON.parse(toolCall.function.arguments);
const result = await executeWebSearch(args.query, args.max_results);
// Send result back to LLM...
} else if (toolCall.function.name === "create_order") {
const args = JSON.parse(toolCall.function.arguments);
const result = await executeCreateOrder(args);
// Send result back to LLM...
}
}
}
});
const responseStream = transformStream(llmStream, (chunk) => {
return chunk.choices[0]?.delta?.content || "";
}) as ReadableStream<string>;
return new NextResponse(responseStream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
},
});
}
5. 在 UI 中显示工具结果
C1Component 会自动将工具交互渲染为表单并显示结果。你只需处理 onAction 回调:
<C1Component
c1Response={c1Response}
onAction={async ({ llmFriendlyMessage, rawAction }) => {
console.log("Tool action triggered:", rawAction);
// Make API call with llmFriendlyMessage to continue conversation
await makeApiCall(llmFriendlyMessage);
}}
/>
高级功能
线程管理(支持多轮对话)
支持用户创建多个对话线程,并提供线程切换、历史记录和持久化功能。
1. 定义线程 API
创建后端端点:
GET /api/threads- 列出所有线程POST /api/threads- 创建新线程PUT /api/threads/:id- 更新线程标题DELETE /api/threads/:id- 删除线程GET /api/threads/:id/messages- 加载线程消息
2. 实现线程管理器
import {
useThreadListManager,
useThreadManager,
} from "@thesysai/genui-sdk";
import { Thread, Message, UserMessage } from "@crayonai/react-core";
export default function App() {
const threadListManager = useThreadListManager({
// Fetch all threads
fetchThreadList: async (): Promise<Thread[]> => {
const response = await fetch("/api/threads");
return response.json();
},
// Delete thread
deleteThread: async (threadId: string): Promise<void> => {
await fetch(`/api/threads/${threadId}`, { method: "DELETE" });
},
// Update thread title
updateThread: async (thread: Thread): Promise<Thread> => {
const response = await fetch(`/api/threads/${thread.threadId}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: thread.title }),
});
return response.json();
},
// Create new thread
createThread: async (firstMessage: UserMessage): Promise<Thread> => {
const response = await fetch("/api/threads", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: firstMessage.message || "New Chat",
}),
});
return response.json();
},
// URL synchronization
onSwitchToNew: () => {
window.history.replaceState(null, "", window.location.pathname);
},
onSelectThread: (threadId: string) => {
const url = new URL(window.location.href);
url.searchParams.set("threadId", threadId);
window.history.replaceState(null, "", url.toString());
},
});
const threadManager = useThreadManager({
threadListManager,
// Load messages for selected thread
loadThread: async (threadId: string): Promise<Message[]> => {
const response = await fetch(`/api/threads/${threadId}/messages`);
return response.json();
},
// Handle message updates (e.g., feedback)
onUpdateMessage: async ({ message }: { message: Message }) => {
if (threadListManager.selectedThreadId) {
await fetch(
`/api/threads/${threadListManager.selectedThreadId}/message`,
{
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(message),
}
);
}
},
});
return (
<C1Chat
threadManager={threadManager}
threadListManager={threadListManager}
/>
);
}
思考状态(进度指示器)
向用户展示 AI 处理时正在执行的操作(搜索网络、分析数据等)。
1. 服务端:写入思考项
import { makeC1Response } from "@thesysai/genui-sdk/server";
export async function POST(req: NextRequest) {
const c1Response = makeC1Response();
// Initial thinking state
c1Response.writeThinkItem({
title: "Thinking…",
description: "Analyzing your question and planning the response.",
});
const { prompt } = await req.json();
// Update thinking state when calling tools
const llmStream = await client.beta.chat.completions.runTools({
model: "c1/anthropic/claude-sonnet-4/v-20250930",
messages: [...],
tools: [
getWebSearchTool(() => {
c1Response.writeThinkItem({
title: "Searching the web…",
description: "Finding the most relevant and up-to-date information.",
});
}),
],
});
transformStream(
llmStream,
(chunk) => {
const content = chunk.choices[0]?.delta?.content;
if (content) {
c1Response.writeContent(content);
}
return content;
},
{
onEnd: () => {
c1Response.end();
},
}
);
return new NextResponse(c1Response.responseStream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
},
});
}
2. 自定义思考组件
// CustomThink.tsx
import { ThinkItem } from "@crayonai/react-core";
export function CustomThink({ item }: { item: ThinkItem }) {
return (
<div className="custom-think">
<div className="spinner" />
<div>
<h4>{item.title}</h4>
<p>{item.description}</p>
</div>
</div>
);
}
// In your app
<C1Chat
apiUrl="/api/chat"
customizeC1={{ thinkComponent: CustomThink }}
/>
消息和线程分享
支持用户通过公开 URL 分享对话。
1. 生成分享链接
import { C1ShareThread } from "@thesysai/genui-sdk";
const selectedThreadId = threadListManager.selectedThreadId;
<C1ShareThread
generateShareLink={
!selectedThreadId
? undefined
: async () => {
const baseUrl = window.location.origin;
return `${baseUrl}/shared/${selectedThreadId}`;
}
}
/>
2. 创建分享视图页面
// app/shared/[threadId]/page.tsx
"use client";
import { C1ChatViewer } from "@thesysai/genui-sdk";
import { Message } from "@crayonai/react-core";
import { use, useEffect, useState } from "react";
import "@crayonai/react-ui/styles/index.css";
export default function ViewSharedThread({
params,
}: {
params: Promise<{ threadId: string }>;
}) {
const { threadId } = use(params);
const [messages, setMessages] = useState<Message[]>([]);
useEffect(() => {
const fetchMessages = async () => {
const response = await fetch(`/api/share/${threadId}`);
const data = await response.json();
setMessages(data);
};
fetchMessages();
}, [threadId]);
if (!messages.length) return <div>Loading...</div>;
return <C1ChatViewer messages={messages} />;
}
生产环境模式
消息持久化
不要在生产环境中使用内存存储!
// ❌ Bad - loses data on restart
const messageStore = new Map<string, Message[]>();
// ✅ Good - use a database
import { db } from "./database"; // D1, PostgreSQL, etc.
export async function saveMessage(threadId: string, message: Message) {
await db.insert(messages).values({
threadId,
role: message.role,
content: message.content,
createdAt: new Date(),
});
}
export async function getThreadMessages(threadId: string): Promise<Message[]> {
return db.select().from(messages).where(eq(messages.threadId, threadId));
}
身份验证集成(Clerk 示例)
import { auth } from "@clerk/nextjs";
export async function POST(req: NextRequest) {
const { userId } = auth();
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Proceed with chat logic, scoping to user
const userThreads = await db
.select()
.from(threads)
.where(eq(threads.userId, userId));
// ...
}
速率限制
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, "1 m"), // 10 requests per minute
});
export async function POST(req: NextRequest) {
const { userId } = auth();
const { success } = await ratelimit.limit(userId);
if (!success) {
return NextResponse.json(
{ error: "Rate limit exceeded. Please try again later." },
{ status: 429 }
);
}
// Proceed...
}
错误边界
import { ErrorBoundary } from "react-error-boundary";
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<h2>Something went wrong</h2>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
export default function App() {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<C1Chat apiUrl="/api/chat" />
</ErrorBoundary>
);
}
性能优化
// 1. Lazy load C1Chat
import { lazy, Suspense } from "react";
const C1Chat = lazy(() =>
import("@thesysai/genui-sdk").then((mod) => ({ default: mod.C1Chat }))
);
export default function App() {
return (
<Suspense fallback={<div>Loading chat...</div>}>
<C1Chat apiUrl="/api/chat" />
</Suspense>
);
}
// 2. Memoize expensive computations
import { useMemo } from "react";
const threadListManager = useMemo(
() =>
useThreadListManager({
// ... config
}),
[] // Empty deps - only create once
);
常见错误及解决方案
1. Agent 响应为空
问题:AI 返回空响应,UI 未显示任何内容。
原因:流式传输转换或响应格式不正确。
解决方案:
// ✅ Use transformStream helper
import { transformStream } from "@crayonai/stream";
const c1Stream = transformStream(llmStream, (chunk) => {
return chunk.choices[0]?.delta?.content || ""; // Fallback to empty string
}) as ReadableStream<string>;
2. 模型未遵循系统提示词
问题:AI 忽略系统提示词中的指令。
原因:系统提示词不在消息数组的首位,或格式不正确。
解决方案:
// ✅ System prompt MUST be first
const messages = [
{ role: "system", content: "You are a helpful assistant." }, // FIRST!
...conversationHistory,
{ role: "user", content: userPrompt },
];
// ❌ Wrong - system prompt after user messages
const messages = [
{ role: "user", content: "Hello" },
{ role: "system", content: "..." }, // TOO LATE
];
3. 版本兼容性错误
问题:出现 TypeError: Cannot read property 'X' of undefined 或组件渲染错误。
原因:SDK 版本不匹配。
解决方案:查看兼容性矩阵:
| C1 版本 | @thesysai/genui-sdk | @crayonai/react-ui | @crayonai/react-core |
|---|---|---|---|
| v-20250930 | ~0.6.40 | ~0.8.42 | ~0.7.6 |
# Update to compatible versions
npm install @thesysai/[email protected] @crayonai/[email protected] @crayonai/[email protected]
4. 主题未生效
问题:UI 组件与自定义主题不匹配。
原因:缺少 ThemeProvider 包装器。
解决方案:
// ❌ Wrong
<C1Component c1Response={response} />
// ✅ Correct
<ThemeProvider theme={customTheme}>
<C1Component c1Response={response} />
</ThemeProvider>
5. 流式传输无法正常工作
问题:UI 未实时更新,而是等待完整响应。
原因:未使用流式传输,或响应头设置不正确。
解决方案:
// 1. Enable streaming in API call
const stream = await client.chat.completions.create({
model: "c1/openai/gpt-5/v-20250930",
messages: [...],
stream: true, // ✅ IMPORTANT
});
// 2. Set proper response headers
return new NextResponse(responseStream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
},
});
// 3. Pass isStreaming prop
<C1Component
c1Response={response}
isStreaming={true} // ✅ Shows loading indicator
/>
6. 工具调用失败
问题:工具未执行或出现验证错误。
原因:Zod Schema 无效或工具格式不正确。
解决方案:
import { z } from "zod";
import zodToJsonSchema from "zod-to-json-schema";
// ✅ Proper Zod schema with descriptions
const toolSchema = z.object({
query: z.string().describe("Search query"), // DESCRIBE all fields
limit: z.number().int().min(1).max(100).describe("Max results"),
});
// ✅ Convert to OpenAI format
const tool = {
type: "function" as const,
function: {
name: "search_web",
description: "Search the web for information", // Clear description
parameters: zodToJsonSchema(toolSchema), // Convert schema
},
};
// ✅ Validate incoming tool calls
const args = toolSchema.parse(JSON.parse(toolCall.function.arguments));
7. 线程状态未持久化
问题:刷新页面后线程消失。
原因:没有后端持久化,使用了内存存储。
解决方案:实现数据库存储(请参阅“生产环境模式”部分)。
8. CSS 冲突
问题:C1 组件的样式与应用样式冲突。
原因:CSS 导入顺序不当,或全局样式覆盖了组件样式。
解决方案:
// ✅ Correct import order
import "@crayonai/react-ui/styles/index.css"; // C1 styles FIRST
import "./your-app.css"; // Your styles SECOND
// In your CSS, use specificity if needed
.your-custom-class .c1-message {
/* Override specific styles */
}
9. TypeScript 类型错误
问题:TypeScript 提示缺少类型或类型不兼容。
原因:软件包版本过旧,或缺少类型定义。
解决方案:
# Update packages
npm install @thesysai/genui-sdk@latest @crayonai/react-ui@latest @crayonai/react-core@latest
# If still errors, check tsconfig.json
{
"compilerOptions": {
"moduleResolution": "bundler", // or "node16"
"skipLibCheck": true // Skip type checking for node_modules
}
}
10. API 的 CORS 错误
问题:调用后端时出现 Access-Control-Allow-Origin 错误。
原因:API 响应中缺少 CORS 标头。
解决方案:
// Next.js API Route
export async function POST(req: NextRequest) {
const response = new NextResponse(stream, {
headers: {
"Content-Type": "text/event-stream",
"Access-Control-Allow-Origin": "*", // Or specific domain
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
},
});
return response;
}
// Express
app.use(cors({
origin: "http://localhost:5173", // Your frontend URL
methods: ["POST", "OPTIONS"],
}));
11. 速率限制问题
问题:API 调用因 429 错误而失败,且没有重试机制。
原因:缺少针对速率限制的退避逻辑。
解决方案:
async function callApiWithRetry(apiCall, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await apiCall();
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
const waitTime = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise((resolve) => setTimeout(resolve, waitTime));
continue;
}
throw error;
}
}
}
// Usage
const response = await callApiWithRetry(() =>
client.chat.completions.create({...})
);
12. 身份验证令牌错误
问题:即使设置了 API 密钥,仍出现 401 Unauthorized 错误。
原因:环境变量未加载,或变量名称不正确。
解决方案:
# .env file (Next.js)
THESYS_API_KEY=your_api_key_here
# Verify it's loaded
# In your code:
if (!process.env.THESYS_API_KEY) {
throw new Error("THESYS_API_KEY is not set");
}
# For Vite, use VITE_ prefix for client-side
VITE_THESYS_API_KEY=your_key # Client-side
THESYS_API_KEY=your_key # Server-side
# Access in Vite
const apiKey = import.meta.env.VITE_THESYS_API_KEY;
# For Cloudflare Workers, use wrangler secrets
npx wrangler secret put THESYS_API_KEY
模板与示例
此技能在 templates/ 目录中包含 15 个以上可用模板:
Vite + React(5 个模板)
basic-chat.tsx- 使用自定义后端的最简 C1Chat 配置custom-component.tsx- 使用 C1Component 和手动状态管理tool-calling.tsx- 网络搜索和数据库查询工具theme-dark-mode.tsx- 自定义主题和深色模式切换package.json- 精确的软件包版本
Next.js(4 个模板)
app/page.tsx- C1Chat 页面组件app/api/chat/route.ts- 流式 API 路由处理程序tool-calling-route.ts- 集成工具的 API 路由package.json- Next.js 依赖配置
Cloudflare Workers(3 个模板)
worker-backend.ts- 使用 TheSys 代理的 Hono APIfrontend-setup.tsx- React 前端配置wrangler.jsonc- Worker 部署配置
共享实用工具(3 个模板)
theme-config.ts- 可复用的主题配置tool-schemas.ts- 工具通用的 Zod 架构streaming-utils.ts- 流式处理辅助函数
其他资源
参考指南
详细指南请参阅 references/ 目录:
component-api.md- 所有组件的完整属性参考ai-provider-setup.md- 各 AI 提供商的分步配置指南tool-calling-guide.md- 全面的工具调用模式指南theme-customization.md- 主题系统深入介绍common-errors.md- 扩展版错误目录及解决方案
脚本
scripts/install-dependencies.sh- 安装所有必需的软件包scripts/check-versions.sh- 验证软件包版本
官方文档
- TheSys 文档:https://docs.thesys.dev
- C1 Playground:https://console.thesys.dev/playground
- GitHub 示例:在 GitHub 上搜索“thesysai”
- Context7:
/websites/thesys_dev
成功指标
- 令牌节省:与手动实现相比约节省 65–70%
- 避免的错误:已记录 12 个以上问题
- 开发速度:快 10 倍(据 TheSys 称)
- 用户参与度:83% 的用户更喜欢交互式 UI
- 软件包版本:最新稳定版(2025 年 10 月)
后续步骤
- 选择框架(Vite+React、Next.js 或 Cloudflare Workers)
- 从
templates/复制相关模板 - 设置
THESYS_API_KEY环境变量 - 使用
npm install安装依赖 - 运行开发服务器
- 自定义主题和 UI 组件
- 添加工具调用以实现高级功能
- 配置适当的持久化后部署到生产环境
如有疑问或遇到问题,请参阅 references/common-errors.md 指南,或查看 TheSys 官方文档。
最后更新:2025-10-26 软件包版本:@thesysai/[email protected] 经过生产环境测试:✅ 是 符合官方标准:✅ 是