1. 项目概述:当AI学会“点餐”

最近在GitHub上闲逛,发现一个挺有意思的项目,叫 lyhue1991/eat_chatgpt 。光看名字,你可能会有点懵:“吃”ChatGPT?这什么操作?点进去一看,原来这是一个用Python写的工具,核心功能是 自动化调用ChatGPT的API,并帮你把消耗的API费用(Token)记录得一清二楚 ,就像给你的AI助手装了个“消费记录仪”。

对于任何一个深度使用ChatGPT API的开发者、团队或者个人来说,这玩意儿简直是刚需。你想啊,OpenAI的API是按Token计费的,你用得多,账单就蹭蹭往上涨。但官方后台的账单统计往往有延迟,而且颗粒度不够细。你很难快速回答:“我昨天调试那个对话系统花了多少钱?”或者“我们团队这个月哪个项目的API开销最大?” eat_chatgpt 就是为了解决这个问题而生的。它像一个透明的中间件,在你和OpenAI API之间架起一座桥,不仅帮你转发请求,还实时、精准地记录下每一次“对话”的成本。

简单来说,它解决了几个核心痛点:

  1. 成本透明化 :实时监控API调用开销,避免账单“惊吓”。
  2. 使用分析 :统计不同模型、不同用途的Token消耗,优化使用策略。
  3. 项目管理 :对于团队协作,可以按项目、按用户细分成本,方便内部核算。

无论你是独立开发者,在调试一个需要大量调用GPT的应用程序;还是团队负责人,需要管理多个项目的AI资源开销;亦或是单纯想了解自己使用习惯的个人用户,这个工具都能提供极大的便利。它把原本黑盒的API消费,变成了可度量、可分析的数据,让你在享受AI强大能力的同时,对自己的“数字粮草”心中有数。

2. 核心原理与架构拆解

2.1 核心工作流:一个“中间人”的自我修养

