1. 从零搭建 AI 智能体,技术选型到底卡在哪一步
AI 智能体(AI Agent)不是单一技术,而是一套「大脑 + 记忆 + 工具 + 编排」的组合拳。它能自己拆解任务、调用外部接口、记住上下文,最后把结果交付给你。适合谁?适合已经会写 Python 或 TypeScript、想把手里的模型能力串成自动化流程的开发者,也适合 Java 技术栈想接入大模型的企业团队。
真正动手时,第一个卡点往往不是框架,而是模型接入。你选了 LangGraph 做编排,结果发现要同时对接豆包、DeepSeek、Qwen 三家 API,每家的 Base URL、鉴权头、模型 ID 命名规则都不一样。写一个智能体,光适配层就写了三百行。更麻烦的是做模型切换测试——今天想对比 DeepSeek-R1 和 Qwen3 在同一个工具调用任务上的表现,得改三处配置、重启两次服务。
我试过最笨的办法:给每个模型写一个 client 类,用工厂模式分发。能跑,但维护成本高,加一个新模型就要动一次代码。后来换成统一 Key 的 API 通道,把模型差异收敛到配置层,代码里只认一个 Base URL 和一个 Key,切换模型只改一个字符串。这篇就按这个思路,把智能体从技术选型到最小闭环跑通的全过程拆开讲,重点放在可复制的配置片段和连通性验证上。
先说技术选型的整体地图,再落到接入层,最后用一次真实的模型切换验证收尾。你跟着做,能拿到一个能跑的最小智能体骨架。
1.1 智能体的四层技术栈
把智能体拆成四层来看,选型就清晰了。
第一层是大脑,也就是大模型。闭源 API 稳定、推理强,适合快速上线;开源本地部署隐私好、可离线,适合数据敏感场景。关键能力看三点:Function Calling 决定它能不能调工具,长上下文决定它能记住多少,思维链决定它推理的深度。
第二层是编排框架。LangChain + LangGraph 是目前最主流的组合,LangGraph 用状态机管理循环、分支和多 Agent 工作流,工业级项目基本绕不开。AutoGen 和 CrewAI 偏多智能体协作,CrewAI 的 API 更轻,适合快速搭专家团队。Java 栈就用 Spring AI,和 Spring Boot 无缝集成。
第三层是记忆系统。短期记忆靠模型原生上下文窗口,长期记忆靠向量数据库,Milvus、Qdrant、FAISS 都行。再往上可以用 Mem0 做记忆管理,用 Neo4j 存关系型知识图谱。
第四层是工具能力。内置的搜索、计算器、代码解释器是基础,企业级还要接 API、数据库、ERP/CRM。代码执行一定要放沙箱,Docker 或 E2B 都行,别让智能体直接跑在生产环境。
这四层里,第一层和第四层都涉及外部调用,也就是最需要统一接入的地方。下面重点讲接入层怎么收敛。
1.2 为什么接入层要先收敛
很多人搭智能体的顺序是:先选框架,再选模型,最后写接入代码。结果框架和模型耦合在一起,换模型等于重构。
正确的顺序是反过来:先把接入层做成一个稳定的、与框架无关的通道,框架只依赖这个通道的接口。这样 LangGraph 也好,CrewAI 也好,甚至你以后换成 Spring AI,接入层都不用动。
接入层要解决三个问题:统一鉴权、统一模型标识、统一错误处理。统一鉴权就是所有模型共用一个 Key;统一模型标识就是用一个字符串指定用哪个模型;统一错误处理就是 401、超时、限流这些异常用同一套逻辑兜住。
这三个问题解决了,模型切换就从「改代码」变成「改配置」。下面进入具体接入。
2. TaoToken 统一 Key 接入前置准备
TaoToken 是一个统一的大模型 API 通道,官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。它做的事情很直接:把多个模型的调用收敛到一个 Base URL 和一个 API Key 上,你用 OpenAI 兼容的格式发请求,它在后面帮你路由到对应的模型。
对智能体开发来说,这意味着你的接入层只需要写一次,之后加模型、换模型都在配置里完成。适合需要多模型调用的开发者,尤其是要做模型对比测试、或者智能体里不同子任务用不同模型的场景。
2.1 拿到 Key 和 Base URL
第一步是注册并创建 API Key。访问 https://taotoken.net/api-keys ,登录后在控制台创建 Key。创建完复制出来,注意它只显示一次,丢了就重新建一个。
Base URL 是 https://taotoken.net/api ,这个地址不加任何查询参数,直接作为 OpenAI 客户端的 base_url 使用。
这里有个容易踩的坑:Base URL 末尾不要带斜杠,也不要自己拼 /v1。OpenAI SDK 会自动补路径,你多写一段就 404。我见过有人写成 https://taotoken.net/api/v1/chat/completions,结果请求路径变成 /api/v1/chat/completions/v1/chat/completions,直接报错。
2.2 确认可用模型 ID
模型 ID 是接入层的关键。TaoToken 的模型列表在文档里能查到,地址是 https://taotoken.net/doc 。常见的几个:DeepSeek 系列、Qwen 系列、GLM 系列都在。
模型 ID 的写法要严格照抄,大小写敏感。比如 deepseek-chat 和 DeepSeek-Chat 可能不是一回事。建议先把你要用的模型 ID 记下来,后面配置里直接用。
如果你不确定某个模型 ID 是否可用,最省事的办法是先用模型对话页面手动发一条消息试试。地址是 https://taotoken.net/chat ,选模型、发消息,能正常回复就说明这个 ID 可用。这一步花两分钟,能省掉后面调试半小时。
2.3 环境变量怎么放
Key 不要硬编码在代码里。用环境变量,本地开发放 .env,生产环境放密钥管理服务。
在项目根目录建一个 .env 文件:
TAOTOKEN_API_KEY=sk-你的实际Key TAOTOKEN_BASE_URL=https://taotoken.net/api然后在代码里用 os.environ 或 dotenv 读取。这样你的代码可以提交到 Git,Key 不会泄露。如果你用 Docker,把这两个变量通过 environment 注入。
前置准备就这些。接下来是核心部分:可复制的配置片段。
3. 可复制配置:智能体接入层的三件套
接入层的核心是「三件套」:Base URL、API Key、Model ID。这三个东西配对了,请求就能通。这一节给出 Python、Node.js 和配置文件三种形态的片段,你按自己的技术栈选。
3.1 Python 接入片段
用 OpenAI SDK 是最省事的,因为 TaoToken 兼容 OpenAI 的请求格式。先装依赖:
pip install openai python-dotenv然后写接入代码:
import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"], ) def chat(model_id: str, messages: list) -> str: resp = client.chat.completions.create( model=model_id, messages=messages, temperature=0.7, ) return resp.choices[0].message.content if __name__ == "__main__": result = chat( model_id="deepseek-chat", messages=[{"role": "user", "content": "用一句话解释什么是智能体"}], ) print(result)这段代码里,model_id 是唯一需要改的地方。想换模型,改这个字符串就行,client 不用动。
3.2 Node.js 接入片段
如果你用 TypeScript 写智能体,接入方式一样:
npm install openai dotenvimport 'dotenv/config'; import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.TAOTOKEN_API_KEY, baseURL: process.env.TAOTOKEN_BASE_URL, }); async function chat(modelId, messages) { const resp = await client.chat.completions.create({ model: modelId, messages, }); return resp.choices[0].message.content; } const answer = await chat('qwen3-turbo', [ { role: 'user', content: '你好,做个自我介绍' }, ]); console.log(answer);注意 baseURL 的拼写,Node SDK 里是 baseURL,Python 里是 base_url,别写混。
3.3 配置文件形态:settings.json 与 TOML
如果你用 Cline、Continue 这类工具,或者想把配置抽出来,用 JSON 或 TOML。
settings.json 形态:
{ "llm": { "provider": "openai-compatible", "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "modelId": "deepseek-chat", "temperature": 0.7 } }TOML 形态:
[llm] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" model_id = "deepseek-chat" temperature = 0.7这两种形态的好处是,模型切换只改 model_id 一行,代码零改动。智能体里如果有多个子任务用不同模型,就配多个 section,比如 [llm.planner] 用推理强的,[llm.executor] 用速度快的。
3.4 在 LangGraph 里挂载
把上面的 client 挂到 LangGraph 的节点里,就是一个最小智能体:
from langgraph.graph import StateGraph, END from typing import TypedDict class State(TypedDict): question: str answer: str def llm_node(state: State) -> State: answer = chat("deepseek-chat", [ {"role": "user", "content": state["question"]} ]) return {"answer": answer} graph = StateGraph(State) graph.add_node("llm", llm_node) graph.set_entry_point("llm") graph.add_edge("llm", END) app = graph.compile() out = app.invoke({"question": "帮我列三个智能体应用场景"}) print(out["answer"])到这里,接入层和编排层就解耦了。llm_node 里只认 chat 函数,chat 函数只认 model_id。换模型、加模型,都在 chat 这一层解决。
配置给完了,下面验证它到底通不通。
4. 验证请求:一次模型切换后的连通性测试
配置写完不代表能跑通。这一节做两件事:先发一个最小请求确认通道通,再做一次模型切换,确认切换后依然通。
4.1 最小连通性请求
先跑一个最简单的请求,不涉及任何框架:
curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-chat", "messages": [{"role": "user", "content": "回复OK两个字"}] }'如果返回的 JSON 里 choices[0].message.content 是「OK」,说明 Key、Base URL、模型 ID 三件套都对。如果报 401,看下一节的排查。
4.2 模型切换验证
连通之后,把 model 换成另一个,比如 qwen3-turbo,再发一次:
curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3-turbo", "messages": [{"role": "user", "content": "回复OK两个字"}] }'两次都返回正常,说明你的接入层支持多模型切换。这一步很关键,因为智能体里经常需要「规划用强模型、执行用快模型」,切换能力是刚需。
4.3 在智能体里做切换测试
把切换逻辑写进代码,验证框架层也能正常切换:
def run_with_model(model_id: str, question: str) -> str: return chat(model_id, [{"role": "user", "content": question}]) for mid in ["deepseek-chat", "qwen3-turbo", "glm-4"]: try: ans = run_with_model(mid, "用一句话说明你的特点") print(f"[{mid}] {ans[:60]}") except Exception as e: print(f"[{mid}] 失败: {e}")跑一遍,三个模型都能返回,说明你的智能体接入层已经具备多模型能力。实测下来,这个循环跑通之后,后面加工具调用、加记忆都只是在这个骨架上挂东西。
4.4 成功结果的判断标准
什么算验证成功?三个标准:第一,HTTP 状态码 200;第二,返回体里有 choices 数组且非空;第三,content 字段有实际文本。三个都满足才算通。
如果只满足前两个,content 是空字符串,可能是模型在思考但没输出,或者 max_tokens 设太小。这时候把 max_tokens 调大再试。
验证通过后,你的智能体最小闭环就成立了:输入问题 → 接入层路由到模型 → 返回答案。接下来是排障。
5. 本篇常见错误排查
接入层报错集中在几类:鉴权、路径、模型 ID、返回解析。这一节按真实报错对照排查。
5.1 401 Unauthorized
报错长这样:
openai.AuthenticationError: Error code: 401 - {'error': {'message': 'Invalid API key'}}原因通常是三个:Key 没读到、Key 复制时带了空格、Key 已失效。
排查顺序:先在终端 echo $TAOTOKEN_API_KEY 看有没有值;再看值首尾有没有空格或换行;最后去控制台确认 Key 还在不在。如果用的是 .env,确认 load_dotenv() 在 client 初始化之前调用。
5.2 local proxy failed 或连接超时
报错类似:
APIConnectionError: Connection error. local proxy failed这个通常是本地网络环境或代理配置导致的。检查你的 HTTP_PROXY、HTTPS_PROXY 环境变量,如果设了但代理不可用,请求会卡住。临时清掉这两个变量再试:
unset HTTP_PROXY HTTPS_PROXY另外确认 Base URL 是 https://taotoken.net/api ,不要自己加端口或路径。
5.3 reading 'choices' 报错
报错长这样:
TypeError: Cannot read properties of undefined (reading 'choices')这是返回体结构和预期不符。常见原因是请求路径拼错了,比如 Base URL 末尾多写了 /v1,导致实际请求打到了错误端点,返回的不是标准 chat completion 结构。
排查:打印完整响应体,看它到底返回了什么。如果是 404 页面或错误 JSON,就是路径问题。把 base_url 改回 https://taotoken.net/api 即可。
5.4 OAuth 相关报错
如果你在 Claude Code 或类似工具里看到 OAuth 报错,比如 token 过期或授权失败,这通常不是 API Key 的问题,而是工具的登录态问题。这类工具如果用 API Key 模式接入,需要在配置里明确指定 Base URL 和 Key,而不是走 OAuth 流程。
以 Claude Code 为例,配置里要写全三件套:Base URL 填 https://taotoken.net/api ,Key 填你的 TaoToken Key,Model ID 填你要用的模型。三个都写对,就不会走 OAuth。
5.5 模型 ID 不存在
报错类似:
model not found: xxx原因就是模型 ID 写错了。去 https://taotoken.net/doc 核对准确的 ID,注意大小写和连字符。别凭记忆写,复制粘贴最稳。
5.6 排查通用思路
遇到任何报错,按这个顺序走:第一步,用 curl 发最小请求,排除代码问题;第二步,检查三件套(Base URL、Key、Model ID);第三步,看完整错误信息,别只看第一行;第四步,去文档核对参数。
大部分问题都在三件套里。把这三样确认对了,剩下的都是小问题。
6. 智能体接入的下一步
最小闭环跑通后,你的智能体已经能调用多个模型了。接下来可以往上加东西:加 Function Calling 让模型能调工具,加向量库做长期记忆,加 LangGraph 的状态机做多步推理。
但无论加什么,接入层都不用动。这就是先收敛接入层的好处——上层怎么变,底层通道是稳定的。
如果你要长期做编码类智能体或者多 Agent 协作,可以考虑 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。它针对长时间、高频次的编码场景做了优化,比按次调用更划算。
想先手动试试模型效果,去模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 发几条消息,确认你要用的模型符合预期,再写进配置。
接入文档在 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= ,需要新建或轮换 Key 的时候去这里。
最后给一个实用技巧:把模型 ID 做成配置项,别写死在代码里。智能体跑起来之后,你会频繁做模型对比,配置化的切换能帮你省下大量改代码的时间。我现在的做法是,每个子任务对应一个配置 section,规划、执行、总结各用各的模型,调优的时候只改配置,代码一行不动。