[{"data":1,"prerenderedAt":1717},["ShallowReactive",2],{"doc-page:\u002Fdocs\u002Fai-api-usage":3},{"doc":4,"prev":1683,"next":1687,"resolvedType":8,"readingMinutes":158,"audience":1691,"checklist":1695,"related":1699},{"path":5,"title":6,"description":7,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13,"body":14},"\u002Fdocs\u002Fai-api-usage","AI API 接入指南","OpenAI、Claude、Gemini 等主流 AI API 的接入方式、SDK 使用与费用优化","article",null,"ai-tools","AI 工具","2026-02-28","i-carbon-chat-bot",{"type":15,"value":16,"toc":1657},"minimark",[17,21,25,29,64,68,72,98,101,313,316,442,446,704,707,710,728,731,735,749,884,887,1017,1021,1035,1152,1156,1159,1179,1368,1372,1375,1418,1421,1457,1460,1488,1491,1505,1508,1512,1515,1526,1530,1533,1547,1550,1553,1567,1570,1584,1587,1613,1616,1653],[18,19,6],"h1",{"id":20},"ai-api-接入指南",[22,23,24],"p",{},"这页适合作为“把模型能力真正接进应用”的起点。API 接入的重点不只是调通一次请求，而是把密钥管理、模型选型、流式输出、重试、成本控制和日志观测一起做稳。",[26,27,28],"h2",{"id":28},"先按产品形态选接法",[30,31,32,40,46,52,58],"ul",{},[33,34,35,39],"li",{},[36,37,38],"strong",{},"只做单轮问答或简单接口封装","：直接用官方 SDK",[33,41,42,45],{},[36,43,44],{},"要在多个模型厂商间切换","：考虑统一 SDK 或抽象层",[33,47,48,51],{},[36,49,50],{},"要做聊天应用","：优先设计消息结构、上下文裁剪和流式返回",[33,53,54,57],{},[36,55,56],{},"要做 Agent \u002F 工具调用","：先把工具协议和错误处理定义清楚",[33,59,60,63],{},[36,61,62],{},"要做企业或团队产品","：先规划密钥、配额、日志、审计和回退策略",[26,65,67],{"id":66},"openai-api","OpenAI API",[69,70,71],"h3",{"id":71},"安装",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-bash shiki shiki-themes github-light github-dark","pnpm add openai\n","bash","",[80,81,82],"code",{"__ignoreMap":78},[83,84,87,91,95],"span",{"class":85,"line":86},"line",1,[83,88,90],{"class":89},"sScJk","pnpm",[83,92,94],{"class":93},"sZZnC"," add",[83,96,97],{"class":93}," openai\n",[69,99,100],{"id":100},"基础调用",[73,102,106],{"className":103,"code":104,"language":105,"meta":78,"style":78},"language-typescript shiki shiki-themes github-light github-dark","import OpenAI from \"openai\";\n\nconst client = new OpenAI({\n  apiKey: process.env.OPENAI_API_KEY,\n});\n\n\u002F\u002F Chat Completion\nconst response = await client.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [\n    { role: \"system\", content: \"你是一位 TypeScript 专家\" },\n    { role: \"user\", content: \"解释 infer 关键字\" },\n  ],\n  temperature: 0.7,\n  max_tokens: 1000,\n});\n\nconsole.log(response.choices[0].message.content);\n","typescript",[80,107,108,127,134,156,168,174,179,186,207,218,224,242,257,263,274,285,290,295],{"__ignoreMap":78},[83,109,110,114,118,121,124],{"class":85,"line":86},[83,111,113],{"class":112},"szBVR","import",[83,115,117],{"class":116},"sVt8B"," OpenAI ",[83,119,120],{"class":112},"from",[83,122,123],{"class":93}," \"openai\"",[83,125,126],{"class":116},";\n",[83,128,130],{"class":85,"line":129},2,[83,131,133],{"emptyLinePlaceholder":132},true,"\n",[83,135,137,140,144,147,150,153],{"class":85,"line":136},3,[83,138,139],{"class":112},"const",[83,141,143],{"class":142},"sj4cs"," client",[83,145,146],{"class":112}," =",[83,148,149],{"class":112}," new",[83,151,152],{"class":89}," OpenAI",[83,154,155],{"class":116},"({\n",[83,157,159,162,165],{"class":85,"line":158},4,[83,160,161],{"class":116},"  apiKey: process.env.",[83,163,164],{"class":142},"OPENAI_API_KEY",[83,166,167],{"class":116},",\n",[83,169,171],{"class":85,"line":170},5,[83,172,173],{"class":116},"});\n",[83,175,177],{"class":85,"line":176},6,[83,178,133],{"emptyLinePlaceholder":132},[83,180,182],{"class":85,"line":181},7,[83,183,185],{"class":184},"sJ8bj","\u002F\u002F Chat Completion\n",[83,187,189,191,194,196,199,202,205],{"class":85,"line":188},8,[83,190,139],{"class":112},[83,192,193],{"class":142}," response",[83,195,146],{"class":112},[83,197,198],{"class":112}," await",[83,200,201],{"class":116}," client.chat.completions.",[83,203,204],{"class":89},"create",[83,206,155],{"class":116},[83,208,210,213,216],{"class":85,"line":209},9,[83,211,212],{"class":116},"  model: ",[83,214,215],{"class":93},"\"gpt-4o\"",[83,217,167],{"class":116},[83,219,221],{"class":85,"line":220},10,[83,222,223],{"class":116},"  messages: [\n",[83,225,227,230,233,236,239],{"class":85,"line":226},11,[83,228,229],{"class":116},"    { role: ",[83,231,232],{"class":93},"\"system\"",[83,234,235],{"class":116},", content: ",[83,237,238],{"class":93},"\"你是一位 TypeScript 专家\"",[83,240,241],{"class":116}," },\n",[83,243,245,247,250,252,255],{"class":85,"line":244},12,[83,246,229],{"class":116},[83,248,249],{"class":93},"\"user\"",[83,251,235],{"class":116},[83,253,254],{"class":93},"\"解释 infer 关键字\"",[83,256,241],{"class":116},[83,258,260],{"class":85,"line":259},13,[83,261,262],{"class":116},"  ],\n",[83,264,266,269,272],{"class":85,"line":265},14,[83,267,268],{"class":116},"  temperature: ",[83,270,271],{"class":142},"0.7",[83,273,167],{"class":116},[83,275,277,280,283],{"class":85,"line":276},15,[83,278,279],{"class":116},"  max_tokens: ",[83,281,282],{"class":142},"1000",[83,284,167],{"class":116},[83,286,288],{"class":85,"line":287},16,[83,289,173],{"class":116},[83,291,293],{"class":85,"line":292},17,[83,294,133],{"emptyLinePlaceholder":132},[83,296,298,301,304,307,310],{"class":85,"line":297},18,[83,299,300],{"class":116},"console.",[83,302,303],{"class":89},"log",[83,305,306],{"class":116},"(response.choices[",[83,308,309],{"class":142},"0",[83,311,312],{"class":116},"].message.content);\n",[69,314,315],{"id":315},"流式输出",[73,317,319],{"className":103,"code":318,"language":105,"meta":78,"style":78},"const stream = await client.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: \"写一首诗\" }],\n  stream: true,\n});\n\nfor await (const chunk of stream) {\n  const content = chunk.choices[0]?.delta?.content || \"\";\n  process.stdout.write(content);\n}\n",[80,320,321,338,346,361,371,375,379,400,426,437],{"__ignoreMap":78},[83,322,323,325,328,330,332,334,336],{"class":85,"line":86},[83,324,139],{"class":112},[83,326,327],{"class":142}," stream",[83,329,146],{"class":112},[83,331,198],{"class":112},[83,333,201],{"class":116},[83,335,204],{"class":89},[83,337,155],{"class":116},[83,339,340,342,344],{"class":85,"line":129},[83,341,212],{"class":116},[83,343,215],{"class":93},[83,345,167],{"class":116},[83,347,348,351,353,355,358],{"class":85,"line":136},[83,349,350],{"class":116},"  messages: [{ role: ",[83,352,249],{"class":93},[83,354,235],{"class":116},[83,356,357],{"class":93},"\"写一首诗\"",[83,359,360],{"class":116}," }],\n",[83,362,363,366,369],{"class":85,"line":158},[83,364,365],{"class":116},"  stream: ",[83,367,368],{"class":142},"true",[83,370,167],{"class":116},[83,372,373],{"class":85,"line":170},[83,374,173],{"class":116},[83,376,377],{"class":85,"line":176},[83,378,133],{"emptyLinePlaceholder":132},[83,380,381,384,386,389,391,394,397],{"class":85,"line":181},[83,382,383],{"class":112},"for",[83,385,198],{"class":112},[83,387,388],{"class":116}," (",[83,390,139],{"class":112},[83,392,393],{"class":142}," chunk",[83,395,396],{"class":112}," of",[83,398,399],{"class":116}," stream) {\n",[83,401,402,405,408,410,413,415,418,421,424],{"class":85,"line":188},[83,403,404],{"class":112},"  const",[83,406,407],{"class":142}," content",[83,409,146],{"class":112},[83,411,412],{"class":116}," chunk.choices[",[83,414,309],{"class":142},[83,416,417],{"class":116},"]?.delta?.content ",[83,419,420],{"class":112},"||",[83,422,423],{"class":93}," \"\"",[83,425,126],{"class":116},[83,427,428,431,434],{"class":85,"line":209},[83,429,430],{"class":116},"  process.stdout.",[83,432,433],{"class":89},"write",[83,435,436],{"class":116},"(content);\n",[83,438,439],{"class":85,"line":220},[83,440,441],{"class":116},"}\n",[69,443,445],{"id":444},"function-calling","Function Calling",[73,447,449],{"className":103,"code":448,"language":105,"meta":78,"style":78},"const response = await client.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: \"北京今天天气怎么样？\" }],\n  tools: [\n    {\n      type: \"function\",\n      function: {\n        name: \"get_weather\",\n        description: \"获取指定城市的天气\",\n        parameters: {\n          type: \"object\",\n          properties: {\n            city: { type: \"string\", description: \"城市名\" },\n          },\n          required: [\"city\"],\n        },\n      },\n    },\n  ],\n});\n\n\u002F\u002F 检查是否需要调用函数\nconst toolCall = response.choices[0].message.tool_calls?.[0];\nif (toolCall) {\n  const args = JSON.parse(toolCall.function.arguments);\n  const weather = await getWeather(args.city);\n  \u002F\u002F 将结果返回给模型继续对话...\n}\n",[80,450,451,467,475,488,493,498,508,513,523,533,538,548,553,569,574,585,590,595,600,605,610,615,621,644,653,675,693,699],{"__ignoreMap":78},[83,452,453,455,457,459,461,463,465],{"class":85,"line":86},[83,454,139],{"class":112},[83,456,193],{"class":142},[83,458,146],{"class":112},[83,460,198],{"class":112},[83,462,201],{"class":116},[83,464,204],{"class":89},[83,466,155],{"class":116},[83,468,469,471,473],{"class":85,"line":129},[83,470,212],{"class":116},[83,472,215],{"class":93},[83,474,167],{"class":116},[83,476,477,479,481,483,486],{"class":85,"line":136},[83,478,350],{"class":116},[83,480,249],{"class":93},[83,482,235],{"class":116},[83,484,485],{"class":93},"\"北京今天天气怎么样？\"",[83,487,360],{"class":116},[83,489,490],{"class":85,"line":158},[83,491,492],{"class":116},"  tools: [\n",[83,494,495],{"class":85,"line":170},[83,496,497],{"class":116},"    {\n",[83,499,500,503,506],{"class":85,"line":176},[83,501,502],{"class":116},"      type: ",[83,504,505],{"class":93},"\"function\"",[83,507,167],{"class":116},[83,509,510],{"class":85,"line":181},[83,511,512],{"class":116},"      function: {\n",[83,514,515,518,521],{"class":85,"line":188},[83,516,517],{"class":116},"        name: ",[83,519,520],{"class":93},"\"get_weather\"",[83,522,167],{"class":116},[83,524,525,528,531],{"class":85,"line":209},[83,526,527],{"class":116},"        description: ",[83,529,530],{"class":93},"\"获取指定城市的天气\"",[83,532,167],{"class":116},[83,534,535],{"class":85,"line":220},[83,536,537],{"class":116},"        parameters: {\n",[83,539,540,543,546],{"class":85,"line":226},[83,541,542],{"class":116},"          type: ",[83,544,545],{"class":93},"\"object\"",[83,547,167],{"class":116},[83,549,550],{"class":85,"line":244},[83,551,552],{"class":116},"          properties: {\n",[83,554,555,558,561,564,567],{"class":85,"line":259},[83,556,557],{"class":116},"            city: { type: ",[83,559,560],{"class":93},"\"string\"",[83,562,563],{"class":116},", description: ",[83,565,566],{"class":93},"\"城市名\"",[83,568,241],{"class":116},[83,570,571],{"class":85,"line":265},[83,572,573],{"class":116},"          },\n",[83,575,576,579,582],{"class":85,"line":276},[83,577,578],{"class":116},"          required: [",[83,580,581],{"class":93},"\"city\"",[83,583,584],{"class":116},"],\n",[83,586,587],{"class":85,"line":287},[83,588,589],{"class":116},"        },\n",[83,591,592],{"class":85,"line":292},[83,593,594],{"class":116},"      },\n",[83,596,597],{"class":85,"line":297},[83,598,599],{"class":116},"    },\n",[83,601,603],{"class":85,"line":602},19,[83,604,262],{"class":116},[83,606,608],{"class":85,"line":607},20,[83,609,173],{"class":116},[83,611,613],{"class":85,"line":612},21,[83,614,133],{"emptyLinePlaceholder":132},[83,616,618],{"class":85,"line":617},22,[83,619,620],{"class":184},"\u002F\u002F 检查是否需要调用函数\n",[83,622,624,626,629,631,634,636,639,641],{"class":85,"line":623},23,[83,625,139],{"class":112},[83,627,628],{"class":142}," toolCall",[83,630,146],{"class":112},[83,632,633],{"class":116}," response.choices[",[83,635,309],{"class":142},[83,637,638],{"class":116},"].message.tool_calls?.[",[83,640,309],{"class":142},[83,642,643],{"class":116},"];\n",[83,645,647,650],{"class":85,"line":646},24,[83,648,649],{"class":112},"if",[83,651,652],{"class":116}," (toolCall) {\n",[83,654,656,658,661,663,666,669,672],{"class":85,"line":655},25,[83,657,404],{"class":112},[83,659,660],{"class":142}," args",[83,662,146],{"class":112},[83,664,665],{"class":142}," JSON",[83,667,668],{"class":116},".",[83,670,671],{"class":89},"parse",[83,673,674],{"class":116},"(toolCall.function.arguments);\n",[83,676,678,680,683,685,687,690],{"class":85,"line":677},26,[83,679,404],{"class":112},[83,681,682],{"class":142}," weather",[83,684,146],{"class":112},[83,686,198],{"class":112},[83,688,689],{"class":89}," getWeather",[83,691,692],{"class":116},"(args.city);\n",[83,694,696],{"class":85,"line":695},27,[83,697,698],{"class":184},"  \u002F\u002F 将结果返回给模型继续对话...\n",[83,700,702],{"class":85,"line":701},28,[83,703,441],{"class":116},[26,705,706],{"id":706},"接入最小流程",[22,708,709],{},"比较稳的接入流程通常是：",[711,712,713,716,719,722,725],"ol",{},[33,714,715],{},"先在本地用最小示例调通",[33,717,718],{},"再把 API Key 放进环境变量",[33,720,721],{},"再补超时、重试和错误日志",[33,723,724],{},"再补流式输出和上下文管理",[33,726,727],{},"最后才做多模型切换、缓存和成本优化",[22,729,730],{},"不要一开始就同时接很多厂商和很多能力，先让一条主链路稳定最重要。",[26,732,734],{"id":733},"anthropic-claude-api","Anthropic Claude API",[73,736,738],{"className":75,"code":737,"language":77,"meta":78,"style":78},"pnpm add @anthropic-ai\u002Fsdk\n",[80,739,740],{"__ignoreMap":78},[83,741,742,744,746],{"class":85,"line":86},[83,743,90],{"class":89},[83,745,94],{"class":93},[83,747,748],{"class":93}," @anthropic-ai\u002Fsdk\n",[73,750,752],{"className":103,"code":751,"language":105,"meta":78,"style":78},"import Anthropic from \"@anthropic-ai\u002Fsdk\";\n\nconst client = new Anthropic({\n  apiKey: process.env.ANTHROPIC_API_KEY,\n});\n\nconst response = await client.messages.create({\n  model: \"claude-sonnet-4-20250514\",\n  max_tokens: 1024,\n  system: \"你是一位资深开发者\",\n  messages: [{ role: \"user\", content: \"比较 React 和 Vue 的优缺点\" }],\n});\n\nconsole.log(response.content[0].text);\n",[80,753,754,768,772,787,796,800,804,821,830,839,849,862,866,870],{"__ignoreMap":78},[83,755,756,758,761,763,766],{"class":85,"line":86},[83,757,113],{"class":112},[83,759,760],{"class":116}," Anthropic ",[83,762,120],{"class":112},[83,764,765],{"class":93}," \"@anthropic-ai\u002Fsdk\"",[83,767,126],{"class":116},[83,769,770],{"class":85,"line":129},[83,771,133],{"emptyLinePlaceholder":132},[83,773,774,776,778,780,782,785],{"class":85,"line":136},[83,775,139],{"class":112},[83,777,143],{"class":142},[83,779,146],{"class":112},[83,781,149],{"class":112},[83,783,784],{"class":89}," Anthropic",[83,786,155],{"class":116},[83,788,789,791,794],{"class":85,"line":158},[83,790,161],{"class":116},[83,792,793],{"class":142},"ANTHROPIC_API_KEY",[83,795,167],{"class":116},[83,797,798],{"class":85,"line":170},[83,799,173],{"class":116},[83,801,802],{"class":85,"line":176},[83,803,133],{"emptyLinePlaceholder":132},[83,805,806,808,810,812,814,817,819],{"class":85,"line":181},[83,807,139],{"class":112},[83,809,193],{"class":142},[83,811,146],{"class":112},[83,813,198],{"class":112},[83,815,816],{"class":116}," client.messages.",[83,818,204],{"class":89},[83,820,155],{"class":116},[83,822,823,825,828],{"class":85,"line":188},[83,824,212],{"class":116},[83,826,827],{"class":93},"\"claude-sonnet-4-20250514\"",[83,829,167],{"class":116},[83,831,832,834,837],{"class":85,"line":209},[83,833,279],{"class":116},[83,835,836],{"class":142},"1024",[83,838,167],{"class":116},[83,840,841,844,847],{"class":85,"line":220},[83,842,843],{"class":116},"  system: ",[83,845,846],{"class":93},"\"你是一位资深开发者\"",[83,848,167],{"class":116},[83,850,851,853,855,857,860],{"class":85,"line":226},[83,852,350],{"class":116},[83,854,249],{"class":93},[83,856,235],{"class":116},[83,858,859],{"class":93},"\"比较 React 和 Vue 的优缺点\"",[83,861,360],{"class":116},[83,863,864],{"class":85,"line":244},[83,865,173],{"class":116},[83,867,868],{"class":85,"line":259},[83,869,133],{"emptyLinePlaceholder":132},[83,871,872,874,876,879,881],{"class":85,"line":265},[83,873,300],{"class":116},[83,875,303],{"class":89},[83,877,878],{"class":116},"(response.content[",[83,880,309],{"class":142},[83,882,883],{"class":116},"].text);\n",[69,885,315],{"id":886},"流式输出-1",[73,888,890],{"className":103,"code":889,"language":105,"meta":78,"style":78},"const stream = client.messages.stream({\n  model: \"claude-sonnet-4-20250514\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"你好\" }],\n});\n\nfor await (const event of stream) {\n  if (\n    event.type === \"content_block_delta\" &&\n    event.delta.type === \"text_delta\"\n  ) {\n    process.stdout.write(event.delta.text);\n  }\n}\n",[80,891,892,907,915,923,936,940,944,961,969,983,993,998,1008,1013],{"__ignoreMap":78},[83,893,894,896,898,900,902,905],{"class":85,"line":86},[83,895,139],{"class":112},[83,897,327],{"class":142},[83,899,146],{"class":112},[83,901,816],{"class":116},[83,903,904],{"class":89},"stream",[83,906,155],{"class":116},[83,908,909,911,913],{"class":85,"line":129},[83,910,212],{"class":116},[83,912,827],{"class":93},[83,914,167],{"class":116},[83,916,917,919,921],{"class":85,"line":136},[83,918,279],{"class":116},[83,920,836],{"class":142},[83,922,167],{"class":116},[83,924,925,927,929,931,934],{"class":85,"line":158},[83,926,350],{"class":116},[83,928,249],{"class":93},[83,930,235],{"class":116},[83,932,933],{"class":93},"\"你好\"",[83,935,360],{"class":116},[83,937,938],{"class":85,"line":170},[83,939,173],{"class":116},[83,941,942],{"class":85,"line":176},[83,943,133],{"emptyLinePlaceholder":132},[83,945,946,948,950,952,954,957,959],{"class":85,"line":181},[83,947,383],{"class":112},[83,949,198],{"class":112},[83,951,388],{"class":116},[83,953,139],{"class":112},[83,955,956],{"class":142}," event",[83,958,396],{"class":112},[83,960,399],{"class":116},[83,962,963,966],{"class":85,"line":188},[83,964,965],{"class":112},"  if",[83,967,968],{"class":116}," (\n",[83,970,971,974,977,980],{"class":85,"line":209},[83,972,973],{"class":116},"    event.type ",[83,975,976],{"class":112},"===",[83,978,979],{"class":93}," \"content_block_delta\"",[83,981,982],{"class":112}," &&\n",[83,984,985,988,990],{"class":85,"line":220},[83,986,987],{"class":116},"    event.delta.type ",[83,989,976],{"class":112},[83,991,992],{"class":93}," \"text_delta\"\n",[83,994,995],{"class":85,"line":226},[83,996,997],{"class":116},"  ) {\n",[83,999,1000,1003,1005],{"class":85,"line":244},[83,1001,1002],{"class":116},"    process.stdout.",[83,1004,433],{"class":89},[83,1006,1007],{"class":116},"(event.delta.text);\n",[83,1009,1010],{"class":85,"line":259},[83,1011,1012],{"class":116},"  }\n",[83,1014,1015],{"class":85,"line":265},[83,1016,441],{"class":116},[26,1018,1020],{"id":1019},"google-gemini-api","Google Gemini API",[73,1022,1024],{"className":75,"code":1023,"language":77,"meta":78,"style":78},"pnpm add @google\u002Fgenerative-ai\n",[80,1025,1026],{"__ignoreMap":78},[83,1027,1028,1030,1032],{"class":85,"line":86},[83,1029,90],{"class":89},[83,1031,94],{"class":93},[83,1033,1034],{"class":93}," @google\u002Fgenerative-ai\n",[73,1036,1038],{"className":103,"code":1037,"language":105,"meta":78,"style":78},"import { GoogleGenerativeAI } from \"@google\u002Fgenerative-ai\";\n\nconst genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);\nconst model = genAI.getGenerativeModel({ model: \"gemini-2.0-flash\" });\n\nconst result = await model.generateContent(\"解释量子计算\");\nconsole.log(result.response.text());\n",[80,1039,1040,1054,1058,1084,1108,1112,1137],{"__ignoreMap":78},[83,1041,1042,1044,1047,1049,1052],{"class":85,"line":86},[83,1043,113],{"class":112},[83,1045,1046],{"class":116}," { GoogleGenerativeAI } ",[83,1048,120],{"class":112},[83,1050,1051],{"class":93}," \"@google\u002Fgenerative-ai\"",[83,1053,126],{"class":116},[83,1055,1056],{"class":85,"line":129},[83,1057,133],{"emptyLinePlaceholder":132},[83,1059,1060,1062,1065,1067,1069,1072,1075,1078,1081],{"class":85,"line":136},[83,1061,139],{"class":112},[83,1063,1064],{"class":142}," genAI",[83,1066,146],{"class":112},[83,1068,149],{"class":112},[83,1070,1071],{"class":89}," GoogleGenerativeAI",[83,1073,1074],{"class":116},"(process.env.",[83,1076,1077],{"class":142},"GEMINI_API_KEY",[83,1079,1080],{"class":112},"!",[83,1082,1083],{"class":116},");\n",[83,1085,1086,1088,1091,1093,1096,1099,1102,1105],{"class":85,"line":158},[83,1087,139],{"class":112},[83,1089,1090],{"class":142}," model",[83,1092,146],{"class":112},[83,1094,1095],{"class":116}," genAI.",[83,1097,1098],{"class":89},"getGenerativeModel",[83,1100,1101],{"class":116},"({ model: ",[83,1103,1104],{"class":93},"\"gemini-2.0-flash\"",[83,1106,1107],{"class":116}," });\n",[83,1109,1110],{"class":85,"line":170},[83,1111,133],{"emptyLinePlaceholder":132},[83,1113,1114,1116,1119,1121,1123,1126,1129,1132,1135],{"class":85,"line":176},[83,1115,139],{"class":112},[83,1117,1118],{"class":142}," result",[83,1120,146],{"class":112},[83,1122,198],{"class":112},[83,1124,1125],{"class":116}," model.",[83,1127,1128],{"class":89},"generateContent",[83,1130,1131],{"class":116},"(",[83,1133,1134],{"class":93},"\"解释量子计算\"",[83,1136,1083],{"class":116},[83,1138,1139,1141,1143,1146,1149],{"class":85,"line":181},[83,1140,300],{"class":116},[83,1142,303],{"class":89},[83,1144,1145],{"class":116},"(result.response.",[83,1147,1148],{"class":89},"text",[83,1150,1151],{"class":116},"());\n",[26,1153,1155],{"id":1154},"ai-sdkvercel","AI SDK（Vercel）",[22,1157,1158],{},"统一的 AI SDK，支持多个提供商。",[73,1160,1162],{"className":75,"code":1161,"language":77,"meta":78,"style":78},"pnpm add ai @ai-sdk\u002Fopenai @ai-sdk\u002Fanthropic\n",[80,1163,1164],{"__ignoreMap":78},[83,1165,1166,1168,1170,1173,1176],{"class":85,"line":86},[83,1167,90],{"class":89},[83,1169,94],{"class":93},[83,1171,1172],{"class":93}," ai",[83,1174,1175],{"class":93}," @ai-sdk\u002Fopenai",[83,1177,1178],{"class":93}," @ai-sdk\u002Fanthropic\n",[73,1180,1182],{"className":103,"code":1181,"language":105,"meta":78,"style":78},"import { generateText, streamText } from \"ai\";\nimport { openai } from \"@ai-sdk\u002Fopenai\";\nimport { anthropic } from \"@ai-sdk\u002Fanthropic\";\n\n\u002F\u002F 统一接口，切换模型只需改一行\nconst result = await generateText({\n  model: openai(\"gpt-4o\"),\n  \u002F\u002F model: anthropic('claude-sonnet-4-20250514'),\n  prompt: \"你好\",\n});\n\n\u002F\u002F 流式\nconst stream = streamText({\n  model: openai(\"gpt-4o\"),\n  messages: [{ role: \"user\", content: \"写一个排序算法\" }],\n});\n\nfor await (const text of stream.textStream) {\n  process.stdout.write(text);\n}\n",[80,1183,1184,1198,1212,1226,1230,1235,1250,1264,1269,1278,1282,1286,1291,1304,1316,1329,1333,1337,1355,1364],{"__ignoreMap":78},[83,1185,1186,1188,1191,1193,1196],{"class":85,"line":86},[83,1187,113],{"class":112},[83,1189,1190],{"class":116}," { generateText, streamText } ",[83,1192,120],{"class":112},[83,1194,1195],{"class":93}," \"ai\"",[83,1197,126],{"class":116},[83,1199,1200,1202,1205,1207,1210],{"class":85,"line":129},[83,1201,113],{"class":112},[83,1203,1204],{"class":116}," { openai } ",[83,1206,120],{"class":112},[83,1208,1209],{"class":93}," \"@ai-sdk\u002Fopenai\"",[83,1211,126],{"class":116},[83,1213,1214,1216,1219,1221,1224],{"class":85,"line":136},[83,1215,113],{"class":112},[83,1217,1218],{"class":116}," { anthropic } ",[83,1220,120],{"class":112},[83,1222,1223],{"class":93}," \"@ai-sdk\u002Fanthropic\"",[83,1225,126],{"class":116},[83,1227,1228],{"class":85,"line":158},[83,1229,133],{"emptyLinePlaceholder":132},[83,1231,1232],{"class":85,"line":170},[83,1233,1234],{"class":184},"\u002F\u002F 统一接口，切换模型只需改一行\n",[83,1236,1237,1239,1241,1243,1245,1248],{"class":85,"line":176},[83,1238,139],{"class":112},[83,1240,1118],{"class":142},[83,1242,146],{"class":112},[83,1244,198],{"class":112},[83,1246,1247],{"class":89}," generateText",[83,1249,155],{"class":116},[83,1251,1252,1254,1257,1259,1261],{"class":85,"line":181},[83,1253,212],{"class":116},[83,1255,1256],{"class":89},"openai",[83,1258,1131],{"class":116},[83,1260,215],{"class":93},[83,1262,1263],{"class":116},"),\n",[83,1265,1266],{"class":85,"line":188},[83,1267,1268],{"class":184},"  \u002F\u002F model: anthropic('claude-sonnet-4-20250514'),\n",[83,1270,1271,1274,1276],{"class":85,"line":209},[83,1272,1273],{"class":116},"  prompt: ",[83,1275,933],{"class":93},[83,1277,167],{"class":116},[83,1279,1280],{"class":85,"line":220},[83,1281,173],{"class":116},[83,1283,1284],{"class":85,"line":226},[83,1285,133],{"emptyLinePlaceholder":132},[83,1287,1288],{"class":85,"line":244},[83,1289,1290],{"class":184},"\u002F\u002F 流式\n",[83,1292,1293,1295,1297,1299,1302],{"class":85,"line":259},[83,1294,139],{"class":112},[83,1296,327],{"class":142},[83,1298,146],{"class":112},[83,1300,1301],{"class":89}," streamText",[83,1303,155],{"class":116},[83,1305,1306,1308,1310,1312,1314],{"class":85,"line":265},[83,1307,212],{"class":116},[83,1309,1256],{"class":89},[83,1311,1131],{"class":116},[83,1313,215],{"class":93},[83,1315,1263],{"class":116},[83,1317,1318,1320,1322,1324,1327],{"class":85,"line":276},[83,1319,350],{"class":116},[83,1321,249],{"class":93},[83,1323,235],{"class":116},[83,1325,1326],{"class":93},"\"写一个排序算法\"",[83,1328,360],{"class":116},[83,1330,1331],{"class":85,"line":287},[83,1332,173],{"class":116},[83,1334,1335],{"class":85,"line":292},[83,1336,133],{"emptyLinePlaceholder":132},[83,1338,1339,1341,1343,1345,1347,1350,1352],{"class":85,"line":297},[83,1340,383],{"class":112},[83,1342,198],{"class":112},[83,1344,388],{"class":116},[83,1346,139],{"class":112},[83,1348,1349],{"class":142}," text",[83,1351,396],{"class":112},[83,1353,1354],{"class":116}," stream.textStream) {\n",[83,1356,1357,1359,1361],{"class":85,"line":602},[83,1358,430],{"class":116},[83,1360,433],{"class":89},[83,1362,1363],{"class":116},"(text);\n",[83,1365,1366],{"class":85,"line":607},[83,1367,441],{"class":116},[26,1369,1371],{"id":1370},"中转-api-代理","中转 API \u002F 代理",[22,1373,1374],{},"国内访问 OpenAI 等 API 可使用兼容的中转服务：",[73,1376,1378],{"className":103,"code":1377,"language":105,"meta":78,"style":78},"const client = new OpenAI({\n  baseURL: \"https:\u002F\u002Fyour-proxy.com\u002Fv1\",\n  apiKey: \"your-key\",\n});\n",[80,1379,1380,1394,1404,1414],{"__ignoreMap":78},[83,1381,1382,1384,1386,1388,1390,1392],{"class":85,"line":86},[83,1383,139],{"class":112},[83,1385,143],{"class":142},[83,1387,146],{"class":112},[83,1389,149],{"class":112},[83,1391,152],{"class":89},[83,1393,155],{"class":116},[83,1395,1396,1399,1402],{"class":85,"line":129},[83,1397,1398],{"class":116},"  baseURL: ",[83,1400,1401],{"class":93},"\"https:\u002F\u002Fyour-proxy.com\u002Fv1\"",[83,1403,167],{"class":116},[83,1405,1406,1409,1412],{"class":85,"line":136},[83,1407,1408],{"class":116},"  apiKey: ",[83,1410,1411],{"class":93},"\"your-key\"",[83,1413,167],{"class":116},[83,1415,1416],{"class":85,"line":158},[83,1417,173],{"class":116},[22,1419,1420],{},"常见兼容 API 提供商：",[30,1422,1423,1433,1441,1449],{},[33,1424,1425,1432],{},[1426,1427,1431],"a",{"href":1428,"rel":1429},"https:\u002F\u002Fopenrouter.ai\u002F",[1430],"nofollow","OpenRouter"," — 聚合多家模型",[33,1434,1435,1440],{},[1426,1436,1439],{"href":1437,"rel":1438},"https:\u002F\u002Fgroq.com\u002F",[1430],"Groq"," — 超快推理",[33,1442,1443,1448],{},[1426,1444,1447],{"href":1445,"rel":1446},"https:\u002F\u002Fwww.together.ai\u002F",[1430],"Together AI"," — 开源模型托管",[33,1450,1451,1456],{},[1426,1452,1455],{"href":1453,"rel":1454},"https:\u002F\u002Fplatform.deepseek.com\u002F",[1430],"DeepSeek"," — 国产高性价比",[26,1458,1459],{"id":1459},"费用优化",[30,1461,1462,1465,1472,1475,1482,1485],{},[33,1463,1464],{},"选择合适的模型：简单任务用小模型（GPT-4o-mini、Haiku）",[33,1466,1467,1468,1471],{},"控制 ",[80,1469,1470],{},"max_tokens","：避免不必要的长输出",[33,1473,1474],{},"缓存常见请求的结果",[33,1476,1477,1478,1481],{},"使用 ",[80,1479,1480],{},"system"," 消息精简上下文",[33,1483,1484],{},"批量请求使用 Batch API（OpenAI 半价）",[33,1486,1487],{},"监控用量：设置 API 用量上限",[26,1489,1490],{"id":1490},"接口设计建议",[30,1492,1493,1496,1499,1502],{},[33,1494,1495],{},"把模型名、温度、最大输出长度做成可配置项",[33,1497,1498],{},"区分用户输入、系统指令和工具结果",[33,1500,1501],{},"为失败请求保留请求 ID、错误码和耗时日志",[33,1503,1504],{},"给外部调用方返回更稳定的业务错误，而不是直接透传上游异常",[26,1506,1507],{"id":1507},"常见问题",[69,1509,1511],{"id":1510},"本地能调通线上报鉴权错误","本地能调通，线上报鉴权错误",[22,1513,1514],{},"优先检查：",[30,1516,1517,1520,1523],{},[33,1518,1519],{},"环境变量是否真的注入到运行环境",[33,1521,1522],{},"是否把客户端调用误写成了服务端调用",[33,1524,1525],{},"不同环境是否用了不同 Key 或 Base URL",[69,1527,1529],{"id":1528},"输出太贵太慢","输出太贵、太慢",[22,1531,1532],{},"高频处理思路：",[30,1534,1535,1538,1541,1544],{},[33,1536,1537],{},"换更小模型",[33,1539,1540],{},"裁剪上下文",[33,1542,1543],{},"限制输出长度",[33,1545,1546],{},"对稳定内容做缓存",[69,1548,1549],{"id":1549},"多厂商接入后逻辑越来越乱",[22,1551,1552],{},"更稳的做法是抽一层统一接口，把这些差异收口：",[30,1554,1555,1558,1561,1564],{},[33,1556,1557],{},"模型名",[33,1559,1560],{},"请求参数",[33,1562,1563],{},"错误结构",[33,1565,1566],{},"流式事件格式",[26,1568,1569],{"id":1569},"风险提醒",[30,1571,1572,1575,1578,1581],{},[33,1573,1574],{},"不要把密钥暴露到前端公开环境变量",[33,1576,1577],{},"不要默认把完整用户隐私数据直接发给第三方模型",[33,1579,1580],{},"中转 API 很方便，但要额外评估稳定性、日志留存和数据边界",[33,1582,1583],{},"先做成本上限与监控，再放给真实用户大规模使用",[26,1585,1586],{"id":1586},"延伸阅读",[30,1588,1589,1595,1601,1607],{},[33,1590,1591],{},[1426,1592,1594],{"href":1593},"\u002Fdocs\u002Fai-tools","AI 工具合集",[33,1596,1597],{},[1426,1598,1600],{"href":1599},"\u002Fdocs\u002Fprompt-engineering","提示词工程",[33,1602,1603],{},[1426,1604,1606],{"href":1605},"\u002Fdocs\u002Fmcp-guide","MCP 模型上下文协议",[33,1608,1609],{},[1426,1610,1612],{"href":1611},"\u002Fdocs\u002Fai-workflow-automation","AI 工作流自动化",[26,1614,1615],{"id":1615},"参考链接",[30,1617,1618,1625,1632,1639,1647],{},[33,1619,1620,1624],{},[1426,1621,67],{"href":1622,"rel":1623},"https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002F",[1430]," — 文档",[33,1626,1627,1624],{},[1426,1628,1631],{"href":1629,"rel":1630},"https:\u002F\u002Fdocs.anthropic.com\u002F",[1430],"Anthropic API",[33,1633,1634,1624],{},[1426,1635,1638],{"href":1636,"rel":1637},"https:\u002F\u002Fai.google.dev\u002Fdocs",[1430],"Gemini API",[33,1640,1641,1646],{},[1426,1642,1645],{"href":1643,"rel":1644},"https:\u002F\u002Fsdk.vercel.ai\u002F",[1430],"Vercel AI SDK"," — 统一 SDK",[33,1648,1649,1652],{},[1426,1650,1431],{"href":1428,"rel":1651},[1430]," — 模型聚合",[1654,1655,1656],"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}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":78,"searchDepth":129,"depth":129,"links":1658},[1659,1660,1666,1667,1670,1671,1672,1673,1674,1675,1680,1681,1682],{"id":28,"depth":129,"text":28},{"id":66,"depth":129,"text":67,"children":1661},[1662,1663,1664,1665],{"id":71,"depth":136,"text":71},{"id":100,"depth":136,"text":100},{"id":315,"depth":136,"text":315},{"id":444,"depth":136,"text":445},{"id":706,"depth":129,"text":706},{"id":733,"depth":129,"text":734,"children":1668},[1669],{"id":886,"depth":136,"text":315},{"id":1019,"depth":129,"text":1020},{"id":1154,"depth":129,"text":1155},{"id":1370,"depth":129,"text":1371},{"id":1459,"depth":129,"text":1459},{"id":1490,"depth":129,"text":1490},{"id":1507,"depth":129,"text":1507,"children":1676},[1677,1678,1679],{"id":1510,"depth":136,"text":1511},{"id":1528,"depth":136,"text":1529},{"id":1549,"depth":136,"text":1549},{"id":1569,"depth":129,"text":1569},{"id":1586,"depth":129,"text":1586},{"id":1615,"depth":129,"text":1615},{"path":1684,"title":1685,"description":1686,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Fai-agents-cli","AI 终端代理与自主工具","Claude Code、Codex CLI、Warp、OpenClaw 等 AI 终端代理和自主代理工具",{"path":1688,"title":1689,"description":1690,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Fai-ide","AI IDE 与编辑器","Cursor、Windsurf、Kiro、Trae 等 AI 驱动的代码编辑器对比与使用指南",[1692,1693,1694],"希望把零散经验整理成长期可复用工作流的人","正在使用 AI 工具、Agent 或自动化工作流的人","希望阅读时顺手建立自己的操作清单或收藏体系的人",[1696,1697,1698],"先浏览标题、摘要和目录，带着问题阅读会更高效","确认模型供应商、API Key、CLI 工具链与本地资源是否已准备好","如果页面里提到相关文档，尽量一起打开对照，效果通常更完整",[1700,1705,1709,1713],{"path":1701,"title":1702,"description":1703,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":1704,"publishedAt":1704,"icon":13},"\u002Fdocs\u002Fskills-guide","AI Agent Skills 指南","理解 skills 的作用、目录结构、编写方式，以及它与 MCP 的关系","2026-03-08",{"path":1706,"title":1707,"description":1708,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Fai-local-models","本地 AI 模型部署","Ollama、LM Studio、vLLM 本地大模型运行与 API 调用",{"path":1710,"title":1711,"description":1712,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Flocal-llm-deployment","本地 LLM 部署指南","使用 Ollama、vLLM、LM Studio 在本地运行大语言模型",{"path":1714,"title":1715,"description":1716,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Fai-coding-rules","AI 编程助手规则配置","Cursor Rules、Claude Projects、Kiro Steering 等 AI 编程助手的规则与上下文配置",1776215711220]