用開發(fā)教程01:TUI 概述與 TaoToken 統(tǒng)一 Key 接入準(zhǔn)備)
1. 從命令行到終端界面TUI 到底解決了什么問題如果你平時(shí)用git commit、npm run dev這類命令那你已經(jīng)在用 CLI 了。CLI 的特點(diǎn)是「輸入一行、輸出一段」交互是線性的。但當(dāng)你需要一邊看文件樹、一邊預(yù)覽內(nèi)容、一邊輸入指令時(shí)CLI 就會(huì)顯得很別扭——你得反復(fù)敲ls、cat、再回到輸入行。TUIText User Interface文本用戶界面就是在這個(gè)縫隙里長(zhǎng)出來的。它同樣跑在終端里但把屏幕當(dāng)成一塊可以自由布局的畫布左邊一欄文件列表右邊一欄內(nèi)容預(yù)覽底部一行輸入框頂部一條狀態(tài)欄。所有元素都是字符拼出來的靠 ANSI 轉(zhuǎn)義碼控制光標(biāo)位置、顏色和樣式。一句話概括TUI 是運(yùn)行在終端里的交互式界面它用字符網(wǎng)格模擬出接近 GUI 的布局和交互體驗(yàn)同時(shí)保留了 CLI 的輕量、可遠(yuǎn)程、可腳本化優(yōu)勢(shì)。它適合誰三類人最該關(guān)注。第一類是經(jīng)常 SSH 到服務(wù)器干活的開發(fā)者服務(wù)器上沒有圖形界面TUI 是唯一能提供「可視化交互」的方案。第二類是做 AI 工具的開發(fā)者大模型的流式輸出、工具調(diào)用狀態(tài)、多輪對(duì)話歷史這些用 TUI 展示天然合適。第三類是想把現(xiàn)有 CLI 工具升級(jí)體驗(yàn)的作者加一個(gè) TUI 外殼用戶留存率往往明顯提升。我試過把一個(gè)內(nèi)部用的日志查詢 CLI 改成 TUI原本要記五六個(gè)參數(shù)的命令變成了方向鍵選擇 回車確認(rèn)團(tuán)隊(duì)里非技術(shù)同事也能直接用了。這就是 TUI 的價(jià)值不犧牲終端的能力卻大幅降低使用門檻。這一章我們先不寫復(fù)雜界面目標(biāo)很明確——把 TUI 的核心概念講清楚把開發(fā)環(huán)境檢查好再把 TaoToken 的統(tǒng)一 Key 通道接通最后用一個(gè)最小請(qǐng)求驗(yàn)證「模型能通、Key 有效」。后面第 2 章開始才真正進(jìn)入終端控制和框架實(shí)戰(zhàn)。先看一張對(duì)比表把 CLI、TUI、GUI 三者的定位擺清楚維度CLITUIGUI學(xué)習(xí)曲線中等需記命令低可視化操作低點(diǎn)按拖拽操作效率極高可管道腳本高快捷鍵驅(qū)動(dòng)中等鼠標(biāo)驅(qū)動(dòng)資源占用極低1MB低5–50MB高100MB啟動(dòng)速度即時(shí)1s數(shù)秒遠(yuǎn)程使用原生 SSH原生 SSH需 RDP/VNC可視化程度無中等豐富AI 流式輸出需自己處理逐字渲染天然適配DOM 重繪有延遲從表里能看出TUI 卡在一個(gè)很甜的位置比 CLI 好看好用比 GUI 輕得多而且遠(yuǎn)程和管道能力一個(gè)不丟。AI 時(shí)代它復(fù)興核心原因就是大模型交互的三個(gè)特性——流式輸出、工具調(diào)用、多輪上下文——恰好都是 TUI 的強(qiáng)項(xiàng)。流式輸出需要逐 token 渲染TUI 的字符網(wǎng)格模型做差分更新非常自然工具調(diào)用需要展示「調(diào)用中→返回結(jié)果」的狀態(tài)卡片TUI 用邊框和顏色就能表達(dá)多輪對(duì)話需要滾動(dòng)歷史TUI 的滾動(dòng)緩沖區(qū)比 Web 的虛擬列表輕量得多。這些在后面章節(jié)會(huì)逐一展開本章先把地基打好。2. TaoToken 統(tǒng)一 Key 接入前的環(huán)境準(zhǔn)備與賬號(hào)配置在寫任何 TUI 代碼之前得先解決一個(gè)現(xiàn)實(shí)問題AI TUI 應(yīng)用要調(diào)用大模型而模型 API 的接入往往涉及多個(gè)廠商、多套 Key、多種計(jì)費(fèi)方式。如果每換一個(gè)模型就改一次代碼里的 base_url 和 key開發(fā)體驗(yàn)會(huì)很碎。TaoToken 在這里扮演的角色是「統(tǒng)一入口」它提供兼容 OpenAI 風(fēng)格的 API 通道你用一套 Key、一個(gè) Base URL就能在多個(gè)模型之間切換。對(duì) TUI 開發(fā)來說這意味著你的應(yīng)用只需要維護(hù)一份配置模型切換只改一個(gè) Model ID 字段。官網(wǎng)入口在這里注冊(cè)和查看文檔都從這進(jìn)https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 通道地址注意這個(gè)不帶 UTM是給代碼里填的https://taotoken.net/api2.1 先檢查本地環(huán)境TUI 開發(fā)對(duì) Node.js 版本有要求尤其是涉及原始模式raw mode和流式處理時(shí)。先跑一遍環(huán)境檢查命令把版本、包管理器、終端能力都確認(rèn)一遍。# 檢查 Node.js 版本建議 18 LTS 以上 node -v # 檢查 npm 版本 npm -v # 檢查終端類型確認(rèn)支持 ANSI echo $TERM # 檢查終端顏色能力256 色會(huì)輸出 256 tput colors # 檢查是否支持 TrueColor輸出 truecolor 或 24bit 為佳 echo $COLORTERM實(shí)測(cè)下來$TERM輸出xterm-256color是最常見的健康狀態(tài)。如果輸出dumb說明當(dāng)前終端不支持 ANSI 控制序列TUI 會(huì)渲染錯(cuò)亂需要換一個(gè)終端模擬器。tput colors輸出 256 或以上顏色就夠用了。再確認(rèn)一下網(wǎng)絡(luò)出口能訪問 API 域名# 檢查 DNS 解析和連通性 curl -s -o /dev/null -w %{http_code}\n https://taotoken.net/api如果返回 401 或 404說明網(wǎng)絡(luò)是通的只是沒帶認(rèn)證信息這是正常現(xiàn)象。如果卡住或報(bào)連接失敗先排查本地網(wǎng)絡(luò)和 DNS。2.2 創(chuàng)建項(xiàng)目并安裝依賴環(huán)境沒問題后建一個(gè)干凈的目錄把后面要用的基礎(chǔ)依賴裝上。mkdir tui-ai-demo cd tui-ai-demo npm init -y # 安裝 TypeScript 和運(yùn)行工具 npm install -D typescript ts-node types/node # 安裝 HTTP 客戶端用于調(diào)用模型 API npm install axios # 初始化 tsconfig npx tsc --inittsconfig.json里建議把target設(shè)為ES2020module設(shè)為commonjsstrict打開。這些配置在后面處理流式響應(yīng)和異步事件時(shí)會(huì)省很多事。2.3 獲取并配置統(tǒng)一 Key登錄 TaoToken 控制臺(tái)在 API Keys 頁面創(chuàng)建一個(gè)新 Key。創(chuàng)建后立刻復(fù)制保存頁面刷新后通常不再完整顯示。拿到 Key 之后不要硬編碼在源碼里。用環(huán)境變量管理這是基本安全習(xí)慣。在項(xiàng)目根目錄建一個(gè).env文件# .env TAOTOKEN_API_KEYsk-你的實(shí)際Key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELdeepseek-flash同時(shí)把.env加進(jìn).gitignore避免誤提交echo .env .gitignore echo node_modules .gitignore如果你用的是 Claude Code 這類工具它的配置方式略有不同通常在~/.claude/settings.json或項(xiàng)目級(jí)配置里指定 Base URL 和 Key。核心三件套永遠(yuǎn)是Base URL API Key Model ID缺一不可。后面第 3 章講具體框架配置時(shí)我會(huì)給出完整的 JSON 片段。這里先給一個(gè)通用的配置結(jié)構(gòu)你可以直接抄{ provider: taotoken, baseUrl: https://taotoken.net/api, apiKey: ${TAOTOKEN_API_KEY}, model: deepseek-flash, timeout: 60000, stream: true }注意apiKey用的是環(huán)境變量占位符代碼里讀取時(shí)再替換成真實(shí)值。這樣配置文件和密鑰分離團(tuán)隊(duì)協(xié)作時(shí)也不會(huì)泄露。3. 可復(fù)制的接入配置與最小請(qǐng)求代碼配置準(zhǔn)備好后寫一個(gè)最小可運(yùn)行腳本驗(yàn)證「Key 有效、模型能通、流式可用」。這一步很關(guān)鍵因?yàn)楹竺嫠?TUI 功能都建立在這條通道之上。如果這里不通界面寫得再漂亮也沒用。3.1 安裝 dotenv 并讀取配置npm install dotenv然后創(chuàng)建src/check-connection.tsimport axios from axios; import * as dotenv from dotenv; dotenv.config(); const BASE_URL process.env.TAOTOKEN_BASE_URL || https://taotoken.net/api; const API_KEY process.env.TAOTOKEN_API_KEY || ; const MODEL process.env.TAOTOKEN_MODEL || deepseek-flash; async function checkConnection(): Promisevoid { if (!API_KEY) { console.error(缺少 TAOTOKEN_API_KEY請(qǐng)檢查 .env 文件); process.exit(1); } console.log(正在驗(yàn)證接入...); console.log(Base URL: ${BASE_URL}); console.log(Model: ${MODEL}); try { const response await axios.post( ${BASE_URL}/v1/chat/completions, { model: MODEL, messages: [ { role: user, content: 用一句話說明 TUI 是什么 } ], stream: false, max_tokens: 100 }, { headers: { Authorization: Bearer ${API_KEY}, Content-Type: application/json }, timeout: 60000 } ); const content response.data?.choices?.[0]?.message?.content; console.log(\n接入成功模型返回); console.log(content); } catch (error: any) { console.error(\n接入失敗); if (error.response) { console.error(狀態(tài)碼: ${error.response.status}); console.error(響應(yīng)體: ${JSON.stringify(error.response.data)}); } else { console.error(error.message); } process.exit(1); } } checkConnection();運(yùn)行它npx ts-node src/check-connection.ts如果一切正常你會(huì)看到模型返回的一句話說明。這一步成功說明 Base URL、Key、Model ID 三件套都對(duì)。3.2 驗(yàn)證流式輸出TUI 的核心體驗(yàn)是流式渲染所以還要單獨(dú)驗(yàn)證流式通道。創(chuàng)建src/check-stream.tsimport axios from axios; import * as dotenv from dotenv; dotenv.config(); const BASE_URL process.env.TAOTOKEN_BASE_URL || https://taotoken.net/api; const API_KEY process.env.TAOTOKEN_API_KEY || ; const MODEL process.env.TAOTOKEN_MODEL || deepseek-flash; async function checkStream(): Promisevoid { const response await axios.post( ${BASE_URL}/v1/chat/completions, { model: MODEL, messages: [ { role: user, content: 數(shù)一下從 1 到 5每個(gè)數(shù)字單獨(dú)一行 } ], stream: true, max_tokens: 200 }, { headers: { Authorization: Bearer ${API_KEY}, Content-Type: application/json }, responseType: stream, timeout: 60000 } ); const stream response.data; let buffer ; stream.on(data, (chunk: Buffer) { buffer chunk.toString(utf-8); const lines buffer.split(\n); buffer lines.pop() || ; for (const line of lines) { const trimmed line.trim(); if (!trimmed.startsWith(data:)) continue; const payload trimmed.slice(5).trim(); if (payload [DONE]) { console.log(\n\n流式結(jié)束); return; } try { const json JSON.parse(payload); const delta json.choices?.[0]?.delta?.content; if (delta) { process.stdout.write(delta); } } catch { // 忽略不完整的分片 } } }); stream.on(error, (err: Error) { console.error(流式錯(cuò)誤:, err.message); }); } checkStream();運(yùn)行npx ts-node src/check-stream.ts你會(huì)看到數(shù)字逐個(gè)蹦出來而不是等全部生成完才顯示。這就是 TUI 里「打字機(jī)效果」的底層原理——逐 chunk 接收、逐 token 渲染。第 8 章會(huì)把這個(gè)邏輯封裝成可復(fù)用的流式渲染器。3.3 配置片段匯總把上面用到的配置整理成一份可直接復(fù)制的清單方便你對(duì)照檢查# 環(huán)境變量.env TAOTOKEN_API_KEYsk-你的實(shí)際Key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELdeepseek-flash// 通用配置結(jié)構(gòu)config.json { provider: taotoken, baseUrl: https://taotoken.net/api, apiKey: ${TAOTOKEN_API_KEY}, model: deepseek-flash, timeout: 60000, stream: true }// 請(qǐng)求頭三件套 headers: { Authorization: Bearer ${API_KEY}, Content-Type: application/json }這三段配置在后續(xù)所有章節(jié)里都會(huì)反復(fù)出現(xiàn)。記住核心Base URL 指向https://taotoken.net/api認(rèn)證用 Bearer Token模型用 Model ID 指定。換模型只改 Model ID其他不動(dòng)。4. 驗(yàn)證請(qǐng)求與成功結(jié)果判讀配置寫完了但「跑通」和「跑對(duì)」是兩回事。這一節(jié)教你怎么判斷請(qǐng)求真的成功了以及成功結(jié)果長(zhǎng)什么樣。4.1 非流式請(qǐng)求的成功判讀運(yùn)行check-connection.ts后正常輸出應(yīng)該類似正在驗(yàn)證接入... Base URL: https://taotoken.net/api Model: deepseek-flash 接入成功模型返回 TUI 是一種在終端中運(yùn)行的文本用戶界面通過字符和 ANSI 控制碼實(shí)現(xiàn)布局與交互。關(guān)鍵判讀點(diǎn)有三個(gè)。第一HTTP 狀態(tài)碼是 200沒有拋異常。第二response.data.choices[0].message.content有實(shí)際文本內(nèi)容不是空字符串。第三返回的model字段和你請(qǐng)求的 Model ID 一致有些通道會(huì)返回實(shí)際路由到的模型名。如果返回內(nèi)容為空但狀態(tài)碼是 200通常是max_tokens設(shè)得太小或者模型把內(nèi)容放進(jìn)了reasoning_content字段部分推理模型會(huì)這樣。這時(shí)候打印完整響應(yīng)體看看結(jié)構(gòu)console.log(JSON.stringify(response.data, null, 2));4.2 流式請(qǐng)求的成功判讀運(yùn)行check-stream.ts后正常輸出是數(shù)字逐個(gè)出現(xiàn)1 2 3 4 5 流式結(jié)束判讀要點(diǎn)數(shù)據(jù)是「漸進(jìn)出現(xiàn)」而不是「一次性刷出」最后能看到[DONE]標(biāo)記被正確處理。如果所有內(nèi)容一次性出現(xiàn)說明stream: true沒生效或者中間層做了緩沖。流式響應(yīng)的數(shù)據(jù)格式是 SSEServer-Sent Events每一行以data:開頭最后一行是data: [DONE]。解析時(shí)要處理分片問題——一個(gè) chunk 可能包含半行 JSON所以要維護(hù) buffer按換行符切分后再解析。上面的代碼已經(jīng)處理了這個(gè)細(xì)節(jié)。4.3 用 curl 快速驗(yàn)證如果你不想寫代碼用 curl 也能驗(yàn)證。非流式curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: deepseek-flash, messages: [{role: user, content: 你好}], max_tokens: 50 }流式加-N禁用緩沖curl -N https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: deepseek-flash, messages: [{role: user, content: 數(shù)到3}], stream: true }curl 能看到原始 SSE 流對(duì)排查「到底是網(wǎng)絡(luò)問題還是代碼問題」特別有用。如果 curl 通但代碼不通問題在代碼如果 curl 也不通問題在配置或網(wǎng)絡(luò)。4.4 成功接入后的狀態(tài)到這里你應(yīng)該已經(jīng)確認(rèn)了三件事Key 有效、Base URL 正確、流式通道可用。這是 TUI 應(yīng)用開發(fā)的「地基驗(yàn)收」。后面寫界面時(shí)模型調(diào)用部分可以直接復(fù)用這兩個(gè)腳本的邏輯。建議把驗(yàn)證腳本保留在項(xiàng)目里作為npm run check命令// package.json { scripts: { check: ts-node src/check-connection.ts, check:stream: ts-node src/check-stream.ts } }每次換 Key、換模型、換網(wǎng)絡(luò)環(huán)境后跑一遍能快速定位問題。5. 常見報(bào)錯(cuò)排查401、local proxy failed、reading choices、OAuth接入階段最容易踩的坑集中在四類報(bào)錯(cuò)。這一節(jié)按真實(shí)錯(cuò)誤信息逐個(gè)拆解給出定位思路和修復(fù)方法。5.1 401 Unauthorized完整報(bào)錯(cuò)通常長(zhǎng)這樣狀態(tài)碼: 401 響應(yīng)體: {error:{message:Invalid API key,type:invalid_request_error}}原因有四種按概率排序第一Key 沒讀到。檢查.env文件是否在項(xiàng)目根目錄dotenv.config()是否在讀取環(huán)境變量之前調(diào)用??梢栽谀_本開頭打印API_KEY.slice(0, 8)確認(rèn)前幾位是否正確。第二Key 復(fù)制時(shí)帶了空格或換行。用trim()清理const API_KEY (process.env.TAOTOKEN_API_KEY || ).trim();第三請(qǐng)求頭格式錯(cuò)誤。必須是Authorization: Bearer sk-xxxBearer和 Key 之間有一個(gè)空格不能少也不能多。第四Key 已失效或被刪除。去控制臺(tái)重新創(chuàng)建一個(gè)。5.2 local proxy failed這個(gè)報(bào)錯(cuò)通常出現(xiàn)在有本地網(wǎng)絡(luò)代理配置的環(huán)境里Error: connect ECONNREFUSED 127.0.0.1:7890 local proxy failed意思是代碼嘗試走本地代理端口但那個(gè)端口沒有服務(wù)在監(jiān)聽。排查步驟先檢查環(huán)境變量里有沒有代理配置echo $HTTP_PROXY echo $HTTPS_PROXY echo $ALL_PROXY如果有值但代理服務(wù)沒開要么啟動(dòng)代理服務(wù)要么清掉這些變量unset HTTP_PROXY HTTPS_PROXY ALL_PROXY在 Node.js 代碼里axios 默認(rèn)會(huì)讀取這些環(huán)境變量。如果不想讓它走代理可以顯式配置const response await axios.post(url, data, { headers: { ... }, proxy: false // 禁用代理 });注意這里說的代理是本地網(wǎng)絡(luò)配置層面的和訪問外部服務(wù)無關(guān)。核心是讓請(qǐng)求走正確的網(wǎng)絡(luò)路徑。5.3 reading choices 或 Cannot read properties of undefined完整報(bào)錯(cuò)TypeError: Cannot read properties of undefined (reading choices)這幾乎總是因?yàn)轫憫?yīng)結(jié)構(gòu)和你預(yù)期的不一樣。常見原因第一請(qǐng)求失敗但沒拋異常返回的是錯(cuò)誤對(duì)象。加一層防御const choices response.data?.choices; if (!Array.isArray(choices) || choices.length 0) { console.error(響應(yīng)結(jié)構(gòu)異常:, JSON.stringify(response.data)); return; } const content choices[0]?.message?.content;第二流式響應(yīng)被當(dāng)成非流式解析。流式返回的是 SSE 文本流沒有choices數(shù)組要按data:行解析。第三模型返回了tool_calls而不是content。如果消息里包含工具調(diào)用message.content可能是 null實(shí)際內(nèi)容在message.tool_calls里。這時(shí)候要判斷const message choices[0]?.message; if (message?.tool_calls) { console.log(模型請(qǐng)求調(diào)用工具:, message.tool_calls); } else { console.log(message?.content); }5.4 OAuth 相關(guān)報(bào)錯(cuò)如果你用的是 Claude Code 這類工具可能遇到OAuth token expired Failed to authenticate: invalid_grant這類報(bào)錯(cuò)和 API Key 模式不同它走的是 OAuth 授權(quán)流程。排查思路第一確認(rèn)你用的是 API Key 模式還是 OAuth 模式。如果用統(tǒng)一 Key 接入應(yīng)該在配置里指定apiKey而不是走 OAuth 登錄。第二檢查配置文件路徑是否正確。Claude Code 的配置通常在~/.claude/settings.json項(xiàng)目級(jí)配置在.claude/settings.json。配置里要寫全三件套{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的Key, ANTHROPIC_MODEL: deepseek-flash } }第三如果之前登錄過 OAuth殘留的 token 可能干擾。清理舊的認(rèn)證緩存后重新用 Key 模式配置。5.5 排查速查表報(bào)錯(cuò)最可能原因快速修復(fù)401 UnauthorizedKey 錯(cuò)誤或未讀取檢查 .env、trim、Bearer 格式local proxy failed本地代理端口無服務(wù)unset 代理變量或 proxy:falsereading choices響應(yīng)結(jié)構(gòu)異常加防御判斷、區(qū)分流式/非流式OAuth token expired認(rèn)證模式混用改用 API Key 模式寫全三件套ECONNREFUSED網(wǎng)絡(luò)不通curl 驗(yàn)證、檢查 DNS404 Not Found路徑錯(cuò)誤確認(rèn)是 /v1/chat/completions排查的核心方法論先用 curl 驗(yàn)證通道再用最小代碼驗(yàn)證邏輯最后才懷疑框架。大部分問題出在配置層而不是代碼層。6. 下一步把統(tǒng)一 Key 接入你的 TUI 應(yīng)用到這里第一章的目標(biāo)已經(jīng)達(dá)成理解了 TUI 是什么、為什么 AI 時(shí)代它復(fù)興、環(huán)境怎么檢查、統(tǒng)一 Key 怎么配、請(qǐng)求怎么驗(yàn)證、報(bào)錯(cuò)怎么排查。接下來你要做的是把這條通道接進(jìn)真正的 TUI 應(yīng)用。第 2 章會(huì)講終端基礎(chǔ)——ANSI 轉(zhuǎn)義碼、原始模式、終端能力檢測(cè)這些是渲染界面的底層。第 3 章開始選框架blessed、ink、Ratatui 各有適用場(chǎng)景我會(huì)給出選擇指南和完整配置。如果你現(xiàn)在就想動(dòng)手建議先把本章的兩個(gè)驗(yàn)證腳本跑通然后嘗試改一下messages內(nèi)容觀察返回變化。再試著把stream從false改成true感受流式和非流式的差異。這個(gè)體感很重要因?yàn)楹竺嫠?TUI 交互設(shè)計(jì)都圍繞流式展開。需要長(zhǎng)期做 AI 編碼和 Agent 開發(fā)的話可以了解 Coding Plan它把模型調(diào)用和開發(fā)工作流整合在一起適合持續(xù)性的項(xiàng)目https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content想直接在瀏覽器里試模型對(duì)話、驗(yàn)證不同 Model ID 的效果用模型對(duì)話頁面最方便https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content管理和創(chuàng)建 API Key 在控制臺(tái)https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Keys 快捷入口https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文檔在這里遇到參數(shù)問題先查文檔https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你用 Claude Code它的接入配置參考這個(gè)頁面https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content最后給一個(gè)實(shí)用建議把本章的check-connection.ts和check-stream.ts當(dāng)成項(xiàng)目的「健康檢查」保留下來。每次環(huán)境變動(dòng)、換 Key、換模型后跑一遍比在復(fù)雜 TUI 代碼里 debug 快得多。下一章我們進(jìn)入終端控制開始真正畫界面。