LLM 峰谷定价怎么吃满:一个能对账的错峰调度器

价格表变了,很多人的批处理任务还在按老姿势跑。

同一份代码、同一个模型,账单能差一倍,差别只在发请求的时刻。为什么错峰这件事一直没被认真做?因为它看起来太简单了,简单到没人愿意为它写调度器。

9 月 10 日 DeepSeek 发布 V4.1 Flash,除了 552B MoE 参数、CED 非对称结构这些模型侧的改动,还有一条容易被忽略的工程条款:峰谷定价被保留,闲时价格是高峰时段的一半。按官方公布的口径,闲时输入(缓存命中)低至 0.02 元/百万 token,输出 4 元;高峰时段输出 8 元(来源:DeepSeek 官方发布信息)。同时官方明确,9 月 14 日 12:00 起 V4 Pro 服务下线,请求路由到 V4.1 Flash。

对做批处理的人来说,这意味着同一份代码、同一个模型,账单能差一倍。差的不是模型选择,而是你发请求的时刻

这篇文章不讲"要不要错峰",讲讲怎么把错峰做成一个能跑、能对账、能重试的调度器。完整代码在第四节,单文件、零第三方依赖,可以直接复制运行。


一、先把问题讲清楚

批量任务和交互式任务在经济特性上完全不同。

交互式请求的约束是延迟,用户等不了 8 小时,所以它必须付高峰价。而批量任务的约束通常只是"明天早上之前跑完"。摘要、分类、抽取、翻译、离线评测、数据集构造,这些任务的共同点是:可以在任意时刻执行,结果一样。

既然时刻可换,钱就可以省。真实场景里的账大概长这样:一万条文档摘要,平均每条 3000 输入 token、400 输出 token。

  • 高峰跑:输出侧 4,000,000 token × 8 元/百万 = 32 元
  • 闲时跑:输出侧 4,000,000 token × 4 元/百万 = 16 元
  • 输入侧如果命中缓存,闲时 0.02 元/百万的价位,让输入成本几乎可以忽略

省下的这 16 元不多,但这是零改动、零风险的节省。当批量任务的规模到千万条量级,这就是一笔预算。

问题在于,把"错峰"写进 crontab 是不够的。你会遇到四个具体麻烦:

  1. 任务跑不完怎么办?跑到窗口结束,剩下的必须留到下一个窗口,不能顺手用高峰价发出去;
  2. 重复投递怎么办?脚本重跑一次,同一批任务发两遍;
  3. 部分失败怎么办?不能因为一条超时把整批重投;
  4. 到底省了多少?没有对账,错峰的收益就是自我安慰。

二、调度器要解决的四件事

我把它拆成四条约束,代码全部围绕它们写:

  • 先落库,后调用。 任何一次请求发出前,任务必须在 SQLite 里存在。进程随时被 kill,重启后状态可恢复。
  • 窗口判定显式带时区。datetime 而不是 date 比较,容器里跑 UTC 的时候才不会把"闲时"算成高峰。
  • 幂等键。 job_id 做主键,INSERT OR IGNORE,重复投递自动拦下。
  • 按服务端 usage 对账。 不信自己的 token 估算,只信响应里的 usage 字段。

展开讲一下第三、四条,这两条最容易被跳过,但恰恰是踩坑最多的地方。

幂等键不是"防重复提交"这么简单。 部分失败重放时,你要的是"失败的那几条重试",而不是"整批重投"。只要 job_id 稳定(比如用文档内容的 sha1),重放天然安全。反过来说,如果 job_id 每次都随机生成,重试就等于重复计费。

对账必须以服务端 usage 为准。 自己按字符数估 token,中文场景下偏差 10% 以上很正常,估出来的"省钱比例"就没有意义。代码里的 cost_of() 只做一件事:把响应里的 prompt_cache_hit_tokens / completion_tokens 按所属计价档乘上单价。

再补一句价格表的处理方式:生效价目里没有明确公布的字段,代码里留 None,对账时直接跳过并提示"未配置字段不计入"。宁可给一个下限估算,也不要算出一个看着完整、实际是编的数字。


三、关键实现

窗口判定。这是全篇最短也最容易写错的函数:

python 复制代码
TZ_CN = timezone(timedelta(hours=8))   # 显式时区,绝不依赖系统本地时区

