CREATE TABLE IF NOT EXISTS _content_info (id TEXT PRIMARY KEY, "ready" BOOLEAN, "structureVersion" VARCHAR, "version" VARCHAR, "__hash__" TEXT UNIQUE); -- structure
INSERT INTO _content_info VALUES ('checksum_docs', false, 'quFkNIUZZFAwcn0ok74-KsIERem9u0p5DW-cqEgxrPA', 'v3.5.0--jyttfyMCdlkkD2Cy6uAigSOupLz7w9JK12BEQDx-Jb8', '0Z0mnYn3eH5Uu-q6HoFazESkAO3KD7UVALLwkXG_HCo'); -- meta
DROP TABLE IF EXISTS _content_docs; -- structure
CREATE TABLE IF NOT EXISTS _content_docs (id TEXT PRIMARY KEY, "title" VARCHAR, "body" TEXT, "description" VARCHAR, "extension" VARCHAR, "meta" TEXT, "navigation" TEXT DEFAULT true, "path" VARCHAR, "seo" TEXT DEFAULT '{}', "stem" VARCHAR, "__hash__" TEXT UNIQUE); -- structure
INSERT INTO _content_docs VALUES ('docs/docs/ai/agent.md', 'AI 智能体接入', '{"type":"minimark","value":[["h1",{"id":"ai-智能体接入"},"AI 智能体接入"],["blockquote",{},["p",{},"集成 AI Agent，实现知识库问答、工作流触发与多模型切换。"]],["h2",{"id":"什么是-ai-智能体"},"🧠 什么是 AI 智能体？"],["p",{},"AI 智能体（AI Agent）是 Websopy 平台的核心能力，它能："],["ul",{},["li",{},"🤖 基于自然语言理解用户意图"],["li",{},"📚 连接你的知识库进行精准问答"],["li",{},"🔗 触发业务工作流执行自动化任务"],["li",{},"🔄 在多个 AI 模型间智能切换"]],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"已完成 ",["a",{"href":"/developer/docs/getting-started/quickstart"},"快速上手"]],["li",{},"已开通 AI 功能（控制台 → 开发者中心 → AI 功能）"]],["h2",{"id":"接入步骤"},"🚀 接入步骤"],["h3",{"id":"第一步安装-ai-sdk"},"第一步：安装 AI SDK"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npm install @websopy/ai-sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/ai-sdk\n"]]]],["h3",{"id":"第二步初始化-agent"},"第二步：初始化 Agent"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { AIAgent } from ''@websopy/ai-sdk''\n\nconst agent = new AIAgent({\n  apiKey: process.env.WEBSOPY_API_KEY,\n  defaultModel: ''gpt-4'',\n  models: [''gpt-4'', ''claude-3'', ''gemini-pro'']\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { AIAgent } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  defaultModel: "],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gemini-pro''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第三步创建会话"},"第三步：创建会话"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const session = await agent.createSession({\n  userId: ''user-123'',\n  knowledgeBaseId: ''kb-abc456'',\n  metadata: {\n    source: ''website'',\n    language: ''zh-CN''\n  }\n})\n\nconsole.log(''会话 ID:'', session.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," session"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createSession"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  userId: "],["span",{"class":"sZZnC"},"''user-123''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  knowledgeBaseId: "],["span",{"class":"sZZnC"},"''kb-abc456''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  metadata: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    source: "],["span",{"class":"sZZnC"},"''website''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    language: "],["span",{"class":"sZZnC"},"''zh-CN''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''会话 ID:''"],["span",{"class":"sVt8B"},", session.id)\n"]]]],["h3",{"id":"第四步发送消息"},"第四步：发送消息"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await agent.sendMessage(session.id, {\n  content: ''我想了解你们的产品价格'',\n  context: {\n    userPlan: ''free'',\n    priority: ''normal''\n  }\n})\n\nconsole.log(''AI 回复:'', response.content)\nconsole.log(''使用模型:'', response.model)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessage"],["span",{"class":"sVt8B"},"(session.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  content: "],["span",{"class":"sZZnC"},"''我想了解你们的产品价格''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  context: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    userPlan: "],["span",{"class":"sZZnC"},"''free''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    priority: "],["span",{"class":"sZZnC"},"''normal''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''AI 回复:''"],["span",{"class":"sVt8B"},", response.content)\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''使用模型:''"],["span",{"class":"sVt8B"},", response.model)\n"]]]],["h3",{"id":"第五步流式响应sse"},"第五步：流式响应（SSE）"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const stream = await agent.sendMessageStream(session.id, {\n  content: ''写一篇关于 AI 的博客文章''\n})\n\nfor await (const chunk of stream) {\n  process.stdout.write(chunk.content)\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessageStream"],["span",{"class":"sVt8B"},"(session.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  content: "],["span",{"class":"sZZnC"},"''写一篇关于 AI 的博客文章''\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  process.stdout."],["span",{"class":"sScJk"},"write"],["span",{"class":"sVt8B"},"(chunk.content)\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"知识库集成"},"📚 知识库集成"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const kb = await agent.createKnowledgeBase({\n  name: ''产品文档'',\n  description: ''公司产品相关文档'',\n  embeddingModel: ''text-embedding-3-small''\n})\n\nawait agent.uploadDocument(kb.id, {\n  file: ''./docs/product-guide.pdf'',\n  metadata: {\n    category: ''documentation'',\n    version: ''2.0''\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," kb"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createKnowledgeBase"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  name: "],["span",{"class":"sZZnC"},"''产品文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  description: "],["span",{"class":"sZZnC"},"''公司产品相关文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  embeddingModel: "],["span",{"class":"sZZnC"},"''text-embedding-3-small''\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"uploadDocument"],["span",{"class":"sVt8B"},"(kb.id, {\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  file: "],["span",{"class":"sZZnC"},"''./docs/product-guide.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  metadata: {\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"    category: "],["span",{"class":"sZZnC"},"''documentation''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"    version: "],["span",{"class":"sZZnC"},"''2.0''\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"多模型切换"},"🔄 多模型切换"],["h3",{"id":"自动路由"},"自动路由"],["p",{},"根据任务类型自动选择最优模型："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const agent = new AIAgent({\n  apiKey: process.env.WEBSOPY_API_KEY,\n  autoRoute: {\n    enabled: true,\n    rules: [\n      { task: ''coding'', models: [''gpt-4'', ''claude-3''] },\n      { task: ''creative'', models: [''gpt-4'', ''gemini-pro''] },\n      { task: ''analysis'', models: [''claude-3'', ''gpt-4''] }\n    ]\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  autoRoute: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    enabled: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    rules: [\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"      { task: "],["span",{"class":"sZZnC"},"''coding''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},"] },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"      { task: "],["span",{"class":"sZZnC"},"''creative''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gemini-pro''"],["span",{"class":"sVt8B"},"] },\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"      { task: "],["span",{"class":"sZZnC"},"''analysis''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},"] }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    ]\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"完整示例"},"🧪 完整示例"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { AIAgent } from ''@websopy/ai-sdk''\n\nasync function main() {\n  const agent = new AIAgent({\n    apiKey: process.env.WEBSOPY_API_KEY,\n    defaultModel: ''gpt-4''\n  })\n\n  const session = await agent.createSession({\n    userId: ''user-123'',\n    knowledgeBaseId: ''kb-product-docs''\n  })\n\n  const messages = [\n    ''你好，我想了解一下企业版的功能'',\n    ''支持私有化部署吗？'',\n    ''好的，我想试用一下''\n  ]\n\n  for (const msg of messages) {\n    const response = await agent.sendMessage(session.id, { content: msg })\n    console.log(`\\n👤 用户: ${msg}`)\n    console.log(`🤖 AI: ${response.content}`)\n  }\n}\n\nmain()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { AIAgent } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," main"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    defaultModel: "],["span",{"class":"sZZnC"},"''gpt-4''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," session"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createSession"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"    userId: "],["span",{"class":"sZZnC"},"''user-123''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"    knowledgeBaseId: "],["span",{"class":"sZZnC"},"''kb-product-docs''\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," messages"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," [\n"]],["span",{"class":"line","line":15},["span",{"class":"sZZnC"},"    ''你好，我想了解一下企业版的功能''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":16},["span",{"class":"sZZnC"},"    ''支持私有化部署吗？''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":17},["span",{"class":"sZZnC"},"    ''好的，我想试用一下''\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"  ]\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{"class":"szBVR"},"  for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," msg"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," messages) {\n"]],["span",{"class":"line","line":21},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessage"],["span",{"class":"sVt8B"},"(session.id, { content: msg })\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"👤 用户: ${"],["span",{"class":"sVt8B"},"msg"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`🤖 AI: ${"],["span",{"class":"sVt8B"},"response"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"content"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":26},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":27},["span",{"class":"sScJk"},"main"],["span",{"class":"sVt8B"},"()\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-支持哪些-embedding-模型"},"Q: 支持哪些 Embedding 模型？"],["p",{},"目前支持："],["ul",{},["li",{},["code",{},"text-embedding-3-small"],"（推荐，速度快）"],["li",{},["code",{},"text-embedding-3-large"],"（高精度）"],["li",{},["code",{},"text-embedding-ada-002"],"（兼容性）"]],["h3",{"id":"q-知识库检索不到相关内容"},"Q: 知识库检索不到相关内容？"],["ol",{},["li",{},"检查文档是否已成功上传和向量化"],["li",{},"调整 ",["code",{},"scoreThreshold"]," 降低阈值"],["li",{},"尝试增加 ",["code",{},"topK"]," 获取更多候选"]],["style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-ai-智能体","depth":2,"text":"🧠 什么是 AI 智能体？"},{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"接入步骤","depth":2,"text":"🚀 接入步骤","children":[{"id":"第一步安装-ai-sdk","depth":3,"text":"第一步：安装 AI SDK"},{"id":"第二步初始化-agent","depth":3,"text":"第二步：初始化 Agent"},{"id":"第三步创建会话","depth":3,"text":"第三步：创建会话"},{"id":"第四步发送消息","depth":3,"text":"第四步：发送消息"},{"id":"第五步流式响应sse","depth":3,"text":"第五步：流式响应（SSE）"}]},{"id":"知识库集成","depth":2,"text":"📚 知识库集成"},{"id":"多模型切换","depth":2,"text":"🔄 多模型切换","children":[{"id":"自动路由","depth":3,"text":"自动路由"}]},{"id":"完整示例","depth":2,"text":"🧪 完整示例"},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-支持哪些-embedding-模型","depth":3,"text":"Q: 支持哪些 Embedding 模型？"},{"id":"q-知识库检索不到相关内容","depth":3,"text":"Q: 知识库检索不到相关内容？"}]}]}}', '集成 AI Agent，实现知识库问答、工作流触发与多模型切换。', 'md', '{"category":"ai","order":1}', 'true', '/docs/ai/agent', '{"title":"AI 智能体接入","description":"集成 AI Agent，实现知识库问答、工作流触发与多模型切换。"}', 'docs/ai/agent', 'aYeCTE7aiIr5B_LqjvVhtpMOyh9-xfwEvuxpdb32bRQ'); -- aYeCTE7aiIr5B_LqjvVhtpMOyh9-xfwEvuxpdb32bRQ
INSERT INTO _content_docs VALUES ('docs/docs/ai/rag.md', 'RAG 知识库搭建', '{"type":"minimark","value":[["h1",{"id":"rag-知识库搭建"},"RAG 知识库搭建"],["blockquote",{},["p",{},"上传文档、向量化存储，构建企业级知识库问答系统。"]],["h2",{"id":"什么是-rag"},"🧠 什么是 RAG？"],["p",{},"RAG（Retrieval-Augmented Generation，检索增强生成）是一种结合「知识检索」和「AI 生成」的技术："],["ol",{},["li",{},["strong",{},"检索"],"：从知识库中找到相关内容"],["li",{},["strong",{},"增强"],"：将检索结果作为上下文"],["li",{},["strong",{},"生成"],"：让 AI 基于上下文生成答案"]],["pre",{"className":["language-text"],"code":"用户问题 → 检索相关文档 → 拼接到 Prompt → AI 生成回答\n","language":"text"},["code",{"__ignoreMap":""},"用户问题 → 检索相关文档 → 拼接到 Prompt → AI 生成回答\n"]],["h2",{"id":"适用场景"},"📋 适用场景"],["ul",{},["li",{},"📄 企业内部文档问答"],["li",{},"🎯 产品 FAQ 自动化"],["li",{},"📚 培训资料检索"],["li",{},"🔍 合同/政策查询"],["li",{},"🏥 专业知识库"]],["h2",{"id":"搭建步骤"},"🚀 搭建步骤"],["h3",{"id":"第一步创建知识库"},"第一步：创建知识库"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const knowledgeBase = await client.ai.createKnowledgeBase({\n  name: ''产品使用手册'',\n  description: ''公司产品相关文档'',\n  embeddingModel: ''text-embedding-3-small'',\n  chunking: {\n    type: ''recursive'',\n    chunkSize: 1000,\n    chunkOverlap: 200\n  }\n})\n\nconsole.log(''知识库 ID:'', knowledgeBase.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," knowledgeBase"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"createKnowledgeBase"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  name: "],["span",{"class":"sZZnC"},"''产品使用手册''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  description: "],["span",{"class":"sZZnC"},"''公司产品相关文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  embeddingModel: "],["span",{"class":"sZZnC"},"''text-embedding-3-small''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  chunking: {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    type: "],["span",{"class":"sZZnC"},"''recursive''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"    chunkSize: "],["span",{"class":"sj4cs"},"1000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    chunkOverlap: "],["span",{"class":"sj4cs"},"200\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''知识库 ID:''"],["span",{"class":"sVt8B"},", knowledgeBase.id)\n"]]]],["h3",{"id":"第二步上传文档"},"第二步：上传文档"],["p",{},"支持格式：PDF、Word、TXT、Markdown、HTML"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 上传单个文件\nconst doc = await client.ai.uploadDocument(knowledgeBase.id, {\n  file: ''./docs/user-guide.pdf'',\n  metadata: {\n    category: ''manual'',\n    version: ''2.0'',\n    language: ''zh-CN''\n  }\n})\n\n// 批量上传\nconst docs = await client.ai.uploadDocuments(knowledgeBase.id, [\n  { file: ''./docs/faq.md'', metadata: { category: ''faq'' } },\n  { file: ''./docs/api.md'', metadata: { category: ''api'' } },\n])\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 上传单个文件\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," doc"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"uploadDocument"],["span",{"class":"sVt8B"},"(knowledgeBase.id, {\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  file: "],["span",{"class":"sZZnC"},"''./docs/user-guide.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  metadata: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    category: "],["span",{"class":"sZZnC"},"''manual''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    version: "],["span",{"class":"sZZnC"},"''2.0''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"    language: "],["span",{"class":"sZZnC"},"''zh-CN''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"// 批量上传\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," docs"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"uploadDocuments"],["span",{"class":"sVt8B"},"(knowledgeBase.id, [\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"  { file: "],["span",{"class":"sZZnC"},"''./docs/faq.md''"],["span",{"class":"sVt8B"},", metadata: { category: "],["span",{"class":"sZZnC"},"''faq''"],["span",{"class":"sVt8B"}," } },\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"  { file: "],["span",{"class":"sZZnC"},"''./docs/api.md''"],["span",{"class":"sVt8B"},", metadata: { category: "],["span",{"class":"sZZnC"},"''api''"],["span",{"class":"sVt8B"}," } },\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"])\n"]]]],["h3",{"id":"第三步配置检索"},"第三步：配置检索"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"await client.ai.configureRetrieval(knowledgeBase.id, {\n  retrieval: {\n    topK: 5,\n    scoreThreshold: 0.7,\n    hybridSearch: true\n  },\n  rerank: {\n    enabled: true,\n    model: ''bge-reranker''\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"configureRetrieval"],["span",{"class":"sVt8B"},"(knowledgeBase.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  retrieval: {\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"    topK: "],["span",{"class":"sj4cs"},"5"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    scoreThreshold: "],["span",{"class":"sj4cs"},"0.7"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    hybridSearch: "],["span",{"class":"sj4cs"},"true\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  rerank: {\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    enabled: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    model: "],["span",{"class":"sZZnC"},"''bge-reranker''\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第四步问答"},"第四步：问答"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await client.ai.ask({\n  knowledgeBaseId: knowledgeBase.id,\n  question: ''如何创建新项目？'',\n  options: {\n    maxTokens: 1000,\n    temperature: 0.7,\n    includeSources: true\n  }\n})\n\nconsole.log(''回答:'', response.answer)\nconsole.log(''引用:'', response.citations)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"ask"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  knowledgeBaseId: knowledgeBase.id,\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  question: "],["span",{"class":"sZZnC"},"''如何创建新项目？''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  options: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    maxTokens: "],["span",{"class":"sj4cs"},"1000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    temperature: "],["span",{"class":"sj4cs"},"0.7"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"    includeSources: "],["span",{"class":"sj4cs"},"true\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''回答:''"],["span",{"class":"sVt8B"},", response.answer)\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''引用:''"],["span",{"class":"sVt8B"},", response.citations)\n"]]]],["h3",{"id":"响应示例"},"响应示例"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"answer\": \"创建新项目的步骤如下：\\n1. 点击「新建项目」按钮\\n2. 填写项目名称和描述\\n3. 选择项目模板\\n4. 点击「创建」完成\",\n  \"citations\": [\n    {\n      \"document_id\": \"doc_abc123\",\n      \"chunk_text\": \"点击「新建项目」按钮，进入项目创建页面...\",\n      \"score\": 0.95\n    }\n  ],\n  \"model\": \"gpt-4\",\n  \"tokens_used\": 850\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"answer\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"创建新项目的步骤如下："],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"1. 点击「新建项目」按钮"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"2. 填写项目名称和描述"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"3. 选择项目模板"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"4. 点击「创建」完成\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"  \"citations\""],["span",{"class":"sVt8B"},": [\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    {\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"},"      \"document_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"doc_abc123\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"},"      \"chunk_text\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"点击「新建项目」按钮，进入项目创建页面...\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"},"      \"score\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"0.95\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  ],\n"]],["span",{"class":"line","line":10},["span",{"class":"sj4cs"},"  \"model\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"gpt-4\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sj4cs"},"  \"tokens_used\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"850\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"最佳实践"},"🧪 最佳实践"],["h3",{"id":"文档准备"},"文档准备"],["ol",{},["li",{},"✅ 清理格式，移除无关内容"],["li",{},"✅ 添加目录和标题结构"],["li",{},"✅ QA 格式文档效果最好"],["li",{},"❌ 避免过长的无结构文本"],["li",{},"❌ 避免大量表格（难以正确分块）"]],["h3",{"id":"检索优化"},"检索优化"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const optimalConfig = {\n  topK: 3,               // 不要太多，可能引入噪音\n  scoreThreshold: 0.75,  // 设置合理阈值\n  enableRerank: true     // 启用重排序\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," optimalConfig"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  topK: "],["span",{"class":"sj4cs"},"3"],["span",{"class":"sVt8B"},",               "],["span",{"class":"sJ8bj"},"// 不要太多，可能引入噪音\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  scoreThreshold: "],["span",{"class":"sj4cs"},"0.75"],["span",{"class":"sVt8B"},",  "],["span",{"class":"sJ8bj"},"// 设置合理阈值\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  enableRerank: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"},"     // 启用重排序\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"prompt-工程"},"Prompt 工程"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await client.ai.ask({\n  knowledgeBaseId: knowledgeBase.id,\n  question: ''...'',\n  systemPrompt: `你是一个专业客服，请基于给定的知识库内容回答用户问题。\n  - 如果知识库中没有相关内容，请如实告知\n  - 回答要简洁、专业、易懂\n  - 适当引用原文帮助用户理解`\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"ask"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  knowledgeBaseId: knowledgeBase.id,\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  question: "],["span",{"class":"sZZnC"},"''...''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  systemPrompt: "],["span",{"class":"sZZnC"},"`你是一个专业客服，请基于给定的知识库内容回答用户问题。\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"},"  - 如果知识库中没有相关内容，请如实告知\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"},"  - 回答要简洁、专业、易懂\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"},"  - 适当引用原文帮助用户理解`\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-检索不到相关内容"},"Q: 检索不到相关内容？"],["ol",{},["li",{},"检查文档是否处理完成（状态为 ",["code",{},"ready"],"）"],["li",{},"降低 ",["code",{},"scoreThreshold"]," 阈值"],["li",{},"尝试 ",["code",{},"hybridSearch: true"]," 混合搜索"],["li",{},"增加 ",["code",{},"topK"]," 获取更多候选"]],["h3",{"id":"q-回答不准确"},"Q: 回答不准确？"],["ol",{},["li",{},"检查源文档质量"],["li",{},"调整 ",["code",{},"chunkSize"],"，太小可能丢失上下文"],["li",{},"启用 ",["code",{},"rerank"]," 提高相关性"],["li",{},"优化 system prompt"]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-rag","depth":2,"text":"🧠 什么是 RAG？"},{"id":"适用场景","depth":2,"text":"📋 适用场景"},{"id":"搭建步骤","depth":2,"text":"🚀 搭建步骤","children":[{"id":"第一步创建知识库","depth":3,"text":"第一步：创建知识库"},{"id":"第二步上传文档","depth":3,"text":"第二步：上传文档"},{"id":"第三步配置检索","depth":3,"text":"第三步：配置检索"},{"id":"第四步问答","depth":3,"text":"第四步：问答"},{"id":"响应示例","depth":3,"text":"响应示例"}]},{"id":"最佳实践","depth":2,"text":"🧪 最佳实践","children":[{"id":"文档准备","depth":3,"text":"文档准备"},{"id":"检索优化","depth":3,"text":"检索优化"},{"id":"prompt-工程","depth":3,"text":"Prompt 工程"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-检索不到相关内容","depth":3,"text":"Q: 检索不到相关内容？"},{"id":"q-回答不准确","depth":3,"text":"Q: 回答不准确？"}]}]}}', '上传文档、向量化存储，构建企业级知识库问答系统。', 'md', '{"category":"ai","order":2}', 'true', '/docs/ai/rag', '{"title":"RAG 知识库搭建","description":"上传文档、向量化存储，构建企业级知识库问答系统。"}', 'docs/ai/rag', 'DcpoLfXPgq7FWv-OLVP6_igv1nI_7FiOGJvjbOBeCDw'); -- DcpoLfXPgq7FWv-OLVP6_igv1nI_7FiOGJvjbOBeCDw
INSERT INTO _content_docs VALUES ('docs/docs/ai/workflow.md', 'AI 工作流配置', '{"type":"minimark","value":[["h1",{"id":"ai-工作流配置"},"AI 工作流配置"],["blockquote",{},["p",{},"使用工作流引擎，构建定时任务与自动化业务流。"]],["h2",{"id":"什么是工作流"},"🔄 什么是工作流？"],["p",{},"工作流（Workflow）是预定义的一系列自动化步骤，可以："],["ul",{},["li",{},"⏰ ",["strong",{},"定时执行"],"：每天早上发送报表"],["li",{},"🔗 ",["strong",{},"事件触发"],"：用户注册后自动发送欢迎邮件"],["li",{},"🔁 ",["strong",{},"条件分支"],"：根据条件执行不同操作"],["li",{},"📊 ",["strong",{},"数据处理"],"：批量处理数据"]],["h2",{"id":"️-核心概念"},"🏗️ 核心概念"],["table",{},["thead",{},["tr",{},["th",{},"概念"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["strong",{},"触发器 (Trigger)"]],["td",{},"工作流的启动条件"]],["tr",{},["td",{},["strong",{},"节点 (Node)"]],["td",{},"工作流中的单个步骤"]],["tr",{},["td",{},["strong",{},"连接 (Edge)"]],["td",{},"节点之间的数据流向"]],["tr",{},["td",{},["strong",{},"变量 (Variable)"]],["td",{},"存储和传递数据"]],["tr",{},["td",{},["strong",{},"执行日志"]],["td",{},"每次运行的记录"]]]],["h2",{"id":"创建第一个工作流"},"🚀 创建第一个工作流"],["h3",{"id":"代码定义"},"代码定义"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WorkflowBuilder } from ''@websopy/ai-sdk''\n\nconst workflow = new WorkflowBuilder({\n  name: ''每日数据报告'',\n  description: ''每天早上 9 点生成数据报告''\n})\n\n// 添加触发器：定时执行\nworkflow.addTrigger({\n  type: ''schedule'',\n  config: {\n    cron: ''0 9 * * *'',  // 每天 9:00\n    timezone: ''Asia/Shanghai''\n  }\n})\n\n// 添加节点：获取数据\nworkflow.addNode(''fetch-data'', {\n  type: ''http-request'',\n  config: {\n    url: ''https://api.analytics.com/daily-stats'',\n    method: ''GET''\n  }\n})\n\n// 添加节点：生成报告\nworkflow.addNode(''generate-report'', {\n  type: ''ai-agent'',\n  config: {\n    prompt: ''根据以下数据生成日报：{{fetch-data.output}}''\n  }\n})\n\n// 添加节点：发送邮件\nworkflow.addNode(''send-email'', {\n  type: ''email'',\n  config: {\n    to: [''team@company.com''],\n    subject: ''📊 每日数据报告'',\n    body: ''{{generate-report.output}}''\n  }\n})\n\n// 节点连接\nworkflow.connect(''fetch-data'', ''generate-report'')\nworkflow.connect(''generate-report'', ''send-email'')\n\n// 保存\nconst created = await client.workflow.create(workflow.toJSON())\nconsole.log(''工作流 ID:'', created.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WorkflowBuilder } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," workflow"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WorkflowBuilder"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  name: "],["span",{"class":"sZZnC"},"''每日数据报告''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  description: "],["span",{"class":"sZZnC"},"''每天早上 9 点生成数据报告''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"// 添加触发器：定时执行\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''schedule''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"    cron: "],["span",{"class":"sZZnC"},"''0 9 * * *''"],["span",{"class":"sVt8B"},",  "],["span",{"class":"sJ8bj"},"// 每天 9:00\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"    timezone: "],["span",{"class":"sZZnC"},"''Asia/Shanghai''\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":16},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":17},["span",{"class":"sJ8bj"},"// 添加节点：获取数据\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''fetch-data''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''http-request''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"},"    url: "],["span",{"class":"sZZnC"},"''https://api.analytics.com/daily-stats''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"},"    method: "],["span",{"class":"sZZnC"},"''GET''\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":25},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":26},["span",{"class":"sJ8bj"},"// 添加节点：生成报告\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''ai-agent''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":29},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":30},["span",{"class":"sVt8B"},"    prompt: "],["span",{"class":"sZZnC"},"''根据以下数据生成日报：{{fetch-data.output}}''\n"]],["span",{"class":"line","line":31},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":32},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":33},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":34},["span",{"class":"sJ8bj"},"// 添加节点：发送邮件\n"]],["span",{"class":"line","line":35},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''send-email''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":36},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''email''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":37},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":38},["span",{"class":"sVt8B"},"    to: ["],["span",{"class":"sZZnC"},"''team@company.com''"],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":39},["span",{"class":"sVt8B"},"    subject: "],["span",{"class":"sZZnC"},"''📊 每日数据报告''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":40},["span",{"class":"sVt8B"},"    body: "],["span",{"class":"sZZnC"},"''{{generate-report.output}}''\n"]],["span",{"class":"line","line":41},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":42},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":43},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":44},["span",{"class":"sJ8bj"},"// 节点连接\n"]],["span",{"class":"line","line":45},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"connect"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''fetch-data''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":46},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"connect"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''send-email''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":47},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":48},["span",{"class":"sJ8bj"},"// 保存\n"]],["span",{"class":"line","line":49},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," created"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"(workflow."],["span",{"class":"sScJk"},"toJSON"],["span",{"class":"sVt8B"},"())\n"]],["span",{"class":"line","line":50},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''工作流 ID:''"],["span",{"class":"sVt8B"},", created.id)\n"]]]],["h3",{"id":"可视化编辑器"},"可视化编辑器"],["p",{},"在控制台 → AI 功能 → 工作流，点击「新建工作流」打开可视化编辑器。"],["h2",{"id":"节点类型"},"📦 节点类型"],["table",{},["thead",{},["tr",{},["th",{},"节点类型"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["code",{},"http-request"]],["td",{},"HTTP 请求"]],["tr",{},["td",{},["code",{},"ai-agent"]],["td",{},"AI 智能体"]],["tr",{},["td",{},["code",{},"condition"]],["td",{},"条件分支"]],["tr",{},["td",{},["code",{},"loop"]],["td",{},"循环"]],["tr",{},["td",{},["code",{},"delay"]],["td",{},"等待/延迟"]],["tr",{},["td",{},["code",{},"webhook"]],["td",{},"Webhook 通知"]],["tr",{},["td",{},["code",{},"transform"]],["td",{},"数据转换"]],["tr",{},["td",{},["code",{},"email"]],["td",{},"发送邮件"]]]],["h2",{"id":"触发器类型"},"🔔 触发器类型"],["h3",{"id":"定时触发"},"定时触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n  type: ''schedule'',\n  config: {\n    cron: ''0 */4 * * *'',  // 每 4 小时\n    interval: ''daily'',    // daily, weekly, monthly\n    time: ''09:00''\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''schedule''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    cron: "],["span",{"class":"sZZnC"},"''0 */4 * * *''"],["span",{"class":"sVt8B"},",  "],["span",{"class":"sJ8bj"},"// 每 4 小时\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    interval: "],["span",{"class":"sZZnC"},"''daily''"],["span",{"class":"sVt8B"},",    "],["span",{"class":"sJ8bj"},"// daily, weekly, monthly\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    time: "],["span",{"class":"sZZnC"},"''09:00''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"webhook-触发"},"Webhook 触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n  type: ''webhook'',\n  config: {\n    // 创建后获得 webhook URL\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''webhook''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"    // 创建后获得 webhook URL\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"事件触发"},"事件触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n  type: ''event'',\n  config: {\n    events: [\n      ''user.created'',\n      ''order.completed'',\n      ''ai.task.failed''\n    ]\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''event''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    events: [\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"},"      ''user.created''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"},"      ''order.completed''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"},"      ''ai.task.failed''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    ]\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"执行与监控"},"📊 执行与监控"],["h3",{"id":"手动执行"},"手动执行"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const run = await client.workflow.run(workflowId, {\n  input: { date: ''2024-01-15'' }\n})\n\nconsole.log(''执行 ID:'', run.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," run"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"run"],["span",{"class":"sVt8B"},"(workflowId, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  input: { date: "],["span",{"class":"sZZnC"},"''2024-01-15''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''执行 ID:''"],["span",{"class":"sVt8B"},", run.id)\n"]]]],["h3",{"id":"查看执行日志"},"查看执行日志"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const logs = await client.workflow.getRunLogs(run.id)\n\nfor (const log of logs) {\n  console.log(`[${log.timestamp}] ${log.node}: ${log.status}`)\n  if (log.error) {\n    console.log(''  错误:'', log.error)\n  }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," logs"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"getRunLogs"],["span",{"class":"sVt8B"},"(run.id)\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," log"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," logs) {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`[${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"timestamp"],["span",{"class":"sZZnC"},"}] ${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"node"],["span",{"class":"sZZnC"},"}: ${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"status"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"  if"],["span",{"class":"sVt8B"}," (log.error) {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''  错误:''"],["span",{"class":"sVt8B"},", log.error)\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-工作流执行失败怎么办"},"Q: 工作流执行失败怎么办？"],["ol",{},["li",{},"查看执行日志定位问题节点"],["li",{},"检查输入数据格式"],["li",{},"查看节点配置是否正确"],["li",{},"联系支持时提供执行 ID"]],["h3",{"id":"q-可以嵌套工作流吗"},"Q: 可以嵌套工作流吗？"],["p",{},"是的，可以在一个工作流中调用另一个工作流："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addNode(''sub-workflow'', {\n  type: ''workflow'',\n  config: {\n    workflowId: ''wf-xxx'',\n    input: ''{{current-data}}''\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''sub-workflow''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  type: "],["span",{"class":"sZZnC"},"''workflow''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    workflowId: "],["span",{"class":"sZZnC"},"''wf-xxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    input: "],["span",{"class":"sZZnC"},"''{{current-data}}''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是工作流","depth":2,"text":"🔄 什么是工作流？"},{"id":"️-核心概念","depth":2,"text":"🏗️ 核心概念"},{"id":"创建第一个工作流","depth":2,"text":"🚀 创建第一个工作流","children":[{"id":"代码定义","depth":3,"text":"代码定义"},{"id":"可视化编辑器","depth":3,"text":"可视化编辑器"}]},{"id":"节点类型","depth":2,"text":"📦 节点类型"},{"id":"触发器类型","depth":2,"text":"🔔 触发器类型","children":[{"id":"定时触发","depth":3,"text":"定时触发"},{"id":"webhook-触发","depth":3,"text":"Webhook 触发"},{"id":"事件触发","depth":3,"text":"事件触发"}]},{"id":"执行与监控","depth":2,"text":"📊 执行与监控","children":[{"id":"手动执行","depth":3,"text":"手动执行"},{"id":"查看执行日志","depth":3,"text":"查看执行日志"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-工作流执行失败怎么办","depth":3,"text":"Q: 工作流执行失败怎么办？"},{"id":"q-可以嵌套工作流吗","depth":3,"text":"Q: 可以嵌套工作流吗？"}]}]}}', '使用工作流引擎，构建定时任务与自动化业务流。', 'md', '{"category":"ai","order":3}', 'true', '/docs/ai/workflow', '{"title":"AI 工作流配置","description":"使用工作流引擎，构建定时任务与自动化业务流。"}', 'docs/ai/workflow', 'EZRBCN9XfN1yY6NZaqT1Tp1EWDfLjaTKQOmEJtLXuwg'); -- EZRBCN9XfN1yY6NZaqT1Tp1EWDfLjaTKQOmEJtLXuwg
INSERT INTO _content_docs VALUES ('docs/docs/api/rest-api.md', 'REST API 完整参考', '{"type":"minimark","value":[["h1",{"id":"rest-api-完整参考"},"REST API 完整参考"],["blockquote",{},["p",{},"200+ 标准接口文档，覆盖用户、内容、AI、支付等全部模块。"]],["h2",{"id":"api-概览"},"📚 API 概览"],["p",{},["strong",{},"基础 URL："]," ",["code",{},"https://api.websopy.com/v1"]],["p",{},["strong",{},"认证方式："]," Bearer Token"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"curl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n     https://api.websopy.com/v1/user/profile\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"curl"],["span",{"class":"sj4cs"}," -H"],["span",{"class":"sZZnC"}," \"Authorization: Bearer YOUR_API_KEY\""],["span",{"class":"sj4cs"}," \\\n"]],["span",{"class":"line","line":2},["span",{"class":"sZZnC"},"     https://api.websopy.com/v1/user/profile\n"]]]],["h2",{"id":"端点列表"},"📋 端点列表"],["h3",{"id":"用户管理-user"},"用户管理 ",["code",{},"/user"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/user/profile"]],["td",{},"获取当前用户信息"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/user/profile"]],["td",{},"更新用户信息"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/user/settings"]],["td",{},"获取用户设置"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/user/settings"]],["td",{},"更新用户设置"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/user/avatar"]],["td",{},"上传头像"]]]],["h3",{"id":"项目管理-projects"},"项目管理 ",["code",{},"/projects"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects"]],["td",{},"列出项目"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/projects"]],["td",{},"创建项目"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects/:id"]],["td",{},"获取项目详情"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/projects/:id"]],["td",{},"更新项目"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/projects/:id"]],["td",{},"删除项目"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects/:id/members"]],["td",{},"获取项目成员"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/projects/:id/members"]],["td",{},"添加成员"]]]],["h3",{"id":"文件存储-storage"},"文件存储 ",["code",{},"/storage"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files"]],["td",{},"列出文件"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/storage/upload"]],["td",{},"上传文件"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files/:id"]],["td",{},"获取文件信息"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/storage/files/:id"]],["td",{},"删除文件"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files/:id/download"]],["td",{},"下载文件"]]]],["h3",{"id":"ai-功能-ai"},"AI 功能 ",["code",{},"/ai"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/chat"]],["td",{},"发送对话请求"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/chat/stream"]],["td",{},"流式对话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/ai/sessions"]],["td",{},"列出会话"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/sessions"]],["td",{},"创建会话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/ai/sessions/:id"]],["td",{},"获取会话详情"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/ai/sessions/:id"]],["td",{},"删除会话"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/knowledge"]],["td",{},"创建知识库"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/knowledge/:id/documents"]],["td",{},"添加文档"]]]],["h3",{"id":"支付-payments"},"支付 ",["code",{},"/payments"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/orders"]],["td",{},"列出订单"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/payments/orders"]],["td",{},"创建订单"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/orders/:id"]],["td",{},"订单详情"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/payments/checkout"]],["td",{},"创建结算会话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/subscriptions"]],["td",{},"订阅列表"]]]],["h2",{"id":"请求与响应"},"🔍 请求与响应"],["h3",{"id":"请求头"},"请求头"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"Authorization: Bearer YOUR_API_KEY\nContent-Type: application/json\nAccept: application/json\nX-Request-ID: unique-request-id\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"Authorization: Bearer YOUR_API_KEY\n"]],["span",{"class":"line","line":2},["span",{},"Content-Type: application/json\n"]],["span",{"class":"line","line":3},["span",{},"Accept: application/json\n"]],["span",{"class":"line","line":4},["span",{},"X-Request-ID: unique-request-id\n"]]]],["h3",{"id":"分页"},"分页"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?page=2&limit=20\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?page=2&limit=20\n"]]]],["p",{},"响应包含分页信息："],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"data\": [...],\n  \"pagination\": {\n    \"page\": 2,\n    \"limit\": 20,\n    \"total\": 100,\n    \"total_pages\": 5\n  }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"data\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"s7hpK"},"..."],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"  \"pagination\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"},"    \"page\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"2"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"},"    \"limit\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"20"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"},"    \"total\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"100"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"},"    \"total_pages\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"5\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"排序"},"排序"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?sort=created_at&order=desc\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?sort=created_at&order=desc\n"]]]],["h3",{"id":"过滤"},"过滤"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?status=active&category=ai\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?status=active&category=ai\n"]]]],["h2",{"id":"错误处理"},"📝 错误处理"],["h3",{"id":"错误码"},"错误码"],["table",{},["thead",{},["tr",{},["th",{},"状态码"],["th",{},"错误码"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"400"],["td",{},["code",{},"INVALID_REQUEST"]],["td",{},"请求参数错误"]],["tr",{},["td",{},"401"],["td",{},["code",{},"UNAUTHORIZED"]],["td",{},"未认证或 Token 无效"]],["tr",{},["td",{},"403"],["td",{},["code",{},"FORBIDDEN"]],["td",{},"无权限访问"]],["tr",{},["td",{},"404"],["td",{},["code",{},"NOT_FOUND"]],["td",{},"资源不存在"]],["tr",{},["td",{},"429"],["td",{},["code",{},"RATE_LIMITED"]],["td",{},"请求过于频繁"]],["tr",{},["td",{},"500"],["td",{},["code",{},"SERVER_ERROR"]],["td",{},"服务器内部错误"]]]],["h3",{"id":"错误响应格式"},"错误响应格式"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"error\": {\n    \"code\": \"INVALID_REQUEST\",\n    \"message\": \"参数 ''name'' 不能为空\",\n    \"details\": {\n      \"field\": \"name\",\n      \"constraint\": \"required\"\n    }\n  }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"error\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"    \"code\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"INVALID_REQUEST\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"},"    \"message\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"参数 ''name'' 不能为空\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"},"    \"details\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"},"      \"field\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"name\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"},"      \"constraint\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"required\"\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"使用示例"},"🔧 使用示例"],["h3",{"id":"javascripttypescript"},"JavaScript/TypeScript"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await fetch(''https://api.websopy.com/v1/projects'', {\n  method: ''POST'',\n  headers: {\n    ''Authorization'': `Bearer ${apiKey}`,\n    ''Content-Type'': ''application/json''\n  },\n  body: JSON.stringify({\n    name: ''我的项目'',\n    description: ''项目描述''\n  })\n})\n\nconst data = await response.json()\nconsole.log(data)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fetch"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1/projects''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  method: "],["span",{"class":"sZZnC"},"''POST''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  headers: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sZZnC"},"    ''Authorization''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"`Bearer ${"],["span",{"class":"sVt8B"},"apiKey"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"},"    ''Content-Type''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''application/json''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  body: "],["span",{"class":"sj4cs"},"JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"stringify"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"    name: "],["span",{"class":"sZZnC"},"''我的项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    description: "],["span",{"class":"sZZnC"},"''项目描述''\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," data"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," response."],["span",{"class":"sScJk"},"json"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"(data)\n"]]]],["h3",{"id":"python"},"Python"],["pre",{"className":"language-python shiki shiki-themes github-light github-dark","code":"import requests\n\nresponse = requests.post(\n    ''https://api.websopy.com/v1/projects'',\n    headers={\n        ''Authorization'': f''Bearer {api_key}'',\n        ''Content-Type'': ''application/json''\n    },\n    json={\n        ''name'': ''我的项目'',\n        ''description'': ''项目描述''\n    }\n)\n\ndata = response.json()\nprint(data)\n","language":"python","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"import requests\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{},"response = requests.post(\n"]],["span",{"class":"line","line":4},["span",{},"    ''https://api.websopy.com/v1/projects'',\n"]],["span",{"class":"line","line":5},["span",{},"    headers={\n"]],["span",{"class":"line","line":6},["span",{},"        ''Authorization'': f''Bearer {api_key}'',\n"]],["span",{"class":"line","line":7},["span",{},"        ''Content-Type'': ''application/json''\n"]],["span",{"class":"line","line":8},["span",{},"    },\n"]],["span",{"class":"line","line":9},["span",{},"    json={\n"]],["span",{"class":"line","line":10},["span",{},"        ''name'': ''我的项目'',\n"]],["span",{"class":"line","line":11},["span",{},"        ''description'': ''项目描述''\n"]],["span",{"class":"line","line":12},["span",{},"    }\n"]],["span",{"class":"line","line":13},["span",{},")\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{},"data = response.json()\n"]],["span",{"class":"line","line":16},["span",{},"print(data)\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"api-概览","depth":2,"text":"📚 API 概览"},{"id":"端点列表","depth":2,"text":"📋 端点列表","children":[{"id":"用户管理-user","depth":3,"text":"用户管理 /user"},{"id":"项目管理-projects","depth":3,"text":"项目管理 /projects"},{"id":"文件存储-storage","depth":3,"text":"文件存储 /storage"},{"id":"ai-功能-ai","depth":3,"text":"AI 功能 /ai"},{"id":"支付-payments","depth":3,"text":"支付 /payments"}]},{"id":"请求与响应","depth":2,"text":"🔍 请求与响应","children":[{"id":"请求头","depth":3,"text":"请求头"},{"id":"分页","depth":3,"text":"分页"},{"id":"排序","depth":3,"text":"排序"},{"id":"过滤","depth":3,"text":"过滤"}]},{"id":"错误处理","depth":2,"text":"📝 错误处理","children":[{"id":"错误码","depth":3,"text":"错误码"},{"id":"错误响应格式","depth":3,"text":"错误响应格式"}]},{"id":"使用示例","depth":2,"text":"🔧 使用示例","children":[{"id":"javascripttypescript","depth":3,"text":"JavaScript/TypeScript"},{"id":"python","depth":3,"text":"Python"}]}]}}', '200+ 标准接口文档，覆盖用户、内容、AI、支付等全部模块。', 'md', '{"category":"api","order":1}', 'true', '/docs/api/rest-api', '{"title":"REST API 完整参考","description":"200+ 标准接口文档，覆盖用户、内容、AI、支付等全部模块。"}', 'docs/api/rest-api', 'UrSAbHsueij0gNTWlXd4iyiJTMb9Byd5YRQx6ZWNkQg'); -- UrSAbHsueij0gNTWlXd4iyiJTMb9Byd5YRQx6ZWNkQg
INSERT INTO _content_docs VALUES ('docs/docs/api/streaming.md', '流式输出（SSE）接入', '{"type":"minimark","value":[["h1",{"id":"流式输出sse接入"},"流式输出（SSE）接入"],["blockquote",{},["p",{},"使用 Server-Sent Events 实现 AI 流式响应，提升用户体验。"]],["h2",{"id":"什么是流式输出"},"🌊 什么是流式输出？"],["p",{},"流式输出（Streaming）是一种数据传输方式，服务器将数据「分块」发送给客户端，而不是等待全部完成后再返回。"],["h3",{"id":"对比"},"对比"],["table",{},["thead",{},["tr",{},["th",{},"方式"],["th",{},"等待时间"],["th",{},"体验"],["th",{},"适用场景"]]],["tbody",{},["tr",{},["td",{},"普通请求"],["td",{},"等待完整响应"],["td",{},"一般"],["td",{},"简单、快速的请求"]],["tr",{},["td",{},"流式输出"],["td",{},"实时看到生成过程"],["td",{},"⭐ 优秀"],["td",{},"AI 生成、长文本"]]]],["h2",{"id":"开始使用"},"🚀 开始使用"],["h3",{"id":"前端接收流式响应"},"前端：接收流式响应"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY\n})\n\nasync function streamChat() {\n  const stream = await client.ai.chatStream({\n    messages: [\n      { role: ''user'', content: ''写一篇关于 AI 的文章'' }\n    ]\n  })\n\n  // 方法 1：遍历数据块\n  for await (const chunk of stream) {\n    if (chunk.type === ''content'') {\n      process.stdout.write(chunk.content)\n    }\n  }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," streamChat"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    messages: [\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"      { role: "],["span",{"class":"sZZnC"},"''user''"],["span",{"class":"sVt8B"},", content: "],["span",{"class":"sZZnC"},"''写一篇关于 AI 的文章''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"    ]\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"  // 方法 1：遍历数据块\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"},"  for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"},"    if"],["span",{"class":"sVt8B"}," (chunk.type "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"      process.stdout."],["span",{"class":"sScJk"},"write"],["span",{"class":"sVt8B"},"(chunk.content)\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"响应数据结构"},"响应数据结构"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"interface StreamChunk {\n  type: ''content'' | ''tool_call'' | ''done'' | ''error''\n  content?: string\n  tool?: {\n    name: string\n    arguments: string\n  }\n  usage?: {\n    promptTokens: number\n    completionTokens: number\n  }\n}\n\n// 示例数据块\n{ type: ''content'', content: ''AI'' }\n{ type: ''content'', content: '' 正在'' }\n{ type: ''content'', content: ''改变'' }\n{ type: ''content'', content: ''世界...'' }\n{ type: ''done'', usage: { promptTokens: 20, completionTokens: 150 } }\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"interface"],["span",{"class":"sScJk"}," StreamChunk"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"s4XuR"},"  type"],["span",{"class":"szBVR"},":"],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''tool_call''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''done''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''error''\n"]],["span",{"class":"line","line":3},["span",{"class":"s4XuR"},"  content"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":4},["span",{"class":"s4XuR"},"  tool"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":5},["span",{"class":"s4XuR"},"    name"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":6},["span",{"class":"s4XuR"},"    arguments"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":8},["span",{"class":"s4XuR"},"  usage"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":9},["span",{"class":"s4XuR"},"    promptTokens"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," number\n"]],["span",{"class":"line","line":10},["span",{"class":"s4XuR"},"    completionTokens"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," number\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"// 示例数据块\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''AI''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"'' 正在''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''改变''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''世界...''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''done''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"usage"],["span",{"class":"sVt8B"},": { "],["span",{"class":"sScJk"},"promptTokens"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"20"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"completionTokens"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"150"],["span",{"class":"sVt8B"}," } }\n"]]]],["h2",{"id":"原生-sse-实现"},"🌐 原生 SSE 实现"],["p",{},"如果不用 SDK，直接使用 Fetch API："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function nativeStream() {\n  const response = await fetch(\n    ''https://api.websopy.com/v1/ai/chat?message=Hello'',\n    {\n      headers: {\n        ''Authorization'': `Bearer ${apiKey}`,\n        ''Accept'': ''text/event-stream''\n      }\n    }\n  )\n\n  const reader = response.body.getReader()\n  const decoder = new TextDecoder()\n\n  while (true) {\n    const { done, value } = await reader.read()\n    if (done) break\n    \n    const chunk = decoder.decode(value)\n    const lines = chunk.split(''\\n'')\n    for (const line of lines) {\n      if (line.startsWith(''data: '')) {\n        const data = JSON.parse(line.slice(6))\n        console.log(''收到:'', data)\n      }\n    }\n  }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," nativeStream"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fetch"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":3},["span",{"class":"sZZnC"},"    ''https://api.websopy.com/v1/ai/chat?message=Hello''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"      headers: {\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"},"        ''Authorization''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"`Bearer ${"],["span",{"class":"sVt8B"},"apiKey"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"},"        ''Accept''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''text/event-stream''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"      }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  )\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," reader"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," response.body."],["span",{"class":"sScJk"},"getReader"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," decoder"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," TextDecoder"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"},"  while"],["span",{"class":"sVt8B"}," ("],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"},"    const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"sj4cs"},"done"],["span",{"class":"sVt8B"},", "],["span",{"class":"sj4cs"},"value"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," reader."],["span",{"class":"sScJk"},"read"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":17},["span",{"class":"szBVR"},"    if"],["span",{"class":"sVt8B"}," (done) "],["span",{"class":"szBVR"},"break\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," decoder."],["span",{"class":"sScJk"},"decode"],["span",{"class":"sVt8B"},"(value)\n"]],["span",{"class":"line","line":20},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," lines"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," chunk."],["span",{"class":"sScJk"},"split"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":21},["span",{"class":"szBVR"},"    for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," line"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," lines) {\n"]],["span",{"class":"line","line":22},["span",{"class":"szBVR"},"      if"],["span",{"class":"sVt8B"}," (line."],["span",{"class":"sScJk"},"startsWith"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''data: ''"],["span",{"class":"sVt8B"},")) {\n"]],["span",{"class":"line","line":23},["span",{"class":"szBVR"},"        const"],["span",{"class":"sj4cs"}," data"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(line."],["span",{"class":"sScJk"},"slice"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"6"],["span",{"class":"sVt8B"},"))\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"},"        console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''收到:''"],["span",{"class":"sVt8B"},", data)\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"},"      }\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"前端组件示例"},"🎨 前端组件示例"],["h3",{"id":"vue-composition-api"},"Vue Composition API"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { ref } from ''vue''\n\nexport function useStreamingChat() {\n  const messages = ref([])\n  const streaming = ref(false)\n  const currentContent = ref('''')\n\n  const sendMessage = async (content) => {\n    streaming.value = true\n    currentContent.value = ''''\n    \n    messages.value.push({ role: ''user'', content })\n    \n    const stream = await client.ai.chatStream({\n      messages: messages.value\n    })\n\n    for await (const chunk of stream) {\n      if (chunk.type === ''content'') {\n        currentContent.value += chunk.content\n      }\n    }\n    \n    messages.value.push({ role: ''assistant'', content: currentContent.value })\n    streaming.value = false\n  }\n\n  return { messages, streaming, currentContent, sendMessage }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { ref } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''vue''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"export"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," useStreamingChat"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," messages"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"([])\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," streaming"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"false"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," currentContent"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"  const"],["span",{"class":"sScJk"}," sendMessage"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"content"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    streaming.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," true\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"    currentContent.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sZZnC"}," ''''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"    messages.value."],["span",{"class":"sScJk"},"push"],["span",{"class":"sVt8B"},"({ role: "],["span",{"class":"sZZnC"},"''user''"],["span",{"class":"sVt8B"},", content })\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"      messages: messages.value\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"    })\n"]],["span",{"class":"line","line":17},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":18},["span",{"class":"szBVR"},"    for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"},"      if"],["span",{"class":"sVt8B"}," (chunk.type "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"        currentContent.value "],["span",{"class":"szBVR"},"+="],["span",{"class":"sVt8B"}," chunk.content\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"},"      }\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"},"    messages.value."],["span",{"class":"sScJk"},"push"],["span",{"class":"sVt8B"},"({ role: "],["span",{"class":"sZZnC"},"''assistant''"],["span",{"class":"sVt8B"},", content: currentContent.value })\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"},"    streaming.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," false\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":27},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":28},["span",{"class":"szBVR"},"  return"],["span",{"class":"sVt8B"}," { messages, streaming, currentContent, sendMessage }\n"]],["span",{"class":"line","line":29},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-流式中断怎么办"},"Q: 流式中断怎么办？"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function streamWithReconnect() {\n  const maxRetries = 3\n  let retries = 0\n  \n  while (retries < maxRetries) {\n    try {\n      const stream = await client.ai.chatStream({...})\n      return stream\n    } catch (error) {\n      retries++\n      await sleep(1000 * retries)  // 指数退避\n    }\n  }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," streamWithReconnect"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," maxRetries"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," 3\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"  let"],["span",{"class":"sVt8B"}," retries "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," 0\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"  while"],["span",{"class":"sVt8B"}," (retries "],["span",{"class":"szBVR"},"<"],["span",{"class":"sVt8B"}," maxRetries) {\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"},"    try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"      const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({"],["span",{"class":"szBVR"},"..."],["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"      return"],["span",{"class":"sVt8B"}," stream\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"      retries"],["span",{"class":"szBVR"},"++\n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"},"      await"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"1000"],["span",{"class":"szBVR"}," *"],["span",{"class":"sVt8B"}," retries)  "],["span",{"class":"sJ8bj"},"// 指数退避\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"q-如何在流式过程中取消请求"},"Q: 如何在流式过程中取消请求？"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const controller = new AbortController()\n\n// 发送请求\nconst stream = await client.ai.chatStream({\n  messages: [...],\n  signal: controller.signal\n})\n\n// 取消请求\ncontroller.abort()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," controller"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AbortController"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"// 发送请求\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  messages: ["],["span",{"class":"szBVR"},"..."],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  signal: controller.signal\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"sJ8bj"},"// 取消请求\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"controller."],["span",{"class":"sScJk"},"abort"],["span",{"class":"sVt8B"},"()\n"]]]],["h3",{"id":"q-sse-和-websocket-区别"},"Q: SSE 和 WebSocket 区别？"],["table",{},["thead",{},["tr",{},["th",{},"特性"],["th",{},"SSE"],["th",{},"WebSocket"]]],["tbody",{},["tr",{},["td",{},"方向"],["td",{},"单向（服务端→客户端）"],["td",{},"双向"]],["tr",{},["td",{},"协议"],["td",{},"HTTP"],["td",{},"ws://"]],["tr",{},["td",{},"重连"],["td",{},"自动"],["td",{},"需手动处理"]],["tr",{},["td",{},"复杂度"],["td",{},"简单"],["td",{},"复杂"]],["tr",{},["td",{},"适用"],["td",{},"AI 流式输出"],["td",{},"实时聊天"]]]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是流式输出","depth":2,"text":"🌊 什么是流式输出？","children":[{"id":"对比","depth":3,"text":"对比"}]},{"id":"开始使用","depth":2,"text":"🚀 开始使用","children":[{"id":"前端接收流式响应","depth":3,"text":"前端：接收流式响应"},{"id":"响应数据结构","depth":3,"text":"响应数据结构"}]},{"id":"原生-sse-实现","depth":2,"text":"🌐 原生 SSE 实现"},{"id":"前端组件示例","depth":2,"text":"🎨 前端组件示例","children":[{"id":"vue-composition-api","depth":3,"text":"Vue Composition API"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-流式中断怎么办","depth":3,"text":"Q: 流式中断怎么办？"},{"id":"q-如何在流式过程中取消请求","depth":3,"text":"Q: 如何在流式过程中取消请求？"},{"id":"q-sse-和-websocket-区别","depth":3,"text":"Q: SSE 和 WebSocket 区别？"}]}]}}', '使用 Server-Sent Events 实现 AI 流式响应，提升用户体验。', 'md', '{"category":"api","order":2}', 'true', '/docs/api/streaming', '{"title":"流式输出（SSE）接入","description":"使用 Server-Sent Events 实现 AI 流式响应，提升用户体验。"}', 'docs/api/streaming', '7KYLowobLFDLS7cOqbBp4iZ20Cc95cZzYg2PYk_PHsE'); -- 7KYLowobLFDLS7cOqbBp4iZ20Cc95cZzYg2PYk_PHsE
INSERT INTO _content_docs VALUES ('docs/docs/api/webhook.md', 'Webhook 事件接入', '{"type":"minimark","value":[["h1",{"id":"webhook-事件接入"},"Webhook 事件接入"],["blockquote",{},["p",{},"订阅业务事件，处理订单支付、AI 任务完成等异步通知。"]],["h2",{"id":"什么是-webhook"},"🔔 什么是 Webhook？"],["p",{},"Webhook 是一种「反向 API 调用」机制："],["ul",{},["li",{},"传统 API：你 → 平台（主动拉取）"],["li",{},"Webhook：平台 → 你（被动接收）"]],["p",{},"当某个事件发生时（如支付成功），平台主动通知你的服务器。"],["h2",{"id":"可订阅的事件"},"📋 可订阅的事件"],["table",{},["thead",{},["tr",{},["th",{},"事件类型"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["code",{},"payment.completed"]],["td",{},"支付完成"]],["tr",{},["td",{},["code",{},"payment.failed"]],["td",{},"支付失败"]],["tr",{},["td",{},["code",{},"subscription.created"]],["td",{},"订阅创建"]],["tr",{},["td",{},["code",{},"subscription.cancelled"]],["td",{},"订阅取消"]],["tr",{},["td",{},["code",{},"ai.task.completed"]],["td",{},"AI 任务完成"]],["tr",{},["td",{},["code",{},"ai.task.failed"]],["td",{},"AI 任务失败"]],["tr",{},["td",{},["code",{},"file.uploaded"]],["td",{},"文件上传完成"]],["tr",{},["td",{},["code",{},"project.created"]],["td",{},"项目创建"]],["tr",{},["td",{},["code",{},"user.invited"]],["td",{},"用户被邀请"]],["tr",{},["td",{},["code",{},"workflow.triggered"]],["td",{},"工作流触发"]]]],["h2",{"id":"配置-webhook"},"🚀 配置 Webhook"],["h3",{"id":"步骤-1创建-webhook-端点"},"步骤 1：创建 Webhook 端点"],["p",{},"在你的服务器创建一个 API 端点："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// Node.js Express 示例\napp.post(''/webhook/websopy'', express.raw({ type: ''application/json'' }), (req, res) => {\n  // 验证签名\n  const signature = req.headers[''x-websopy-signature'']\n  const timestamp = req.headers[''x-websopy-timestamp'']\n  \n  if (!verifySignature(req.body, signature, timestamp)) {\n    return res.status(401).send(''Invalid signature'')\n  }\n  \n  // 处理事件\n  const event = JSON.parse(req.body)\n  console.log(''收到事件:'', event.type)\n  \n  // 立即返回 200（重要！）\n  res.status(200).send(''OK'')\n  \n  // 异步处理业务逻辑\n  processEvent(event)\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// Node.js Express 示例\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook/websopy''"],["span",{"class":"sVt8B"},", express."],["span",{"class":"sScJk"},"raw"],["span",{"class":"sVt8B"},"({ type: "],["span",{"class":"sZZnC"},"''application/json''"],["span",{"class":"sVt8B"}," }), ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"  // 验证签名\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," signature"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," req.headers["],["span",{"class":"sZZnC"},"''x-websopy-signature''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," timestamp"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," req.headers["],["span",{"class":"sZZnC"},"''x-websopy-timestamp''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"  if"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"!"],["span",{"class":"sScJk"},"verifySignature"],["span",{"class":"sVt8B"},"(req.body, signature, timestamp)) {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"    return"],["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"401"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Invalid signature''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"  // 处理事件\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," event"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(req.body)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"  console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''收到事件:''"],["span",{"class":"sVt8B"},", event.type)\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":15},["span",{"class":"sJ8bj"},"  // 立即返回 200（重要！）\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"  res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":18},["span",{"class":"sJ8bj"},"  // 异步处理业务逻辑\n"]],["span",{"class":"line","line":19},["span",{"class":"sScJk"},"  processEvent"],["span",{"class":"sVt8B"},"(event)\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"步骤-2在控制台配置"},"步骤 2：在控制台配置"],["ol",{},["li",{},"进入 ",["strong",{},"开发者中心 → Webhook"]],["li",{},"点击 ",["strong",{},"添加端点"]],["li",{},"填写配置："]],["table",{},["thead",{},["tr",{},["th",{},"配置项"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"URL"],["td",{},"你的服务器地址，如 ",["code",{},"https://your-server.com/webhook/websopy"]]],["tr",{},["td",{},"事件类型"],["td",{},"选择要订阅的事件"]],["tr",{},["td",{},"密钥"],["td",{},"用于验证签名的密钥"]]]],["h3",{"id":"步骤-3验证签名"},"步骤 3：验证签名"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import crypto from ''crypto''\n\nfunction verifySignature(body, signature, timestamp) {\n  const secret = process.env.WEBSOPY_WEBHOOK_SECRET\n  \n  // 检查时间戳（5分钟内有效）\n  const ts = parseInt(timestamp)\n  if (Date.now() - ts > 5 * 60 * 1000) {\n    return false\n  }\n  \n  // 计算签名\n  const payload = `${timestamp}.${body}`\n  const expectedSignature = crypto\n    .createHmac(''sha256'', secret)\n    .update(payload)\n    .digest(''hex'')\n  \n  return crypto.timingSafeEqual(\n    Buffer.from(signature),\n    Buffer.from(expectedSignature)\n  )\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," crypto "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''crypto''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," verifySignature"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"body"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"signature"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"timestamp"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," secret"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_WEBHOOK_SECRET\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"  // 检查时间戳（5分钟内有效）\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," ts"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," parseInt"],["span",{"class":"sVt8B"},"(timestamp)\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"  if"],["span",{"class":"sVt8B"}," (Date."],["span",{"class":"sScJk"},"now"],["span",{"class":"sVt8B"},"() "],["span",{"class":"szBVR"},"-"],["span",{"class":"sVt8B"}," ts "],["span",{"class":"szBVR"},">"],["span",{"class":"sj4cs"}," 5"],["span",{"class":"szBVR"}," *"],["span",{"class":"sj4cs"}," 60"],["span",{"class":"szBVR"}," *"],["span",{"class":"sj4cs"}," 1000"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"},"    return"],["span",{"class":"sj4cs"}," false\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":12},["span",{"class":"sJ8bj"},"  // 计算签名\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," payload"],["span",{"class":"szBVR"}," ="],["span",{"class":"sZZnC"}," `${"],["span",{"class":"sVt8B"},"timestamp"],["span",{"class":"sZZnC"},"}.${"],["span",{"class":"sVt8B"},"body"],["span",{"class":"sZZnC"},"}`\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," expectedSignature"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," crypto\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"    ."],["span",{"class":"sScJk"},"createHmac"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''sha256''"],["span",{"class":"sVt8B"},", secret)\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"    ."],["span",{"class":"sScJk"},"update"],["span",{"class":"sVt8B"},"(payload)\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"    ."],["span",{"class":"sScJk"},"digest"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''hex''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"},"  return"],["span",{"class":"sVt8B"}," crypto."],["span",{"class":"sScJk"},"timingSafeEqual"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"    Buffer."],["span",{"class":"sScJk"},"from"],["span",{"class":"sVt8B"},"(signature),\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"},"    Buffer."],["span",{"class":"sScJk"},"from"],["span",{"class":"sVt8B"},"(expectedSignature)\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"},"  )\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"事件数据格式"},"📨 事件数据格式"],["h3",{"id":"通用结构"},"通用结构"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"id\": \"evt_abc123xyz\",\n  \"type\": \"payment.completed\",\n  \"created_at\": \"2024-01-15T10:30:00Z\",\n  \"data\": {\n    // 事件相关数据\n  }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"evt_abc123xyz\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"  \"type\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"payment.completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"},"  \"created_at\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"2024-01-15T10:30:00Z\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"},"  \"data\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"    // 事件相关数据\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"支付完成事件"},"支付完成事件"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"id\": \"evt_abc123xyz\",\n  \"type\": \"payment.completed\",\n  \"created_at\": \"2024-01-15T10:30:00Z\",\n  \"data\": {\n    \"order_id\": \"ord_xyz789\",\n    \"amount\": 29900,\n    \"currency\": \"CNY\",\n    \"payment_method\": \"alipay\",\n    \"status\": \"completed\",\n    \"user_id\": \"user_123\"\n  }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"evt_abc123xyz\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"  \"type\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"payment.completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"},"  \"created_at\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"2024-01-15T10:30:00Z\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"},"  \"data\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"},"    \"order_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"ord_xyz789\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"},"    \"amount\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"29900"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":8},["span",{"class":"sj4cs"},"    \"currency\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"CNY\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sj4cs"},"    \"payment_method\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"alipay\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sj4cs"},"    \"status\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sj4cs"},"    \"user_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"user_123\"\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"失败重试"},"⏰ 失败重试"],["p",{},"如果你的服务器返回非 200 状态码，Websopy 会自动重试："],["table",{},["thead",{},["tr",{},["th",{},"重试次数"],["th",{},"延迟"]]],["tbody",{},["tr",{},["td",{},"第 1 次"],["td",{},"1 分钟"]],["tr",{},["td",{},"第 2 次"],["td",{},"5 分钟"]],["tr",{},["td",{},"第 3 次"],["td",{},"30 分钟"]],["tr",{},["td",{},"第 4 次"],["td",{},"2 小时"]],["tr",{},["td",{},"第 5 次"],["td",{},"12 小时"]]]],["p",{},"超过重试次数仍未成功，事件将被标记为失败，可在控制台手动重试。"],["h3",{"id":"幂等处理"},"幂等处理"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const processedEvents = new Set()\n\napp.post(''/webhook/websopy'', async (req, res) => {\n  const event = JSON.parse(req.body)\n  \n  // 幂等检查\n  if (processedEvents.has(event.id)) {\n    return res.status(200).send(''Already processed'')\n  }\n  \n  try {\n    await processEvent(event)\n    processedEvents.add(event.id)\n    res.status(200).send(''OK'')\n  } catch (error) {\n    res.status(500).send(''Error'')\n  }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," processedEvents"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," Set"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook/websopy''"],["span",{"class":"sVt8B"},", "],["span",{"class":"szBVR"},"async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," event"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(req.body)\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"  // 幂等检查\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"  if"],["span",{"class":"sVt8B"}," (processedEvents."],["span",{"class":"sScJk"},"has"],["span",{"class":"sVt8B"},"(event.id)) {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"    return"],["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Already processed''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"},"  try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"},"    await"],["span",{"class":"sScJk"}," processEvent"],["span",{"class":"sVt8B"},"(event)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"    processedEvents."],["span",{"class":"sScJk"},"add"],["span",{"class":"sVt8B"},"(event.id)\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"    res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"  } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"    res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"500"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Error''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"本地开发测试"},"🧪 本地开发测试"],["h3",{"id":"使用-ngrok"},"使用 ngrok"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 安装 ngrok\nnpm install -g ngrok\n\n# 启动本地服务\nngrok http 3000\n\n# 复制输出的 https URL 到 Webhook 配置\n# https://abc123.ngrok.io/webhook/websopy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 安装 ngrok\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sj4cs"}," -g"],["span",{"class":"sZZnC"}," ngrok\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 启动本地服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"ngrok"],["span",{"class":"sZZnC"}," http"],["span",{"class":"sj4cs"}," 3000\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 复制输出的 https URL 到 Webhook 配置\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# https://abc123.ngrok.io/webhook/websopy\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-收到重复事件怎么办"},"Q: 收到重复事件怎么办？"],["p",{},"使用事件 ID 做幂等检查，参考上文示例。"],["h3",{"id":"q-处理超时怎么办"},"Q: 处理超时怎么办？"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"app.post(''/webhook'', async (req, res) => {\n  // 立即返回\n  res.status(200).send(''OK'')\n  \n  // 异步处理\n  setImmediate(() => processEvent(req.body))\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook''"],["span",{"class":"sVt8B"},", "],["span",{"class":"szBVR"},"async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"},"  // 立即返回\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  \n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"  // 异步处理\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"  setImmediate"],["span",{"class":"sVt8B"},"(() "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sScJk"}," processEvent"],["span",{"class":"sVt8B"},"(req.body))\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-webhook","depth":2,"text":"🔔 什么是 Webhook？"},{"id":"可订阅的事件","depth":2,"text":"📋 可订阅的事件"},{"id":"配置-webhook","depth":2,"text":"🚀 配置 Webhook","children":[{"id":"步骤-1创建-webhook-端点","depth":3,"text":"步骤 1：创建 Webhook 端点"},{"id":"步骤-2在控制台配置","depth":3,"text":"步骤 2：在控制台配置"},{"id":"步骤-3验证签名","depth":3,"text":"步骤 3：验证签名"}]},{"id":"事件数据格式","depth":2,"text":"📨 事件数据格式","children":[{"id":"通用结构","depth":3,"text":"通用结构"},{"id":"支付完成事件","depth":3,"text":"支付完成事件"}]},{"id":"失败重试","depth":2,"text":"⏰ 失败重试","children":[{"id":"幂等处理","depth":3,"text":"幂等处理"}]},{"id":"本地开发测试","depth":2,"text":"🧪 本地开发测试","children":[{"id":"使用-ngrok","depth":3,"text":"使用 ngrok"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-收到重复事件怎么办","depth":3,"text":"Q: 收到重复事件怎么办？"},{"id":"q-处理超时怎么办","depth":3,"text":"Q: 处理超时怎么办？"}]}]}}', '订阅业务事件，处理订单支付、AI 任务完成等异步通知。', 'md', '{"category":"api","order":3}', 'true', '/docs/api/webhook', '{"title":"Webhook 事件接入","description":"订阅业务事件，处理订单支付、AI 任务完成等异步通知。"}', 'docs/api/webhook', 'JzUDaOPT8P4lqAf6z6op6nMpr0qauqZr8pTO6bB32u8'); -- JzUDaOPT8P4lqAf6z6op6nMpr0qauqZr8pTO6bB32u8
INSERT INTO _content_docs VALUES ('docs/docs/deploy/docker.md', 'Docker Compose 部署', '{"type":"minimark","value":[["h1",{"id":"docker-compose-部署"},"Docker Compose 部署"],["blockquote",{},["p",{},"一键部署全套服务（前端+后端+数据库+AI），本地与云端通用。"]],["h2",{"id":"什么是-docker-compose"},"🐳 什么是 Docker Compose？"],["p",{},"Docker Compose 是一个工具，用于定义和运行多容器 Docker 应用。通过一个 ",["code",{},"docker-compose.yml"]," 文件，你可以一键启动所有相关服务。"],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"Docker 20.10+"],["li",{},"Docker Compose 2.0+"],["li",{},"至少 4GB 内存"]],["h2",{"id":"快速开始"},"🚀 快速开始"],["h3",{"id":"第一步下载模板"},"第一步：下载模板"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 克隆模板仓库\ngit clone https://github.com/websopy/deploy-templates.git websopy-deploy\ncd websopy-deploy\n\n# 选择版本\ngit checkout v2.3.0\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 克隆模板仓库\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," clone"],["span",{"class":"sZZnC"}," https://github.com/websopy/deploy-templates.git"],["span",{"class":"sZZnC"}," websopy-deploy\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," websopy-deploy\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"# 选择版本\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.3.0\n"]]]],["h3",{"id":"第二步配置环境"},"第二步：配置环境"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 复制环境变量文件\ncp .env.example .env\n\n# 编辑配置\nnano .env\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 复制环境变量文件\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env.example"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 编辑配置\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]]]],["p",{},"关键配置："],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"# 版本\nWEBSOPY_VERSION=2.3.0\n\n# 数据库\nPOSTGRES_DB=websopy\nPOSTGRES_USER=websopy\nPOSTGRES_PASSWORD=your-strong-password\n\n# Redis\nREDIS_PASSWORD=your-redis-password\n\n# JWT 密钥（生成随机字符串）\nJWT_SECRET=$(openssl rand -hex 32)\n\n# 域名（可选）\nDOMAIN=your-domain.com\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# 版本\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_VERSION=2.3.0\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{},"# 数据库\n"]],["span",{"class":"line","line":5},["span",{},"POSTGRES_DB=websopy\n"]],["span",{"class":"line","line":6},["span",{},"POSTGRES_USER=websopy\n"]],["span",{"class":"line","line":7},["span",{},"POSTGRES_PASSWORD=your-strong-password\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{},"# Redis\n"]],["span",{"class":"line","line":10},["span",{},"REDIS_PASSWORD=your-redis-password\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{},"# JWT 密钥（生成随机字符串）\n"]],["span",{"class":"line","line":13},["span",{},"JWT_SECRET=$(openssl rand -hex 32)\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{},"# 域名（可选）\n"]],["span",{"class":"line","line":16},["span",{},"DOMAIN=your-domain.com\n"]]]],["h3",{"id":"第三步启动服务"},"第三步：启动服务"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 一键启动所有服务\ndocker-compose up -d\n\n# 查看服务状态\ndocker-compose ps\n\n# 查看日志\ndocker-compose logs -f\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 一键启动所有服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 查看服务状态\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 查看日志\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]]]],["h3",{"id":"第四步验证部署"},"第四步：验证部署"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 检查服务健康状态\ncurl http://localhost:3000/api/health\n\n# 预期输出\n{\"status\":\"ok\",\"version\":\"2.3.0\",\"services\":{\"db\":\"up\",\"redis\":\"up\",\"ai\":\"up\"}}\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 检查服务健康状态\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"curl"],["span",{"class":"sZZnC"}," http://localhost:3000/api/health\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 预期输出\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"{"],["span",{"class":"sScJk"},"\"status\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sScJk"},"\"ok\""],["span",{"class":"sScJk"},","],["span",{"class":"sScJk"},"\"version\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sScJk"},"\"2.3.0\""],["span",{"class":"sScJk"},","],["span",{"class":"sScJk"},"\"services\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sZZnC"},"{"],["span",{"class":"sVt8B"},"\""],["span",{"class":"sScJk"},"db"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\",\""],["span",{"class":"sScJk"},"redis"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\",\""],["span",{"class":"sScJk"},"ai"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\"}}\n"]]]],["h2",{"id":"️-服务架构"},"🏗️ 服务架构"],["pre",{"className":["language-text"],"code":"                    ┌─────────────┐\n                    │   Nginx     │\n                    │  (反向代理)   │\n                    └──────┬──────┘\n                           │\n           ┌───────────────┼───────────────┐\n           │               │               │\n      ┌────▼────┐    ┌─────▼────┐    ┌────▼────┐\n      │  Web    │    │   API    │    │  Worker │\n      │ (前端)   │    │ (后端)    │    │ (异步)   │\n      └─────────┘    └─────┬────┘    └─────────┘\n                           │\n              ┌────────────┼────────────┐\n              │            │            │\n         ┌────▼───┐  ┌─────▼────┐  ┌───▼────┐\n         │Postgres│  │  Redis   │  │  AI    │\n         │(数据库) │  │ (缓存)    │  │(AI服务) │\n         └────────┘  └──────────┘  └────────┘\n","language":"text"},["code",{"__ignoreMap":""},"                    ┌─────────────┐\n                    │   Nginx     │\n                    │  (反向代理)   │\n                    └──────┬──────┘\n                           │\n           ┌───────────────┼───────────────┐\n           │               │               │\n      ┌────▼────┐    ┌─────▼────┐    ┌────▼────┐\n      │  Web    │    │   API    │    │  Worker │\n      │ (前端)   │    │ (后端)    │    │ (异步)   │\n      └─────────┘    └─────┬────┘    └─────────┘\n                           │\n              ┌────────────┼────────────┐\n              │            │            │\n         ┌────▼───┐  ┌─────▼────┐  ┌───▼────┐\n         │Postgres│  │  Redis   │  │  AI    │\n         │(数据库) │  │ (缓存)    │  │(AI服务) │\n         └────────┘  └──────────┘  └────────┘\n"]],["h2",{"id":"常用命令"},"🔧 常用命令"],["h3",{"id":"启动与停止"},"启动与停止"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 启动所有服务\ndocker-compose up -d\n\n# 停止所有服务\ndocker-compose down\n\n# 重启所有服务\ndocker-compose restart\n\n# 重启指定服务\ndocker-compose restart api\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 启动所有服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 停止所有服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 重启所有服务\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 重启指定服务\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," api\n"]]]],["h3",{"id":"日志查看"},"日志查看"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看所有日志\ndocker-compose logs -f\n\n# 查看特定服务日志\ndocker-compose logs -f api\ndocker-compose logs -f web\n\n# 查看最近 100 行\ndocker-compose logs --tail=100\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看所有日志\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 查看特定服务日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f"],["span",{"class":"sZZnC"}," api\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f"],["span",{"class":"sZZnC"}," web\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 查看最近 100 行\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," --tail=100\n"]]]],["h3",{"id":"进入容器"},"进入容器"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 进入 API 容器\ndocker-compose exec api sh\n\n# 进入数据库\ndocker-compose exec postgres psql -U websopy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 进入 API 容器\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," sh\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 进入数据库\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy\n"]]]],["h2",{"id":"数据持久化"},"💾 数据持久化"],["p",{},"数据存储在 Docker volumes 中："],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看 volumes\ndocker volume ls | grep websopy\n\n# 备份数据\ndocker-compose exec postgres pg_dump -U websopy > backup.sql\n\n# 恢复数据\ndocker exec -i $(docker-compose ps -q postgres) psql -U websopy < backup.sql\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看 volumes\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," volume"],["span",{"class":"sZZnC"}," ls"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 备份数据\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sZZnC"}," backup.sql\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 恢复数据\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sVt8B"}," $("],["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sj4cs"}," -q"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sVt8B"},") "],["span",{"class":"sZZnC"},"psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," <"],["span",{"class":"sZZnC"}," backup.sql\n"]]]],["h2",{"id":"故障排查"},"🐛 故障排查"],["h3",{"id":"服务无法启动"},"服务无法启动"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 检查 Docker 是否运行\ndocker info\n\n# 2. 查看详细日志\ndocker-compose up\n\n# 3. 检查端口占用\nlsof -i :80\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 检查 Docker 是否运行\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," info\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 查看详细日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 检查端口占用\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"lsof"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sZZnC"}," :80\n"]]]],["h3",{"id":"数据库连接失败"},"数据库连接失败"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 检查 postgres 是否运行\ndocker-compose ps postgres\n\n# 2. 查看数据库日志\ndocker-compose logs postgres\n\n# 3. 测试连接\ndocker-compose exec postgres psql -U websopy -c \"SELECT 1\"\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 检查 postgres 是否运行\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sZZnC"}," postgres\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 查看数据库日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," postgres\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 测试连接\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sj4cs"}," -c"],["span",{"class":"sZZnC"}," \"SELECT 1\"\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-docker-compose","depth":2,"text":"🐳 什么是 Docker Compose？"},{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"快速开始","depth":2,"text":"🚀 快速开始","children":[{"id":"第一步下载模板","depth":3,"text":"第一步：下载模板"},{"id":"第二步配置环境","depth":3,"text":"第二步：配置环境"},{"id":"第三步启动服务","depth":3,"text":"第三步：启动服务"},{"id":"第四步验证部署","depth":3,"text":"第四步：验证部署"}]},{"id":"️-服务架构","depth":2,"text":"🏗️ 服务架构"},{"id":"常用命令","depth":2,"text":"🔧 常用命令","children":[{"id":"启动与停止","depth":3,"text":"启动与停止"},{"id":"日志查看","depth":3,"text":"日志查看"},{"id":"进入容器","depth":3,"text":"进入容器"}]},{"id":"数据持久化","depth":2,"text":"💾 数据持久化"},{"id":"故障排查","depth":2,"text":"🐛 故障排查","children":[{"id":"服务无法启动","depth":3,"text":"服务无法启动"},{"id":"数据库连接失败","depth":3,"text":"数据库连接失败"}]}]}}', '一键部署全套服务（前端+后端+数据库+AI），本地与云端通用。', 'md', '{"category":"deploy","order":1}', 'true', '/docs/deploy/docker', '{"title":"Docker Compose 部署","description":"一键部署全套服务（前端+后端+数据库+AI），本地与云端通用。"}', 'docs/deploy/docker', 'JLPDy1ukkZcXDwJc1JrVAKX-blTkv_BsqqzsEhQ4L1A'); -- JLPDy1ukkZcXDwJc1JrVAKX-blTkv_BsqqzsEhQ4L1A
INSERT INTO _content_docs VALUES ('docs/docs/deploy/private-deploy.md', '私有化部署完全指南', '{"type":"minimark","value":[["h1",{"id":"私有化部署完全指南"},"私有化部署完全指南"],["blockquote",{},["p",{},"Docker Compose 一键部署，HTTPS 配置、备份策略与版本升级。"]],["h2",{"id":"什么是私有化部署"},"🏠 什么是私有化部署？"],["p",{},"私有化部署让你在自己的服务器上运行 Websopy 平台，享受："],["ul",{},["li",{},"🔒 ",["strong",{},"数据完全自主"]," - 所有数据存储在你的服务器"],["li",{},"⚙️ ",["strong",{},"完全可控"]," - 自定义配置、插件、界面"],["li",{},"💰 ",["strong",{},"成本可控"]," - 无按调用量计费"],["li",{},"🏢 ",["strong",{},"合规无忧"]," - 满足数据不出网要求"]],["h2",{"id":"系统要求"},"📋 系统要求"],["h3",{"id":"最低配置"},"最低配置"],["table",{},["thead",{},["tr",{},["th",{},"资源"],["th",{},"最低要求"]]],["tbody",{},["tr",{},["td",{},"CPU"],["td",{},"4 核"]],["tr",{},["td",{},"内存"],["td",{},"8 GB"]],["tr",{},["td",{},"硬盘"],["td",{},"100 GB SSD"]],["tr",{},["td",{},"系统"],["td",{},"Ubuntu 20.04+ / CentOS 8+"]]]],["h3",{"id":"推荐配置"},"推荐配置"],["table",{},["thead",{},["tr",{},["th",{},"资源"],["th",{},"推荐配置"]]],["tbody",{},["tr",{},["td",{},"CPU"],["td",{},"8 核+"]],["tr",{},["td",{},"内存"],["td",{},"16 GB+"]],["tr",{},["td",{},"硬盘"],["td",{},"500 GB SSD+"]],["tr",{},["td",{},"系统"],["td",{},"Ubuntu 22.04 LTS"]]]],["h3",{"id":"软件依赖"},"软件依赖"],["ul",{},["li",{},"Docker 20.10+"],["li",{},"Docker Compose 2.0+"],["li",{},"Git"],["li",{},"域名（可选，用于 HTTPS）"]],["h2",{"id":"开始部署"},"🚀 开始部署"],["h3",{"id":"第一步准备服务器"},"第一步：准备服务器"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 更新系统\nsudo apt update && sudo apt upgrade -y\n\n# 安装 Docker（Ubuntu/Debian）\ncurl -fsSL https://get.docker.com | sh\nsudo usermod -aG docker $USER\n\n# 验证安装\ndocker --version\ndocker-compose --version\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 更新系统\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," apt"],["span",{"class":"sZZnC"}," update"],["span",{"class":"sVt8B"}," && "],["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," apt"],["span",{"class":"sZZnC"}," upgrade"],["span",{"class":"sj4cs"}," -y\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 安装 Docker（Ubuntu/Debian）\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"curl"],["span",{"class":"sj4cs"}," -fsSL"],["span",{"class":"sZZnC"}," https://get.docker.com"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," sh\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," usermod"],["span",{"class":"sj4cs"}," -aG"],["span",{"class":"sZZnC"}," docker"],["span",{"class":"sVt8B"}," $USER\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 验证安装\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker"],["span",{"class":"sj4cs"}," --version\n"]],["span",{"class":"line","line":10},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sj4cs"}," --version\n"]]]],["h3",{"id":"第二步下载部署包"},"第二步：下载部署包"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 创建工作目录\nmkdir -p ~/websopy && cd ~/websopy\n\n# 下载最新版本\nwget https://releases.websopy.com/on-premise/latest.tar.gz\n\n# 解压\ntar -xzf latest.tar.gz\ncd websopy-deploy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 创建工作目录\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"mkdir"],["span",{"class":"sj4cs"}," -p"],["span",{"class":"sZZnC"}," ~/websopy"],["span",{"class":"sVt8B"}," && "],["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," ~/websopy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 下载最新版本\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"wget"],["span",{"class":"sZZnC"}," https://releases.websopy.com/on-premise/latest.tar.gz\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 解压\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -xzf"],["span",{"class":"sZZnC"}," latest.tar.gz\n"]],["span",{"class":"line","line":9},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," websopy-deploy\n"]]]],["h3",{"id":"第三步配置环境"},"第三步：配置环境"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 复制配置文件\ncp .env.example .env\n\n# 编辑配置文件\nnano .env\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 复制配置文件\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env.example"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 编辑配置文件\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]]]],["p",{},"关键配置项："],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"# 版本配置\nWEBSOPY_VERSION=latest\n\n# 数据库配置\nDB_HOST=postgres\nDB_PORT=5432\nDB_NAME=websopy\nDB_USER=websopy\nDB_PASSWORD=your-secure-password\n\n# Redis 配置\nREDIS_HOST=redis\nREDIS_PORT=6379\nREDIS_PASSWORD=your-redis-password\n\n# 域名配置（可选）\nDOMAIN=your-domain.com\nHTTPS_ENABLED=true\n\n# 管理员账户\nADMIN_EMAIL=admin@yourcompany.com\nADMIN_PASSWORD=your-admin-password\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# 版本配置\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_VERSION=latest\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{},"# 数据库配置\n"]],["span",{"class":"line","line":5},["span",{},"DB_HOST=postgres\n"]],["span",{"class":"line","line":6},["span",{},"DB_PORT=5432\n"]],["span",{"class":"line","line":7},["span",{},"DB_NAME=websopy\n"]],["span",{"class":"line","line":8},["span",{},"DB_USER=websopy\n"]],["span",{"class":"line","line":9},["span",{},"DB_PASSWORD=your-secure-password\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{},"# Redis 配置\n"]],["span",{"class":"line","line":12},["span",{},"REDIS_HOST=redis\n"]],["span",{"class":"line","line":13},["span",{},"REDIS_PORT=6379\n"]],["span",{"class":"line","line":14},["span",{},"REDIS_PASSWORD=your-redis-password\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{},"# 域名配置（可选）\n"]],["span",{"class":"line","line":17},["span",{},"DOMAIN=your-domain.com\n"]],["span",{"class":"line","line":18},["span",{},"HTTPS_ENABLED=true\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{},"# 管理员账户\n"]],["span",{"class":"line","line":21},["span",{},"ADMIN_EMAIL=admin@yourcompany.com\n"]],["span",{"class":"line","line":22},["span",{},"ADMIN_PASSWORD=your-admin-password\n"]]]],["h3",{"id":"第四步启动服务"},"第四步：启动服务"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 拉取镜像\ndocker-compose pull\n\n# 启动所有服务\ndocker-compose up -d\n\n# 查看服务状态\ndocker-compose ps\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 拉取镜像\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 启动所有服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 查看服务状态\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]]]],["h3",{"id":"第五步访问平台"},"第五步：访问平台"],["p",{},"服务启动后，通过浏览器访问："],["ul",{},["li",{},"前端界面：",["code",{},"http://your-server-ip:80"]],["li",{},"管理后台：",["code",{},"http://your-server-ip:80/admin"]],["li",{},"API 端点：",["code",{},"http://your-server-ip:8080/api/v1"]]],["h2",{"id":"https-配置"},"🔒 HTTPS 配置"],["h3",{"id":"使用-lets-encrypt推荐"},"使用 Let''s Encrypt（推荐）"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 申请 SSL 证书\ncertbot --nginx -d your-domain.com\n\n# 重启 nginx\ndocker-compose restart nginx\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 申请 SSL 证书\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"certbot"],["span",{"class":"sj4cs"}," --nginx"],["span",{"class":"sj4cs"}," -d"],["span",{"class":"sZZnC"}," your-domain.com\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 重启 nginx\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," nginx\n"]]]],["h2",{"id":"备份策略"},"💾 备份策略"],["h3",{"id":"自动备份脚本"},"自动备份脚本"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"#!/bin/bash\nBACKUP_DIR=/data/backups/websopy\nDATE=$(date +%Y%m%d_%H%M%S)\n\nmkdir -p $BACKUP_DIR\n\n# 备份数据库\ndocker exec websopy-postgres pg_dump -U websopy > $BACKUP_DIR/db_$DATE.sql\n\n# 备份上传文件\ntar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /data/websopy/uploads\n\n# 保留最近 30 天的备份\nfind $BACKUP_DIR -mtime +30 -delete\n\necho \"备份完成: $DATE\"\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"#!/bin/bash\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"BACKUP_DIR"],["span",{"class":"szBVR"},"="],["span",{"class":"sZZnC"},"/data/backups/websopy\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"DATE"],["span",{"class":"szBVR"},"="],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d_%H%M%S"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"mkdir"],["span",{"class":"sj4cs"}," -p"],["span",{"class":"sVt8B"}," $BACKUP_DIR\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 备份数据库\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," websopy-postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sVt8B"}," $BACKUP_DIR"],["span",{"class":"sZZnC"},"/db_"],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},".sql\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 备份上传文件\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -czf"],["span",{"class":"sVt8B"}," $BACKUP_DIR"],["span",{"class":"sZZnC"},"/uploads_"],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},".tar.gz"],["span",{"class":"sZZnC"}," /data/websopy/uploads\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"# 保留最近 30 天的备份\n"]],["span",{"class":"line","line":14},["span",{"class":"sScJk"},"find"],["span",{"class":"sVt8B"}," $BACKUP_DIR "],["span",{"class":"sj4cs"},"-mtime"],["span",{"class":"sZZnC"}," +30"],["span",{"class":"sj4cs"}," -delete\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"sj4cs"},"echo"],["span",{"class":"sZZnC"}," \"备份完成: "],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},"\"\n"]]]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 设置定时任务（每天凌晨 3 点执行）\ncrontab -e\n# 添加行: 0 3 * * * /data/websopy/backup.sh >> /var/log/backup.log 2>&1\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 设置定时任务（每天凌晨 3 点执行）\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"crontab"],["span",{"class":"sj4cs"}," -e\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"# 添加行: 0 3 * * * /data/websopy/backup.sh >> /var/log/backup.log 2>&1\n"]]]],["h2",{"id":"常见问题"},"🐛 常见问题"],["h3",{"id":"q-服务启动失败"},"Q: 服务启动失败？"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看日志\ndocker-compose logs -f\n\n# 检查端口占用\nnetstat -tlnp | grep -E ''80|443|5432|6379''\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看日志\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 检查端口占用\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"netstat"],["span",{"class":"sj4cs"}," -tlnp"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sj4cs"}," -E"],["span",{"class":"sZZnC"}," ''80|443|5432|6379''\n"]]]],["h3",{"id":"q-内存不足"},"Q: 内存不足？"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看内存使用\ndocker stats\n\n# 增加 swap\nsudo fallocate -l 4G /swapfile\nsudo chmod 600 /swapfile\nsudo mkswap /swapfile\nsudo swapon /swapfile\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看内存使用\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," stats\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 增加 swap\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," fallocate"],["span",{"class":"sj4cs"}," -l"],["span",{"class":"sZZnC"}," 4G"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," chmod"],["span",{"class":"sj4cs"}," 600"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":7},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," mkswap"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," swapon"],["span",{"class":"sZZnC"}," /swapfile\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是私有化部署","depth":2,"text":"🏠 什么是私有化部署？"},{"id":"系统要求","depth":2,"text":"📋 系统要求","children":[{"id":"最低配置","depth":3,"text":"最低配置"},{"id":"推荐配置","depth":3,"text":"推荐配置"},{"id":"软件依赖","depth":3,"text":"软件依赖"}]},{"id":"开始部署","depth":2,"text":"🚀 开始部署","children":[{"id":"第一步准备服务器","depth":3,"text":"第一步：准备服务器"},{"id":"第二步下载部署包","depth":3,"text":"第二步：下载部署包"},{"id":"第三步配置环境","depth":3,"text":"第三步：配置环境"},{"id":"第四步启动服务","depth":3,"text":"第四步：启动服务"},{"id":"第五步访问平台","depth":3,"text":"第五步：访问平台"}]},{"id":"https-配置","depth":2,"text":"🔒 HTTPS 配置","children":[{"id":"使用-lets-encrypt推荐","depth":3,"text":"使用 Let''s Encrypt（推荐）"}]},{"id":"备份策略","depth":2,"text":"💾 备份策略","children":[{"id":"自动备份脚本","depth":3,"text":"自动备份脚本"}]},{"id":"常见问题","depth":2,"text":"🐛 常见问题","children":[{"id":"q-服务启动失败","depth":3,"text":"Q: 服务启动失败？"},{"id":"q-内存不足","depth":3,"text":"Q: 内存不足？"}]}]}}', 'Docker Compose 一键部署，HTTPS 配置、备份策略与版本升级。', 'md', '{"category":"deploy","order":2}', 'true', '/docs/deploy/private-deploy', '{"title":"私有化部署完全指南","description":"Docker Compose 一键部署，HTTPS 配置、备份策略与版本升级。"}', 'docs/deploy/private-deploy', 'cEk_JZvZaEC-Q8JKLtEhR4k3b9LNnnRxxcs2pGB9R8w'); -- cEk_JZvZaEC-Q8JKLtEhR4k3b9LNnnRxxcs2pGB9R8w
INSERT INTO _content_docs VALUES ('docs/docs/deploy/upgrade.md', '版本升级与回滚', '{"type":"minimark","value":[["h1",{"id":"版本升级与回滚"},"版本升级与回滚"],["blockquote",{},["p",{},"平滑升级生产环境，数据库迁移方案，紧急回滚操作手册。"]],["h2",{"id":"️-升级前必读"},"⚠️ 升级前必读"],["h3",{"id":"重要检查清单"},"重要检查清单"],["ul",{"className":["contains-task-list"]},["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 备份数据库"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 查阅版本更新日志"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 在测试环境验证"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 确认回滚方案"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 通知相关人员"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 选择低峰期执行"]],["h3",{"id":"版本兼容性"},"版本兼容性"],["table",{},["thead",{},["tr",{},["th",{},"当前版本"],["th",{},"可直接升级到"]]],["tbody",{},["tr",{},["td",{},"2.0.x"],["td",{},"2.1.x"]],["tr",{},["td",{},"2.1.x"],["td",{},"2.2.x, 2.3.x"]],["tr",{},["td",{},"2.2.x"],["td",{},"2.3.x"]],["tr",{},["td",{},"1.x"],["td",{},"需要先升级到 2.0"]]]],["h2",{"id":"升级步骤"},"🚀 升级步骤"],["h3",{"id":"准备工作"},"准备工作"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 进入部署目录\ncd ~/websopy-deploy\n\n# 2. 备份当前版本配置\ncp docker-compose.yml docker-compose.yml.bak\ncp .env .env.bak\n\n# 3. 备份数据库（必须！）\ndocker-compose exec postgres pg_dump -U websopy > backups/db_backup_$(date +%Y%m%d).sql\n\n# 4. 备份上传文件\ntar -czf backups/uploads_$(date +%Y%m%d).tar.gz -C /data/websopy uploads/\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 进入部署目录\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," ~/websopy-deploy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 备份当前版本配置\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," docker-compose.yml"],["span",{"class":"sZZnC"}," docker-compose.yml.bak\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env"],["span",{"class":"sZZnC"}," .env.bak\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 3. 备份数据库（必须！）\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sZZnC"}," backups/db_backup_"],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d"],["span",{"class":"sVt8B"},")"],["span",{"class":"sZZnC"},".sql\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"# 4. 备份上传文件\n"]],["span",{"class":"line","line":12},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -czf"],["span",{"class":"sZZnC"}," backups/uploads_"],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d"],["span",{"class":"sVt8B"},")"],["span",{"class":"sZZnC"},".tar.gz"],["span",{"class":"sj4cs"}," -C"],["span",{"class":"sZZnC"}," /data/websopy"],["span",{"class":"sZZnC"}," uploads/\n"]]]],["h3",{"id":"执行升级"},"执行升级"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 停止服务\ndocker-compose down\n\n# 2. 拉取新版本镜像\ndocker-compose pull\n\n# 3. 更新代码（如果使用 git 部署）\ngit fetch origin\ngit checkout v2.3.0\n\n# 4. 检查新版本配置变更\ngit diff v2.2.0 v2.3.0 -- .env.example\n\n# 5. 合并配置变更\nnano .env\n\n# 6. 启动服务\ndocker-compose up -d\n\n# 7. 执行数据库迁移\ndocker-compose run --rm api websopy migrate\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 停止服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 拉取新版本镜像\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 更新代码（如果使用 git 部署）\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," fetch"],["span",{"class":"sZZnC"}," origin\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.3.0\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"# 4. 检查新版本配置变更\n"]],["span",{"class":"line","line":12},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," diff"],["span",{"class":"sZZnC"}," v2.2.0"],["span",{"class":"sZZnC"}," v2.3.0"],["span",{"class":"sj4cs"}," --"],["span",{"class":"sZZnC"}," .env.example\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"# 5. 合并配置变更\n"]],["span",{"class":"line","line":15},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":16},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":17},["span",{"class":"sJ8bj"},"# 6. 启动服务\n"]],["span",{"class":"line","line":18},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{"class":"sJ8bj"},"# 7. 执行数据库迁移\n"]],["span",{"class":"line","line":21},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate\n"]]]],["h3",{"id":"验证升级"},"验证升级"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 检查服务状态\ndocker-compose ps\n\n# 检查 API 健康\ncurl http://localhost:3000/api/health\n\n# 检查版本号\ndocker-compose exec api websopy --version\n\n# 查看迁移日志\ndocker-compose logs api | grep -i migrate\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 检查服务状态\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 检查 API 健康\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"curl"],["span",{"class":"sZZnC"}," http://localhost:3000/api/health\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 检查版本号\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sj4cs"}," --version\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 查看迁移日志\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," api"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sZZnC"}," migrate\n"]]]],["h2",{"id":"数据库迁移"},"🔧 数据库迁移"],["h3",{"id":"手动迁移"},"手动迁移"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看待执行迁移\ndocker-compose run --rm api websopy migrate:status\n\n# 执行迁移\ndocker-compose run --rm api websopy migrate\n\n# 回滚上一个迁移\ndocker-compose run --rm api websopy migrate:rollback\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看待执行迁移\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate:status\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 执行迁移\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 回滚上一个迁移\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate:rollback\n"]]]],["h2",{"id":"️-紧急回滚"},"⤵️ 紧急回滚"],["h3",{"id":"自动回滚"},"自动回滚"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 如果启动失败，查看错误\ndocker-compose logs api\n\n# 回滚到上一个版本\ndocker-compose down\ngit checkout v2.2.0\ndocker-compose pull\ndocker-compose up -d\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 如果启动失败，查看错误\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," api\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 回滚到上一个版本\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.2.0\n"]],["span",{"class":"line","line":7},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]]]],["h3",{"id":"恢复数据库"},"恢复数据库"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 停止服务\ndocker-compose down\n\n# 删除新数据库\ndocker-compose exec postgres dropdb -U websopy websopy\n\n# 创建空数据库\ndocker-compose exec postgres createdb -U websopy websopy\n\n# 恢复备份\ndocker exec -i $(docker-compose ps -q postgres) psql -U websopy < backups/db_backup_20240115.sql\n\n# 启动服务\ndocker-compose up -d\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 停止服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 删除新数据库\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," dropdb"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 创建空数据库\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," createdb"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 恢复备份\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sVt8B"}," $("],["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sj4cs"}," -q"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sVt8B"},") "],["span",{"class":"sZZnC"},"psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," <"],["span",{"class":"sZZnC"}," backups/db_backup_20240115.sql\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"# 启动服务\n"]],["span",{"class":"line","line":14},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]]]],["h2",{"id":"版本更新日志"},"📊 版本更新日志"],["h3",{"id":"v230最新"},"v2.3.0（最新）"],["p",{},["strong",{},"新增功能："]],["ul",{},["li",{},"🚀 AI 流式输出优化，延迟降低 50%"],["li",{},"📊 新增数据看板组件"],["li",{},"🔔 支持自定义 Webhook 事件"]],["p",{},["strong",{},"Breaking Changes："]],["ul",{},["li",{},"⚠️ API ",["code",{},"/ai/chat"]," 端点参数变更"],["li",{},"⚠️ 环境变量 ",["code",{},"AI_MODEL"]," 重命名为 ",["code",{},"DEFAULT_MODEL"]]],["h3",{"id":"v220"},"v2.2.0"],["p",{},["strong",{},"新增功能："]],["ul",{},["li",{},"💬 多语言支持"],["li",{},"📱 移动端优化"],["li",{},"🔐 SSO 单点登录"]],["h3",{"id":"v210"},"v2.1.0"],["p",{},["strong",{},"新增功能："]],["ul",{},["li",{},"🤖 AI Agent 功能"],["li",{},"📚 RAG 知识库"],["li",{},"⚡ 工作流自动化"]],["h2",{"id":"测试环境验证"},"🧪 测试环境验证"],["h3",{"id":"测试清单"},"测试清单"],["ul",{"className":["contains-task-list"]},["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 首页访问正常"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 用户登录/注册"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 主要功能操作"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," API 接口调用"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," Webhook 接收"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 性能无明显下降"]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-迁移失败怎么办"},"Q: 迁移失败怎么办？"],["ol",{},["li",{},"停止所有服务"],["li",{},"恢复数据库备份"],["li",{},"检查迁移脚本错误"],["li",{},"联系技术支持"]],["h3",{"id":"q-镜像拉取失败"},"Q: 镜像拉取失败？"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 使用国内镜像源\nnano /etc/docker/daemon.json\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 使用国内镜像源\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," /etc/docker/daemon.json\n"]]]],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n  \"registry-mirrors\": [\"https://mirror.ccs.tencentyun.com\"]\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"  \"registry-mirrors\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"https://mirror.ccs.tencentyun.com\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"}\n"]]]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"sudo systemctl restart docker\ndocker-compose pull\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," systemctl"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," docker\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"️-升级前必读","depth":2,"text":"⚠️ 升级前必读","children":[{"id":"重要检查清单","depth":3,"text":"重要检查清单"},{"id":"版本兼容性","depth":3,"text":"版本兼容性"}]},{"id":"升级步骤","depth":2,"text":"🚀 升级步骤","children":[{"id":"准备工作","depth":3,"text":"准备工作"},{"id":"执行升级","depth":3,"text":"执行升级"},{"id":"验证升级","depth":3,"text":"验证升级"}]},{"id":"数据库迁移","depth":2,"text":"🔧 数据库迁移","children":[{"id":"手动迁移","depth":3,"text":"手动迁移"}]},{"id":"️-紧急回滚","depth":2,"text":"⤵️ 紧急回滚","children":[{"id":"自动回滚","depth":3,"text":"自动回滚"},{"id":"恢复数据库","depth":3,"text":"恢复数据库"}]},{"id":"版本更新日志","depth":2,"text":"📊 版本更新日志","children":[{"id":"v230最新","depth":3,"text":"v2.3.0（最新）"},{"id":"v220","depth":3,"text":"v2.2.0"},{"id":"v210","depth":3,"text":"v2.1.0"}]},{"id":"测试环境验证","depth":2,"text":"🧪 测试环境验证","children":[{"id":"测试清单","depth":3,"text":"测试清单"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-迁移失败怎么办","depth":3,"text":"Q: 迁移失败怎么办？"},{"id":"q-镜像拉取失败","depth":3,"text":"Q: 镜像拉取失败？"}]}]}}', '平滑升级生产环境，数据库迁移方案，紧急回滚操作手册。', 'md', '{"category":"deploy","order":3}', 'true', '/docs/deploy/upgrade', '{"title":"版本升级与回滚","description":"平滑升级生产环境，数据库迁移方案，紧急回滚操作手册。"}', 'docs/deploy/upgrade', '11srh3Gbi3w-1nElqY5llMQiImDxTsYpCUFtqmAQbFA'); -- 11srh3Gbi3w-1nElqY5llMQiImDxTsYpCUFtqmAQbFA
INSERT INTO _content_docs VALUES ('docs/docs/getting-started/apikey.md', 'API Key 创建与管理', '{"type":"minimark","value":[["h1",{"id":"api-key-创建与管理"},"API Key 创建与管理"],["blockquote",{},["p",{},"在控制台创建 API Key，了解权限范围与速率限制，安全使用建议。"]],["h2",{"id":"什么是-api-key"},"🔑 什么是 API Key？"],["p",{},"API Key 是调用 Websopy API 的凭证，类似于「数字身份证」，用于："],["ul",{},["li",{},"✅ 身份认证 - 证明你是平台用户"],["li",{},"✅ 权限控制 - 控制可以访问哪些资源"],["li",{},"✅ 用量统计 - 记录 API 调用情况"],["li",{},"✅ 计费依据 - 按使用量进行计费"]],["h2",{"id":"创建-api-key"},"📋 创建 API Key"],["h3",{"id":"步骤-1进入控制台"},"步骤 1：进入控制台"],["ol",{},["li",{},"登录 ",["a",{"href":"https://console.websopy.com","rel":["nofollow"]},"Websopy 控制台"]],["li",{},"导航到 ",["strong",{},"开发者中心 → API Key"]],["li",{},"点击 ",["strong",{},"创建新 Key"]]],["h3",{"id":"步骤-2配置-key"},"步骤 2：配置 Key"],["table",{},["thead",{},["tr",{},["th",{},"配置项"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["strong",{},"名称"]],["td",{},"给 Key 取个易识别的名字，如「生产环境」「测试用」"]],["tr",{},["td",{},["strong",{},"权限范围"]],["td",{},"选择 Key 允许的操作（见下文）"]],["tr",{},["td",{},["strong",{},"有效期"]],["td",{},"设置过期时间（可选）"]],["tr",{},["td",{},["strong",{},"IP 白名单"]],["td",{},"限制只有指定 IP 才能使用（可选）"]]]],["h3",{"id":"步骤-3保存-key"},"步骤 3：保存 Key"],["p",{},"⚠️ ",["strong",{},"重要"],"：API Key 只显示一次，请立即："],["ol",{},["li",{},"复制保存到安全位置"],["li",{},"设置环境变量"]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# Linux/macOS\necho ''export WEBSOPY_API_KEY=\"ws_live_xxxxx\"'' >> ~/.bashrc\nsource ~/.bashrc\n\n# Windows PowerShell\n[Environment]::SetEnvironmentVariable(\"WEBSOPY_API_KEY\", \"ws_live_xxxxx\", \"User\")\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# Linux/macOS\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"echo"],["span",{"class":"sZZnC"}," ''export WEBSOPY_API_KEY=\"ws_live_xxxxx\"''"],["span",{"class":"szBVR"}," >>"],["span",{"class":"sZZnC"}," ~/.bashrc\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"source"],["span",{"class":"sZZnC"}," ~/.bashrc\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"# Windows PowerShell\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"[Environment]::SetEnvironmentVariable("],["span",{"class":"sScJk"},"\"WEBSOPY_API_KEY\""],["span",{"class":"sScJk"},","],["span",{"class":"sZZnC"}," \"ws_live_xxxxx\","],["span",{"class":"sZZnC"}," \"User\""],["span",{"class":"sVt8B"},")\n"]]]],["h2",{"id":"️-权限范围"},"🛡️ 权限范围"],["h3",{"id":"可用权限"},"可用权限"],["table",{},["thead",{},["tr",{},["th",{},"权限"],["th",{},"说明"],["th",{},"适用场景"]]],["tbody",{},["tr",{},["td",{},["code",{},"user:read"]],["td",{},"读取用户信息"],["td",{},"数据展示"]],["tr",{},["td",{},["code",{},"user:write"]],["td",{},"修改用户信息"],["td",{},"用户管理"]],["tr",{},["td",{},["code",{},"project:read"]],["td",{},"读取项目"],["td",{},"数据展示"]],["tr",{},["td",{},["code",{},"project:write"]],["td",{},"创建/修改/删除项目"],["td",{},"项目管理"]],["tr",{},["td",{},["code",{},"storage:read"]],["td",{},"读取文件"],["td",{},"文件读取"]],["tr",{},["td",{},["code",{},"storage:write"]],["td",{},"上传/删除文件"],["td",{},"文件管理"]],["tr",{},["td",{},["code",{},"ai:agent"]],["td",{},"使用 AI 智能体"],["td",{},"AI 功能"]],["tr",{},["td",{},["code",{},"ai:knowledge"]],["td",{},"管理知识库"],["td",{},"知识库管理"]],["tr",{},["td",{},["code",{},"payment:read"]],["td",{},"读取账单"],["td",{},"账单查看"]],["tr",{},["td",{},["code",{},"admin:*"]],["td",{},"所有权限"],["td",{},"⚠️ 仅管理员"]]]],["h3",{"id":"权限组合"},"权限组合"],["p",{},"推荐按最小权限原则配置："],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"// 只读权限（安全）\n{\n  \"permissions\": [\"user:read\", \"project:read\", \"storage:read\"]\n}\n\n// 读写权限（一般开发）\n{\n  \"permissions\": [\"user:read\", \"user:write\", \"project:*\", \"storage:*\"]\n}\n\n// AI 功能\n{\n  \"permissions\": [\"ai:agent\", \"ai:knowledge\"]\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 只读权限（安全）\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"  \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"user:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"project:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"storage:read\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":5},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"// 读写权限（一般开发）\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":8},["span",{"class":"sj4cs"},"  \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"user:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"user:write\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"project:*\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"storage:*\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"// AI 功能\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":13},["span",{"class":"sj4cs"},"  \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"ai:agent\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"ai:knowledge\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"ip-白名单"},"🚫 IP 白名单"],["p",{},"增强安全性，限制只有指定 IP 可以使用 Key："],["ol",{},["li",{},"创建/编辑 Key 时开启「IP 白名单」"],["li",{},"添加允许的 IP 地址或 CIDR 范围"]],["pre",{"className":["language-text"],"code":"# 支持的格式\n203.0.113.1           # 单个 IP\n203.0.113.0/24        # IP 段\n203.0.113.1,198.51.100.0/24  # 多个，用逗号分隔\n","language":"text","meta":""},["code",{"__ignoreMap":""},"# 支持的格式\n203.0.113.1           # 单个 IP\n203.0.113.0/24        # IP 段\n203.0.113.1,198.51.100.0/24  # 多个，用逗号分隔\n"]],["h2",{"id":"️-速率限制"},"⏱️ 速率限制"],["table",{},["thead",{},["tr",{},["th",{},"套餐"],["th",{},"请求限制"]]],["tbody",{},["tr",{},["td",{},"免费版"],["td",{},"100 次/分钟"]],["tr",{},["td",{},"专业版"],["td",{},"1,000 次/分钟"]],["tr",{},["td",{},"企业版"],["td",{},"10,000 次/分钟"]]]],["h3",{"id":"查看当前用量"},"查看当前用量"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY\n})\n\n// 获取当前配额\nconst quota = await client.account.getQuota()\nconsole.log(''今日剩余:'', quota.remaining)\nconsole.log(''重置时间:'', quota.resetAt)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"// 获取当前配额\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," quota"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.account."],["span",{"class":"sScJk"},"getQuota"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''今日剩余:''"],["span",{"class":"sVt8B"},", quota.remaining)\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''重置时间:''"],["span",{"class":"sVt8B"},", quota.resetAt)\n"]]]],["h3",{"id":"处理限流"},"处理限流"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function callWithRetry(fn, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn()\n    } catch (error) {\n      if (error.code === ''RATE_LIMIT_EXCEEDED'') {\n        // 等待后重试\n        await sleep(error.retryAfter * 1000)\n        continue\n      }\n      throw error\n    }\n  }\n}\n\nfunction sleep(ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," callWithRetry"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"fn"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"maxRetries"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," 3"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"  for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"let"],["span",{"class":"sVt8B"}," i "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," 0"],["span",{"class":"sVt8B"},"; i "],["span",{"class":"szBVR"},"<"],["span",{"class":"sVt8B"}," maxRetries; i"],["span",{"class":"szBVR"},"++"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"    try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"      return"],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fn"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"},"      if"],["span",{"class":"sVt8B"}," (error.code "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''RATE_LIMIT_EXCEEDED''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"        // 等待后重试\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"        await"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"(error.retryAfter "],["span",{"class":"szBVR"},"*"],["span",{"class":"sj4cs"}," 1000"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"},"        continue\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"      }\n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"},"      throw"],["span",{"class":"sVt8B"}," error\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"    }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"ms"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":17},["span",{"class":"szBVR"},"  return"],["span",{"class":"szBVR"}," new"],["span",{"class":"sj4cs"}," Promise"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"resolve"],["span",{"class":"szBVR"}," =>"],["span",{"class":"sScJk"}," setTimeout"],["span",{"class":"sVt8B"},"(resolve, ms))\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"安全最佳实践"},"🔐 安全最佳实践"],["h3",{"id":"推荐做法"},"✅ 推荐做法"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 1. 使用环境变量，不硬编码\nconst client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY  // ✅ 正确\n})\n\n// ❌ 危险：硬编码在代码中\nconst client = new WebsopyClient({\n  apiKey: ''ws_live_xxxxx''  // ❌ 危险\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 1. 使用环境变量，不硬编码\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sJ8bj"},"  // ✅ 正确\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":5},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"// ❌ 危险：硬编码在代码中\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  apiKey: "],["span",{"class":"sZZnC"},"''ws_live_xxxxx''"],["span",{"class":"sJ8bj"},"  // ❌ 危险\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 2. 区分不同环境的 Key\nconst client = new WebsopyClient({\n  apiKey: process.env.NODE_ENV === ''production'' \n    ? process.env.WEBSOPY_API_KEY_PROD \n    : process.env.WEBSOPY_API_KEY_DEV\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 2. 区分不同环境的 Key\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"NODE_ENV"],["span",{"class":"szBVR"}," ==="],["span",{"class":"sZZnC"}," ''production''"],["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"    ?"],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_PROD"],["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"    :"],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_DEV\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 3. 前端使用受限 Key\nconst client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY_PUBLIC,\n  // 前端 Key 应该只开只读权限\n  allowedMethods: [''user.getProfile'', ''project.list'']\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 3. 前端使用受限 Key\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_PUBLIC"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"  // 前端 Key 应该只开只读权限\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  allowedMethods: ["],["span",{"class":"sZZnC"},"''user.getProfile''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''project.list''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"避免事项"},"❌ 避免事项"],["ol",{},["li",{},["strong",{},"不要"],"将 Key 提交到代码仓库"],["li",{},["strong",{},"不要"],"在前端暴露有写权限的 Key"],["li",{},["strong",{},"不要"],"使用同一个 Key 处理所有业务"],["li",{},["strong",{},"不要"],"通过 URL 参数传递 Key"]],["pre",{"className":"language-gitignore shiki shiki-themes github-light github-dark","code":"# .gitignore\n.env\n.env.*\n*.local\n","language":"gitignore","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# .gitignore\n"]],["span",{"class":"line","line":2},["span",{},".env\n"]],["span",{"class":"line","line":3},["span",{},".env.*\n"]],["span",{"class":"line","line":4},["span",{},"*.local\n"]]]],["h2",{"id":"key-轮换"},"🔄 Key 轮换"],["p",{},"定期更换 API Key 是个好习惯："],["ol",{},["li",{},"在控制台创建新 Key"],["li",{},"更新所有使用旧 Key 的地方"],["li",{},"验证新 Key 正常工作"],["li",{},"禁用或删除旧 Key"]],["h2",{"id":"审计日志"},"📊 审计日志"],["p",{},"在控制台查看 API Key 的使用记录："],["ul",{},["li",{},"调用时间、频率"],["li",{},"调用的接口"],["li",{},"请求来源 IP"],["li",{},"错误情况"]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-api-key","depth":2,"text":"🔑 什么是 API Key？"},{"id":"创建-api-key","depth":2,"text":"📋 创建 API Key","children":[{"id":"步骤-1进入控制台","depth":3,"text":"步骤 1：进入控制台"},{"id":"步骤-2配置-key","depth":3,"text":"步骤 2：配置 Key"},{"id":"步骤-3保存-key","depth":3,"text":"步骤 3：保存 Key"}]},{"id":"️-权限范围","depth":2,"text":"🛡️ 权限范围","children":[{"id":"可用权限","depth":3,"text":"可用权限"},{"id":"权限组合","depth":3,"text":"权限组合"}]},{"id":"ip-白名单","depth":2,"text":"🚫 IP 白名单"},{"id":"️-速率限制","depth":2,"text":"⏱️ 速率限制","children":[{"id":"查看当前用量","depth":3,"text":"查看当前用量"},{"id":"处理限流","depth":3,"text":"处理限流"}]},{"id":"安全最佳实践","depth":2,"text":"🔐 安全最佳实践","children":[{"id":"推荐做法","depth":3,"text":"✅ 推荐做法"},{"id":"避免事项","depth":3,"text":"❌ 避免事项"}]},{"id":"key-轮换","depth":2,"text":"🔄 Key 轮换"},{"id":"审计日志","depth":2,"text":"📊 审计日志"}]}}', '在控制台创建 API Key，了解权限范围与速率限制，安全使用建议。', 'md', '{"category":"getting-started","order":3}', 'true', '/docs/getting-started/apikey', '{"title":"API Key 创建与管理","description":"在控制台创建 API Key，了解权限范围与速率限制，安全使用建议。"}', 'docs/getting-started/apikey', 'fQFIkHHXSPhhlV3j4D80tdOAwNTjeCDNIiP8ku6c2Dc'); -- fQFIkHHXSPhhlV3j4D80tdOAwNTjeCDNIiP8ku6c2Dc
INSERT INTO _content_docs VALUES ('docs/docs/getting-started/quickstart.md', '5 分钟快速上手', '{"type":"minimark","value":[["h1",{"id":"_5-分钟快速上手"},"5 分钟快速上手"],["blockquote",{},["p",{},"本教程将带你完成 Websopy SDK 的安装、配置，并发送你的第一个 API 请求。"]],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"Node.js 16.x 或更高版本"],["li",{},"npm 8.x 或 yarn 1.22+"],["li",{},"一个 Websopy 账户（",["a",{"href":"https://websopy.com/register","rel":["nofollow"]},"立即注册"],"）"]],["h2",{"id":"开始"},"🚀 开始"],["h3",{"id":"第一步安装-sdk"},"第一步：安装 SDK"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 使用 npm\nnpm install @websopy/sdk\n\n# 或使用 yarn\nyarn add @websopy/sdk\n\n# 或使用 pnpm\npnpm add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 使用 npm\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 或使用 yarn\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"yarn"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 或使用 pnpm\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"pnpm"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"第二步获取-api-key"},"第二步：获取 API Key"],["ol",{},["li",{},"登录 ",["a",{"href":"https://console.websopy.com","rel":["nofollow"]},"Websopy 控制台"]],["li",{},"进入 ",["strong",{},"开发者中心 → API Key"]],["li",{},"点击 ",["strong",{},"创建新 Key"]],["li",{},"选择权限范围（建议先选择「只读」权限测试）"],["li",{},"复制生成的 Key（注意：Key 只显示一次，请妥善保存）"]],["h3",{"id":"第三步初始化客户端"},"第三步：初始化客户端"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n  apiKey: ''your-api-key-here'',\n  // 可选：指定 API 端点\n  baseUrl: ''https://api.websopy.com/v1''\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  apiKey: "],["span",{"class":"sZZnC"},"''your-api-key-here''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"  // 可选：指定 API 端点\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  baseUrl: "],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第四步发送第一个请求"},"第四步：发送第一个请求"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function main() {\n  try {\n    // 获取用户信息\n    const user = await client.user.getProfile()\n    console.log(''当前用户:'', user.name)\n    \n    // 创建第一个项目\n    const project = await client.project.create({\n      name: ''我的第一个项目'',\n      description: ''通过 API 创建''\n    })\n    console.log(''项目创建成功:'', project.id)\n    \n    // 获取项目列表\n    const projects = await client.project.list()\n    console.log(''项目总数:'', projects.total)\n  } catch (error) {\n    console.error(''请求失败:'', error.message)\n  }\n}\n\nmain()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," main"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"  try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"    // 获取用户信息\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," user"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.user."],["span",{"class":"sScJk"},"getProfile"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''当前用户:''"],["span",{"class":"sVt8B"},", user.name)\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"    // 创建第一个项目\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," project"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"      name: "],["span",{"class":"sZZnC"},"''我的第一个项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"      description: "],["span",{"class":"sZZnC"},"''通过 API 创建''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"    })\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''项目创建成功:''"],["span",{"class":"sVt8B"},", project.id)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"    \n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"    // 获取项目列表\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"},"    const"],["span",{"class":"sj4cs"}," projects"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"list"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''项目总数:''"],["span",{"class":"sVt8B"},", projects.total)\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"  } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"    console."],["span",{"class":"sScJk"},"error"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''请求失败:''"],["span",{"class":"sVt8B"},", error.message)\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":21},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":22},["span",{"class":"sScJk"},"main"],["span",{"class":"sVt8B"},"()\n"]]]],["h3",{"id":"第五步运行代码"},"第五步：运行代码"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npx ts-node your-script.ts\n# 或\nnode your-script.js\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npx"],["span",{"class":"sZZnC"}," ts-node"],["span",{"class":"sZZnC"}," your-script.ts\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"},"# 或\n"]],["span",{"class":"line","line":3},["span",{"class":"sScJk"},"node"],["span",{"class":"sZZnC"}," your-script.js\n"]]]],["p",{},["strong",{},"预期输出："]],["pre",{"className":["language-text"],"code":"当前用户: 张三\n项目创建成功: proj_abc123xyz\n项目总数: 5\n","language":"text"},["code",{"__ignoreMap":""},"当前用户: 张三\n项目创建成功: proj_abc123xyz\n项目总数: 5\n"]],["h2",{"id":"恭喜"},"🎉 恭喜！"],["p",{},"你已经成功发送了第一个 API 请求。接下来你可以："],["ul",{},["li",{},"📖 继续阅读 ",["a",{"href":"/developer/docs/getting-started/apikey"},"API Key 创建与管理"]],["li",{},"🔌 查看 ",["a",{"href":"/developer/docs/api/rest-api"},"REST API 完整参考"]],["li",{},"🤖 尝试 ",["a",{"href":"/developer/docs/ai/agent"},"AI 智能体接入"]]],["h2",{"id":"️-常见问题"},"⚠️ 常见问题"],["h3",{"id":"q-报-invalid-api-key-错误"},"Q: 报 \"Invalid API Key\" 错误？"],["p",{},"检查以下几点："],["ol",{},["li",{},"API Key 是否正确复制（不要有空格）"],["li",{},"Key 是否已过期或被禁用"],["li",{},"Key 的权限范围是否包含当前操作"]],["h3",{"id":"q-报-rate-limit-exceeded-错误"},"Q: 报 \"Rate Limit Exceeded\" 错误？"],["p",{},"免费账户默认 100 次/分钟。如需更高配额，在控制台升级套餐。"],["h3",{"id":"q-如何开启调试模式"},"Q: 如何开启调试模式？"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n  apiKey: ''your-api-key'',\n  debug: true  // 打印详细请求日志\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  apiKey: "],["span",{"class":"sZZnC"},"''your-api-key''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  debug: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"},"  // 打印详细请求日志\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"相关资源"},"📚 相关资源"],["ul",{},["li",{},["a",{"href":"https://github.com/websopy/sdk","rel":["nofollow"]},"SDK 源码仓库"]],["li",{},["a",{"href":"https://github.com/websopy/examples","rel":["nofollow"]},"示例代码集合"]],["li",{},["a",{"href":"https://status.websopy.com","rel":["nofollow"]},"API 状态页"]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"开始","depth":2,"text":"🚀 开始","children":[{"id":"第一步安装-sdk","depth":3,"text":"第一步：安装 SDK"},{"id":"第二步获取-api-key","depth":3,"text":"第二步：获取 API Key"},{"id":"第三步初始化客户端","depth":3,"text":"第三步：初始化客户端"},{"id":"第四步发送第一个请求","depth":3,"text":"第四步：发送第一个请求"},{"id":"第五步运行代码","depth":3,"text":"第五步：运行代码"}]},{"id":"恭喜","depth":2,"text":"🎉 恭喜！"},{"id":"️-常见问题","depth":2,"text":"⚠️ 常见问题","children":[{"id":"q-报-invalid-api-key-错误","depth":3,"text":"Q: 报 \"Invalid API Key\" 错误？"},{"id":"q-报-rate-limit-exceeded-错误","depth":3,"text":"Q: 报 \"Rate Limit Exceeded\" 错误？"},{"id":"q-如何开启调试模式","depth":3,"text":"Q: 如何开启调试模式？"}]},{"id":"相关资源","depth":2,"text":"📚 相关资源"}]}}', '安装 Websopy SDK、配置客户端，并发送你的第一个 API 请求。', 'md', '{"category":"getting-started","order":1}', 'true', '/docs/getting-started/quickstart', '{"title":"5 分钟快速上手","description":"安装 Websopy SDK、配置客户端，并发送你的第一个 API 请求。"}', 'docs/getting-started/quickstart', '4575Hr8iOEk8iSu56Q0rFEwsSUvUlE6sWzPVgMB-77A'); -- 4575Hr8iOEk8iSu56Q0rFEwsSUvUlE6sWzPVgMB-77A
INSERT INTO _content_docs VALUES ('docs/docs/getting-started/sdk-installation.md', '安装 SDK 与初始化', '{"type":"minimark","value":[["h1",{"id":"安装-sdk-与初始化"},"安装 SDK 与初始化"],["blockquote",{},["p",{},"详细指南：安装 @websopy/sdk，配置 WebsopyClient，发送第一个 API 请求。"]],["h2",{"id":"sdk-概述"},"📦 SDK 概述"],["p",{},"Websopy 提供多种语言的 SDK："],["table",{},["thead",{},["tr",{},["th",{},"语言"],["th",{},"SDK"],["th",{},"源码"]]],["tbody",{},["tr",{},["td",{},"JavaScript/TypeScript"],["td",{},["code",{},"@websopy/sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-js","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Python"],["td",{},["code",{},"websopy-sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-python","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Go"],["td",{},["code",{},"github.com/websopy/sdk-go"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-go","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Java"],["td",{},["code",{},"com.websopy:sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-java","rel":["nofollow"]},"GitHub"]]]]],["p",{},"本教程以 JavaScript/TypeScript 为例。"],["h2",{"id":"安装"},"🚀 安装"],["h3",{"id":"npm"},"npm"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npm install @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"yarn"},"yarn"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"yarn add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"yarn"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"pnpm"},"pnpm"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"pnpm add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"pnpm"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"cdn浏览器端"},"CDN（浏览器端）"],["pre",{"className":"language-html shiki shiki-themes github-light github-dark","code":"<script src=\"https://unpkg.com/@websopy/sdk/dist/websopy.min.js\"></script>\n","language":"html","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"<"],["span",{"class":"s9eBZ"},"script"],["span",{"class":"sScJk"}," src"],["span",{"class":"sVt8B"},"="],["span",{"class":"sZZnC"},"\"https://unpkg.com/@websopy/sdk/dist/websopy.min.js\""],["span",{"class":"sVt8B"},"></"],["span",{"class":"s9eBZ"},"script"],["span",{"class":"sVt8B"},">\n"]]]],["h2",{"id":"️-初始化配置"},"⚙️ 初始化配置"],["h3",{"id":"基本配置"},"基本配置"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n  apiKey: ''ws_live_xxxxxxxxxxxx'',\n  // API 版本（可选，默认 v1）\n  version: ''v1'',\n  // 超时时间（毫秒）\n  timeout: 30000,\n  // 重试次数\n  retries: 3\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  apiKey: "],["span",{"class":"sZZnC"},"''ws_live_xxxxxxxxxxxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"  // API 版本（可选，默认 v1）\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  version: "],["span",{"class":"sZZnC"},"''v1''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"  // 超时时间（毫秒）\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  timeout: "],["span",{"class":"sj4cs"},"30000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sJ8bj"},"  // 重试次数\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  retries: "],["span",{"class":"sj4cs"},"3\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"多环境配置"},"多环境配置"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const config = {\n  // 开发环境\n  dev: {\n    apiKey: ''ws_test_xxxxx'',\n    baseUrl: ''https://api-dev.websopy.com/v1''\n  },\n  // 生产环境\n  prod: {\n    apiKey: process.env.WEBSOPY_API_KEY,\n    baseUrl: ''https://api.websopy.com/v1''\n  }\n}\n\nconst client = new WebsopyClient(\n  process.env.NODE_ENV === ''production'' ? config.prod : config.dev\n)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," config"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"},"  // 开发环境\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  dev: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"    apiKey: "],["span",{"class":"sZZnC"},"''ws_test_xxxxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    baseUrl: "],["span",{"class":"sZZnC"},"''https://api-dev.websopy.com/v1''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  },\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"  // 生产环境\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"  prod: {\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"    apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"    baseUrl: "],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"  }\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"  process.env."],["span",{"class":"sj4cs"},"NODE_ENV"],["span",{"class":"szBVR"}," ==="],["span",{"class":"sZZnC"}," ''production''"],["span",{"class":"szBVR"}," ?"],["span",{"class":"sVt8B"}," config.prod "],["span",{"class":"szBVR"},":"],["span",{"class":"sVt8B"}," config.dev\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},")\n"]]]],["h3",{"id":"环境变量"},"环境变量"],["p",{},"创建 ",["code",{},".env"]," 文件："],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"WEBSOPY_API_KEY=ws_live_xxxxxxxxxxxx\nWEBSOPY_BASE_URL=https://api.websopy.com/v1\nWEBSOPY_TIMEOUT=30000\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"WEBSOPY_API_KEY=ws_live_xxxxxxxxxxxx\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_BASE_URL=https://api.websopy.com/v1\n"]],["span",{"class":"line","line":3},["span",{},"WEBSOPY_TIMEOUT=30000\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import ''dotenv/config''\nimport { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY,\n  baseUrl: process.env.WEBSOPY_BASE_URL\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sZZnC"}," ''dotenv/config''\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  baseUrl: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_BASE_URL\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"api-模块"},"📚 API 模块"],["p",{},"SDK 按功能模块组织："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 用户管理\nclient.user\n\n// 项目管理\nclient.project\n\n// 文件存储\nclient.storage\n\n// AI 功能\nclient.ai\n\n// 支付功能\nclient.payment\n\n// Webhook\nclient.webhook\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 用户管理\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"client.user\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"// 项目管理\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"client.project\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"// 文件存储\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"client.storage\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"// AI 功能\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"client.ai\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"// 支付功能\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"client.payment\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"sJ8bj"},"// Webhook\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"client.webhook\n"]]]],["h2",{"id":"完整示例"},"🧪 完整示例"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nasync function demo() {\n  const client = new WebsopyClient({\n    apiKey: process.env.WEBSOPY_API_KEY\n  })\n\n  // 1. 获取用户信息\n  const user = await client.user.getProfile()\n  console.log(''用户:'', user.name)\n\n  // 2. 列出项目\n  const { items: projects } = await client.project.list({\n    limit: 10,\n    status: ''active''\n  })\n\n  // 3. 创建项目\n  const project = await client.project.create({\n    name: ''新项目'',\n    description: ''通过 SDK 创建''\n  })\n\n  // 4. 上传文件\n  const file = await client.storage.upload({\n    file: ''./demo.pdf'',\n    folder: ''documents''\n  })\n\n  console.log(''文件上传成功:'', file.url)\n}\n\ndemo().catch(console.error)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," demo"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"    apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"  // 1. 获取用户信息\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," user"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.user."],["span",{"class":"sScJk"},"getProfile"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"  console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''用户:''"],["span",{"class":"sVt8B"},", user.name)\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"sJ8bj"},"  // 2. 列出项目\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"},"  const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"s4XuR"},"items"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"projects"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"list"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"    limit: "],["span",{"class":"sj4cs"},"10"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"    status: "],["span",{"class":"sZZnC"},"''active''\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":17},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":18},["span",{"class":"sJ8bj"},"  // 3. 创建项目\n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," project"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"    name: "],["span",{"class":"sZZnC"},"''新项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"},"    description: "],["span",{"class":"sZZnC"},"''通过 SDK 创建''\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":23},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":24},["span",{"class":"sJ8bj"},"  // 4. 上传文件\n"]],["span",{"class":"line","line":25},["span",{"class":"szBVR"},"  const"],["span",{"class":"sj4cs"}," file"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.storage."],["span",{"class":"sScJk"},"upload"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"},"    file: "],["span",{"class":"sZZnC"},"''./demo.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"},"    folder: "],["span",{"class":"sZZnC"},"''documents''\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"},"  })\n"]],["span",{"class":"line","line":29},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":30},["span",{"class":"sVt8B"},"  console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''文件上传成功:''"],["span",{"class":"sVt8B"},", file.url)\n"]],["span",{"class":"line","line":31},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":32},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":33},["span",{"class":"sScJk"},"demo"],["span",{"class":"sVt8B"},"()."],["span",{"class":"sScJk"},"catch"],["span",{"class":"sVt8B"},"(console.error)\n"]]]],["h2",{"id":"typescript-类型"},"🔧 TypeScript 类型"],["p",{},"SDK 提供完整的 TypeScript 类型定义："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import type { \n  Project, \n  User, \n  CreateProjectOptions \n} from ''@websopy/sdk/types''\n\nfunction createProject(options: CreateProjectOptions): Promise<Project> {\n  return client.project.create(options)\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"szBVR"}," type"],["span",{"class":"sVt8B"}," { \n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  Project, \n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  User, \n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"  CreateProjectOptions \n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"} "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk/types''\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," createProject"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"options"],["span",{"class":"szBVR"},":"],["span",{"class":"sScJk"}," CreateProjectOptions"],["span",{"class":"sVt8B"},")"],["span",{"class":"szBVR"},":"],["span",{"class":"sScJk"}," Promise"],["span",{"class":"sVt8B"},"<"],["span",{"class":"sScJk"},"Project"],["span",{"class":"sVt8B"},"> {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"},"  return"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"(options)\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-esm-和-commonjs-兼容"},"Q: ESM 和 CommonJS 兼容？"],["p",{},"是的，SDK 同时支持两种模块格式："],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// ESM\nimport { WebsopyClient } from ''@websopy/sdk''\n\n// CommonJS\nconst { WebsopyClient } = require(''@websopy/sdk'')\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// ESM\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"// CommonJS\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"sj4cs"},"WebsopyClient"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"sScJk"}," require"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''@websopy/sdk''"],["span",{"class":"sVt8B"},")\n"]]]],["h3",{"id":"q-如何调试"},"Q: 如何调试？"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n  apiKey: process.env.WEBSOPY_API_KEY,\n  debug: true  // 打印详细日志\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"  apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"  debug: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"},"  // 打印详细日志\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"sdk-概述","depth":2,"text":"📦 SDK 概述"},{"id":"安装","depth":2,"text":"🚀 安装","children":[{"id":"npm","depth":3,"text":"npm"},{"id":"yarn","depth":3,"text":"yarn"},{"id":"pnpm","depth":3,"text":"pnpm"},{"id":"cdn浏览器端","depth":3,"text":"CDN（浏览器端）"}]},{"id":"️-初始化配置","depth":2,"text":"⚙️ 初始化配置","children":[{"id":"基本配置","depth":3,"text":"基本配置"},{"id":"多环境配置","depth":3,"text":"多环境配置"},{"id":"环境变量","depth":3,"text":"环境变量"}]},{"id":"api-模块","depth":2,"text":"📚 API 模块"},{"id":"完整示例","depth":2,"text":"🧪 完整示例"},{"id":"typescript-类型","depth":2,"text":"🔧 TypeScript 类型"},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-esm-和-commonjs-兼容","depth":3,"text":"Q: ESM 和 CommonJS 兼容？"},{"id":"q-如何调试","depth":3,"text":"Q: 如何调试？"}]}]}}', '详细指南：安装 @websopy/sdk，配置 WebsopyClient，发送第一个 API 请求。', 'md', '{"category":"getting-started","order":2}', 'true', '/docs/getting-started/sdk-installation', '{"title":"安装 SDK 与初始化","description":"详细指南：安装 @websopy/sdk，配置 WebsopyClient，发送第一个 API 请求。"}', 'docs/getting-started/sdk-installation', 'EKNThPWC-_GFUSshnSWFUOfjbjixZ-uyiP-PhVgh7Q8'); -- EKNThPWC-_GFUSshnSWFUOfjbjixZ-uyiP-PhVgh7Q8
INSERT INTO _content_docs VALUES ('docs/docs/index.md', 'Websopy 开发文档', '{"type":"minimark","value":[["h1",{"id":"websopy-开发文档"},"📚 Websopy 开发文档"],["blockquote",{},["p",{},"欢迎来到 Websopy 开发者文档中心。在这里，你可以找到从快速上手到高级功能的所有开发资源。"]],["h2",{"id":"快速开始"},"🚀 快速开始"],["p",{},"新用户推荐从这里开始，5 分钟内体验平台核心功能。"],["ul",{},["li",{},["a",{"href":"/developer/docs/getting-started/quickstart"},"5 分钟快速上手"]," — 安装 SDK、获取 API Key、发送第一个请求"],["li",{},["a",{"href":"/developer/docs/getting-started/sdk-installation"},"安装 SDK 与初始化"]," — 多语言 SDK 安装与配置"],["li",{},["a",{"href":"/developer/docs/getting-started/apikey"},"API Key 创建与管理"]," — 创建、配置与安全最佳实践"]],["h2",{"id":"api-参考"},"🔌 API 参考"],["p",{},"学习如何调用平台 API，掌握数据交互。"],["ul",{},["li",{},["a",{"href":"/developer/docs/api/rest-api"},"REST API 完整参考"]," — 200+ 标准接口文档"],["li",{},["a",{"href":"/developer/docs/api/streaming"},"流式输出（SSE）接入"]," — AI 流式响应实现"],["li",{},["a",{"href":"/developer/docs/api/webhook"},"Webhook 事件接入"]," — 异步通知与回调处理"]],["h2",{"id":"ai-功能"},"🤖 AI 功能"],["p",{},"集成 AI 能力，构建智能应用。"],["ul",{},["li",{},["a",{"href":"/developer/docs/ai/agent"},"AI 智能体接入"]," — 知识库问答与多模型切换"],["li",{},["a",{"href":"/developer/docs/ai/rag"},"RAG 知识库搭建"]," — 企业级知识库问答系统"],["li",{},["a",{"href":"/developer/docs/ai/workflow"},"AI 工作流配置"]," — 定时任务与自动化业务流"]],["h2",{"id":"部署运维"},"🚢 部署运维"],["p",{},"私有化部署、升级与运维指南。"],["ul",{},["li",{},["a",{"href":"/developer/docs/deploy/docker"},"Docker Compose 部署"]," — 一键部署全套服务"],["li",{},["a",{"href":"/developer/docs/deploy/private-deploy"},"私有化部署完全指南"]," — HTTPS 配置与备份策略"],["li",{},["a",{"href":"/developer/docs/deploy/upgrade"},"版本升级与回滚"]," — 平滑升级与紧急回滚"]]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"快速开始","depth":2,"text":"🚀 快速开始"},{"id":"api-参考","depth":2,"text":"🔌 API 参考"},{"id":"ai-功能","depth":2,"text":"🤖 AI 功能"},{"id":"部署运维","depth":2,"text":"🚢 部署运维"}]}}', '从快速上手到深度定制，全面的开发指引与 API 参考。', 'md', '{}', 'true', '/docs', '{"title":"Websopy 开发文档","description":"从快速上手到深度定制，全面的开发指引与 API 参考。"}', 'docs/index', 'qEoSynz5hB-SQGtmZjVElCwLL5C7cF4uMYesuclKZW4'); -- qEoSynz5hB-SQGtmZjVElCwLL5C7cF4uMYesuclKZW4
UPDATE _content_info SET ready = true WHERE id = 'checksum_docs'; -- meta