Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: test

on:
push:
branches: [master]
pull_request:

jobs:
unittest:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# 零第三方依赖(纯标准库),无需 pip install
- name: 离线单测(44 项)
run: python -m unittest tests.test_offline
- name: 端到端冒烟(11 项,子进程级)
run: python tools/smoke_e2e.py
- name: 实验框架 dry-run
run: python experiments/run_experiments.py --dry-run
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# CHANGELOG

按日期复述演进(问题清单冻结于 09-01,仓库 09-05 建立;v1.2 为首个全量快照,其后一律走 PR 流)。

## 2026-09-01 · 契约冻结(v0)

- 问题全景分析定稿:31 条问题清单 + A/B/C 分级 + 范围切割(主线 / 非目标)
- **IR v0 三层契约冻结**(L0 内容块 / L1 规范请求 / L2 会话缓存上下文),05A/05B 据此并行
- 缓存最小 token 阈值、计费与 TTL 不对称逐模型核对官方文档(docs.anthropic.com 与 platform.claude.com 一致)

## 2026-09-05 · v1.2 全量实现(PR #1)

- IR 契约 / 3 对 adapter / 状态层(SQLite + TTL + prev_id 反查)/ 网关(预热校验 + 记忆注入 + 限流 + usage 归一 + 历史落库)/ 5 项埋点 / 实验框架 / 工具链
- **两轮代码自查修复 9 项缺陷**(3 严重:状态层空转 / 多轮链断 / prev_id 回传上游),各配回归测试 → 抗漂移机制实战验证
- 25 项单测 + 11 项端到端冒烟全过

## 2026-09-08 · 实验交付(PR #2)

- 缓存命中率全量实测 **exp1–19 + E20–E28**(Anthropic 兼容端点真实调用)
- 主数字:LOCKED vs DYNAMIC ≈ **7.3×**(跨模型一致);E27「05B 救援」:Responses 透传 0% → 转 Messages 99.85%
- 「20-block 回看窗口」**决定性证伪**(60 块 100% 命中),从执行方案删除

## 2026-09-09 · 覆盖补全 + 可观测对账 + 弹网页(PR #3 / #4 / #5)

- E30–E34 进阶实验:并发冷启动重复写入(E32,single-flight 必要性)/ 前缀字节边界 / 命中快 ~1.65s(E33)/ opus-5 悬案定性为「端点异常」(E34)/ 23711 token 仍全缓存
- **E29 埋点对账**:起网关连真实端点,埋点与 API usage 逐字段一致
- 弹网页编排界面:记忆勾选/裁剪 + 缓存前缀可视化 + 回写状态层
- 修复网关后端路径映射(`PB_CHAT_PATH` / `PB_RESPONSE_PATH` / `PB_ANTHROPIC_PATH` 可覆盖)

## 2026-09-09 · 文档一致性修订(本提交)

- 全库清除「20-block 回看窗口」残留表述(ir-schema / capability-matrix / 实验脚本注释),统一指向证伪结论
- capability-matrix v0.2:状态列按实码校准(prev_id / 断点布局已实现;SSE 更正为「整读透传」);补「手动断点 vs 自动缓存」决策记录
- ir-schema 补「变更记录」(冻结 = L0/L1 语义层 + 修订必配回归测试的抗漂移机制)
- experiment-results 补「第〇节 · 证伪条件预登记」(实验编号 = 假设编号,回链问题清单条目)
- 新增 `docs/LIMITATIONS.md`:12 项未闭环/边界项四要素(影响半径 / 触发条件 / 绕过方式 / 后续路线)+ 结论隔离证明
- README:状态表加「证据」列;SSE 措辞更正;新增「与上游 TencentDB-Agent-Memory 的关系」

## 2026-09-09 · v1.4 代码补强:第三轮自查 + 工具 ID 映射 + 结构化重放(本提交)

