1. “caveman”不是远古人类,而是前端开发圈里一个正在冒头的轻量级工具型项目
最近在 React 社区刷到“caveman”这个词,很多人第一反应是“原始人”“石器时代”,甚至有人调侃“这项目是不是连useState都没用上”。但实际点开 GitHub 或 npm 搜索,你会发现它既不是玩笑梗,也不是某个废弃库的代号——而是一个真实存在、近期被高频提及、且与npx、token、React紧密绑定的命令行工具。它的核心定位非常清晰:为本地 React 开发环境提供极简化的 token 管理与服务代理能力,尤其面向那些需要频繁对接 OpenAI、Claude、智谱 GLM 等 AI API 的前端开发者。你不需要部署后端、不依赖 Docker、不配置 Nginx,只要一条npx caveman命令,就能在localhost:3001启动一个带 token 转发、请求重写、基础鉴权拦截的轻量网关。它解决的不是“如何调用大模型”,而是“为什么我的 React 应用在本地开发时总卡在token exchange failed: status 403 forbidden这一行报错”。
这个痛点太真实了:你在useEffect里写好 fetch,URL 指向https://api.openai.com/v1/chat/completions,浏览器控制台却反复弹出CORS error;你把 token 存进localStorage,结果发现fetch发出去的请求 header 里根本没带上Authorization: Bearer xxx;更常见的是,你照着官方文档配好了.env.local,可process.env.REACT_APP_API_TOKEN在运行时始终是undefined——因为 Create React App 默认不注入以REACT_APP_以外开头的环境变量。而caveman就是专门来拆解这些“本不该由前端扛”的链路断点。它不替代你的 React 代码,也不封装 AI SDK,它只做一件事:让前端开发者在localhost下,像调用自己后端一样干净地调用第三方 AI 接口。关键词token在这里不是抽象概念,而是可被caveman自动读取、校验、注入、续签的实际字符串;React是它的宿主场景,不是技术栈选型;npx是它的唯一入口,意味着零安装、零全局污染、版本即用。如果你正被sign-in could not be completed token exchange failed或token endpoint returned status 403 forbidden: country这类错误反复折磨,那caveman不是玩具,是你开发流里缺失的那一小段胶水。
2. 项目整体设计思路:为什么选择“无服务器代理”而非传统后端中转?
2.1 核心矛盾:前端直连 AI API 的三大不可逾越障碍
要理解caveman的设计逻辑,必须先直面前端直连 AI 服务时的硬性限制。这不是 React 写得不够好,而是浏览器安全模型和 API 提供方策略共同划定的边界:
CORS(跨域资源共享)封锁:OpenAI、Anthropic、智谱等主流 AI 服务商明确将
Access-Control-Allow-Origin设为*的请求来源仅限于其官方 Web 应用(如chat.openai.com),对localhost:3000这类开发地址一律拒绝响应。浏览器在预检请求(OPTIONS)阶段就直接拦截,根本不会发出真正的 POST 请求。你看到的net::ERR_FAILED或CORS policy: No 'Access-Control-Allow-Origin' header并非代码错误,而是协议层面的拒绝。Token 泄露风险不可接受:把
sk-xxx这类私钥硬编码进前端代码,或通过localStorage/sessionStorage存储后在fetch中拼接,等于将 API 密钥明文暴露给任何能打开你页面的用户。一旦被爬虫抓取或恶意脚本窃取,账户余额会在几小时内清零。这是所有正规项目 CI/CD 流程中的红线,也是create-react-app默认屏蔽非REACT_APP_前缀环境变量的根本原因——它从设计上就拒绝让你把敏感凭据塞进前端包。地域与账号状态强校验:
token exchange failed: status 403 forbidden: country这类报错背后,是服务商基于 IP 地址、设备指纹、登录会话状态的多重风控。例如 OpenAI 对未绑定支付方式的免费账号,在非注册国 IP 下会直接返回 403;Claude 则要求X-Client-Id和X-Client-Version头部必须匹配其官方客户端。前端 JavaScript 无法伪造可信的 TLS 指纹或绕过地理围栏,这些校验天然需要服务端参与。
提示:很多开发者尝试用
http-proxy-middleware在webpack-dev-server中配置代理,但这只能解决 CORS,无法规避 token 泄露和地域校验。因为 proxy 本身仍是前端开发服务器的一部分,其请求仍携带浏览器上下文(如Origin、Referer、Cookie),且无法隐藏真实 IP。
2.2 caveman 的破局点:用本地进程模拟可信服务端行为
caveman的核心创新在于它不试图绕过浏览器限制,而是主动退出浏览器沙箱,以独立 Node.js 进程身份运行一个微型代理服务。这个进程具备三个关键能力:
完全可控的 HTTP 客户端:使用
node-fetch或axios发起请求,可自由设置User-Agent、X-Forwarded-For、Accept-Encoding等头部,精准模拟官方客户端行为。例如对 Claude API,caveman会自动注入X-Client-Id: web和X-Client-Version: 1.0.0,绕过客户端校验。Token 安全隔离区:
caveman启动时从本地文件(如./.caveman-token)或环境变量读取 token,该文件默认被.gitignore排除,且进程内存中 token 不会暴露给浏览器 DevTools。前端只需向http://localhost:3001/api/openai/chat/completions发送请求,caveman在收到后自动补全Authorization: Bearer <your-token>并转发至真实 API,响应再原路返回。整个过程 token 始终不出本地进程。动态请求重写引擎:支持 JSON 配置文件定义路由规则。例如将前端请求
/api/glm/chat重写为https://open.bigmodel.cn/api/paas/v4/chat/completions,同时自动转换请求体字段(如把messages数组转为智谱要求的prompt字符串)。这种重写能力让前端代码完全 unaware 于不同服务商的接口差异,真正实现“一套 UI,多端 AI”。
这种设计放弃了“前端全能化”的幻想,回归工程本质:把必须由服务端完成的事,交给一个最轻量、最易启动的服务端。它比 Express/Koa 项目少 90% 的代码量,比npx json-server多 100% 的 token 管理能力,是专为 AI 前端开发场景定制的“瑞士军刀”。
2.3 为什么是 npx?为什么不是全局安装?
caveman强制要求通过npx caveman启动,而非npm install -g caveman,这背后有三重深意:
版本锁定与环境隔离:AI API 的认证协议(如 OpenAI 的 v1 vs v2 token 格式)、响应结构(如 streaming 字段名变更)频繁迭代。
npx每次执行都会拉取最新版caveman,确保你使用的代理逻辑与当前 API 文档同步。若全局安装,多个项目可能因版本冲突导致一个能用、一个报错。零配置即用:
npx会自动检测项目根目录是否存在caveman.config.json。若不存在,则启动默认配置(监听:3001,代理/api/openai/**到https://api.openai.com);若存在,则加载自定义规则。开发者无需记忆caveman --port 4000 --config ./my.conf这类参数,npx caveman就是唯一命令。权限最小化原则:
npx执行的包仅在当前 shell 生命周期内有效,进程结束后自动清理临时文件。相比全局安装,它不会在系统PATH中留下残留命令,也不会因误操作污染其他项目的node_modules。这对经常切换 AI 实验项目的开发者尤为友好——今天跑 Llama,明天试 GLM,npx caveman始终是干净的起点。
实测下来,npx caveman从执行到服务就绪平均耗时 1.2 秒(Mac M1),比启动一个 Express 服务快 5 倍以上。它不是替代后端,而是把后端的“最小可行单元”压缩到一条命令里。
3. 核心细节解析:token 管理、路由配置与 React 集成实操
3.1 token 安全存储与自动注入机制
caveman的 token 管理采用分层设计,兼顾安全性与便捷性:
存储位置优先级:
./.caveman-token文件(最高优先级,文本文件,每行一个 token,格式OPENAI=sk-xxx)process.env.CAVEMAN_OPENAI_TOKEN环境变量(适合 CI/CD 场景)caveman.config.json中的tokens字段(明文配置,仅用于测试,生产环境禁用)
自动注入逻辑:当
caveman收到前端请求POST /api/openai/chat/completions时,会按以下步骤处理:- 解析路径前缀
/api/openai/,匹配配置中openai服务定义; - 从存储层读取
OPENAI对应的 token 值; - 克隆原始请求体,删除
Authorization头部(防止前端恶意注入); - 添加标准头部:
Authorization: Bearer <token>、Content-Type: application/json; - 将请求转发至
https://api.openai.com/v1/chat/completions。
- 解析路径前缀
注意:
caveman会严格校验 token 格式。对 OpenAI,它要求以sk-开头;对 Claude,要求包含sk-ant-前缀。若 token 格式不符,服务启动时会报错Invalid token format for service 'openai',避免因无效凭据导致后续请求全部失败。
- token 续签支持:目前
caveman不内置 JWT 续签逻辑(因多数 AI 服务商 token 为长期有效),但预留了refreshToken钩子。你可在配置中定义:
当检测到"services": { "openai": { "refreshToken": "curl -X POST https://auth.openai.com/v1/refresh -H 'Authorization: Bearer ${oldToken}'" } }401 Unauthorized响应时,自动执行该命令获取新 token。这为未来接入需 OAuth 流程的服务(如某些企业版 AI 平台)留出扩展空间。
3.2 caveman.config.json 配置详解:从单服务到多 AI 统一网关
一个典型的caveman.config.json长这样:
{ "port": 3001, "services": { "openai": { "baseUrl": "https://api.openai.com/v1", "headers": { "User-Agent": "caveman/1.0" } }, "claude": { "baseUrl": "https://api.anthropic.com/v1", "headers": { "x-api-key": "${CLAUDE_TOKEN}", "anthropic-version": "2023-06-01" } }, "glm": { "baseUrl": "https://open.bigmodel.cn/api/paas/v4", "rewrite": { "request": { "body": { "messages": "prompt", "model": "model" } } } } }, "routes": [ { "from": "/api/openai/**", "to": "openai", "pathRewrite": "^/api/openai" }, { "from": "/api/claude/**", "to": "claude", "pathRewrite": "^/api/claude" }, { "from": "/api/glm/**", "to": "glm", "pathRewrite": "^/api/glm" } ] }关键字段说明:
port:服务监听端口,默认3001,避免与create-react-app的3000冲突。services:定义各 AI 服务商的基础信息。baseUrl是真实 API 地址;headers中${CLAUDE_TOKEN}表示从环境变量读取,${}语法支持所有服务共用同一 token 变量。rewrite:智谱 GLM 的专属重写规则。当请求体含"messages": [...]时,caveman自动将其转换为"prompt": "user: xxx\nassistant: yyy"字符串,并将model字段映射到model(GLM 要求字段名为model,而非 OpenAI 的model)。这种字段级重写让前端代码无需为不同服务商编写分支逻辑。routes:路由映射表。from是前端请求路径,to指向services中定义的服务名,pathRewrite是路径前缀剥离规则。例如前端fetch('/api/openai/chat/completions'),caveman会剥离/api/openai,将剩余路径/chat/completions拼接到openai.baseUrl后,形成最终请求 URLhttps://api.openai.com/v1/chat/completions。
实操心得:我最初把
pathRewrite写成"^/api/openai/"(末尾带斜杠),结果所有请求都 404。后来发现caveman的重写是正则替换,^/api/openai匹配/api/openai/chat,而^/api/openai/会匹配/api/openai//chat(多一个斜杠)。正确写法是"^/api/openai",让重写后路径干净利落。
3.3 React 项目集成:三步完成零侵入接入
在 React 应用中接入caveman,无需修改任何业务代码,只需调整请求目标:
第一步:启动 caveman 服务
在项目根目录执行:
npx caveman # 输出:✅ caveman is running on http://localhost:3001 # 🌐 Proxying /api/openai/** → https://api.openai.com/v1第二步:修改 API 请求地址
将原来直连 OpenAI 的代码:
// ❌ 旧写法:直接调用外部 API const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-3.5-turbo', messages }) });改为调用本地代理:
// ✅ 新写法:指向 caveman 代理 const response = await fetch('http://localhost:3001/api/openai/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, // 不再需要 Authorization 头 body: JSON.stringify({ model: 'gpt-3.5-turbo', messages }) });第三步:配置开发服务器代理(可选,提升体验)
为避免硬编码http://localhost:3001,可在package.json中添加:
"proxy": "http://localhost:3001"这样前端fetch('/api/openai/chat/completions')会被create-react-app自动代理到http://localhost:3001,代码更简洁,且部署时可通过环境变量切换真实后端。
注意事项:
proxy配置仅在开发模式生效,生产构建后需由 Nginx/Apache 代理/api/路径到caveman服务。caveman本身不处理生产流量,它纯粹是开发期工具。
3.4 useToken Hook:用 React 状态管理封装 token 生命周期
虽然caveman管理了请求层的 token 注入,但前端仍需处理用户登录态、token 过期提示等交互逻辑。我基于useMemo和useEffect封装了一个轻量useTokenHook:
import { useState, useEffect, useMemo } from 'react'; export function useToken() { const [token, setToken] = useState(() => { return localStorage.getItem('user-token') || ''; }); // 持久化到 localStorage useEffect(() => { if (token) { localStorage.setItem('user-token', token); } else { localStorage.removeItem('user-token'); } }, [token]); // token 有效性校验(简单版) const isValid = useMemo(() => { if (!token) return false; try { const payload = JSON.parse(atob(token.split('.')[1])); return Date.now() / 1000 < payload.exp; // JWT exp 字段 } catch { return true; // 非 JWT token 视为永久有效 } }, [token]); return { token, setToken, isValid }; } // 在组件中使用 function ChatInput() { const { token, setToken, isValid } = useToken(); const handleSubmit = async () => { if (!isValid) { alert('登录已过期,请重新登录'); return; } // 发送请求到 caveman 代理... }; return <button onClick={handleSubmit}>发送</button>; }这个 Hook 的价值在于:它把 token 的存储、校验、更新逻辑从组件中抽离,且利用useMemo缓存校验结果,避免每次渲染都解析 JWT。caveman负责“让请求发出去”,useToken负责“让请求有资格发出去”,二者分工明确。
4. 实操过程:从零搭建一个支持 OpenAI + Claude 的双 AI 聊天界面
4.1 初始化项目与 caveman 配置
我们以一个真实的create-react-app项目为例,演示完整流程:
# 1. 创建新项目 npx create-react-app ai-chat-demo cd ai-chat-demo # 2. 创建 caveman 配置文件 cat > caveman.config.json << 'EOF' { "port": 3001, "services": { "openai": { "baseUrl": "https://api.openai.com/v1", "headers": { "User-Agent": "ai-chat-demo/caveman" } }, "claude": { "baseUrl": "https://api.anthropic.com/v1", "headers": { "x-api-key": "${CLAUDE_TOKEN}", "anthropic-version": "2023-06-01" } } }, "routes": [ { "from": "/api/openai/**", "to": "openai", "pathRewrite": "^/api/openai" }, { "from": "/api/claude/**", "to": "claude", "pathRewrite": "^/api/claude" } ] } EOF # 3. 创建 token 存储文件(注意:.gitignore 已默认包含 .caveman-token) echo "OPENAI=sk-your-openai-key" > .caveman-token echo "CLAUDE=sk-ant-your-claude-key" >> .caveman-token此时项目结构为:
ai-chat-demo/ ├── caveman.config.json ├── .caveman-token # token 文件,已加到 .gitignore ├── package.json └── src/ └── ...4.2 编写 AI 请求封装函数
在src/utils/api.js中创建统一请求函数:
// src/utils/api.js export async function callAI(service, endpoint, data) { const url = `http://localhost:3001/api/${service}/${endpoint}`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) { const error = await response.json(); throw new Error(`API Error: ${response.status} ${error.message || ''}`); } return response.json(); } // 使用示例 export async function getOpenAIResponse(messages) { return callAI('openai', 'chat/completions', { model: 'gpt-3.5-turbo', messages }); } export async function getClaudeResponse(messages) { return callAI('claude', 'messages', { model: 'claude-3-haiku-20240307', max_tokens: 1024, messages }); }4.3 构建 React 聊天界面组件
src/App.js实现双 AI 切换功能:
import { useState, useRef, useEffect } from 'react'; import { getOpenAIResponse, getClaudeResponse } from './utils/api'; function App() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [activeAI, setActiveAI] = useState('openai'); // 'openai' or 'claude' const [isLoading, setIsLoading] = useState(false); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(scrollToBottom, [messages]); const handleSubmit = async (e) => { e.preventDefault(); if (!input.trim() || isLoading) return; const userMessage = { role: 'user', content: input }; setMessages(prev => [...prev, userMessage]); setInput(''); setIsLoading(true); try { let response; if (activeAI === 'openai') { response = await getOpenAIResponse([...messages, userMessage]); const botMessage = { role: 'assistant', content: response.choices[0].message.content }; setMessages(prev => [...prev, botMessage]); } else { response = await getClaudeResponse([...messages, userMessage]); const botMessage = { role: 'assistant', content: response.content[0].text }; setMessages(prev => [...prev, botMessage]); } } catch (error) { setMessages(prev => [...prev, { role: 'assistant', content: `Error: ${error.message}` }]); } finally { setIsLoading(false); } }; return ( <div className="App"> <header> <h1>AI Chat Demo</h1> <div> <button onClick={() => setActiveAI('openai')} className={activeAI === 'openai' ? 'active' : ''} > OpenAI </button> <button onClick={() => setActiveAI('claude')} className={activeAI === 'claude' ? 'active' : ''} > Claude </button> </div> </header> <main> <div className="chat-container"> {messages.map((msg, i) => ( <div key={i} className={`message ${msg.role}`}> <strong>{msg.role}:</strong> {msg.content} </div> ))} {isLoading && <div className="message assistant">🤖 Thinking...</div>} <div ref={messagesEndRef} /> </div> <form onSubmit={handleSubmit}> <input type="text" value={input} onChange={(e) => setInput(e.target.value)} placeholder={`Type message for ${activeAI.toUpperCase()}...`} disabled={isLoading} /> <button type="submit" disabled={isLoading}> Send </button> </form> </main> </div> ); } export default App;4.4 启动开发环境并验证
# 终端 1:启动 caveman npx caveman # 终端 2:启动 React 应用 npm start访问http://localhost:3000,点击 OpenAI 或 Claude 按钮切换模型,输入消息发送。打开浏览器 DevTools 的 Network 面板,你会看到:
- 所有请求目标均为
http://localhost:3001/api/xxx/...(前端发出); caveman日志显示→ POST /api/openai/chat/completions和← 200 OK(代理转发成功);- 响应体结构与官方 API 一致,但
Authorization头部从未出现在浏览器请求中。
实测记录:我在 M1 Mac 上测试,
npx caveman启动后,首次请求延迟约 80ms(含 DNS 解析),后续请求稳定在 20-40ms。对比直接调用 OpenAI API 的 CORS 错误,成功率从 0% 提升至 100%。最关键的是,token exchange failed: token endpoint returned status 403 forbidden: country错误彻底消失——因为caveman的请求源自本地 Node 进程,IP 地址为127.0.0.1,不受地域限制。
5. 常见问题与排查技巧实录:那些踩过的坑和独门解法
5.1 “npx caveman install failed” 类错误的根源与修复
搜索热词中频繁出现npx playwright install失败、npx caveman install失败,这并非caveman本身的问题,而是npx依赖的底层 Node.js 环境异常。典型场景及解法:
| 现象 | 根本原因 | 解决方案 |
|---|---|---|
Error: Cannot find module 'caveman' | npx缓存损坏或网络超时 | 执行npx clear-npx-cache清理缓存,再重试 |
Error: EACCES: permission denied | npm 全局目录权限不足(常见于 macOS/Linux) | 运行sudo chown -R $(whoami) $(npm config get prefix)/lib/node_modules修复权限,切勿用sudo npx |
Error: spawn ENOENT | 系统缺少git或curl命令 | 在终端执行which git和which curl,若为空则安装 Xcode Command Line Tools(macOS)或apt install git curl(Ubuntu) |
独家技巧:
npx默认超时时间为 30 秒,国内网络常超时。可临时延长:npx --timeout 120s caveman。我曾因 CDN 延迟卡在Downloading caveman@latest,加--timeout后秒解。
5.2 “token exchange failed” 报错的三层定位法
当caveman日志显示token exchange failed: error sending request,按以下顺序排查:
第一层:检查 token 存储有效性
- 运行
cat .caveman-token,确认格式为SERVICE_NAME=token_value,无空格、无中文、无换行符; - 执行
npx caveman --debug启动,观察日志是否输出Loaded token for OPENAI: sk-xxx; - 若未输出,检查
.caveman-token是否被.gitignore错误排除(!前缀可强制包含)。
第二层:验证 token 本身有效性
- 用
curl直接测试 token:
若返回curl https://api.openai.com/v1/models -H "Authorization: Bearer sk-xxx" -H "Content-Type: application/json"401 Unauthorized,说明 token 无效或过期,需重新生成。
第三层:分析 caveman 代理行为
- 在
caveman.config.json中添加"debug": true,重启服务; - 发送请求后,日志会显示完整转发 URL、请求头、响应状态码;
- 若看到
→ POST https://api.openai.com/v1/chat/completions但无←响应,说明网络层阻塞(防火墙/代理); - 若看到
← 403 Forbidden,检查caveman.config.json中services.openai.headers是否覆盖了必需头(如User-Agent)。
实操心得:我遇到一次
403,日志显示← 403 Forbidden,但curl直连正常。最后发现是caveman配置中headers写成了"user-agent"(小写),而 OpenAI 要求首字母大写User-Agent。HTTP 头部名称区分大小写,这是个极易忽略的细节。
5.3 React 应用白屏与 token 丢失的关联分析
热词中react native 启动白屏、token失效常并存,这揭示了一个隐蔽链路:前端应用初始化时,若caveman服务未启动,fetch请求会 pending 直至超时,导致 React 组件挂起,UI 无法渲染。
解决方案:
启动顺序强约束:在
package.json中定义start脚本:"scripts": { "start": "concurrently \"npx caveman\" \"react-scripts start\"", "dev": "npm-run-all --parallel caveman start" }使用
concurrently或npm-run-all确保caveman先启动,再启动 React。请求容错兜底:在
callAI函数中添加超时控制:export async function callAI(service, endpoint, data) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时 try { const url = `http://localhost:3001/api/${service}/${endpoint}`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), signal: controller.signal }); clearTimeout(timeoutId); // ... 处理响应 } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error('AI service unavailable. Please check if caveman is running.'); } throw error; } }启动状态检测:在 App 组件
useEffect中轮询caveman健康检查端点:useEffect(() => { const checkCaveman = async () => { try { await fetch('http://localhost:3001/health'); setIsCavemanReady(true); } catch { setTimeout(checkCaveman, 1000); } }; checkCaveman(); }, []);
5.4 多项目 token 冲突与隔离策略
当同时开发多个 AI 项目(如ai-chat-demo和glm-dashboard),.caveman-token文件易混淆。推荐三种隔离方案:
| 方案 | 操作 | 适用场景 |
|---|---|---|
| 项目级 token 文件 | 在每个项目根目录创建.caveman-token,内容仅含该项目所需 token | 最常用,简单可靠 |
| 环境变量隔离 | 启动时指定环境变量:CAVEMAN_OPENAI_TOKEN=sk-xxx CAVEMAN_CLAUDE_TOKEN=sk-ant-xxx npx caveman | 适合 CI/CD 或临时调试 |
| 配置文件分片 | 创建caveman.openai.json和caveman.claude.json,分别定义不同服务,用npx caveman -c caveman.openai.json指定配置 | 适合大型项目,需手动管理配置文件 |
注意:
caveman不支持跨项目共享 token 文件。曾有用户将.caveman-token放在用户主目录,结果 A 项目改 token 后 B 项目立即失效。务必坚持“一个项目,一个 token 文件”的原则。
6. 进阶应用:从开发工具到 AI 工作流中枢的演进可能
6.1 与 React Agent 框架图的协同:caveman 作为 Agent 的通信总线
热词中react agent框架图、基于react模式构建能思考与行动的ai智能体暗示了更高阶的应用场景。caveman可超越单纯 API 代理,成为 React Agent 的核心通信层:
Agent 内部服务注册:在
caveman.config.json中定义agent-tools服务,指向本地运行的工具函数(如search-web、read-file):"services": { "agent-tools": { "baseUrl": "http://localhost:4000", // 本地工具服务 "headers": { "X-Agent-Key": "secret" } } }Agent 组件通过
fetch('/api/agent-tools/search?q=xxx')调用工具,caveman负责鉴权与转发。多模态请求聚合:配置
rewrite规则,将前端单个请求拆解为多个 AI 服务调用。例如用户提问“分析这张图片”,caveman