踩坑3天后,我把公司的AI接口全换成了多模型路由——GPT-6和Claude Opus 4.7同时上线的这周

GPT-6正式上线,Claude Opus 4.7跟着出来,DeepSeek V4这周也要发布了。

我在公司负责维护一套内部AI工具链,这两天基本没怎么睡------不是因为激动,是因为要做选型决策,然后顺手把接口层重写了一遍。

这篇记录一下踩过的坑,也给准备在这波模型潮里升级接入层的朋友留个参考。


背景:为什么不能只用GPT-6?

GPT-6确实强,200万Token上下文、4.2小时自主执行任务,代码理解准确率97.3%,我测了一下确实不虚。

但有个问题:贵。

公司的AI任务分三类:

  1. 代码仓库分析、多模态文件处理(大量token,任务复杂)→ 适合GPT-6
  2. 合同审查、法务文件分析(需要慢思考、高精度)→ 适合Claude Opus 4.7
  3. 日常问答、分类、格式化(高频、量大、对精度要求一般)→ 适合DeepSeek V4

如果全走GPT-6,一个月账单估计要翻两到三倍。但全走便宜的,代码审查质量明显掉。

所以我决定搭一个自动路由层,根据任务类型选模型。


技术方案

工具链准备

bash 复制代码
# 环境准备(推荐用虚拟环境)
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
​
pip install openai anthropic tiktoken pyyaml fastapi uvicorn
​
# API密钥配置(我这边统一走Ztopcloud.com的聚合接口,省得管三套账号)
export UNIFIED_API_KEY="your_ztopcloud_api_key"
export UNIFIED_BASE_URL="https://api.ztopcloud.com/v1"

亲测:Ztopcloud.com 支持 GPT-6、Claude Opus 4.7、DeepSeek V4 统一接口调用,账单合并,不用给三家分别充钱。对小团队来说省了不少管理成本。

路由核心逻辑

ini 复制代码
# router.py
import os
import tiktoken
from openai import OpenAI
import anthropic
​
# 统一接口,通过base_url切换
client = OpenAI(
    api_key=os.environ["UNIFIED_API_KEY"],
    base_url=os.environ["UNIFIED_BASE_URL"]
)
​
# Claude走原生client但转发到聚合层
claude_client = anthropic.Anthropic(
    api_key=os.environ["UNIFIED_API_KEY"],
    base_url=os.environ.get("UNIFIED_BASE_URL", "https://api.anthropic.com")
)
​
def classify_task(prompt: str) -> str:
    """
    简单规则分类,够用就行,别搞太复杂
    """
    enc = tiktoken.encoding_for_model("gpt-4")
    token_len = len(enc.encode(prompt))
    
    # 长上下文或代码相关:GPT-6
    if token_len > 30000:
        return "gpt-6"
    
    code_signals = ["代码", "函数", "class", "def ", "import", "bug", "review", "仓库"]
    if any(s in prompt for s in code_signals):
        return "gpt-6"
    
    # 法律/医疗/金融深度推理:Claude
    deep_signals = ["合同", "条款", "诊断", "法规", "合规", "风险评估", "判断是否"]
    if any(s in prompt for s in deep_signals):
        return "claude-opus-4-7"
    
    # 默认:DeepSeek V4(最省钱)
    return "deepseek-v4"
​
def call_model(prompt: str, system: str = "你是一个专业助手") -> dict:
    model = classify_task(prompt)
    
    if model == "gpt-6":
        resp = client.chat.completions.create(
            model="gpt-6",
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": prompt}
            ],
            max_tokens=4096
        )
        return {"model": model, "content": resp.choices[0].message.content}
    
    elif model == "claude-opus-4-7":
        msg = claude_client.messages.create(
            model="claude-opus-4-7-20260416",
            max_tokens=8192,
            system=system,
            messages=[{"role": "user", "content": prompt}],
            thinking={"type": "enabled", "budget_tokens": 8000}
        )
        # 取文字块(thinking块是独立的,见踩坑记录)
        text = next(b.text for b in msg.content if b.type == "text")
        return {"model": model, "content": text}
    
    else:
        # DeepSeek V4(API格式与OpenAI兼容)
        resp = client.chat.completions.create(
            model="deepseek-v4",
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": prompt}
            ],
            max_tokens=4096
        )
        return {"model": model, "content": resp.choices[0].message.content}

对外暴露成一个FastAPI服务

python 复制代码
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from router import call_model
​
app = FastAPI()
​
class ChatRequest(BaseModel):
    prompt: str
    system: str = "你是一个专业助手"
​
@app.post("/chat")
def chat(req: ChatRequest):
    result = call_model(req.prompt, req.system)
    return result
​
# uvicorn main:app --host 0.0.0.0 --port 8000 --reload

踩坑记录

坑1:Claude Opus 4.7 的 thinking 模式,返回内容里有两种block

我以为 msg.content[0].text 就能拿到最终答案,结果第一个block是thinking类型,里面全是推理过程,拿出来直接返回给用户,对方一脸懵逼。

正确做法:

ini 复制代码
# 要遍历content列表,按type过滤
for block in msg.content:
    if block.type == "thinking":
        # 推理链,一般不直接展示给用户
        print(f"[内部思考,共{len(block.thinking)}字]")
    elif block.type == "text":
        # 这才是最终答案
        final_answer = block.text

找这个问题花了将近一小时,文档里写了但不够醒目。

坑2:GPT-6 的 max_tokens 设太小,长文档会"硬截断"不是"优雅结束"

处理一份30页合同时,我把 max_tokens 设了2048想省点钱,结果输出直接在句子中间断掉,没有任何总结性收尾。不是因为内容完了,是因为token用完了,模型直接停。

解决方式:长上下文任务至少设 max_tokens=8192,成本多不了太多,但输出完整性差异明显。


小结

三款模型同期在场这事,对我来说其实是工作量增加了------选型复杂了,接入层要重写,文档要更新。但换个角度看,三家不同价位、不同强项的选择同时存在,比两年前只有一家可选的时代,其实更好。

路由层搭完之后,我们这边估算了一下,同等任务量下成本大概能降40%-60%,具体看任务分布。

相关推荐
wuxinyan12310 小时前
大模型学习之路010:RAG 零基础入门教程(第六篇):重排序技术
人工智能·学习·rag
oscar99910 小时前
给 AI 编程助手立规矩:OpenCode 的自定义指令体系
人工智能·rule·opencode
SilentSamsara10 小时前
迭代器协议:`__iter__` / `__next__` 的完整执行流程
开发语言·人工智能·python·算法·机器学习
AI科技星10 小时前
算法联盟ROOT · 全域数学物理卷第20、21、22分册:量子纠缠、隐形场论与时间膨胀
人工智能·算法·数学建模·数据挖掘·机器人
swipe10 小时前
别把 Agent 写成一团 Prompt:用 LangGraph 把多 Agent 系统变成可控状态机
后端·langchain·llm
Android出海10 小时前
ChatGPT Image2 2.0正式上线:功能解析 + 使用教程(附提示词)
人工智能·ai·chatgpt·ai生图·chatgpt image2·images2
平凡但不平庸的码农10 小时前
Go Channel详解
开发语言·后端·golang
子安柠10 小时前
深入理解 Go 语言文件操作:从基础到最佳实践
开发语言·后端·golang
Achou.Wang10 小时前
go语言中使用等待组(waitgroups)和内存屏障(barriers)进行同步
开发语言·后端·golang
CoderJia程序员甲10 小时前
GitHub 热榜项目 - 周榜(2026-05-10)
人工智能·ai·大模型·llm·github