eat_chatgpt 的核心思想并不复杂,但设计得很巧妙。它本质上是一个 HTTP代理服务器 数据记录器 。我们来看一下它的典型工作流程:

  1. 配置转向 :你不再直接向 api.openai.com 发送请求,而是将你的应用程序(比如你写的Python脚本、集成了OpenAI SDK的服务)的API请求目标,改为 eat_chatgpt 服务所在的本地地址(例如 http://localhost:8000 )。
  2. 请求拦截与转发 eat_chatgpt 服务在本地启动后,监听指定的端口。当它收到你的请求时,会先进行“验票”——验证你的请求格式和API Key(它支持配置多个Key并轮询使用)。验证通过后,它会原封不动地将你的请求转发给真正的OpenAI API服务器。
  3. 响应接收与解析 :OpenAI服务器处理完请求,将结果(比如生成的文本)返回给 eat_chatgpt
  4. 关键一步:Token计数与记录 :在这里, eat_chatgit 会做一件最重要的事: 解析响应体 。OpenAI的API响应中,通常会包含一个 usage 字段,里面明确列出了本次请求消耗的 prompt_tokens (提示词Token数)、 completion_tokens (补全内容Token数)和 total_tokens (总Token数)。 eat_chatgpt 会精准地提取这些数据。
  5. 数据落地与返回 :提取到Token数据后, eat_chatgpt 会将这些消费记录,连同时间戳、使用的API Key别名、调用的模型名称、请求的端点(如 /v1/chat/completions )等信息,一起写入数据库(默认使用SQLite,轻量便捷)。最后,它再将OpenAI的原始响应返回给你的应用程序。

整个过程中,你的应用程序几乎无感,它只是觉得自己在和“OpenAI API”对话,但实际上背后多了一个默默记账的管家。这个架构的优势在于 非侵入性 ——你不需要修改核心业务代码,只需改变一个配置项(API的base_url),就能获得完整的成本监控能力。

2.2 技术栈选型:为什么是它们?

项目的技术选型体现了作者“轻量、实用、易部署”的思路:

  • 语言:Python :这是自然的选择。OpenAI官方SDK就是Python写的,生态完善。Python在数据处理、快速开发原型和搭建轻量级HTTP服务方面有巨大优势,也降低了贡献者和使用者的门槛。
  • Web框架:FastAPI :这是项目的亮点之一。FastAPI以其高性能和自动生成交互式API文档(Swagger UI)而闻名。使用FastAPI意味着:
    • 开发效率高 :类型提示(Type Hints)让代码更健壮,自动请求验证。
    • 自带管理界面潜力 :基于Swagger UI,可以快速扩展出一个查看统计数据的后台页面(事实上,很多衍生项目已经这么做了)。
    • 异步支持 :为高并发场景下的请求转发和记录提供了可能。
  • 数据存储:SQLite :默认使用SQLite,这是一个非常务实的决定。对于个人或小团队使用,SQLite无需安装独立的数据库服务,单个文件即可,部署和迁移极其简单。数据表结构通常包含 id , timestamp , api_key , model , prompt_tokens , completion_tokens , total_tokens , request_path 等字段,清晰记录了每一次消费。
  • 配置管理:Pydantic + 环境变量/配置文件 :通常使用Pydantic模型来定义和验证配置(如多个API Key及其别名、代理服务器端口、数据库路径等)。配置可以通过 .env 文件或YAML配置文件加载,兼顾了安全性和灵活性。

注意 :这种代理模式意味着你的所有API请求都会流经这个本地服务。因此,务必确保该服务运行在可信赖的安全环境中。虽然它本身不存储你的对话内容(除非你特意扩展功能去记录),但理论上可以接触到完整的请求和响应数据。

2.3 与官方计费方式的差异

理解 eat_chatgpt 的计数原理,需要先明白OpenAI的计费方式。OpenAI的计费是基于 Token 的,Token可以理解为单词或词根片段。计费公式大致是: 总费用 = (提示Token数 * 提示单价) + (补全Token数 * 补全单价) 。单价因模型而异(如GPT-4 Turbo比GPT-3.5-Turbo贵很多)。

OpenAI官方后台的账单数据是 聚合和延迟 的。它告诉你某个时间段内总共花了多少钱,但如果你想了解“今天下午3点我那个调试请求花了多少”,或者“对比一下用 gpt-3.5-turbo gpt-4 回答同一个问题的成本差异”,官方后台就无能为力了。

eat_chatgpt 的优势就在于 实时性和细粒度

  • 实时 :请求完成,记录即刻落库,你可以随时查询。
  • 细粒度 :记录到每一次API调用,关联具体的模型、API Key和时间点。
  • 可定制 :基于数据库中的原始记录,你可以用SQL查询或简单的脚本,生成任意维度的报表:按天统计、按模型统计、按API Key(对应不同项目或成员)统计。

它弥补了官方后台在 精细化成本管理和分析 方面的不足,是从“能用”到“用得明白、用得经济”的关键工具。

3. 从零开始部署与配置实战

3.1 环境准备与项目获取

假设你已经在本地或服务器上有了Python环境(建议Python 3.8+),我们开始动手。

首先,通过Git克隆项目代码。打开你的终端(命令行),执行:

git clone https://github.com/lyhue1991/eat_chatgpt.git
cd eat_chatgpt

接下来是安装依赖。一个规范的项目通常会有 requirements.txt pyproject.toml 文件。我们查看并安装:

# 查看依赖文件
ls -la requirements.txt pyproject.toml

# 如果存在 requirements.txt
pip install -r requirements.txt

# 或者,如果项目使用 poetry 管理(有 pyproject.toml)
# pip install poetry
# poetry install

如果项目没有明确的依赖文件,根据其代码结构,核心依赖通常包括 fastapi , uvicorn (ASGI服务器), openai , pydantic , sqlalchemy 等。你可以尝试手动安装:

pip install fastapi uvicorn openai pydantic sqlalchemy

实操心得 :强烈建议在安装前,先创建一个独立的Python虚拟环境(如使用 venv conda )。这能避免包版本冲突,保持项目环境干净。命令如 python -m venv venv ,然后激活(Windows: venv\Scripts\activate , Mac/Linux: source venv/bin/activate )。

3.2 核心配置详解

配置是让 eat_chatgpt 为你工作的关键。你需要告诉它:你的OpenAI API Key是什么,服务监听在哪个端口,数据存到哪里。

最常见的方式是使用一个配置文件,比如 config.yaml ,或者通过环境变量设置。我们以创建一个 config.yaml 文件为例:

# config.yaml
server:
  host: "0.0.0.0"  # 监听所有网络接口,如果仅本地使用可改为 "127.0.0.1"
  port: 8000        # 服务端口,可自定义

openai:
  api_keys:
    - key: "sk-your-openai-api-key-here-1"  # 替换成你的真实API Key
      name: "my_main_key"                   # 给这个Key起个别名,方便区分
    - key: "sk-your-openai-api-key-here-2"
      name: "project_a_key"
  # 如果你需要通过代理访问OpenAI(在某些网络环境下可能需要),可以配置
  # proxy: "http://your-proxy:port"

database:
  url: "sqlite:///./eat_chatgpt.db"  # SQLite数据库文件路径,会在当前目录生成
  # 如果想用其他数据库,如PostgreSQL,可改为:
  # url: "postgresql://user:password@localhost/dbname"

logging:
  level: "INFO"  # 日志级别:DEBUG, INFO, WARNING, ERROR

关键配置项解析:

  1. openai.api_keys :这是核心。你可以配置多个API Key。 eat_chatgpt 可以实现简单的 负载均衡或故障转移 ,即按顺序或随机使用这些Key,防止单个Key的速率限制(Rate Limit)被触发。 name 字段非常重要,它会在数据库记录中标识这次调用用的是哪个Key,便于你按项目或团队核算成本。
  2. database.url :默认的SQLite连接字符串 sqlite:///./eat_chatgpt.db 意味着在项目根目录下创建一个名为 eat_chatgpt.db 的数据库文件。请确保运行程序的用户对该目录有读写权限。
  3. server.host port :如果你只在本地机器上使用(比如你的Python脚本和 eat_chatgpt 服务跑在同一台电脑), host 设为 127.0.0.1 更安全。如果你需要让局域网内其他机器也能通过这个代理服务调用API(比如团队共用),则需要设为 0.0.0.0 ,并注意防火墙设置。

重要安全警告 :配置文件里包含了你的API Key,这是非常敏感的信息! 绝对不要 config.yaml 提交到Git等版本控制系统。你应该将 config.yaml 添加到 .gitignore 文件中。一种更佳实践是使用环境变量来存储API Key,在代码中通过 os.getenv('OPENAI_API_KEY') 读取。你可以创建一个 .env 文件(同样要加入 .gitignore )来管理环境变量。

3.3 启动服务与验证

配置好后,启动服务。通常项目会有一个主入口文件,比如 main.py app.py 。使用 uvicorn 启动FastAPI应用:

# 假设主文件是 main.py,应用实例名为 app
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
  • --reload :开发时非常有用,代码修改后会自动重启服务。
  • 如果配置文件中已经指定了host和port,启动命令可以简化为 uvicorn main:app --reload

看到类似下面的输出,说明服务启动成功:

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [12345] using WatchFiles
INFO:     Started server process [12346]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

验证服务是否正常:

  1. 访问API文档 :FastAPI自动生成了交互式文档。打开浏览器,访问 http://localhost:8000/docs 。你应该能看到Swagger UI界面,里面列出了 eat_chatgpt 暴露的端点(如转发请求的端点、查询消费记录的端点等)。这是一个很好的健康检查。
  2. 发送一个测试请求 :你可以直接用 curl 命令或Python脚本来测试。这里用Python示例:
    import openai
    from openai import OpenAI
    
    # 关键步骤:将client的base_url指向你的eat_chatgpt服务
    client = OpenAI(
        api_key="any-string-will-do",  # 这里可以随便填,因为eat_chatgpt会用自己配置的Key
        base_url="http://localhost:8000/v1",  # 注意这里!指向代理服务
    )
    
    try:
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[{"role": "user", "content": "Hello, how are you?"}],
            max_tokens=50
        )
        print(response.choices[0].message.content)
        print(f"本次消耗Token: {response.usage.total_tokens}")
    except Exception as e:
        print(f"请求失败: {e}")
    
    如果这个脚本能成功返回AI的回复,并且打印出Token消耗,同时你的 eat_chatgpt 服务日志有相应的请求记录,那么恭喜你,代理服务配置成功了!

