☰
大模型赋能前端开发:用Claude Code手搓Presentation Agent,TaoToken配置与踩坑全记录
2026/9/26 4:01:59 网站建设 项目流程

1. 从零手搓 Presentation Agent,我到底卡在哪

先说结论:用 Claude Code 做一个能跑通的 Presentation Agent,前端部分几乎可以端到端交给模型,真正拖慢进度的是三件事——Key 管理混乱、Agent 上下文失控、生成结果没法自动评估。这篇就把这三件事拆开讲,给你一份能直接复制的 settings.json 骨架,以及一套可复现的验证动作。

Presentation Agent 是什么?简单说,用户输入一句「帮我做一个关于新能源汽车出海趋势的演示」,Agent 自动完成大纲生成、内容检索、页面渲染,最后吐出一套可翻页的 HTML 演示页面。它和传统 PPT 生成最大的区别是:不生成 .pptx 文件,而是直接生成网页,靠浏览器翻页。这样做的好处是排版自由度高、移动端适配容易、部署就是静态托管。

适合谁看?三类人:一是想用 Claude Code 做前端 Agent 但被配置卡住的开发者;二是已经在写 Agent 但 token 消耗失控、想找优化思路的人;三是想理解「代码工具 + 大模型」这套组合拳到底能省多少工程量的技术负责人。

我自己的落地链路是这样的:Claude Code 负责写代码和调 prompt,TaoToken 提供统一的模型接入 Key,settings.json 管住工具链和权限边界,最后用三个 Agent(Outline / Search / HTML)串成 workflow。下面按这个顺序展开,每一步都给可复制的配置和验证命令。

2. TaoToken 前置:统一 Key 接入与项目初始化

在动手写 Agent 之前,先把模型接入这层理顺。我踩过的第一个坑就是:一开始每个 Agent 各写一套请求逻辑,Key 散落在环境变量、配置文件、甚至硬编码里,改一次模型要翻五个文件。后来统一走 TaoToken 的 API 网关,所有 Agent 共用一个 base_url 和一个 Key,切换模型只改一个字段。

TaoToken 在这里扮演的角色是「统一入口」:它兼容 OpenAI 风格的接口协议,所以 Claude Code 生成的代码里,只要把 base_url 指向https://taotoken.net/api,再用标准的 chat completions 调用方式,就能对接上。你不需要为每个模型单独写适配层。

第一步,去控制台创建一个 API Key。地址是 https://taotoken.net/api-keys ,登录后新建 Key,复制出来。注意这个 Key 只在创建时完整显示一次,丢了就得重建。

第二步,把 Key 写进项目根目录的.env文件,不要提交到 git:

# .env TAOTOKEN_API_KEY=sk-你的key TAOTOKEN_BASE_URL=https://taotoken.net/api

第三步,在.gitignore里加上.env,这一步很多人会忘,一旦 Key 推到公开仓库,基本等于报废。

# .gitignore .env node_modules/ dist/

第四步,验证 Key 是否可用。用 curl 发一个最小请求,确认能拿到返回:

curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "回复 OK 两个字母"}], "max_tokens": 16 }'

如果返回里有choices[0].message.content,说明接入通了。如果返回 401,检查 Key 有没有多余空格;返回 404,检查 base_url 是不是写成了带/v1的旧格式——TaoToken 的路径就是/api/chat/completions,不要自己加/v1。

提示:把 base_url 和 Key 都放进环境变量,代码里用process.env.TAOTOKEN_BASE_URL读取。这样本地、CI、线上三套环境可以共用一份代码,只换环境变量。

3. 可复制配置:settings.json 骨架与工具链

Claude Code 的 settings.json 是整个项目的控制中枢,它决定了模型能用哪些工具、能读写哪些目录、单次会话的 token 上限。我最初的版本几乎是空的,结果 Claude Code 在生成代码时反复去读 node_modules,白白烧掉大量 token。下面这份是我调了多轮之后稳定下来的骨架。

