← Back to home@KingVergil

ds-football-agent

No description

Stars
0
Language
Python
Created
Aug 14, 2026
Updated
Sep 17, 2026

Introduction

ds-agents — 足球投注分析 agent(DSH harness + Python 引擎)

多智能体足球投注分析系统:DSH harness 插件负责只读数据工具 + 仪表盘 + 桥接, Python 引擎负责确定性业务(资金 / 订单 / 结算 / 因子)与分析执行(随仓库发布)。

harness 插件(只读工具 + 斗狗场) ──POST /ds-run──►  python -m src.bridge(引擎)
                                                    │  数据准备 → 读人设 → 查资金
                                                    │  → LLM 决策 → 下单 → 结算 → 因子
                                                    └──► 写回 roles/<狗>/(本地唯一真源)

为什么这么改

这套结构是 2026-08 逐步收敛的结果,最直接的触发点是:dsh(harness agent)老是「逃逸」。

  • 问题:agent 不按固定流程走。分析/结算/因子这类流程本质是确定性的 (取数 → 读人设 → 查资金 → 决策 → 下单 → 结算 → 因子),但把入口暴露成 LLM 工具后, agent 经常自己用 bash/文件操作复刻流程、跳步骤、乱调工具——结果不可控、难审计、出错难排查。
  • 对策:固定流从 LLM 工具面板拿掉,收敛成「薄壳」。执行入口只剩斗狗场按钮 (POST /ds-run → python 桥),每一步都带任务记录(/ds-tasks),进度和结果可查; agent 的工具面板只剩只读数据工具(lota_matches / lota_match / lota_sections / lota_status)。LLM 只保留两个决策点:analyze 的一次判断,和回放暂停时起草方向建议 (供用户编辑后注入下一周期退役评估)。
  • 执行核心是 Python 引擎,所以一起开源:资金/订单/结算/因子早已在 python-engine 落地,JS 侧只是壳。只发插件不发引擎,克隆下来会是一个跑不起来的空壳;这次把引擎 代码(src/、CLI、脚本)一起发布。
  • JS 镜像退役:同一套业务逻辑一度有 JS 镜像(settleEngine / placeOrders / factorInduction / factorReview…),双份实现必然漂移、维护成本翻倍。现在以 Python 引擎为唯一实现,JS 侧删除镜像,只保留只读工具、仪表盘和桥。
  • 数据获取收敛到 Python:刷新比赛/特征/段落早已由引擎(src/data_manager.py, 桥 prepare)完成,旧 JS 版 lota_fetcher.js 是上一代残留,已删除;密钥一律走 环境变量(LOTA_API_KEY / DEEPSEEK_API_KEY / 邮件授权码),不落代码。
  • 7 只狗与运行时数据不公开:角色人设、资金、订单、因子记忆属于私有运行时数据; 公开仓库只发布代码 + 历史比赛数据包。狗列表改为按本地角色派生 (python -m src.role_registry live),因此公开克隆零狗时群体操作自然为空操作, 用户创建自己的狗后自动生效,无需改代码。
  • 历史数据包随仓库一起发:仓库根目录 fixtures/ 下有 testdata-14d.tar.gz / testdata-30d.tar.gz(未解压的归档,不是目录树,见 数据在哪);实时数据需要 LOTA_API_KEY(找维护者要)。

架构分层