4. 集成到现有项目与高级用法

4.1 改造你的现有应用

将现有项目接入 eat_chatgpt 非常简单,核心就是修改一点配置。无论你用的是OpenAI官方Python库,还是LangChain、LlamaIndex等高级框架,原理相通。

场景一:直接使用OpenAI Python库 如上一步验证所示,你只需要在初始化 OpenAI client时,将 base_url 参数设置为你的 eat_chatgpt 服务地址(加上 /v1 路径)。你的API Key可以填写任意值(或留空),因为实际的认证和转发由代理服务完成。

场景二:在LangChain中使用 LangChain是构建AI应用的热门框架。集成同样简单:

from langchain_openai import ChatOpenAI

# 通常的用法是:
# llm = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key="your-key")

# 接入eat_chatgpt后:
llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    openai_api_key="dummy-key", # 虚拟Key,代理会替换它
    base_url="http://localhost:8000/v1" # 指定代理地址
)

这样,所有通过这个 llm 对象发起的调用,都会被路由到你的记账代理。

场景三:环境变量配置(推荐) 为了避免硬编码,最佳实践是通过环境变量配置。你可以在启动你的应用前设置环境变量:

export OPENAI_API_BASE=http://localhost:8000/v1
export OPENAI_API_KEY=dummy_key
# 然后运行你的应用