def in_offpeak(now: datetime) -> bool:
    minutes = now.hour * 60 + now.minute
    for start, end in OFFPEAK:
        a, b = _hm(start), _hm(end)
        if a <= b:
            if a <= minutes < b:
                return True
        else:                           # 跨天窗口,例如 22:00-02:00
            if minutes >= a or minutes < b:
                return True
    return False

注意 a <= b 的分支。优惠窗口经常是跨天的(凌晨开始、早上结束),用 date 比较或者假设 start < end 都会在跨天时失败。

未到窗口时不要 sleep 一分钟轮询,直接算出下一个窗口开启时刻,带 0~90 秒抖动后一次性睡过去。抖动是必要的:整点齐发会让同一批人在同一秒撞上速率限制。

python 复制代码
def next_window_start(now: datetime) -> datetime:
    today = now.replace(second=0, microsecond=0)
    candidates = []
    for start, _ in OFFPEAK:
        a = _hm(start)
        cand = today.replace(hour=a // 60, minute=a % 60)
        if cand <= now:
            cand += timedelta(days=1)
        candidates.append(cand)
    return min(candidates) + timedelta(seconds=random.randint(0, 90))

状态流转。看到 runningfailed 两种状态应该能猜到设计意图:崩溃时可能留下 running 的僵尸任务,恢复时按 attempts 决定重试还是放弃。

python 复制代码
def mark(con, job_id: str, **kw) -> None:
    kw["updated"] = datetime.now(TZ_CN).isoformat(timespec="seconds")
    sets = ", ".join(f"{k}=?" for k in kw)
    con.execute(f"UPDATE jobs SET {sets} WHERE id=?", (*kw.values(), job_id))
    con.commit()

限流退避。429 是错峰调度里最常见的错误,说明你和别人想的是同一件事。别用固定间隔硬刷:

python 复制代码
if e.code == 429:
    back = min(2 ** (attempts + 1) * 2, 120)
    print(f"  429 限流,退避 {back}s")
    time.sleep(back)

四、完整代码

保存为 offpeak_scheduler.py,Python 3.8+,只用标准库。

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
offpeak_scheduler.py  按峰谷定价窗口调度的 LLM 批量任务队列(单文件,零第三方依赖)

设计目标
  1. 任务只落库、不丢:先写 SQLite,再发请求;
  2. 不在优惠时段就等待,而不是硬刷(避免高峰价 + 触发限流);
  3. 幂等:同一 job_id 重复投递不会重复计费;
  4. 可对账:按服务端返回的 usage 累加,输出「实付 / 高峰价 / 省下多少」。

用法
  python offpeak_scheduler.py init   --db jobs.db --demo
  python offpeak_scheduler.py run    --db jobs.db --dry-run --at "2026-09-12T07:00:00+08:00"
  python offpeak_scheduler.py run    --db jobs.db
  python offpeak_scheduler.py report --db jobs.db

环境变量:LLM_API_KEY,LLM_BASE_URL

免责:价格表与优惠时段均为配置项,默认值取自 2026-09-10 官方公布口径,
未公布的字段留 None(不计入对账)。上线前请以官方文档核对 PRICES / OFFPEAK。
"""
import argparse
import json
import os
import random
import sqlite3
import sys
import time
import urllib.error
import urllib.request
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone

TZ_CN = timezone(timedelta(hours=8))          # 显式时区,绝不依赖系统本地时区

# 优惠时段(北京时间)。跨天窗口,判定必须用 datetime 而不是 date。
OFFPEAK = [("00:30", "08:30")]

# 价格表:元 / 百万 token。None = 未获取到官方口径,不计入对账。
PRICES = {
    "peak":    {"in_cache": None, "in_miss": None, "out": 8.00},
    "offpeak": {"in_cache": 0.02, "in_miss": None, "out": 4.00},
}

# ---------- 时间窗口 ----------
def _hm(s: str) -> int:
    h, m = s.split(":")
    return int(h) * 60 + int(m)

def in_offpeak(now: datetime) -> bool:
    """now 必须带时区;返回是否落在任一优惠窗口内。"""
    minutes = now.hour * 60 + now.minute
    for start, end in OFFPEAK:
        a, b = _hm(start), _hm(end)
        if a <= b:
            if a <= minutes < b:
                return True
        else:                                  # 跨天窗口,例如 22:00-02:00
            if minutes >= a or minutes < b:
                return True
    return False

def next_window_start(now: datetime) -> datetime:
    """返回下一个优惠窗口的开始时刻(带抖动,避免整点齐发)。"""
    today = now.replace(second=0, microsecond=0)
    candidates = []
    for start, _ in OFFPEAK:
        a = _hm(start)
        cand = today.replace(hour=a // 60, minute=a % 60)
        if cand <= now:
            cand += timedelta(days=1)
        candidates.append(cand)
    return min(candidates) + timedelta(seconds=random.randint(0, 90))

# ---------- 存储 ----------
DDL = """
CREATE TABLE IF NOT EXISTS jobs (
  id        TEXT PRIMARY KEY,
  prompt    TEXT NOT NULL,
  state     TEXT NOT NULL DEFAULT 'pending',
  attempts  INTEGER NOT NULL DEFAULT 0,
  in_cache  INTEGER NOT NULL DEFAULT 0,
  in_miss   INTEGER NOT NULL DEFAULT 0,
  out       INTEGER NOT NULL DEFAULT 0,
  billed    TEXT,
  result    TEXT,
  err       TEXT,
  created   TEXT NOT NULL,
  updated   TEXT
);
"""

def connect(path: str) -> sqlite3.Connection:
    con = sqlite3.connect(path, timeout=30)
    con.execute("PRAGMA journal_mode=WAL")
    con.executescript(DDL)
    return con

def enqueue(con, job_id: str, prompt: str) -> bool:
    """先落库,后调用。已存在则跳过(幂等)。"""
    cur = con.execute(
        "INSERT OR IGNORE INTO jobs(id, prompt, created) VALUES (?,?,?)",
        (job_id, prompt, datetime.now(TZ_CN).isoformat(timespec="seconds")),
    )
    con.commit()
    return cur.rowcount == 1

def take_pending(con, limit: int) -> list:
    return con.execute(
        "SELECT id, prompt, attempts FROM jobs WHERE state IN ('pending','failed') "
        "ORDER BY created LIMIT ?", (limit,)
    ).fetchall()

def mark(con, job_id: str, **kw) -> None:
    kw["updated"] = datetime.now(TZ_CN).isoformat(timespec="seconds")
    sets = ", ".join(f"{k}=?" for k in kw)
    con.execute(f"UPDATE jobs SET {sets} WHERE id=?", (*kw.values(), job_id))
    con.commit()

# ---------- 调用 ----------
@dataclass
class Usage:
    in_cache: int
    in_miss: int
    out: int

def _post(base_url: str, api_key: str, model: str, prompt: str, timeout: int = 120) -> dict:
    body = json.dumps({
        "model": model,
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.3,
    }).encode("utf-8")
    req = urllib.request.Request(
        base_url.rstrip("/") + "/chat/completions",
        data=body,
        headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))

def call_model(prompt: str, cfg, dry: bool):
    """返回 (文本, Usage)。dry=True 时走本地假实现,便于离线联调。"""
    if dry:
        time.sleep(0.01)
        n_in = 120 + len(prompt) // 3
        return ("[dry-run] " + prompt[:24], Usage(n_in // 2, n_in // 2, 60 + len(prompt) // 4))
    data = _post(cfg.base_url, cfg.api_key, cfg.model, prompt)
    u = data.get("usage", {}) or {}
    cache_hit = int(u.get("prompt_cache_hit_tokens", 0) or 0)
    in_all = int(u.get("prompt_tokens", 0) or 0)
    text = data["choices"][0]["message"]["content"]
    return text, Usage(cache_hit, max(in_all - cache_hit, 0), int(u.get("completion_tokens", 0) or 0))

def cost_of(billed: str, u: Usage) -> float:
    p = PRICES.get(billed, {})
    per_m = 1_000_000
    total = 0.0
    for key, tokens in (("in_cache", u.in_cache), ("in_miss", u.in_miss), ("out", u.out)):
        price = p.get(key)
        if price is None:                      # 未配置的价格不计入,避免算出假数字
            continue
        total += price * tokens / per_m
    return total

# ---------- 主循环 ----------
def run(args) -> int:
    cfg = argparse.Namespace(
        base_url=args.base_url or os.environ.get("LLM_BASE_URL", "https://api.deepseek.com/v1"),
        api_key=os.environ.get("LLM_API_KEY", ""),
        model=args.model,
    )
    if not cfg.api_key and not args.dry_run:
        print("[FATAL] 缺少 LLM_API_KEY;如需离线联调用 --dry-run", file=sys.stderr)
        return 2

    con = connect(args.db)
    now = datetime.fromisoformat(args.at).astimezone(TZ_CN) if args.at else datetime.now(TZ_CN)

    pending = take_pending(con, args.limit)
    if not pending:
        print(f"[{now:%Y-%m-%d %H:%M}] 无待处理任务")
        return 0

    print(f"[{now:%Y-%m-%d %H:%M} 北京] 待处理 {len(pending)} 条,"
          f"当前处于{'优惠' if in_offpeak(now) else '高峰'}时段")
    if not in_offpeak(now):
        wake = next_window_start(now)
        wait = (wake - now).total_seconds()
        print(f"  非优惠时段,等待至 {wake:%Y-%m-%d %H:%M:%S}({wait/60:.1f} 分钟后),本轮不发请求")
        if not args.force:
            return 0
        print("  [--force] 忽略窗口,按高峰价立即执行")

    billed = "offpeak" if in_offpeak(now) and not args.force else "peak"
    ok = fail = 0
    paid = 0.0
    for job_id, prompt, attempts in pending:
        if not in_offpeak(datetime.now(TZ_CN)) and not args.force:
            print("  窗口结束,停止本轮")
            break
        mark(con, job_id, state="running", attempts=attempts + 1)
        try:
            text, u = call_model(prompt, cfg, args.dry_run)
        except urllib.error.HTTPError as e:
            body = e.read()[:200].decode("utf-8", "ignore")
            mark(con, job_id, state="failed", err=f"HTTP {e.code}: {body}")
            fail += 1
            if e.code == 429:                  # 限流:指数退避,别用固定间隔硬刷
                back = min(2 ** (attempts + 1) * 2, 120)
                print(f"  429 限流,退避 {back}s")
                time.sleep(back)
            continue
        except Exception as e:                 # 超时/网络抖动同样只重试单条
            mark(con, job_id, state="failed", err=f"{type(e).__name__}: {e}")
            fail += 1
            continue

        c = cost_of(billed, u)
        paid += c
        mark(con, job_id, state="done", result=text[:2000], err=None,
             in_cache=u.in_cache, in_miss=u.in_miss, out=u.out, billed=billed)
        ok += 1

    print(f"  完成 {ok} 条 / 失败 {fail} 条 · 本轮实付约 ¥{paid:.4f}(按 {billed} 价)")
    return 0

def report(args) -> int:
    con = connect(args.db)
    rows = con.execute(
        "SELECT billed, COUNT(*), SUM(in_cache), SUM(in_miss), SUM(out) FROM jobs "
        "WHERE state='done' GROUP BY billed"
    ).fetchall()
    if not rows:
        print("暂无已完成任务")
        return 0
    print(f"{'计价档':<10}{'条数':>6}{'缓存命中入':>12}{'未命中入':>12}{'出':>12}{'实付¥':>10}")
    total_paid = total_peak = 0.0
    for billed, n, ic, im, out in rows:
        u = Usage(ic or 0, im or 0, out or 0)
        paid = cost_of(billed, u)
        peak = cost_of("peak", u)
        total_paid += paid
        total_peak += peak
        print(f"{billed:<10}{n:>6}{u.in_cache:>12}{u.in_miss:>12}{u.out:>12}{paid:>10.4f}")
    saved = total_peak - total_paid
    pct = (saved / total_peak * 100) if total_peak else 0.0
    print(f"\n按高峰价应付 ¥{total_peak:.4f} → 实付 ¥{total_paid:.4f},"
          f"省下 ¥{saved:.4f}({pct:.1f}%)")
    print("注:未配置价格的字段不计入,故上表为下限估算。")
    return 0

def demo_init(args) -> int:
    con = connect(args.db)
    n = 0
    for i in range(20):
        if enqueue(con, f"job-{i:03d}", f"把下面这段技术文档总结成 3 条要点:doc-{i}"):
            n += 1
    print(f"已入队 {n} 条演示任务(其余为重复投递,被幂等键拦下)")
    return 0

def main() -> int:
    ap = argparse.ArgumentParser(description="峰谷定价下的 LLM 批量任务调度器")
    sub = ap.add_subparsers(dest="cmd", required=True)
    for name, fn in (("init", demo_init), ("run", run), ("report", report)):
        p = sub.add_parser(name)
        p.add_argument("--db", default="jobs.db")
        p.add_argument("--limit", type=int, default=200)
        p.add_argument("--model", default="deepseek-v4.1-flash")
        p.add_argument("--base-url", default=None)
        p.add_argument("--dry-run", action="store_true")
        p.add_argument("--at", default=None, help="模拟当前时间,ISO8601 带时区")
        p.add_argument("--force", action="store_true", help="忽略窗口,按高峰价立即执行")
        p.add_argument("--demo", action="store_true", help="init 子命令:造演示任务")
        p.set_defaults(func=fn)
    args = ap.parse_args()
    return args.func(args)

if __name__ == "__main__":
    raise SystemExit(main())

五、跑一遍看看

先造 20 条演示任务,然后用 --at 把"当前时间"分别设成高峰和闲时,验证窗口判定。--at 这个参数值得专门加:时间相关的逻辑不注入时钟就没法自动化验证,你不可能真的等到凌晨三点。

bash 复制代码
python offpeak_scheduler.py init --db jobs_demo.db --demo
复制代码
已入队 20 条演示任务(其余为重复投递,被幂等键拦下)

下午三点跑一次,它应该拒绝工作,并告诉你下一个窗口在哪:

bash 复制代码
python offpeak_scheduler.py run --db jobs_demo.db --dry-run --at "2026-09-12T15:00:00+08:00"
复制代码
[2026-09-12 15:00 北京] 待处理 20 条,当前处于高峰时段
  非优惠时段,等待至 2026-09-13 00:30:34(570.6 分钟后),本轮不发请求

凌晨三点再跑,正常执行:

bash 复制代码
python offpeak_scheduler.py run --db jobs_demo.db --dry-run --at "2026-09-12T03:00:00+08:00"
复制代码
[2026-09-12 03:00 北京] 待处理 20 条,当前处于优惠时段
  完成 20 条 / 失败 0 条 · 本轮实付约 ¥0.0053(按 offpeak 价)

最后对账:

bash 复制代码
python offpeak_scheduler.py report --db jobs_demo.db
复制代码
计价档           条数       缓存命中入        未命中入           出       实付¥
offpeak       20        1280        1280        1320    0.0053

按高峰价应付 ¥0.0106 → 实付 ¥0.0053,省下 ¥0.0053(49.8%)
注:未配置价格的字段不计入,故上表为下限估算。

省下 49.8%,接近理论上的"闲时五折"。差额来自缓存命中输入这一项:闲时 0.02 元/百万的价位在高峰档没有公布值,代码按未配置处理,所以 Peak 侧少算了一部分,实际节省只会略高于这个数。这就是"留 None 而不是猜一个数"的价值:结果偏保守,但方向不会骗人。

要挂到生产上,cron 只需要一条,让它每 30 分钟醒一次,非窗口期会立刻自己判断并退出:

bash 复制代码
*/30 * * * * cd /opt/batch && LLM_API_KEY=xxx /usr/bin/python3 offpeak_scheduler.py run --db jobs.db >> run.log 2>&1

六、几个工程取舍

不过,有几个取舍值得单独说清楚,因为它们决定了这套东西能不能长期跑下去。

为什么用 SQLite,不用 Redis。 这个场景的瓶颈是"等待",不是"吞吐"。单机批处理用 SQLite 有 WAL 模式,写入足够、天然持久化、零运维;换成 Redis 你要额外担心持久化配置和内存上限。任务并发到需要几十个 worker 抢同一个队列时,再考虑 Redis 或 MQ 不迟。

为什么不用 Celery。 Celery 解决的是"把任务分发到多台机器",你要解决的是"把任务推迟到某个时间点"。为一个时间判断引入 broker + result backend,是负债而不是能力。

为什么不用 APScheduler 之类的时间库。 窗口判定就是两次整数比较,二十行代码。引入依赖的收益是负的。

--force 为什么要留。 线上总会有"这张报表客户现在就要"的场景。留一个显式的强制通道,比让同事偷偷改系统时间好。代价是它会按高峰价计费,所以代码里把它写进 billed 字段,账单上看得见。

幂等键怎么选。 演示里用的是顺序 id,生产环境建议用「文档内容 sha1 + 提示词模板版本号」。模板改了就应该重跑,内容没变就不该重复计费,这两件事都由键的设计决定。


七、踩坑清单

  1. 时区。 容器里默认 UTC,北京时间 03:00 在容器里是 19:00,正好落在高峰。代码里所有 now 都显式声明时区,in_offpeak() 拿到不带的时区对象时应该直接抛错而不是静默按本地时区算。
  2. 跨天窗口。 00:3008:30 看着不跨天,但窗口的概念是每天循环的;一旦你把窗口配成 22:00-06:00,只用 start < end 判断的实现立刻失效。
  3. 整点齐发。 别在窗口开启的整秒启动全部任务,加随机抖动。这是错峰方案里最容易制造限流的地方,因为你想省钱的时候,别人也在想。
  4. 在窗口末尾开始的长任务。 循环里每次迭代都重新判断 in_offpeak(),窗口结束就停在安全点,不要在窗口最后一分钟起一个跑十分钟的请求。
  5. 对账窗口与实际计费不一致。 计费以服务端时间为准,客户端时钟有漂移。窗口边界前后 1 分钟内的请求,建议在对账时单独标出来核对,别默认自己一定在闲时。
  6. 把"缓存命中价"和"KV 压缩"混为一谈。 这是两件事:缓存命中省的是 prefill 的输入计算,KV Cache 压缩省的是显存占用。前者影响账单,后者影响你能开多长的上下文。
  7. running 状态的僵尸任务。 进程被 SIGKILL 时会留下 running。恢复逻辑里要显式处理:超过 N 分钟仍为 running 的任务,按 attempts 决定重试或标记失败。
  8. 别把延迟敏感任务塞进来。 这个调度器的语义是"可以等"。实时客服、在线搜索补全这类任务放进来,省下的钱不够赔体验。

八、留两个问题给你

  1. 你的批量任务里,有多少比例是真的可以等到凌晨执行?如果这个比例很高,卡点通常在哪一步,是调度、是上游数据就绪时间,还是业务方不接受延迟?
  2. 如果厂商把"闲时折扣"从五折改成七折甚至取消,你的成本模型还能站得住吗?换模型、换架构、还是压缩输入长度,你会先动哪一个?
  3. 你现在的批处理是怎么触发的,定时任务、消息队列,还是人工点一下?有没有遇到过跑到一半窗口结束、剩下任务按高峰价发出去的情况?

上面三个问题里如果有一个是你踩过的坑,欢迎在评论区留言,我会把典型做法整理成下一篇。


数据与事件来源

  • DeepSeek V4.1 Flash 发布信息与定价(2026-09-10):模型规模 552B MoE、CED 非对称结构、输入激活 8B / 输出激活 16B、MIT 许可、9 月 14 日 12:00 起 V4 Pro 下线并路由至 V4.1 Flash,闲时输入(缓存命中)0.02 元/百万 token、输出 4 元、高峰输出 8 元。来源:DeepSeek 官方发布信息;转述见腾讯研究院 AI 速递(20260911)。上述价格口径已与官方发布信息及第三方转述交叉核对。
  • 优惠时段的具体起止以 DeepSeek 开放平台定价文档为准;本文代码将窗口与价格全部做成配置项(OFFPEAK / PRICES),未在公开口径中明确的价格字段留 None 且不计入对账,不做估算填充。
  • 文中的命令输出为本机实际执行 offpeak_scheduler.py--dry-run 模式)所得,非示意性粘贴;文中所有金额均可用随文脚本复算核实。
相关推荐
小白跃升坊1 小时前
大模型推理入门:从原理到实践
ai·大模型·llm·推理优化
2601_962218611 小时前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法
FOAF-lambda1 小时前
uiautomation-new 控件方位的使用
开发语言·python
OKkankan1 小时前
LangChain能力详解!:从工具调用到 LangSmith——让聊天模型具备实时交互能力!
开发语言·python·langchain
张忠琳1 小时前
【deepseek-harness】DeepSeek Harness Agent Loop 模块深度架构分析之一
ai·agent·deepseek·harness·dsh
99316662 小时前
一个人用 AI 的困局:它从不反对你,所以我让 5 个 AI 开了场圆桌会议
github·deepseek
yunwei372 小时前
eBPF 教程:追踪 CUDA GPU 操作
linux·后端·性能优化
韩曙亮3 小时前
【AI 大模型】国内各平台 AI 大模型 价格、性能 对比分析 ② ( 智谱 BigModel | 腾讯云 TokenHub | 千问 AI 平台 )
人工智能·ai·大模型·腾讯云·ai大模型·千问·智谱
2601_962298273 小时前
Python自动化脚本的编写01
python·appium·自动化脚本·web自动化·应收账款管理