{ "model": "claude-sonnet-4-20250514", "env": { "TAOTOKEN_API_KEY": "${TAOTOKEN_API_KEY}", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" }, "permissions": { "allow": [ "Read(src/**)", "Read(prompts/**)", "Write(src/**)", "Write(prompts/**)", "Bash(npm run build)", "Bash(npm run test)" ], "deny": [ "Read(node_modules/**)", "Read(.env)", "Write(.env)", "Bash(rm -rf *)" ] }, "tools": { "search": { "provider": "serper", "maxCalls": 8 }, "fetch": { "maxCalls": 12, "maxContentLength": 8000 } }, "limits": { "maxAgentTurns": 6, "maxTokensPerSession": 200000 } }

几个关键点解释一下。permissions.deny里把node_modules和.env挡掉,是防止模型在探索代码库时把无关文件读进来,这一条直接把我单次会话的输入 token 砍掉了将近四成。tools.fetch.maxContentLength限制单页抓取长度,避免一个长网页把上下文撑爆。limits.maxAgentTurns是防死循环的保险丝,Agent 在搜索和抓取之间来回横跳时,超过 6 轮就强制停。

工具链这边,我用了两个外部工具:搜索走 serper.dev,抓取走一个 MCP fetch 工具。MCP 的配置放在项目根目录的.mcp.json:

{ "mcpServers": { "fetch": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fetch"], "env": { "MAX_CONTENT_LENGTH": "8000" } } } }

配好之后,Claude Code 启动时会自动加载这个 MCP server,Agent 就能通过标准接口调用 fetch。这里有个坑:MCP server 首次启动要下载依赖,如果网络慢会卡住,建议先在终端手动跑一次npx -y @modelcontextprotocol/server-fetch把包缓存下来。

注意:settings.json 里的${TAOTOKEN_API_KEY}是引用系统环境变量,不是字面量。如果你直接写死 Key,一旦这个文件被分享出去就泄露了。

4. 验证请求:三个 Agent 的串联与成功结果

配置就绪后,开始写 Agent 主流程。我的设计是三个 Agent 串行加并行混合:Outline Agent 先跑,产出结构化大纲;Search Agent 按大纲的每个子主题并行执行;HTML Agent 拿到全部内容后生成页面。

先看 Outline Agent 的核心 prompt。这里用 JSON schema 约束输出,方便后续解析:

OUTLINE_PROMPT = """ 你的任务是根据用户描述生成演示大纲。 大纲包含 {num_topics} 个子主题,每个子主题包含 3-5 个要点。 要求: - 如果涉及时效性信息,使用搜索工具获取最新内容 - 搜索到链接后,可用 fetch 工具阅读详情 - 最终必须返回符合以下 schema 的 JSON: {schema} """

调用时把Outline.model_json_schema()塞进{schema}占位符。实测下来,加了 schema 约束之后,模型返回非法 JSON 的概率从大概三成降到几乎为零。

Search Agent 并行执行的部分,用 asyncio 控制:

import asyncio async def run_search_agents(topics): tasks = [search_one(topic) for topic in topics] results = await asyncio.gather(*tasks, return_exceptions=True) return [r for r in results if not isinstance(r, Exception)]

每个search_one内部限制最多 3 次搜索加 4 次 fetch,超过就返回已有内容。这个限制很关键,不加的话单个 Agent 能把 token 烧到失控。

HTML Agent 内部再分四步:主题样式设计、封面页、目录页、内容页。样式设计先产出一份 CSS 变量表,后面所有页面复用,保证视觉一致:

:root { --primary: #2563eb; --bg: #0f172a; --text: #e2e8f0; --radius: 12px; }

验证成功的标志是什么?跑完一次完整流程后,你应该得到:一个outline.json(含 5 个子主题)、五个content-*.json(每个含要点和配图链接)、一个index.html(能在浏览器打开并翻页)。我用一个「2025 新能源汽车出海」的输入实测,从触发到生成完毕大约 90 秒,消耗约 180K token,其中输入占七成。

如果你想先单独验证模型对话链路是否通,可以直接用模型对话页面发一条测试消息,确认返回正常再跑完整 Agent。地址是 https://taotoken.net/chat 。

5. 本篇常见错排查

这一节把我实际撞过的报错按现象归类,你遇到时可以直接对号入座。

报错一:401 Unauthorized。九成是 Key 问题。先确认.env里的 Key 没有首尾空格,再确认代码读取环境变量的时机——如果你在模块顶层就读了process.env,而 dotenv 还没加载,拿到的就是 undefined。把dotenv.config()放到所有 import 之前。

报错二:Agent 陷入搜索死循环。现象是 token 飞快消耗但迟迟不返回。原因是 prompt 里没给终止条件。解决方法是双保险:prompt 里写明「最多搜索 3 次」,代码里用maxAgentTurns硬截断。我试过只靠 prompt 约束,模型偶尔会无视,加上代码层截断才彻底稳住。

报错三:生成的 HTML 图片全部裂开。因为 Search Agent 返回的是外链,源站做了防盗链或者链接过期。两个解法:一是把图片下载到本地public/images/再引用相对路径;二是至少加referrerpolicy="no-referrer"和onerror兜底。我后来选了下载到本地,顺便还能拿到图片真实尺寸,排版时能提前预留位置。

报错四:内容页布局错位。典型表现是文字溢出容器或者图片被截断。根因是没限制页面尺寸。给每个内容页加固定宽高比容器,内部用 flex 布局,超出部分用overflow: hidden加省略号。别指望模型一次生成完美布局,先保证不崩,再谈美观。

报错五:MCP fetch 工具调用超时。检查.mcp.json里的 command 路径是否正确,以及 npx 能否正常拉包。如果公司网络有限制,先在本地把包装好,再把 command 改成绝对路径。

报错六:不同 Agent 重复抓同一个来源。这是并行执行的副作用。缓解办法是在 Search Agent 之间共享一个已访问 URL 集合,抓之前先查重。更彻底的做法是先用一个 Agent 做全局信息收集,再分发给下游,但那样对单 Agent 能力要求更高。

提示:排查 token 异常时,用 claude-monitor 这类工具看实时用量,能快速定位是哪个 Agent 在烧钱。我最初就是靠它发现 Search Agent 的输入 token 占了总量的七成。

6. 语义一致收尾:把这条链路跑成你自己的

整套流程跑通之后,你会发现真正省时间的不是「模型帮你写代码」,而是「模型帮你把不熟悉的领域趟平」。前端我不算熟,但靠 Claude Code 端到端生成,从零到部署上线也就断断续续花了一个多月,其中大部分时间是在调 prompt 和排查上面那些报错。

如果你打算复现,建议按这个顺序推进:先把 TaoToken 的 Key 和 base_url 配好,用 curl 验证通;再把 settings.json 和 .mcp.json 落地,确认权限和工具链生效;然后单独跑 Outline Agent,确认 JSON 输出稳定;最后再串 Search 和 HTML。每一步都验证过再往下走,比一口气写完再调试省事得多。

长期做编码类 Agent 的话,可以考虑 Coding Plan 这类按周期计费的方案,比按量付费在密集开发期更划算,具体在 https://taotoken.net/coding-plan 看。接入文档在 https://taotoken.net/doc ,里面把接口参数和错误码列得比较全,排障时对着查比瞎猜快。

最后留一句实在话:Agent 的输出质量,七分靠上下文管理,三分靠模型能力。你把 settings.json 的权限边界收窄、把 prompt 的终止条件写死、把工具调用次数卡住,效果自然就稳了。剩下的美学问题,那是另一个战场。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询