或者在Python代码中:

import os
os.environ["OPENAI_API_BASE"] = "http://localhost:8000/v1"
os.environ["OPENAI_API_KEY"] = "dummy_key"
# 之后再初始化OpenAI client或LangChain

这种方式使得代码与配置解耦,更灵活、更安全。

4.2 多API Key管理与轮询策略

如果你有多个OpenAI API Key(比如来自不同项目或团队成员), eat_chatgpt 的多Key配置功能就派上大用场了。在配置文件中列出所有Key后,代理服务内部会实现一个简单的调度策略。

常见的策略有:

  1. 顺序轮询 (Round Robin) :按配置顺序依次使用每个Key,均匀分配请求。
  2. 随机选择 :每次请求随机挑选一个Key。
  3. 基于额度的权重分配 :如果知道每个Key的剩余额度,可以优先使用额度多的Key(但这需要额外调用OpenAI的额度查询接口)。

eat_chatgpt 的基础版本可能实现的是简单的顺序或随机轮询。 这种策略的主要目的是绕过单个API Key的速率限制(RPM/TPM限制) 。例如,GPT-4 API可能限制每分钟最多请求40次(RPM)。如果你有一个高频应用,单个Key很快会触限。通过多个Key轮询,你可以将请求分散,有效提升整体可用吞吐量。

注意事项 :使用多Key轮询时,账单管理会变得稍微复杂。你需要定期汇总所有Key在OpenAI官方后台的消费。而 eat_chatgpt 数据库的记录,正是帮你做这件事的利器——你可以按 api_key_name 字段分组统计,轻松知道每个Key(对应每个项目或人)各自花了多少钱。

4.3 数据查询与可视化分析

数据记录在SQLite里,你可以用任何喜欢的方式查询和分析。

基础SQL查询示例:

  1. 查看总消费(按Token计)

    SELECT SUM(total_tokens) as total_tokens_consumed FROM api_usage_logs;
    
  2. 按模型统计消耗

    SELECT model, SUM(prompt_tokens) as total_prompt, SUM(completion_tokens) as total_completion, SUM(total_tokens) as total
    FROM api_usage_logs
    GROUP BY model
    ORDER BY total DESC;
    

    这个查询能让你一眼看出哪个模型最“烧钱”。

  3. 按日期(天)统计

    SELECT DATE(timestamp) as day, SUM(total_tokens) as daily_tokens
    FROM api_usage_logs
    GROUP BY day
    ORDER BY day;
    
  4. 按API Key(项目)统计

    SELECT api_key_name, SUM(total_tokens) as project_tokens
    FROM api_usage_logs
    GROUP BY api_key_name;
    

