
Plano 网关开发指南Envoy Proxy-WASM Filter 的工具链、构建与本地调试【免费下载链接】planoPlano is an AI-native proxy server and data plane for agentic apps. Smart LLM routing, observability, agent orchestration, and guardrails so you stay focused on your agents core logic.项目地址: https://gitcode.com/GitHub_Trending/ar/planoPlano 是一个面向 Agent 应用的 AI 原生代理服务器与数据平面其核心流量路径由 Envoy 与两枚以 Rust 编写的 Proxy-WASM 过滤器llm_gateway与prompt_gateway构成。本文以 config/README.md 为主线完整讲解这套 WASM 过滤器从工具链安装、编译构建、单元测试到本地容器化联调的全部流程并结合仓库内的 Dockerfile、docker-compose.dev.yaml 与 envoy.template.yaml 源码讲清每个步骤背后的实现原理。读完本文你将能够独立搭建 Plano 网关的本地开发环境并在不改动 Docker 镜像的前提下完成 WASM 插件的快速迭代验证。一、背景Plano 网关中的 WASM 过滤器Plano 的网关层由三个核心进程协作运行见 supervisord.confconfig_generator启动时根据plano_config.yaml渲染出最终的 Envoy 配置与环境变量替换文件envoy负责全部流量的监听、路由与过滤WASM 过滤器挂载其上brightstaffPlano 的智能路由服务为 LLM 请求选择目标模型与提供商。其中llm_gateway与prompt_gateway是两枚独立的 Proxy-WASM 过滤器均以 Rust 编写并编译为wasm32-wasip1目标。从 crates/Cargo.toml 可以看到两者与common、brightstaff、hermesllm共同组成一个 Cargo workspace而 crates/llm_gateway/Cargo.toml 与 crates/prompt_gateway/Cargo.toml 都声明了crate-type [cdylib]并依赖proxy-wasm 0.2.1——这正是它们能作为 Envoy wasm 过滤器加载的基石。入口代码通过proxy_wasm::main!宏注册根上下文见 crates/llm_gateway/src/lib.rs。版本说明本仓库当前编译产物为prompt_gateway.wasm与llm_gateway.wasm见 DockerfileREADME 中提到的intelligent_prompt_gateway.wasm是早期版本的产物文件名开发时以实际挂载的 wasm 文件为准。二、添加工具链安装wasm32-wasip1目标Rust 默认不会安装 WebAssembly 交叉编译目标首次开发前需要手动添加$ rustup target add wasm32-wasip1wasm32-wasip1即 WASI Preview 1 目标对应 Envoyenvoy.wasm.runtime.v8运行时见 envoy.template.yaml。该目标在仓库的容器构建流程中同样被使用——Dockerfile 的依赖缓存阶段就执行了rustup target add wasm32-wasip1并预编译了两枚过滤器的依赖以加速镜像构建。三、构建 WASM 过滤器工具链就绪后在仓库根目录执行$ cargo build --target wasm32-wasip1 --release这条命令会通过 workspace 配置见 crates/Cargo.toml一次性编译llm_gateway、prompt_gateway及其依赖。构建产物位于crates/target/wasm32-wasip1/release/目录下llm_gateway.wasmprompt_gateway.wasm从源码结构看llm_gateway的代码组织为filter_context、stream_context、metrics三个模块负责 LLM 路由与流式转发prompt_gateway则包含context、filter_context、http_context、stream_context、metrics、tools等模块见 crates/prompt_gateway/src承担 prompt 侧的过滤、工具调用与上下文处理职责。在生产镜像中这两枚 wasm 产物被复制到/etc/envoy/proxy-wasm-plugins/见 Dockerfile再由 Envoy 配置通过filename字段加载。四、运行单元测试WASM 过滤器同样遵循标准 Rust 测试流程$ cargo testcargo test会在 workspace 下执行所有 crate 的测试。为了支撑过滤器状态相关的并发安全测试两枚网关的 Cargo.toml 都引入了serial_test 3.1.1作为 dev-dependencyprompt_gateway还额外使用pretty_assertions提供更友好的断言输出。测试用例可以在crates/llm_gateway与crates/prompt_gateway的源码中按模块查找。五、本地开发构建镜像并挂载热迭代本地开发的核心思路是用已打包的 Plano 镜像承载运行时把易变的配置文件与 wasm 二进制通过 volume 挂载进容器从而避免反复重建镜像。整个流程如下5.1 第一步构建 Plano Docker 镜像只需一次$ sh build_filter_image.shbuild_filter_image.sh 的内容实质是一条 docker build 命令docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.35Dockerfile 采用多阶段构建先缓存依赖阶段deps再分别编译 WASM 插件阶段wasm-builder与 brightstaff 二进制阶段brightstaff-builder最后将 Envoy、WASM 插件、brightstaff、planoaiCLI 与 supervisor 配置组装进运行镜像。镜像的ENTRYPOINT为 supervisord启动后依次拉起 config_generator、brightstaff 与 envoy。5.2 第二步编译开发版 WASM 二进制$ cargo build --target wasm32-wasip1 --release与第三步共用同一命令。开发时每次修改 Rust 源码后重新执行此命令即可刷新crates/target/wasm32-wasip1/release/下的 wasm 文件。5.3 第三步启动 Envoy 与 Plano 服务$ docker compose -f docker-compose.dev.yaml up planodocker-compose.dev.yaml 将以下文件挂载进容器这正是无需重建镜像的关键宿主机路径容器内路径作用${PLANO_CONFIG_FILE:-../demos/getting_started/weather_forecast/plano_config.yaml}/app/plano_config.yamlPlano 业务配置./envoy.template.yaml/app/envoy.template.yamlEnvoy 配置模板Jinja2 语法./plano_config_schema.yaml/app/plano_config_schema.yaml配置校验 Schema../cli/planoai/config_generator.py/app/planoai/config_generator.py配置渲染器../crates/target/wasm32-wasip1/release/llm_gateway.wasm/etc/envoy/proxy-wasm-plugins/llm_gateway.wasmLLM 网关 WASM 插件../crates/target/wasm32-wasip1/release/prompt_gateway.wasm/etc/envoy/proxy-wasm-plugins/prompt_gateway.wasmPrompt 网关 WASM 插件~/plano_logs/var/log/访问日志与进程日志任何挂载文件发生变化只需重启容器即可生效docker compose -f docker-compose.dev.yaml restart plano。5.4 端口与环境变量开发 compose 暴露了如下端口10000:10000LLM 网关入口/v1/chat/completions等 OpenAI 兼容接口10001:10001Prompt 网关入口11000:11000outbound 工具/上游 API 流量12000:12000LLM egress 出口流量19901:9901Envoy admin 管理端口用于查看配置、统计与运行状态。同时需要准备以下环境变量未设置时 compose 会直接报错退出OPENAI_API_KEYOpenAI 提供商密钥MISTRAL_API_KEYMistral 提供商密钥OTEL_TRACING_GRPC_ENDPOINTOpenTelemetry gRPC 上报端点开发模式下指向http://host.docker.internal:4317配合extra_hosts中映射的host.docker.internal可让容器内直接访问宿主机的 Jaeger/OTel Collector。5.5 启动时序与日志定位容器内由 supervisord.conf 编排启动顺序config_generator先行渲染配置并生成/tmp/config_ready标记文件brightstaff与envoy各自轮询该标记后才启动。启动失败时 supervisord 会主动kill -15关闭整个容器便于在docker compose logs中直接看到失败原因。访问日志写入/var/log/access_*.logaccess_ingress.log、access_ingress_prompt.log、access_internal.log、access_llm.log、access_agent.log由于该目录被挂载到宿主机的~/plano_logs可以在宿主机直接tail -f ~/plano_logs/access_llm.log观察 LLM 流量。Envoy 的 wasm 日志级别可通过LOG_LEVEL环境变量控制supervisord 中传递了--component-log-level wasm:${LOG_LEVEL:-info}调试过滤器时可将LOG_LEVELdebug甚至trace提级查看。六、理解底层wasm 过滤器如何被加载与配置本地开发中频繁改动的envoy.template.yaml是一份 Jinja2 模板最终由 config_generator 渲染成 Envoy 可用的envoy.yaml模板路径常量见 cli/planoai/config_generator.py 附近的ENVOY_CONFIG_TEMPLATE_FILE。以 prompt 网关为例模板中是这样挂载 wasm 过滤器的见 envoy.template.yaml- name: envoy.filters.http.wasm_prompt typed_config: type: type.googleapis.com/udpa.type.v1.TypedStruct type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm value: config: name: http_config root_id: prompt_gateway configuration: type: type.googleapis.com/google.protobuf.StringValue value: | {{ plano_config | indent(32) }} vm_config: runtime: envoy.wasm.runtime.v8 code: local: filename: /etc/envoy/proxy-wasm-plugins/prompt_gateway.wasm几个关键点root_id与 Rust 侧注册的上下文一一对应prompt_gateway/llm_gatewayEnvoy 据此把请求分发到正确的过滤器实例configuration字段把渲染后的plano_config或plano_llm_config以 YAML 字符串注入 WASM 虚拟机过滤器启动时解析这份配置完成模型提供商、监听器、重试策略等初始化vm_config.runtime固定为envoy.wasm.runtime.v8加载的代码即本地挂载的 wasm 产物——这就是修改 wasm 后只需重启容器即可生效的原因。LLM 网关的挂载方式完全一致见 envoy.template.yaml且 egress listeneregress_traffic_llm端口 12001上同样挂载llm_gateway.wasm见 envoy.template.yaml从而在出站方向执行模型路由与流式响应处理。模板中还内置了针对time_to_first_token直方图桶的统计配置见 envoy.template.yaml配合 Envoy admin 端口可以观测网关性能。七、快速验证一条命令跑通本地链路参考 config/test_passthrough.yaml 提供的 passthrough 认证场景可以在本地完成端到端冒烟验证pip install planoai planoai up config/test_passthrough.yamlcurl http://localhost:10000/v1/chat/completions \ -H Authorization: Bearer sk-your-virtual-key \ -H Content-Type: application/json \ -d {model: gpt-4o, messages: [{role: user, content: Hello}]}该配置演示了将客户端的Authorization头直接透传给上游适用于在 LiteLLM、OpenRouter 等代理前部署 Plano 的场景是验证 LLM 网关 wasm 过滤器链路是否正常的轻量手段。更完整的业务配置示例可参考demos/目录下的plano_config.yaml例如 demos/getting_started/weather_forecast/config.yaml其路径也正是开发 compose 的默认PLANO_CONFIG_FILE。八、常见问题排查构建报错找不到wasm32-wasip1target回到第二节执行rustup target add wasm32-wasip1并确认rustc版本与仓库 Dockerfile 使用的 1.93.0 大致相当。修改配置或 wasm 后未生效检查挂载路径是否与 docker-compose.dev.yaml 一致尤其是 wasm 产物路径crates/target/wasm32-wasip1/release/然后执行docker compose -f docker-compose.dev.yaml restart plano切勿只重启 envoy 而忽略 config_generator 的重新渲染。容器启动即退出多半是 config 渲染失败或环境变量缺失。OPENAI_API_KEY、MISTRAL_API_KEY未设置时 compose 会直接报错渲染失败时可在docker compose logs中看到 config_generator 的报错并触发整体关闭见 supervisord.conf 中kill -15逻辑。无法定位请求问题先用 Envoy admin 端口http://localhost:19901检查 listener/cluster 状态再按 5.5 节查看对应access_*.log必要时将LOG_LEVEL调至debug/trace观察 wasm 内部日志。SSE 流式响应被截断模板中的 gzip 解压过滤器将window_bits设为 15见 envoy.template.yaml小于上游压缩窗口时 zlib 会在流中途静默停止输出切勿随意调低该值。通过以上流程你可以在完全不重建镜像的情况下对 Plano 的llm_gateway/prompt_gateway两枚 Envoy WASM 过滤器进行修改 → 编译 → 重启容器 → 验证的快速开发闭环并将这套流程平滑迁移到生产镜像的构建复用 Dockerfile 的多阶段构建模式中。【免费下载链接】planoPlano is an AI-native proxy server and data plane for agentic apps. Smart LLM routing, observability, agent orchestration, and guardrails so you stay focused on your agents core logic.项目地址: https://gitcode.com/GitHub_Trending/ar/plano创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考