跳到主要内容

IDE AI 流量正向代理

企业经常需要对开发者工具外发的 AI 流量取得可见性——提示词和代码上下文正从员工机器流向 api.githubcopilot.com 等官方后端。本指南把 AISIX 部署为正向代理链路中的明文接收端:一台 TLS 终止的出口设备(由你运维——AISIX 不做任何 TLS 拦截)把解密后的 HTTP 递交给网关,网关完成审计、护栏、限流后,携带员工自己的凭证把每个请求原样中继到官方后端。

IDE 无需任何修改:它继续使用官方服务、自己的短期 Token 和正常的代理设置。

流量拓扑

网关的接收契约就是普通 HTTP:origin-form 请求携带原始 Host(透明重定向和代理链式转发都满足这一点;链式代理发来的 absolute-form 请求目标同样接受)。hosts 白名单命中入站 host 的路由会在网关自身的路径路由之前分发,因此打到 /v1/chat/completions 的 Copilot 请求绝不会落入网关的类型化 chat 端点。

为 Copilot host 配置路由

Copilot 的 host 集合发布在 GitHub 的白名单参考中。一条路由即可覆盖全部——hosts 白名单是配置中唯一需要的 Copilot 专有知识:

passthrough_routes:
- name: copilot
hosts:
# Chat / Agent 推理,以及 Copilot CLI 的 MCP 服务器
- api.githubcopilot.com
- "*.individual.githubcopilot.com"
- "*.business.githubcopilot.com"
- "*.enterprise.githubcopilot.com"
# 代码补全(fill-in-the-middle)
- "proxy.individual.githubcopilot.com"
- "proxy.business.githubcopilot.com"
- "proxy.enterprise.githubcopilot.com"
- copilot-proxy.githubusercontent.com
# Token 交换及其他 GitHub API 流量 —— 纯中继
- api.github.com
preserve_host: true # 目标 = https://<命中的 host>
auth_mode: header_key # 设备注入的网关 Key
auth_header_name: x-aisix-api-key
credential_mode: forward_client # 员工的 Copilot Token 上行到上游
identity_header: x-aisix-user # 设备注入的员工身份

无需按协议做任何配置:网关从每个请求自身识别其请求体信封。可识别的信封包括 OpenAI 兼容 chat(messages,Anthropic Messages 信封共用这个键)、旧式补全/FIM(prompt)和 OpenAI Responses API(input)。其余流量(MCP JSON-RPC、GitHub REST)作为不透明请求体中继。识别结果驱动 guardrail 文本提取、审计捕获和 Token 用量记录;中继的字节永远不被修改。

在设备注入的网关 API Key 上授予该路由:

api_keys:
- display_name: egress-device
allowed_models: []
allowed_routes: [copilot]

