1. 为什么新闻阅读 App 需要 AI 摘要,以及这套骨架解决什么问题
用开源框架搭一个简约新闻阅读 App,核心诉求通常就两个:界面干净、阅读高效。但真正动手之后你会发现,用户点进一篇长文,滑三屏还没看到重点,跳出率立刻上去。这时候给列表页或详情页加一个「AI 摘要」按钮,把千字长文压成三五行要点,体验提升非常直接。
问题在于,AI 摘要要调用大模型,而大模型接入这件事本身挺碎:不同厂商的 Key 格式不一样,有的走 OpenAI 兼容协议,有的要单独 SDK;本地开发时你还得在多个工具之间来回切 Key。我这次的做法是,用 TaoToken 作为统一的 Key/API 通道,把摘要能力接进 App 的后端服务里,前端只调自己后端的/api/summary,不直接碰模型。
这篇要交付的东西很具体:一份可复制的settings.json和config.toml配置骨架,CC Switch 与 Cline 两个工具的接入步骤,以及一次摘要请求的完整验证动作。适合正在用 Flutter / Node.js 这类开源栈做新闻 App、想快速跑通 AI 摘要链路的开发者。读完你能拿到一套能直接改改就用的配置,而不是又一篇讲概念的概述。
先说清楚整体链路,避免后面配置时迷路:
Flutter App(列表/详情页) ↓ HTTP Node.js Express 后端 /api/summary ↓ OpenAI 兼容协议 TaoToken 统一 API 通道 ↓ 大模型返回摘要文本前端不持有任何模型 Key,Key 只存在于后端环境变量或本地配置文件里。这样即使 App 打包分发,也不会把凭证泄露出去。下面按这个链路一步步搭。
2. TaoToken 前置准备:拿 Key、认清两个地址
在写任何配置之前,先把凭证和地址准备好。TaoToken 在这里扮演的是统一入口:你只需要一个 Key,就能通过 OpenAI 兼容的方式调用背后的模型,不用为每个模型单独维护一套鉴权逻辑。
第一步,打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册并登录。然后在控制台里创建一个 API Key。创建入口在 console 页面:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,Key 的管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
这里有个容易踩的点:Key 只在创建时完整显示一次,关掉弹窗就再也看不到全量字符串了。所以创建完立刻复制,存进密码管理器或者本地.env文件,别截图发聊天窗口。
第二步,记住两个地址的区别,很多人第一次会搞混:
| 用途 | 地址 | 说明 |
|---|---|---|
| 官网/控制台 | https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= | 注册、充值、看用量 |
| API 基址 | https://taotoken.net/api | 代码里填的 base_url,不带 UTM |
注意 API 基址后面不要再加/v1之类的后缀去猜,具体路径以接入文档为准。文档地址:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。如果你用的是 Claude Code 这类工具,对应的接入说明在 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
第三步,确认你要用哪个模型做摘要。摘要任务对模型要求不高,选一个响应快、成本低的就行。具体模型名以模型对话页面里列出的为准:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。别凭记忆写模型名,写错了会直接报 404 或 model not found。
提示:本地开发阶段,建议把 Key 放在项目根目录的
.env里,并确保.gitignore已经包含.env。我见过太多人第一次提交就把 Key 推上去了。
3. 可复制配置骨架:settings.json 与 config.toml
这一节是全文的核心交付。两个配置文件分别对应不同的工具链:settings.json给 Cline 这类 VS Code 插件用,config.toml给 CC Switch 这类需要 TOML 配置的工具用。你可以按自己实际用的工具挑一个,也可以两个都留着。
3.1 settings.json 骨架
Cline 的配置走 JSON,核心是把 provider 指向 OpenAI 兼容模式,base_url 填 TaoToken 的 API 地址。下面这份可以直接复制,把YOUR_TAOTOKEN_KEY和模型名替换掉:
{ "cline.apiProvider": "openai", "cline.openAiApiKey": "YOUR_TAOTOKEN_KEY", "cline.openAiBaseUrl": "https://taotoken.net/api", "cline.openAiModelId": "你的摘要模型名", "cline.openAiModelInfo": { "maxTokens": 4096, "contextWindow": 128000, "supportsImages": false }, "cline.temperature": 0.3, "cline.requestTimeout": 60000 }几个参数值得解释一下。temperature设成 0.3 是因为摘要要的是稳定、忠实原文,不需要发散;设太高模型会自己加戏。requestTimeout给到 60 秒,长文摘要偶尔会慢一点,超时太短会误报失败。supportsImages设 false,因为纯文本摘要用不上多模态,关掉能省一点开销。
3.2 config.toml 骨架
CC Switch 用的是 TOML 格式,结构上更清晰一些。同样替换占位符即可:
[provider] name = "taotoken" api_base = "https://taotoken.net/api" api_key = "YOUR_TAOTOKEN_KEY" protocol = "openai-compatible" [model] id = "你的摘要模型名" max_tokens = 4096 temperature = 0.3 [request] timeout_ms = 60000 retry = 2 retry_delay_ms = 1500 [summary] system_prompt = "你是一个新闻摘要助手。请用不超过120字概括以下新闻的核心事实,保留关键人物、时间、地点,不要加入评论。" max_input_chars = 8000[summary]这一段是我专门为新闻场景加的。system_prompt把输出约束在 120 字以内,前端展示时不会撑破卡片;max_input_chars限制输入长度,超长文章先截断再送,避免一次请求烧掉太多 token。retry = 2是应对偶发的网络抖动,重试两次基本能覆盖大部分瞬时失败。
注意:两个配置里的
api_base都只写到https://taotoken.net/api,不要自己拼/v1/chat/completions这种路径。工具内部会按协议补全,你多写一段反而会 404。
3.3 后端服务里的环境变量
前端 App 不直接读上面两个文件,真正调用发生在你的 Node.js 后端。所以后端还需要一份环境变量:
# .env TAOTOKEN_API_KEY=YOUR_TAOTOKEN_KEY TAOTOKEN_BASE_URL=https://taotoken.net/api SUMMARY_MODEL=你的摘要模型名后端读取时用process.env.TAOTOKEN_API_KEY,这样配置和代码分离,换 Key 不用改代码。下面一节就把这个后端接口写出来。
4. 接入步骤:CC Switch 与 Cline 怎么配
配置骨架有了,接下来是把它落到具体工具里。两个工具的接入路径不太一样,分开说。
4.1 Cline 接入步骤
Cline 是 VS Code 里的编码助手插件,配好之后你可以在编辑器里直接让它帮你写摘要接口的代码,也能用它测试模型连通性。
打开 VS Code,安装 Cline 插件后,点侧边栏的 Cline 图标进入设置。在 API Provider 下拉里选OpenAI Compatible,然后把上面settings.json里的字段对应填进去:API Key 填你的 TaoToken Key,Base URL 填https://taotoken.net/api,Model ID 填模型名。
填完点保存,Cline 会做一次连通性检查。如果状态变成绿色可用,说明通道通了。这一步失败的话,九成是 Base URL 多写了路径,或者 Key 前后带了空格。
4.2 CC Switch 接入步骤
CC Switch 走的是 TOML 配置。把上面config.toml的内容写进它的配置文件路径(具体路径看工具文档,通常在用户目录下的配置文件夹里),保存后重启工具让它重新加载。
重启后,在 CC Switch 里发起一次测试对话,输入「用一句话说明你是什么模型」。能正常返回就说明[provider]和[model]两段配对了。如果报鉴权错误,检查api_key是否被引号包住、有没有多余换行。
4.3 后端摘要接口实现
工具配好只是方便你开发,真正给 App 用的是后端接口。用 Express 写一个最小可用的/api/summary:
// server.js import express from "express"; import fetch from "node-fetch"; const app = express(); app.use(express.json()); const BASE_URL = process.env.TAOTOKEN_BASE_URL; const API_KEY = process.env.TAOTOKEN_API_KEY; const MODEL = process.env.SUMMARY_MODEL; app.post("/api/summary", async (req, res) => { const { content } = req.body; if (!content || content.length < 50) { return res.status(400).json({ error: "content too short" }); } const trimmed = content.slice(0, 8000); try { const resp = await fetch(`${BASE_URL}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}`, }, body: JSON.stringify({ model: MODEL, temperature: 0.3, max_tokens: 512, messages: [ { role: "system", content: "你是一个新闻摘要助手。请用不超过120字概括以下新闻的核心事实,保留关键人物、时间、地点,不要加入评论。", }, { role: "user", content: trimmed }, ], }), }); if (!resp.ok) { const errText = await resp.text(); return res.status(502).json({ error: "upstream failed", detail: errText }); } const data = await resp.json(); const summary = data.choices?.[0]?.message?.content ?? ""; res.json({ summary }); } catch (e) { res.status(500).json({ error: e.message }); } }); app.listen(3000, () => console.log("summary service on :3000"));这段代码的关键点:Key 从环境变量读,不硬编码;输入截断到 8000 字符;上游失败时把原始错误透传出来方便排查,而不是吞掉。前端 Flutter 侧只需要 POST 文章正文到这个接口,拿summary字段渲染即可。
5. 验证请求:一次摘要调用跑通全链路
配置写完必须验证,否则你不知道是配置错了还是代码错了。验证分两步:先用 curl 直接打后端,确认后端逻辑没问题;再用 curl 直接打 TaoToken,确认通道没问题。
5.1 验证后端接口
启动服务后,用 curl 发一篇测试文本:
curl -X POST http://localhost:3000/api/summary \ -H "Content-Type: application/json" \ -d '{"content":"某开源社区今日发布了新一代跨平台 UI 框架的稳定版本,该版本重构了渲染管线,官方称在低端设备上的首屏渲染时间平均缩短约三成。团队同时公布了未来半年的路线图,重点包括无障碍支持和多语言排版优化。"}'预期返回类似:
{ "summary": "某开源社区发布跨平台 UI 框架稳定版,重构渲染管线,低端设备首屏渲染时间平均缩短约三成,并公布未来半年路线图,重点为无障碍支持与多语言排版优化。" }拿到这段 JSON,说明后端到模型的整条链路是通的。如果返回 502,看detail字段里的上游报错;如果返回 500,多半是环境变量没加载。
5.2 直接验证 TaoToken 通道
想确认问题出在通道还是代码,绕过后端直接打 API:
curl -X POST https://taotoken.net/api/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -d '{ "model": "'"$SUMMARY_MODEL"'", "messages": [{"role": "user", "content": "回复两个字:通了"}], "max_tokens": 16 }'能返回内容就说明 Key 和地址都对。这一步通了但后端不通,问题一定在你的服务代码或环境变量上,排查范围立刻缩小。
5.3 前端联调
Flutter 侧用 Dio 发请求,注意 Android 模拟器访问本机要用10.0.2.2而不是localhost:
final resp = await Dio().post( 'http://10.0.2.2:3000/api/summary', data: {'content': articleBody}, ); final summary = resp.data['summary'];拿到summary后渲染到详情页顶部的摘要卡片里,整个 AI 摘要功能就算跑通了。
6. 本篇常见错排查
配置和验证过程中,下面这几个错误出现频率最高,基本覆盖了 90% 的失败场景。
401 Unauthorized:Key 错了或没带上。检查Authorization头是不是Bearer加 Key,中间有一个空格;检查 Key 有没有复制时漏掉尾部字符。如果用的是 Cline,去设置里重新粘贴一次 Key。
404 Not Found:Base URL 写多了路径。https://taotoken.net/api后面不要再加/v1或/chat/completions,工具会自己补。这个错误我踩过,改了半天代码才发现是地址多写了一截。
model not found:模型名写错或该模型当前不可用。去模型对话页面确认可用模型列表,复制准确名称。别用记忆里的名字。
请求超时:长文摘要耗时较长,把timeout_ms或requestTimeout调到 60000 以上。同时确认max_input_chars没有设得过大,输入越长响应越慢。
返回内容为空:检查max_tokens是不是设得太小,比如设成 16 时模型可能还没输出完整就被截断。摘要场景建议至少 256。
中文乱码:确认请求头Content-Type: application/json带了charset=utf-8,Node.js 侧express.json()默认按 UTF-8 解析,一般不会出问题,但 Flutter 侧要确保字符串编码正确。
提示:排查时养成「先直连 API、再查后端、最后看前端」的顺序。从最内层往外层查,能最快定位问题在哪一段。
如果你在接入过程中卡在鉴权或路径问题上,直接翻接入文档比反复试错快得多:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。需要管理或新建 Key 就去 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。想先在网页里试模型效果、确认摘要质量再写代码,用模型对话页面最省事:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
最后说个实际经验:摘要的 system prompt 值得多调几轮。我一开始没限制字数,模型有时输出两百多字,卡片直接撑爆;加上「不超过120字」之后稳定多了。另外新闻类内容建议在 prompt 里明确「保留时间、地点、人物」,否则模型容易把关键事实压掉,只剩一句泛泛的概括,用户看了等于没看。