进阶可视化: 对于不熟悉SQL的用户,或者想要更直观的图表,可以:

  • 使用轻量级BI工具 :比如 Metabase Redash ,连接SQLite数据库,拖拽生成仪表盘,监控每日成本趋势、模型使用占比等。
  • 用Python脚本生成报表 :使用 pandas 读取数据,用 matplotlib plotly 画图。
    import pandas as pd
    import sqlite3
    import matplotlib.pyplot as plt
    
    conn = sqlite3.connect('eat_chatgpt.db')
    df = pd.read_sql_query("SELECT * FROM api_usage_logs", conn)
    conn.close()
    
    # 按天汇总
    df['date'] = pd.to_datetime(df['timestamp']).dt.date
    daily_cost = df.groupby('date')['total_tokens'].sum()
    
    # 画图
    daily_cost.plot(kind='line', title='Daily Token Consumption')
    plt.xlabel('Date')
    plt.ylabel('Total Tokens')
    plt.grid(True)
    plt.show()
    
  • 扩展 eat_chatgpt 本身 :如果你懂一些Web开发,可以基于FastAPI的Swagger UI或自己写一个简单的HTML页面,增加一个数据看板端点,直接在内网浏览器里查看图表。这是很多开发者喜欢对这个项目进行的二次开发。

5. 常见问题、故障排查与优化实践

5.1 部署与连接问题

问题1:服务启动失败,提示端口被占用 ( Address already in use )

  • 原因 :你指定的端口(默认8000)已被其他程序(可能是另一个 eat_chatgpt 实例或其他服务)使用。
  • 解决
    1. 换一个端口,修改配置文件的 port 字段,比如改为 8001
    2. 找出占用端口的进程并关闭它。在Linux/Mac上可以用 lsof -i:8000 ,在Windows上可以用 netstat -ano | findstr :8000

问题2:应用程序连接 eat_chatgpt 失败,报超时或连接拒绝

  • 原因
    • eat_chatgpt 服务没有成功启动。
    • 客户端配置的 base_url 地址或端口错误。
    • 防火墙或安全组规则阻止了连接(尤其在服务器部署时)。
  • 排查步骤
    1. 检查服务状态 :确认 uvicorn 进程正在运行,且日志没有报错。
    2. 本地连通性测试 :在运行 eat_chatgpt 的机器上,用 curl http://localhost:8000/docs 测试,看是否能访问API文档。
    3. 检查客户端配置 :确保 base_url 的IP和端口完全正确。如果是局域网其他机器访问,需使用服务器的局域网IP,而非 localhost
    4. 检查防火墙 :在服务器上,确保防火墙放行了对应端口(如 sudo ufw allow 8000/tcp 对于Ubuntu的UFW)。

问题3:请求被转发到OpenAI时失败,返回认证错误或网络错误

  • 原因
    • config.yaml 中配置的OpenAI API Key无效或已过期。
    • 网络无法访问 api.openai.com (在某些地区可能需要配置代理)。
    • OpenAI服务本身暂时不可用。
  • 排查步骤
    1. 检查API Key :去OpenAI平台检查Key是否有效、是否有余额、是否被禁用。
    2. 检查代理配置 :如果你的网络环境需要代理才能访问外部API,确保在 eat_chatgpt 的配置中正确设置了 openai.proxy 字段。
    3. 查看 eat_chatgpt 日志 :日志通常会记录转发请求时的详细错误信息,是排查的第一手资料。
    4. 直接测试OpenAI API :暂时绕过 eat_chatgpt ,用同样的API Key直接调用OpenAI官方接口,验证Key和网络本身是否正常。

5.2 数据记录与准确性疑问

问题4:数据库中没有记录,但请求似乎成功了

  • 原因
    • 请求可能没有经过 eat_chatgpt 代理(客户端配置未生效)。
    • 程序在处理响应、解析 usage 字段或写入数据库时发生了静默错误。
    • 数据库文件权限问题,导致写入失败。
  • 解决
    1. 首先确认客户端配置的 base_url 绝对正确。
    2. 提高 eat_chatgpt 的日志级别到 DEBUG ,查看每个请求处理的详细流程,看是否在某个环节出错。
    3. 检查SQLite数据库文件路径的写入权限。

