把 EdgeOne Agents(DeepSeek Harness)变成 OpenAI 兼容 API 的网关
纯文本模式 · 工具调用模式 · 工具名白名单 / 别名过滤 · 会话池 · 会话粘性 · 生命周期自愈 · 流式 / 非流式
EdgeOne2API 是一个自托管的 OpenAI 兼容反向代理网关,将 EdgeOne Agents / DeepSeek Harness(deepseek-harness.edgeone.cool)包装为统一的 /v1/chat/completions 服务。
- 上游是带 agent loop 的对话引擎,原生输出流式 block 事件(文本、推理、工具调用),且自带一套平台原生工具(
mcp__edgeone__*/ Codex 风格bash/str_replace_editor); - 本网关负责两件事:把 agent 协议翻译成 OpenAI 标准协议,以及保证工具只在客户端执行、上游沙箱永不介入;
- 对客户端只暴露 OpenAI 兼容接口,现有 SDK / 前端 / 工具 零改造接入。
⚠️ 合规须知:本项目是非官方网关,使用 EdgeOne Agents 会话作为上游,仅限本人授权账号、本机 / 私有环境测试。详细边界见安全与合规。
| 能力 | 说明 |
|---|---|
| 🎭 双模式 | 未声明 tools → 纯文本模式:折叠上游一切工具事件、finish_reason 归一为 stop、工具驱动的轮次自动续读直到输出正文;声明 tools → 工具调用模式:解析上游原生 tool-call block(或 ToolForge JSON 文本协议),返回标准 tool_calls |
| 🛡️ 工具名白名单 + 别名过滤 | 上游漂移出的 bash / str_replace_editor / mcp__edgeone__* 等名字,在到达客户端前被校验 / 改写 / 丢弃——杜绝「客户端报 Tool not found → 模型编造沙箱被挡」的故障链 |
| 🧲 会话池 | pool_min ~ pool_max 弹性伸缩(默认 4~32),空闲自动回补、突发并发预热(最多 4 个并行在途)、浏览器指纹限流后 24h 冷却 |
| 📎 会话粘性 | X-Session-Key 头部或请求体 conversation_id / user_id 自动绑定固定上游会话,多轮对话上下文连续;达 max_req_per_session 或连续失败自动轮换,轮换后对话历史重放保持上下文 |
| 💊 生命周期自愈 | 上游约 20 分钟回收空闲会话——session not found 被识别为生命周期事件(MarkGone)而非配额事件,换新会话重试,不烧指纹、不 502;真实配额错误(IsQuotaError)才冷却指纹 24h |
| 🔒 沙箱隔离 | SSE 流在 turn 结束时立即 cancel,上游 agent loop(沙箱工具执行)在启动前即被掐断——工具永远跑在客户端,不在沙箱 |
| ⚡ 流式 + 非流式 | SSE 透传 / 折叠 / 续读;非流式由本地聚合为单响应 |
| 🧠 推理强度 | 支持 reasoning_effort(off / high / max),全局兜底 default_reasoning_effort,模型映射可逐模型指定 |
| 📊 可观测 | /healthz 探活、/pool 会话池状态(free / bound / active / 冷却 / 命中率,非阻塞读取)、每请求 [TOOLS] 过滤日志 |
| 🔑 可选鉴权 | 配置 api_key 后 /v1/* 与 /pool 均需 Bearer token;空 = 不鉴权(/healthz 恒放行) |
flowchart LR
Client["客户端 / SDK\nOpenAI 兼容请求"] --> H
subgraph GWI["EdgeOne2API 网关"]
H["HTTP Handler\n鉴权 · 双模式路由 · 工具名过滤"] --> P
P["会话池\n4~32 弹性 · 指纹冷却 · 生命周期"] --> U
S["会话粘性路由\nX-Session-Key 绑定"] --> P
U["上游 Client\nsession.create / session.prompt\nSSE block 解析"]
end
U -->|"JSON-RPC + SSE"| EO["EdgeOne Agents\nDeepSeek Harness"]
EO -->|"text / reasoning / tool-call blocks"| U
上游事件在网关侧经历统一处理管线(internal/upstream/client.go):block 事件解析(text-delta / reasoning-delta / block-start / tool-call-delta / block-end)、textOnly 折叠与续读、turn 结束即 cancel;工具调用结果再经 internal/server/toolfilter.go 白名单 / 别名过滤后才返回客户端。
- Docker + Docker Compose(推荐部署方式)或宿主机 Go ≥ 1.21(
go.mod声明 1.21;镜像用 1.23 构建) - 一个可访问
deepseek-harness.edgeone.cool的网络环境
git clone https://github.com/lwjlwjlwjlwj/edgeone2api.git
cd edgeone2api
cp config.example.json config.json编辑 config.json,至少确认 upstream_url 与 models;api_key 留空 = 不鉴权(公网部署务必设置)。
# 启动服务
docker compose up -d --build
# 健康检查(预热完成后返回池状态)
curl -s http://localhost:7863/healthz
# {"poolSize":4,"status":"ok"}go build ./...
go vet ./...
go test ./... # 完整测试套件
go run ./cmd/server -config config.json# 模型列表
curl -s http://localhost:7863/v1/models -H "Authorization: Bearer your-api-key"
# 会话池状态(free/bound/total、指纹冷却、对话缓存命中率)
curl -s http://localhost:7863/pool -H "Authorization: Bearer your-api-key"
# 流式聊天
curl -sN http://localhost:7863/v1/chat/completions \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"model":"@makers/deepseek-v4-flash","messages":[{"role":"user","content":"你好"}],"stream":true}'
# 工具调用(返回 finish_reason="tool_calls" 与标准 tool_calls,由客户端执行)
curl -s http://localhost:7863/v1/chat/completions \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"model":"@makers/deepseek-v4-flash","messages":[{"role":"user","content":"杭州天气怎么样?"}],
"tools":[{"type":"function","function":{"name":"get_weather","description":"查询天气",
"parameters":{"type":"object","properties":{"city":{"type":"string"}}}}}]}'config.example.json 是配置项最完整的参考:每个字段、默认值与结构都能在其中找到。下表为字段含义速查。
| 字段 | 默认 | 说明 |
|---|---|---|
listen |
:7863 |
HTTP 监听地址 |
api_key |
空 | 网关鉴权密钥;空 = 不鉴权直接放行(公网必须设置) |
models |
见示例 | 对外暴露的模型列表(/v1/models 返回) |
pool_min / pool_max |
4 / 32 |
会话池弹性范围(pool_min: 0 = 完全惰性,不预建也不预热,首个请求按需创建) |
ttl_minutes |
0 |
会话 TTL(0 = 不过期,仅失败或达上限时回收) |
free_ttl_minutes |
90 |
空闲会话回收上限(上游约 1.5-2h 销毁空闲会话,早于它回收避免僵尸会话) |
bind_ttl_minutes |
30 |
绑定会话(会话连续性)空闲超时 |
max_req_per_session |
200 |
单会话最大请求数,超出自动轮换 |
upstream_url |
https://deepseek-harness.edgeone.cool |
上游 Harness 地址 |
agent_preset |
minimal |
上游会话预设(minimal/makers/standard/code/cordis) |
request_timeout_seconds |
600 |
非流式整体超时(流式无总时长上限) |
stream_idle_seconds |
180 |
流式:无上游事件 N 秒判定死连接(0 = 禁用) |
default_reasoning_effort |
off |
全局推理强度兜底(off/high/max/空),客户端与 model_map 均未指定时生效 |
request_jitter_ms |
0 |
发送前随机延迟 [0,N),伪并发防抖 |
max_concurrent |
0 |
并发上游请求上限(0 = 不限) |
model_map |
见示例 | 模型名 → 上游 provider/model 映射,可带每模型 reasoning_effort |
加载顺序:JSON 文件 → EDGEONE_API_* 环境变量(变量非空才覆盖):
EDGEONE_API_LISTEN · EDGEONE_API_KEY · EDGEONE_API_MODELS · EDGEONE_API_POOL_MIN · EDGEONE_API_POOL_MAX · EDGEONE_API_TTL_MINUTES · EDGEONE_API_BIND_TTL_MINUTES · EDGEONE_API_MAX_REQ_PER_SESSION · EDGEONE_API_UPSTREAM
无需配置文件也可运行:
EDGEONE_API_LISTEN=:7863 EDGEONE_API_POOL_MIN=4 EDGEONE_API_POOL_MAX=32 ./edgeone2apimodel_map 将客户端请求的模型名映射到上游 provider/model,客户端可选传 reasoning_effort(off/high/max),或由映射默认指定。
| 模型 | provider | 推理强度 |
|---|---|---|
@makers/deepseek-v4-flash |
edgeone-makers | off / high / max |
@makers/deepseek-v4-pro |
edgeone-makers | off / high / max |
@makers/hy3 / @makers/hy3-preview |
edgeone-makers | 无 |
@makers/minimax-m3 / @makers/minimax-m2.7 |
edgeone-makers | 无 |
@makers/kimi-k2.6 |
edgeone-makers | 无 |
deepseek-officialprovider 的模型需要额外的上游凭证,默认不可用,已从默认model_map排除。
客户端是否声明 tools 决定走哪条路:
| 模式 | 触发条件 | 行为 |
|---|---|---|
| 纯文本模式(textOnly) | 请求不带 tools |
上游 tool-call block 事件在客户端流中折叠丢弃(日志 textOnly: dropping tool-call block);工具驱动的轮次不会终止对话——turn/end 时若本轮只有被丢弃的工具调用,自动续读后续轮次直到模型输出真正正文;finish_reason 统一归一为 stop。效果:永远得到一段完整纯文本回答,不白屏、不空回复 |
| 工具调用模式 | 请求带 tools |
① 原生通道:上游发 tool-call block(block-start → tool-call-delta → block-end),网关流式拼装为标准 tool_calls;② 文本协议通道(ToolForge fallback):模型以纯文本 JSON {"tool_calls":[...]} 声明时,网关解析并补发结构化 tool_calls delta。两通道都经过工具名过滤层 |
上游模型可能输出它自己平台的原生工具名(Codex/EdgeOne 风格的 bash、str_replace_editor、mcp__edgeone__*),而客户端声明的是 exec、read 等。网关在返回前做一层过滤(internal/server/toolfilter.go):
| 类别 | 处理 |
|---|---|
| 客户端已声明的名字 | 原样透传 |
别名表命中(bash/shell/sh/zsh/python/python3→exec、str_replace_editor/text_editor/read_file→read、write_file→write、glob/grep/code_search→exec) |
改写为目标名(仅当目标名被客户端声明才生效) |
mcp__edgeone__* / edgeone__* / workspace_run_command 等平台能力 |
一律丢弃,绝不透传、绝不别名 |
| 其余未知名 | 丢弃 + 日志 [TOOLS] filter: drop tool "X" |
- 白名单每请求动态构建自客户端
tools声明,零维护; - 别名表加新映射只需补一行(
internal/server/toolfilter.go的upstreamAliases); - 流式路径按 index 追踪已丢弃调用,后续参数增量一并抑制;全部调用被过滤时
finish_reason从tool_calls归一为stop,客户端不会收到「有 finish 无数据」。
为什么要有这层过滤:没有它,上游漂移名会被原样透传给客户端 → 客户端回
Tool not found→ 模型据此编造「沙箱策略挡住执行」的叙事并甩脚本给用户。过滤层从源头消灭这条故障链。
上游失败按三档分类(internal/server/server.go 的 markRetryable),差别在于「对当前会话下多重的手」——会话创建要 20-44s,烧掉的指纹 24h 不可用,所以分类必须准:
| 事件 | 判定依据 | 处置 |
|---|---|---|
配额 / 限流(IsQuotaError) |
RPC 错误码(rate_limit / quota_exceeded / resource_exhausted …)或 HTTP 429 |
MarkQuotaExceeded():回收会话 + 该浏览器指纹冷却 24h。这是唯一会烧指纹的情况 |
会话已销毁(IsSessionNotFound) |
RPC 错误码(session_not_found / session_expired …)或明确点名 session 的报错 |
MarkGone():回收会话、不烧指纹,换新会话透明重试。上游约 20 分钟回收空闲会话,属正常生命周期 |
瞬时故障(IsTransientError) |
超时、连接重置、EOF、上游 5xx | 换会话重试,但不强制销毁当前会话:仅 FailedCount+1,连续 3 次才回收。不烧指纹 |
| 其他错误 | — | 不重试,直接返回客户端(502) |
| 绑定会话锁竞争 | 并发同 key 请求 | CAS 门控 + active 标志的 tryLock(),杜绝 mutex 永不释放导致的请求挂死 |
分类基于上游返回的结构化 RPC 错误码(
RPCFailure.Code),而非报错文本子串匹配。早期版本用strings.Contains(msg, "not found")判会话失效,会把session.selectModel failed: model not found(模型名写错)误判成会话已死——因为包装前缀里就带session字样。同理超时曾被归入配额,一次慢响应就让指纹停用一整天。
/pool 端点可实时观察:free / bound / exhausted_fps(冷却指纹数)/ dialog_hit_rate(对话缓存命中率,多轮上下文复用收益)。
- 预防半:系统指令(
BuildDirective)明确告知模型——「EdgeOne 沙箱与mcp__edgeone__*是平台自身运行时,不是用户的机器;需要工具时以 tool_calls 请求调用方执行」; - 执行半:
defer cs.Cancel()在 SSE 流 turn 结束瞬间掐断上游,agent loop(沙箱工具执行)在启动前即被终止; - 兜底半:即使模型仍发出平台工具名,
toolfilter也会拦截。
| 端点 | 鉴权 | 说明 |
|---|---|---|
POST /v1/chat/completions |
Bearer(api_key 非空时) |
OpenAI 兼容补全;流式 / 非流式;双模式路由 |
POST /v1/messages |
x-api-key 或 Bearer |
Anthropic Messages 兼容(Claude Code 直连);流式 / 非流式;tool_use 双向映射 |
POST /anthropic/v1/messages |
x-api-key 或 Bearer |
同上,兼容 ANTHROPIC_BASE_URL 带路径前缀的客户端 |
POST /v1/messages/count_tokens |
x-api-key 或 Bearer |
Anthropic token 计数(粗估,Claude Code 上下文条用) |
POST /v1/responses |
Bearer | OpenAI Responses 兼容(input/instructions,typed SSE 事件) |
GET /v1/models |
Bearer(api_key 非空时) |
模型列表(配置的 models) |
GET /pool |
Bearer(api_key 非空时) |
会话池状态:free / bound / total、指纹冷却、对话缓存命中率 |
GET /usage |
Bearer(api_key 非空时) |
累计用量:boot_id、prompt/completion token 估算、请求数 / 错误数 |
GET /healthz |
无 | 健康检查:{"poolSize":4,"status":"ok"} |
鉴权规则:仅当
api_key非空才校验;api_key为空时上述端点直接放行;/healthz恒无鉴权(供容器 healthcheck 使用,只暴露poolSize)。Anthropic 端点优先认x-api-key头(Claude Code 标准),回退到Authorization: Bearer。
/pool、/usage会暴露运行内部状态,因此和/v1/*一样受api_key保护。
网关在一条会话池上同时讲三种协议,共用同一套工具调用管线与错误分类,客户端零改造接入:
| 协议 | 端点 | 典型客户端 |
|---|---|---|
| OpenAI Chat Completions | /v1/chat/completions |
Cherry Studio、OpenAI SDK、各类前端 |
| Anthropic Messages | /v1/messages |
Claude Code(ANTHROPIC_BASE_URL 指向本网关) |
| OpenAI Responses | /v1/responses |
Responses SDK、部分 Agent 框架 |
Anthropic 适配做了完整的块级双向转换:请求侧 system(字符串 / 块数组)、messages(text / tool_use / tool_result 块)、tools(input_schema→parameters)翻成内部格式;响应侧把 reasoning_content→thinking 块、tool_calls→tool_use 块、finish_reason→stop_reason(stop→end_turn、tool_calls→tool_use)。流式严格遵循 message_start → ping → content_block_start → content_block_delta → content_block_stop → message_delta → message_stop 序列,message_stop 必达(缺了 Claude Code 会挂等流结束)。
max_tokens 与 temperature 为兼容 OpenAI 协议而接受但忽略:上游 session.prompt 不提供任何采样参数,唯一可调的是 reasoning_effort(经 session.selectModel 传递)。客户端传了这两个字段时,进程会打印一次提示日志,不会静默丢弃而不告知。
同一会话尽量复用同一上游会话,多轮对话上下文连续。键解析优先级:X-Session-Key 头部 > 请求体会话键(透明粘性,移植自 workbuddy2api):
- 请求带
X-Session-Key: <任意字符串>即绑定固定会话;同一 key 后续请求共享上下文(响应头回显当前绑定) - 未带头部时自动从请求体提取会话键,按序:
metadata.conversation_id→metadata.conversationId→conversation_id→conversationId→metadata.user_id(snake/camel 双命名均识别)——客户端零感知,同一对话自动钉在同一上游会话 - 两者皆无 → 取池中空闲会话(stateless,用完即还)
- 会话达
max_req_per_session或连续失败自动轮换为全新会话;轮换后把该键的对话历史重放进新会话([Cache Hit]前缀),上下文不丢 - 空闲绑定超
bind_ttl_minutes(默认 30m)由 maintenance 回收,会话归还自由池
- 上游 block 事件按规范白名单重建为 OpenAI SSE 帧:
text-delta→content、reasoning-delta→reasoning_content、tool-call block →tool_calls(按 index 合并,block-end为权威参数) - textOnly 模式:工具事件折叠、
finish_reason归一stop、工具轮次自动续读 - 工具调用模式:原生 block 通道 + ToolForge JSON 文本协议 fallback 双通道,均过过滤层
上游为 EdgeOne Agents / DeepSeek Harness 的非公开 / 逆向接口,路径以代码内常量为准:
| 相对路径 | 方法 | 用途 |
|---|---|---|
/api/session.create |
POST | 创建会话(支持 agentPreset) |
/api/session.prompt |
POST | 发送提示(mode: "steer"|"queue") |
/api/session.selectModel |
POST | 选择模型 |
| SSE event stream | GET | 流式 block 事件(text / reasoning / tool-call) |
多阶段镜像(构建 → alpine 运行时),无外部依赖,以非 root 用户运行。
镜像不内置 config.json:默认只用编译进二进制的默认值 + 环境变量,因此不会出现「忘记挂载配置 → 落到示例配置的空 api_key → 公网无鉴权放行」这条路径。要用配置文件就显式挂载并指定:
docker build -t edgeone2api .
# A) 纯环境变量(最简,无需配置文件)
docker run -d --name edgeone2api -p 7863:7863 \
-e EDGEONE_API_KEY=your-api-key \
-e EDGEONE_API_POOL_MIN=4 -e EDGEONE_API_POOL_MAX=32 \
edgeone2api
# B) 挂载配置文件(需自己加 --config)
docker run -d --name edgeone2api -p 7863:7863 \
-v "$PWD/config.json:/app/config.json:ro" \
edgeone2api --config /app/config.json或 docker compose up -d --build(端口映射与配置见 docker-compose.yml)。
容器 stop 时进程收到 SIGTERM 会优雅退出:停止接收新连接,等在途请求(含流式)最多 30s 自然结束,再关闭会话池。
验证不依赖 mock——直接请求真实上游(@makers/deepseek-v4-flash):
python3 scripts/gen_demo_data.py # 生成演示数据到 /tmp/kuku2api_demo/
python3 scripts/verify_longctx.py # 长上下文 + 多轮会话连续性
python3 scripts/verify_tools.py # 工具调用矩阵(非流式/流式/多轮链式闭环/名字翻译/纯文本防泄漏)api_key明文存于config.json(或环境变量);切勿提交 git——.gitignore已排除config.json/deploy.config.json等- 本项目无内置 TLS;公网部署必须设置
api_key,建议前置反代 / 内网
- 日志字段:会话 key、工具名、过滤行为——不含
api_key/ 上游凭证明文 - 日志写 stdout / stderr(容器内
docker logs),无落盘日志文件
- 上游 EdgeOne Agents 属商业平台,本项目是其非官方 OpenAI 兼容网关;使用其会话做 API 网关涉及目标平台服务条款与账号风险,作者不对账号封禁、条款违约或使用结果负责
- 仅限本人授权账号、本机 / 私有环境测试;不得共享、转售、违规分发
这是幻觉(通常由工具名漂移触发):模型引用的报错原文(如 sandbox mode workspace-write)在本项目与客户端代码中均不存在,且同会话 exec 往往已成功返回真实数据。根因是模型混淆了三套工具名(客户端声明的 exec/read、平台原生 mcp__edgeone__*、臆造的 bash/str_replace_editor),网关旧版直接透传导致客户端回 Tool not found。
当前版本已根治:toolfilter 白名单 / 别名 / 丢弃三层处理 + 指令明确「沙箱是平台运行时,不是你的机器」。若仍复现,检查日志 [TOOLS] filter: drop tool "X"——出现即表示需要补别名映射。
当前版本已把 session not found 判定为生命周期事件(MarkGone):换新会话透明重试,不烧指纹、不 502。若仍见 502,查看日志是否 fingerprint exhausted / cooling down(真实配额问题,冷却 24h 自动恢复)。
超时/连接重置/上游 5xx 现在归为瞬时错误(IsTransientError,日志 [RETRY] transient upstream failure):换会话重试一次,既不烧指纹,也不强制销毁原会话——它只累计失败计数,连续 3 次才回收。此前超时被误判为配额,一次慢响应就会让指纹停用 24h。
旧版本的 bug,已修。Stats() 曾为读取 active 去抢会话锁,而该锁在会话被借出期间全程持有:/pool 会被在途请求阻塞(实测 1.5s),且拿到锁时请求已结束、标志早已清零,所以永远读到 0。现在改为原子读,不加锁。
上游不返回 token 计数,网关也不做本地估算,因此 prompt_tokens / completion_tokens / total_tokens 恒为 0。依赖 token 计费或配额统计的客户端需自行计算。
编辑 config.json 的 model_map 增加映射(provider/model/reasoning_effort),并同步 models 列表;/v1/models 即刻生效。
textOnly 模式已保证「工具轮次自动续读直到正文」+ finish_reason 归一 stop。若仍异常,检查 stream_idle_seconds 是否过小(默认 180s,上游长思考时可能被误判死连接)。
以符号名(而非行号)定位——行号会随代码演进失效。
| 断言 | 出处 |
|---|---|
| 双模式路由(textOnly = 无 tools) | internal/server/server.go(textOnly := len(req.Tools) == 0) |
| textOnly 折叠 / 续读 / 归一 | internal/upstream/client.go(StreamEvents 的 droppedTools 分支) |
| 工具名白名单 + 别名 + 禁止前缀 | internal/server/toolfilter.go(newToolFilter / resolve) |
平台工具 mcp__edgeone__* 一律丢弃 |
internal/server/toolfilter.go(forbiddenPrefixes) |
全过滤时 finish_reason 归一 stop |
internal/server/server.go(emittedToolCall 跟踪) |
| 错误三分类(配额 / 生命周期 / 瞬时) | internal/server/server.go(markRetryable)、internal/upstream/client.go(IsQuotaError / IsSessionNotFound / IsTransientError) |
| 结构化 RPC 错误码分类(不再子串匹配) | internal/upstream/client.go(RPCFailure / HTTPStatusError / quotaCodes / sessionGoneCodes) |
| 配额错误冷却指纹 24h | internal/auth/pool.go(MarkQuotaExceeded / exhaustFingerprint) |
| 绑定锁 CAS + active 防泄漏 | internal/auth/pool.go(tryLock) |
/pool 状态采样不阻塞在途请求 |
internal/auth/pool.go(Stats 读 active / FailedCount 原子量,不取 s.mu) |
| 创建失败必然上报(不再空转) | internal/auth/pool.go(warm / warmError,Acquire / Bind 先查错后预热) |
pool_min: 0 完全惰性 |
internal/auth/pool.go(NewPool 的 switch cfg.MinSize 与 maintain 的预热门控) |
| turn 结束 cancel 掐断沙箱 | internal/server/server.go(defer cs.Cancel()) |
| SSE block 事件解析 | internal/upstream/client.go(block-start / tool-call-delta / block-end) |
| ToolForge JSON 文本协议 fallback | internal/server/server.go(parseToolCalls / emitToolCallsSSE) |
| 上游 RPC 端点 | internal/upstream/client.go(session.create / session.prompt / session.selectModel) |
| 优雅停机(SIGTERM 排空在途请求) | cmd/server/main.go(signal.NotifyContext / httpServer.Shutdown) |
本项目仅供学习和研究使用。使用者需遵守 EdgeOne Agents / DeepSeek Harness 服务条款,自行承担使用风险(包括账号封禁、条款违约等)。作者不对任何因使用本项目产生的直接或间接损失负责。
本项目采用 MIT License 开源协议。
- 允许任意使用、复制、修改、合并、发布、分发、再授权及销售
- 再分发(源码或二进制形式)时,请保留原仓库的 MIT 版权声明与许可声明(如在 NOTICE 或 README 中注明原始出处
https://github.com/lwjlwjlwjlwj/edgeone2api) - 本项目不授予任何上游(EdgeOne / DeepSeek Harness)接口或服务的权利;使用者仍需自行遵守上游服务条款