层是什么提供什么归属
插件 ds-agents-lota-data能力(工具 + UI)只读数据工具 + 「斗狗场」仪表盘 + 创建狗 + 回放入口开源(harness-plugin/)
Python 引擎执行核心数据准备 / 分析下单 / 结算 / 因子归纳 / 因子退役 / 状态 / 重置开源(python-engine/)
数据获取层(python 引擎)缓存生产者抓 Lota API → 写本地缓存(src/data_manager.py / 桥 prepare)开源(需 LOTA_API_KEY)
运行时数据 python-engine/data/本地真源matches/features/tags 缓存 + roles/<狗>/(人设/资金/订单/因子)私有(不入库)
  • 固定流不走 LLM 工具面板:数据准备 / 分析 / 结算 / 因子归纳 / 因子退役 的执行入口只有 斗狗场按钮(POST /ds-run → 插件直接 spawn python -m src.bridge)与回放(/ds-replay)。
  • harness agent 只剩两个职责:回答数据/状态类问题(只读工具);回放暂停时起草 「下一轮方向建议」供用户编辑(ds_replay 半交互)。
  • LLM 只在引擎内两处:analyze 的一次决策 + factor 相关旁路调用;确定性业务全部在引擎代码里。

数据流

Lota API ──(python 引擎数据层 + LOTA_API_KEY)──► 本地缓存 matches/features/tags
                                        │
                            ┌───────────┴───────────┐
                            ▼                       ▼
                     lota_* 只读工具          /ds-dashboard 仪表盘
                            │                       │
                            └──── POST /ds-run ─────┘
                                        ▼
                          python -m src.bridge(NDJSON 协议)
                              ├─ analyze:读人设/记忆/资金 → LLM 决策 → 下单
                              ├─ settle / factor-induction / factor-review
                              └─ 写回 roles/<狗>/ + factors/

桥协议(stdin 单行 JSON 请求 / stdout NDJSON 事件)见 harness-plugin/docs/bridge.md。

部署使用

1. 前置

  • DSH harness(Cordis 运行环境,自带 Node 运行时)

  • Python 3.10+

  • 引擎依赖(python-engine/requirements.txt):

    python -m pip install -r python-engine/requirements.txt   # requests + langgraph
    
  • Python 引擎自带数据获取(src/data_manager.py,需 LOTA_API_KEY,见 fetcher_protocol.md)

可选:playwright 只用于 python-engine/docs/render_diagrams.py 渲染架构图, 日常分析/结算/因子流程不需要。

2. 装插件 + 配引擎

把 harness-plugin/ 作为 npm 包(ds-agents-lota-data)或本地路径,插件行并入 composition:

- id: lota-data
  name: 'ds-agents-lota-data'
  config:
    cacheDir: ./python-engine/data   # 缓存根目录(matches/features/tags/roles)
    engineRoot: ./python-engine      # Python 引擎根目录
    # pythonBin: <解释器绝对路径>     # 可选;缺省按平台自动选(Windows=python,macOS/Linux=python3)
    # envFile: <路径>                # 可选密钥文件;缺省自动读 <engineRoot>/.env 与 ~/.env

引擎需要环境变量(DEEPSEEK_API_KEY 做 LLM 决策、LOTA_API_KEY 拉数据):

# 方式 A(推荐,Windows/macOS/Linux 通用):写 .env(默认读 <engineRoot>/.env)
cp python-engine/.env.example python-engine/.env
# 编辑 python-engine/.env,填 DEEPSEEK_API_KEY / LOTA_API_KEY

# 方式 B(macOS/Linux):放 ~/.zshrc,插件 bridge.js 会读它注入子进程(历史兜底)
export DEEPSEEK_API_KEY=...
export LOTA_API_KEY=...

读取优先级:环境变量 > .env(config.envFile → <engineRoot>/.env → ~/.env)> ~/.zshrc / ~/.bashrc(仅非 Windows)。

一键安装(macOS / Linux / Windows 通用)

node harness-plugin/scripts/install.mjs \
  --profile-dir <dsh profile 目录,如 ~/.dsh/profiles/web> \
  --set-keys DEEPSEEK_API_KEY=... LOTA_API_KEY=...

幂等完成「装进 profile node_modules + 写 cordis.patch.yml 挂载条目 + 写密钥文件 (Windows 写 .env,macOS/Linux 再追加 ~/.zshrc)」,全程不需要管理员权限。

Windows 用户:没有 ~/.zshrc 也没关系——密钥放 python-engine/.env 即可; python3 是商店别名,插件自动改用 python(或 config.pythonBin 配绝对路径)。