问题5:记录的Token数与OpenAI后台账单对不上

  • 原因 :这是最需要关注的问题。可能存在轻微差异,但不应过大。
    • 缓存差异 :OpenAI的计费账单可能存在轻微的延迟(小时级别)。
    • 请求范围 :确认 eat_chatgpt 记录的时间范围与你在后台查询的范围完全一致。
    • 记录遗漏 :某些类型的API调用(如非Chat Completion的端点,如Embeddings、Audio)可能未被 eat_chatgpt 正确捕获或解析,这取决于其代码实现是否支持这些端点。
    • Key轮询 :如果你用了多个Key,需要在OpenAI后台汇总所有Key的消费,才能与 eat_chatgpt 的总记录对比。
  • 行动 :建议定期(如每周)进行对账。用SQL汇总 eat_chatgpt 数据库的 total_tokens ,与OpenAI后台各API Key的消费Token总数对比。如果发现持续性的、显著的差异,需要检查 eat_chatgpt 的代码是否支持你使用的所有API模型和端点。

5.3 性能、安全与扩展建议

性能考量: eat_chatgpt 作为代理,会增加一点网络延迟(本地网络通常可忽略),并且会进行JSON解析和数据库写入操作。在高并发场景下,这可能成为瓶颈。

  • 优化建议
    • 数据库优化 :SQLite在极高并发写入时可能锁库。对于生产环境,可以考虑迁移到PostgreSQL或MySQL,并优化索引(如在 timestamp , api_key_name 上建索引)。
    • 异步写入 :检查 eat_chatgpt 是否使用了异步数据库驱动(如 asyncpg for PostgreSQL, aiosqlite for SQLite)。如果没有,可以考虑将数据库写入操作改为异步,避免阻塞请求响应。
    • 批量写入 :对于极端高频场景,可以改为先将消费记录暂存到内存队列(如Redis),然后由后台 worker 批量写入数据库,但这会牺牲一定的实时性。

安全警告(再次强调):

  • API Key安全 eat_chatgpt 的配置文件存储了你的API Key。务必确保配置文件 ( config.yaml .env ) 的访问权限仅限于可信用户,并 绝不 提交到公开仓库。
  • 服务暴露 :如果将 host 设置为 0.0.0.0 ,你的代理服务就暴露在了网络上。如果没有身份验证,任何人都可以向你的服务发送请求并消耗你的API Key! 务必为生产环境部署添加认证层 。例如:
    • eat_chatgpt 服务前加一层反向代理(如Nginx),并配置HTTP Basic Auth或API Token认证。
    • 修改 eat_chatgpt 代码,在转发请求前验证客户端来源IP或特定的请求头Token。
  • 数据隐私 :默认情况下, eat_chatgpt 可能只记录元数据(Token数、模型等)。但如果你修改了代码以记录完整的请求和响应内容(用于调试),那么这些数据包含了你和AI的对话,属于敏感信息。必须妥善保管数据库,考虑加密存储或定期清理。

功能扩展思路: 开源项目的魅力在于可以按需定制。你可以基于 eat_chatgpt 进行扩展:

  1. 成本预警 :写一个定时脚本,查询最近一小时/一天的Token消耗,如果超过阈值,就发送邮件、Slack或钉钉通知。
  2. 预算控制 :扩展服务,为每个API Key(或项目)设置月度Token预算,当接近预算时自动拒绝请求或切换Key。
  3. 更丰富的仪表盘 :利用FastAPI很容易创建一个内部分析页面,用图表展示成本趋势、模型使用分布、热门请求类型等。
  4. 支持更多AI服务商 :除了OpenAI,还可以扩展支持 Anthropic Claude、Google Gemini、国内大模型等API的计费记录,做成一个统一的多平台AI成本管理工具。

lyhue1991/eat_chatgpt 这个项目,从一个非常具体的痛点出发,用简洁有效的架构提供了解决方案。它可能不是功能最全面的,但其设计理念和实现方式,为所有关心AI应用成本的开发者提供了一个极佳的起点和参考。把它用起来,你就能真正看清,你和AI的每一次“对话”,价值几何。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