- **第三轮自查(评审前逐文件复查)再发现 2 个真实 bug,各配回归测试**:
- 跨协议工具参数丢失:OpenAI 系 `arguments` 是 JSON 字符串,to_ir 只塞 `extra` 不解析,`tool_input` 恒为 None → 转到 Anthropic 全部渲染成空 `input {}`(`TestCrossProtocolToolArgs` 4 项)
- thinking `signature` 与 `redacted_thinking` 在 to_ir 被丢 → 多轮思考链下一轮必 400(`TestThinkingSignature` 2 项)
- **工具调用 ID 双向持久映射**(问题清单组4#3,原 LIMITATIONS #2):`src/state/idmap.py` 会话级 canonical ↔ 各协议外部形式,SQLite 持久、铸造稳定(前缀不抖动)、会话间隔离(并发分叉不串号);网关 to_ir 后归一、from_ir 前翻译、落库前翻回 canonical(`TestToolIdMap` 5 项)
- **状态层重放保留结构化块**(原 LIMITATIONS #3):`assistant_from_upstream()` 保留 thinking(signature / redacted)与 tool_use(含解析后 tool_input)入历史,多轮思考链/工具链不再断(`TestAssistantFromUpstream` 4 项)
- 测试 25 → **40 项全过** + 11 项端到端冒烟全过(Python 3.13)

## 2026-09-09 · property-based 测试 + 有损清单 + CI(本提交)

- **`TestPropertyRoundTrip`**(问题清单组5#10):stdlib 实现、固定种子可复现,440 个随机用例断言四条性质——断点恒在 [3,4] / 未知顶层字段必降级 / 工具参数跨协议守恒 / thinking signature 往返守恒(参数丢失 bug 正是这类性质被抓出的)。测试 40 → **44 项全过**
- **新增 `docs/lossy-fields.md`**(问题清单主线交付物):从三个 adapter 实码推导的有损字段清单(块级 / 参数级 / usage 归一级),含两处诚实标注的清单盲区(工具定义内部字段无 dropped 记录、多模态/流式未覆盖)
- **GitHub Actions CI**:`.github/workflows/test.yml`,Python 3.11/3.12/3.13 矩阵跑单测 + 冒烟 + dry-run(零依赖,无需装包);README 加 badge 行
- README 修正一处悬空引用(原指向方案 v3.1 已不存在的节号,改指实验文档方法学节)
- 文档口径:实验文档成本列改为**相对倍数**(7.35× / 10.2× / 7.9×),不再出现绝对金额;ir-schema 移除签字栏(冻结约束以「双方确认 + 变更记录」为准)
49 changes: 33 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# protocol-bridge

[![test](https://github.com/H2Rhan/protocol-bridge/actions/workflows/test.yml/badge.svg)](https://github.com/H2Rhan/protocol-bridge/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
![python](https://img.shields.io/badge/python-3.11%2B-blue)
![deps](https://img.shields.io/badge/deps-stdlib%20only-brightgreen)

犀牛鸟开源实战 · TRACK 05A/05B 协议转换组

OpenAI Chat / OpenAI Response ↔ Anthropic 的协议转换层(网关/代理 + 独立状态层)。
Expand All @@ -10,27 +15,31 @@ OpenAI Chat / OpenAI Response ↔ Anthropic 的协议转换层(网关/代理 +

## 当前状态

| 模块 | 状态 | 说明 |
| 模块 | 状态 | 证据 |
|---|---|---|
| IR v0 契约 | ✅ 离线 | `docs/ir-schema.md` + `src/ir/model.py` |
| 状态层(SQLite 持久化)+ 可切换 Session 配置 | ✅ v1.1 | `src/state/` + `config/session.json`,重启不丢 |
| 三对 adapter(字段映射) | ✅ 离线 | `src/adapters/`,录制样例可测 |
| 网关转发 + SSE 透传 | ✅ 离线(mock)/ Groq 真实链路已验证 | `src/gateway/` |
| 记忆注入(幂等去重 + memory_cap) | ✅ v1.1 新增 | `inject_memories`,管理口 `/v1/admin/session/meta` |
| 预热拒绝条件校验 | ✅ v1.1 新增 | stream/thinking/structured outputs/tool_choice 四类冲突 400 |
| IR v0 契约(三层 + 变更记录) | ✅ 冻结(语义层) | `docs/ir-schema.md` + `src/ir/model.py`;抗漂移机制见变更记录节 |
| 状态层(SQLite 持久化)+ 可切换 Session 配置 | ✅ v1.1 | `src/state/` + `config/session.json`,重启不丢(`TestStateLayer`) |
| 三对 adapter(字段映射) | ✅ 离线 | `src/adapters/`,录制样例可测(`TestAdapterRoundTrip`) |
| 网关转发 | ✅ 离线(mock)/ Groq 真实链路已验证 | `src/gateway/`;E29 真实端点对账 |
| SSE 流式 | ◐ 整读透传 | 逐块转换未实现 → `docs/LIMITATIONS.md` #1;E21 证明流式无损命中率 |
| 记忆注入(幂等去重 + memory_cap) | ✅ v1.1 新增 | `inject_memories` + `TestGatewayPolicies`;管理口 `/v1/admin/session/meta` |
| 工具调用全链路(含 ID 双向映射) | ✅ **v1.4** | 跨协议参数/签名不丢(`TestCrossProtocolToolArgs`/`TestThinkingSignature`);`src/state/idmap.py` 会话级映射(`TestToolIdMap`) |
| 状态层重放(结构化块) | ✅ **v1.4** | thinking(signature/redacted)与 tool_use 入历史(`TestAssistantFromUpstream`) |
| 预热拒绝条件校验 | ✅ v1.1 新增 | stream/thinking/structured outputs/tool_choice 四类冲突 400(`TestWarmup`) |
| 限流 | ✅ v1.1 新增 | `PB_CONCURRENCY`(默认 2) |
| 命中率埋点(5 项暴露) | ✅ 已实做对账 | v1.1 起真实统计、v1.2 预热轮单列/加锁;E29 实测埋点与 API usage 逐字段一致 |
| max_tokens:0 预热路径 | ✅ 字段处理 | 用录制响应样例测 |
| **两轮代码自查(9 bug 修复 + 回归测试)** | ✅ **v1.2 新增** | 含 3 个严重项(状态层空转 / 多轮链断 / prev_id 回传),见 `docs/REVIEW.md` 第五节 |
| 三组对照实验 | ✅ 34 组全量实测 | `experiments/`(`rich_experiments.py` E20–E28 + `rich_experiments2.py` E30–E34);结果见 `docs/experiment-results.md` |
| TRACK04 签字确认稿 | ✅ v1.1 新增 | `docs/TRACK04_签字确认稿.md`,分工会直接签 |
| 命中率埋点(5 项暴露) | ✅ 已对账 | **E29:埋点与真实端点 usage 逐字段一致** |
| max_tokens:0 预热路径 | ✅ 实测有效 | 录制样例测 + 实测预热后 100% 命中(exp17) |
| **两轮代码自查(9 bug 修复 + 回归测试)** | ✅ **v1.2 新增** | 含 3 个严重项,各配回归测试(`TestAuditFindings`),见 `docs/REVIEW.md` 第五节 |
| 三组对照实验 | ✅ 34 组全量实测 | `docs/experiment-results.md`(含第〇节证伪条件预登记) |
| TRACK04 边界参数对齐稿 | ✅ 已对齐 | `docs/TRACK04_签字确认稿.md`(single_task 等三参数已定稿) |
| 弹网页(本地仪表盘) | ✅ 记忆编排界面 | `src/webui/` 安全骨架 + 记忆勾选/裁剪 + 缓存前缀可视化 |
| 已知限制(边界自觉) | 📋 12 项四要素 | `docs/LIMITATIONS.md`(含结论隔离证明) |

## 快速开始(离线)

```bash
# 零外部依赖(仅标准库),Python 3.11+
python -m unittest tests.test_offline -v # 25 项离线单测:IR 往返 / adapter / 状态层 / 预热 / 自查回归 / 多轮链 E2E
python -m unittest tests.test_offline -v # 40 项离线单测:IR 往返 / adapter / 状态层 / 预热 / 三轮自查回归 / 多轮链 E2E / ID 映射
python tools/smoke_e2e.py # 11 项端到端冒烟:真起 mock+网关子进程,5 组链路断言
python tools/mock_backend.py # 起 mock backend(127.0.0.1:9100,按端点返回三种协议形状)
python -m src.gateway.server # 起网关(转发到 mock)
Expand All @@ -54,7 +63,7 @@ python -m src.gateway.server
- Anthropic 目标需 Anthropic 协议端点(Groq 无 `/v1/messages`);网关自动带 `anthropic-version` 头(`PB_ANTHROPIC_VERSION` 可覆盖)。
- 接 Anthropic 端点调试缓存链路前,先跑验站脚本确认透传(PASS 才可用):
`python tools/verify_cache.py --base https://<端点域名> --model <模型> --key <key>`
正式实验数据口径(共享账号缓存污染与缓解)见方案 v3.1 §3.6.1。
正式实验数据口径(缓存污染与缓解:唯一 run_id 前缀隔离)见 `docs/experiment-results.md` 第七节「方法学与踩坑」第 1 条。

## 设计要点(对应执行方案 v3)

Expand All @@ -69,23 +78,31 @@ python -m src.gateway.server
## 实验(已完成,34 组)

- 缓存命中率实测 **34 组**(exp1–19 三组对照 + E20–E28 覆盖 + E30–E34 进阶),量化取舍结论见 `docs/experiment-results.md`。
- **实验编号 = 假设编号**:问题清单的 A 级条目在写代码前即登记为待判决假设(测试左移),回链表见实验文档第〇节。判决分布:证实 8 · 证伪/反向 4 · 反转 1(含「20-block 回看窗口」证伪、「05B 透传不可行 → 转 Messages 可达」反转)。
- 核心结论:LOCKED vs DYNAMIC ≈ **7.3×**(跨模型一致);命中比冷启动快 **~1.65s**;缓存按 provider 隔离、不跨模型复用;haiku-4.5 阈值 4096 token。
- 配套脚本:`experiments/run_experiments.py`(三组对照)、`rich_experiments.py`(E20–E28)、`rich_experiments2.py`(E30–E34)。

## 与上游 TencentDB-Agent-Memory 的关系

[TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory) 的核心机制是「proxy 不改协议、每轮向上下文注入 L2/L3 记忆」——**本仓库的 34 组实验量化的正是这套机制的成本语义**:同一份记忆,锁死注入 vs 动态注入成本差 7.3×;低于模型阈值静默不缓存;断点布局直接决定前缀稳定性。

可拆出提上游的方向:AgentMemory proxy 目前**没有 `cache_control` 断点布局与缓存命中率埋点**——本仓库的断点布局(3 固定 + 1 滚动)与 5 项埋点(E29 已与真实端点对账)可作为参考实现。

## 目录

```
src/
ir/ IR 数据模型(L0/L1/L2)
adapters/ chat / response / anthropic 三对 adapter
state/ 会话表 + TTL + session 配置 + build_prefix
gateway/ HTTP 转发 + SSE 透传
gateway/ HTTP 转发(SSE 为整读透传,逐块转换见 docs/LIMITATIONS.md #1)
observability/ 命中率埋点(5 项暴露)
warmup/ max_tokens:0 预热
webui/ 弹网页本地仪表盘(安全骨架 + 记忆编排界面)
config/ session.json(Session 边界可切换配置)
experiments/ 三组对照 + rich_experiments.py(E20–E28)+ rich_experiments2.py(E30–E34)
tests/ 离线单测(录制样例 + 自查回归 + 多轮链 E2E)
tools/ mock_backend + verify_cache + smoke_e2e + recordings
docs/ ir-schema.md / capability-matrix.md / REVIEW.md / TRACK04_签字确认稿.md
docs/ ir-schema.md / capability-matrix.md / experiment-results.md / LIMITATIONS.md / REVIEW.md / TRACK04_签字确认稿.md
CHANGELOG.md 按日期演进记录(v0 契约冻结 → v1.2 → 实验交付 → 覆盖补全)
```
Loading
Loading