登录流量(github.com/login/*)和遥测 host 可以在设备侧绕开网关——它们不携带提示词内容。没有被分流到网关的流量根本不会到达网关。

如果希望按流量类别应用不同策略——例如只对推理挂 DLP guardrail 和 Token 限流、GitHub REST 调用不扫描,或者在日志中区分归因——仍然可以把 host 类别拆成多条路由(chat、补全、MCP、辅助流量)。每条路由携带自己的 guardrail 挂载、限流和用量事件上的 route_name。两个路由特性保证最细粒度的拆分也可以表达:带 hosts 匹配的路由可以占用网关自身保留的路径前缀(/mcp/v1 等),因为 host 匹配的请求在网关自身端点之前分发;preserve_host 路由把 path_prefix 仅当作匹配条件——上游拥有自己的路径空间,完整路径原样转发。

GitHub Copilot CLI(Agent)

Copilot CLI 是终端 Agent,不是编辑器插件:它会推理、调用工具、改文件、执行 shell 命令,并与 MCP 服务器通信。它的全部流量都走上面那一条 copilot 路由——信封识别按请求逐个处理:

  • 推理轮次使用的端点和信封随所选模型而变:GPT 系模型以 OpenAI Responses 信封发往 /responses,Claude 系模型以 Anthropic Messages 信封发往 /v1/messages。两者都无需配置——每个请求都从自身请求体识别——流式 Token 用量两种情况下都会被提取,因此 Token 限流、成本核算与用量报表都覆盖 Agent 流量。
  • GitHub MCP 服务器位于 /mcp/readonly与推理同一个 host。JSON-RPC 请求体不匹配任何 LLM 信封,因此原样中继——同时仍然受认证、限流和归因约束。
  • 授权、模型目录、版本检查是普通 REST 调用,原样中继。

一次 CLI 会话涉及的端点(全部在 copilot 路由上):

流量端点
Agent 推理chat host 上的 POST /responsesPOST /v1/messages,取决于所选模型
MCP 会话(初始化、工具调用、销毁)POST/GET/DELETE /mcp/readonly
授权与策略GET /copilot_internal/user/copilot_internal/managed_settings
模型目录chat host 上的 GET /models
版本检查GET /repos/github/copilot-cli/releases/latest

CLI 本身无需任何配置:它遵循机器的代理设置,出口设备看到的流量与其他客户端并无不同。

接入之后 Agent 的端到端行为与直连一致——推理、读写文件、执行 shell 命令、装载 MCP 工具(CLI 自带的 /context 视图会显示 MCP 工具定义占用的上下文,只有 MCP 会话经网关建立成功才会出现)。交互命令照常可用;其中会发起网络请求的那些(/model/context/usage/mcp/review/security-review 等)与 Agent 自身的对话轮走同样的路由,也会被一并审计。

网关认证选项

员工的请求在 Authorization 里携带他们自己的 Copilot Token,因此网关凭证需要另一条通道:

  • header_key(上例所示) —— 出口设备向每个转发请求注入 x-aisix-api-key: <gateway key>。网关消费并剥离该请求头;Authorization 逐字透传到上游。按 Key 的限流、预算和归因照常工作。
  • anonymous —— 如果设备无法注入请求头,把路由绑定到一个专用 API Key,并将 source_cidrs 收紧到设备地址。流量以该主体运行,其限流与归因生效;网络可达性即是闸门。

按员工归因

AISIX 不解析 Copilot Token(其中不携带企业身份)。如果设备能注入员工身份——例如来自它自己的认证——就把该请求头名配置为路由的 identity_header。它的值在转发前剥离,并记录到每条用量事件的 client_identity 字段,可在环境的 Logs 页面搜索。设备不注入时,记录的客户端来源 IP 是兜底归因。

审计、DLP 与限流

  • 内容审计 —— 配置 content_mode: full 的可观测性导出器;chat 提示词/响应和补全上下文随即记录到导出器目的地(按识别出的信封结构化)。参见可观测性导出器
  • DLP —— 给路由挂载护栏(passthrough_route 挂载作用域)。命中时请求在离开网络前被 422 拦截;流式响应则在被扣住的帧释放前,以 content_filter 错误帧结束。参见护栏行为
  • 限流 —— 注入的网关 Key(或 anonymous 主体)的请求限流生效。Token 用量来自识别出的信封,因此 Token 维度同样累积。

不依赖生产设备做验证

任何能携带原始 Host 转发解密请求的 TLS 终止代理都可以替代生产设备。mitmproxy 加上一段简短的脚本,就能在一台机器上复现完整拓扑——真实的 Copilot 客户端、真实的后端,既不需要企业 CA,也不需要采购设备。下面的步骤假定网关监听 127.0.0.1:3100、代理监听 127.0.0.1:8888

1. 带着 Copilot 路由启动网关。 加载上文的路由,以及授予该路由的 API Key。在独立部署的网关上这就是一个 resources.yaml(参见资源文件参考),调用方 Key 通过环境变量提供:

api_keys:
- display_name: egress-device
key_env: EGRESS_DEVICE_KEY
allowed_models: []
allowed_routes: [copilot]

代理监听端口使用明文 HTTP,这正是设备投递过来的形态——这一段链路不需要任何 TLS 材料。

2. 安装 mitmproxy 并生成 CA。

pipx install mitmproxy # 或:pip install mitmproxy
mitmdump --version # 首次运行会写出 ~/.mitmproxy/mitmproxy-ca-cert.pem

3. 编写模拟设备的脚本。 它做的正是生产设备的工作:把 Copilot host 的流量以明文分流到网关,保留原始 Host,并注入网关 Key 和员工身份。

mitm_to_aisix.py
from mitmproxy import http

AISIX_HOST, AISIX_PORT = "127.0.0.1", 3100
GATEWAY_KEY = "<EGRESS_DEVICE_KEY 对应的明文 Key>"
IDENTITY = "alice@example.com"

# 三个后缀同时覆盖了 proxy.* 补全 host。
COPILOT_HOSTS = {
"api.githubcopilot.com",
"copilot-proxy.githubusercontent.com",
"api.github.com",
}
COPILOT_SUFFIXES = (
".individual.githubcopilot.com",
".business.githubcopilot.com",
".enterprise.githubcopilot.com",
)


def _diverted(host: str) -> bool:
return host in COPILOT_HOSTS or host.endswith(COPILOT_SUFFIXES)


def request(flow: http.HTTPFlow) -> None:
host = flow.request.pretty_host
if not _diverted(host):
return # 其余流量照常发往它自己的真实目的地
flow.request.host = AISIX_HOST
flow.request.port = AISIX_PORT
flow.request.scheme = "http"
flow.request.headers["host"] = host # 赋值 .host 会改写 Host 头,这里把原值钉回去
flow.request.headers["x-aisix-api-key"] = GATEWAY_KEY
flow.request.headers["x-aisix-user"] = IDENTITY


def responseheaders(flow: http.HTTPFlow) -> None:
if "text/event-stream" in flow.response.headers.get("content-type", ""):
flow.response.stream = True # 逐帧中继 SSE,而不是整包缓冲

两行注释标出的地方都是关键。mitmproxy 的 .host setter 会连带改写 Host 请求头。不把原值钉回去的话,每个请求到达网关时都是 Host: 127.0.0.1:3100,匹配不到任何路由,会落到网关自身的路径路由上。mitmproxy 还默认缓冲响应体。不加 stream 钩子的话,流式回答会一次性抵达客户端——看起来就像是网关把它缓冲了。

4. 启动代理。

mitmdump -s mitm_to_aisix.py --listen-port 8888

5. 在接入客户端之前先做一次链路冒烟。 一条命令即可验证三跳——代理分流、网关路由命中、用你自己的凭证中继到真实后端:

curl -x "http://127.0.0.1:8888" --cacert ~/.mitmproxy/mitmproxy-ca-cert.pem \
-H "authorization: Bearer <你的 GitHub Token>" "https://api.github.com/user"

返回 401 且文案指名 x-aisix-api-key,说明脚本注入的 Key 没送到;403 说明该 Key 没有这条路由的授权;404 通常意味着漏了 Host 钉回。

6. 把 Copilot 客户端指向代理并信任 CA。 Copilot CLI 除机器的代理设置外无需任何配置:

export HTTPS_PROXY=http://127.0.0.1:8888 HTTP_PROXY=http://127.0.0.1:8888
export NODE_EXTRA_CA_CERTS=$HOME/.mitmproxy/mitmproxy-ca-cert.pem
copilot

VS Code 插件则在设置中写入 "http.proxy": "http://127.0.0.1:8888",并让扩展宿主信任该 CA。两种做法二选一:把 ~/.mitmproxy/mitmproxy-ca-cert.pem 加入操作系统信任库,或在启动 VS Code 的环境中导出 NODE_EXTRA_CA_CERTS

7. 正常使用 Copilot,然后在网关侧查看结果。 chat、内联补全和完整的 agent 会话行为不变——读写文件、执行 shell 工具、建立 MCP 会话都照常。而在网关侧,现在每次交换都可见。用量事件携带命中的 route_name 和注入的 client_identity,可在环境的 Logs 页面搜索;独立部署的网关则在配置的可观测性导出器上查看。Token 数从识别出的信封中提取,content_mode: full 的导出器记录提示词、补全内容和补全上下文。最快的端到端 DLP 校验:给路由挂一条 keyword guardrail,然后在提示词里输入该关键词。请求会以 422 中止,后端根本不会被联系。

流式补全逐帧通过,除非挂载了 hold-back 护栏——那时帧按扫描批次释放。

范围与限制

  • 透传路由不中继 WebSocket 流量——在设备侧让它绕开网关。
  • preserve_host 目标恒为 443 端口上的 https://<host>
  • AISIX 不做 TLS 拦截,也不提供 CA 工具;解密设备由你运维。