3. 准备数据

两种方式,二选一:

  • 公开数据包(开箱即玩):见下面 数据在哪(公开数据包)。
  • 实时数据:配好 LOTA_API_KEY 后由引擎自己拉——桥 prepare(live 强制刷新 / replay 缓存优先) 会抓比赛 + compact-fet + 切 sections;命令行可用 dsfootball_cli.py dashboard 触发。 需要实时数据 / 申请 LOTA_API_KEY:加微信 researcher22(自建端点则用 LOTA_API_BASE 环境变量指过去,不要把地址写进代码)。

数据在哪(公开数据包)

⚠️ 常见误会:数据包在仓库根目录的 fixtures/,不是 python-engine/fixtures; 而且它是两个 .tar.gz 归档,clone 下来不会自动出现 matches/、features/ 目录,必须自己解压。python-engine/data/(运行时缓存)按设计不入库, git clone 后本来是空的,不是克隆出错。

文件(仓库根 fixtures/)覆盖范围解压后大小
testdata-14d.tar.gz2026-08-01 ~ 08-14(14 个足球日)testdata-14d/{matches,features}:1519 场 / 672 场特征1.3 MB
testdata-30d.tar.gz2026-07-19 ~ 08-19(32 个足球日)testdata-30d/{matches,features}:2792 场 / 1371 场特征2.7 MB

获取与使用(三选一):

# ① 已经 clone:数据就在仓库里,直接解压
tar -xzf fixtures/testdata-30d.tar.gz          # → ./testdata-30d/{matches,features}

# ② 不想 clone:直连下载(仓库内文件)
curl -LO https://github.com/KingVergil/ds-football-agent/raw/main/fixtures/testdata-30d.tar.gz

# ③ 在线浏览 / 挑单个文件
#    https://github.com/KingVergil/ds-football-agent/tree/main/fixtures

校验完整性(两个包的摘要):

2149be9b976fb0fc570f58b1061de8cac9350ba8094880a1ea04c6c02b1a7d14  testdata-14d.tar.gz
5f6716d0f95b5f174dfac5ea5664e08580adb5c6bbf5b3821091aa4d2edaf72e  testdata-30d.tar.gz

然后把插件的 cacheDir 指向解压目录(或把 matches/、features/ 拷进你的缓存根目录):

- id: lota-data
  name: 'ds-agents-lota-data'
  config:
    cacheDir: ./testdata-30d

数据包内容与「哪些没打包(tags/、roles/)及其原因」见 fixtures/README.md。

4. 初始化一只狗(角色)

一只狗 = roles/<狗>/persona.md(人设,唯一源)+ roles/<狗>/<狗>.json (资金/订单/limits/status)+ 可选注册表条目(data/dogs.json,结构化配置), 外加引擎按需生成的 memory/、factors/。初始化方式:

  1. 斗狗场「创建狗」(推荐):仪表盘表单 → POST /ds-dogs,插件幂等补建 persona.md(默认保守模板)与 <狗>.json(初始资金默认 10000),并写入 dogs.json 注册表。 新建狗默认 status=sandbox(观察期,不进全量默认列表)。
  2. 插件 config.roles 内联:config.roles: [{ name, scope, initial_capital, alpha_mode, limits, enabled, emoji, c1, c2 }]。 只影响展示/默认列表,角色文件仍需在本地存在。
  3. 手动建目录:mkdir -p roles/<狗>/,写 persona.md 与 <狗>.json (字段见 python-engine/src/role_registry.py::sync_from_registry), 然后 python -m src.role_registry sync 幂等补缺/迁移。

