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":"\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"},">\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 {\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