初始化完成后:

  • status=live 的狗进入全量默认列表(python -m src.role_registry live), 斗狗场逐狗按钮(及逐狗 CLI)都会带上它;
  • 人设/limits/scope 后续可在斗狗场编辑狗(PATCH /ds-dogs/<name>),资金与订单不受影响;
  • 删除狗只移注册表(DELETE /ds-dogs/<name>),历史订单/因子/资金保留;
  • 公开仓库不携带任何狗数据:本地没有 roles/<狗>/ 就不会出现在任何列表/群体操作里。

狗列表完全由本地角色派生(python-engine/src/role_registry.py),与仓库里提交了什么无关。

5. 日常使用

在挂载插件的 preset 下开 session:

你要干的直接说
分析下单斗狗场逐狗点「⚡ 分析」(或「分析 <狗>」)
结算斗狗场「🧾 结算」
因子归纳 / 退役斗狗场「🧬 归纳」「🪦 Review」
酒馆对话斗狗场「🍶 酒馆」:跟狗按人设纯聊天、不出单;要单去「⚡ 分析」
回放「跑回放」/ ds_replay 工具
数据/状态问答「<狗> 余额多少」「今天有哪些竞彩比赛」

逐狗命令行(python-engine/;批量操作统一走斗狗场按钮):

python dsfootball_cli.py prefetch <day> --jingcai                          # 分析前预取
python dsfootball_cli.py agent <狗> analyze <day> --prefetched --jingcai   # 单狗分析;批量用「⚡ 分析」
python dsfootball_cli.py agent <狗> settle <day> --jingcai                # 单狗结算;批量用「🧾 结算」
python dsfootball_cli.py agent <狗> status                                # 某狗状态
python dsfootball_cli.py dashboard                                         # 刷新数据并打开看板
python dsfootball_cli.py factor-induction                                  # 因子归纳

./batch_agents.sh 已停用,不再作为入口;一律用上面的 python CLI 或斗狗场按钮(Windows/macOS 通用,无需 shell)。

群体操作(analyze/settle/factor)只作用于本地 status=live 的角色; 公开仓库零狗时它们自然为空操作,创建狗后自动生效。

目录结构

harness-plugin/            # 开源插件(入库)
├─ index.js                # 插件本体:只读工具注册 + 斗狗场 + 定时器 + prompt section
├─ bridge.js               # dsh ↔ python-engine 统一桥(NDJSON,func 白名单)
├─ dashboard.js / client.js  # 「斗狗场」仪表盘(/ds-dashboard + /ds-dogs + /ds-run + /ds-replay)
├─ dogRegistry.js          # 运行时狗注册表(创建/编辑/删除狗,幂等补建 Python 角色)
├─ replay.js / tools/replayTool.js  # 回放(沙箱目录模型,半交互)
├─ tools/deterministic.js  # 只读数据工具(lota_matches / lota_match / lota_sections / lota_status)
├─ tools/roles.js          # 角色解析(狗列表按本地角色派生)
├─ scripts/install.mjs     # 跨平台一键安装器(macOS / Linux / Windows)
├─ docs/                   # 桥协议 / 缓存格式 / 回放设计
└─ SKILL.md / cordis.yml / package.json

python-engine/             # Python 引擎(入库)
├─ src/bridge.py           # 统一桥入口(8 个 func 白名单)
├─ src/agent.py            # 角色 Agent(人设/资金/订单/记忆)
├─ src/data_manager.py     # 数据获取层(Lota API,需 LOTA_API_KEY)
├─ src/place_orders.py / settle.py / factor_*.py  # 下单/结算/因子
├─ src/role_registry.py    # 角色注册表(live/all/alpha/sync)
├─ dsfootball_cli.py                     # CLI 逐狗操作
├─ data/                   # 运行时数据(私有,不入库)
└─ docs/                   # 架构/格式文档

fixtures/                  # 公开数据包:未解压的 tar.gz(解压后是 matches/ + features/)

数据协议

开源仓库不绑定数据源。缓存格式 + Fetcher 接入见:

自建数据源按 cache_format_spec.md 产出缓存即可;唯一数据专有点是 odds.js 的盘口排版解析。

License

MIT