语言选型方法
按 Agent 产品、模型实验、工具服务、运行时和 AI infra 判断 TypeScript、Python、Go、Rust 的适用边界。
语言选型先看系统边界,而不是先看个人偏好。Agent 项目通常同时包含产品 UI、模型调用、工具执行、任务调度、检索系统、评测系统和运行时隔离,不同层的语言选择可以不同。
一个简单但有效的判断方式是:先问“这段代码主要在保护什么边界”。如果它保护的是用户体验和前后端接口,优先 TypeScript;如果它保护的是模型实验效率和数据处理效率,优先 Python;如果它保护的是服务稳定性和并发吞吐,优先 Go;如果它保护的是本地运行时、沙箱和安全边界,优先 Rust。
推荐分层
| 系统层 | 推荐语言 | 说明 |
|---|---|---|
| 产品 UI 和交互 | TypeScript | React、Next.js、Vercel AI SDK、streaming UI、工具调用展示和人工确认体验。 |
| Agent 编排和产品后端 | TypeScript 优先,Python 次之 | 如果产品主栈是 Web/Node,优先 TypeScript;如果重模型实验和图编排,可选 Python。 |
| RAG、评测和数据处理 | Python 优先 | 文档处理、embedding、rerank、notebook、评测脚本和 ML 生态更完整。 |
| 工具服务和调度控制面 | Go | 高并发服务、队列消费、节点管理、HTTP/gRPC 服务和部署运维更直接。 |
| Sandbox、runtime、CLI 和安全边界 | Rust | 内存安全、性能、跨平台分发和底层解析场景更强。 |
决策表
| 你要做什么 | 默认选择 | 为什么 |
|---|---|---|
| Chat UI、任务进度、工具调用卡片、人工确认 | TypeScript | UI 状态、服务端接口和流式事件可以共享类型,适合产品化。 |
| Next.js API route、Server Action、MCP client/server | TypeScript | Node.js 生态与 Web 产品层贴近,适合把工具 schema 和 UI message 串起来。 |
| RAG pipeline、文档解析、embedding、rerank | Python | 数据处理、模型实验、notebook 和检索生态更完整。 |
| 离线评测、golden tasks、LLM-as-Judge | Python | 写批处理脚本、pytest fixture 和评测报告更直接。 |
| 任务调度、队列 worker、节点控制面 | Go | 并发、部署、健康检查、超时取消和运维接口更稳定。 |
| 高风险工具网关、长任务服务、爬虫调度 | Go | context.Context、HTTP/gRPC、pprof、race detector 对生产服务友好。 |
| 本地 CLI、文件索引、代码解析、diff/search | Rust | 性能、跨平台分发和内存安全更适合本地工具。 |
| Sandbox、插件运行时、权限隔离 | Rust | 所有权模型和显式错误处理更适合构建强边界。 |
决策问题
- 这个模块是面向用户交互、模型实验、后台服务还是运行时底层。
- 是否需要强类型约束工具 schema 和 UI 状态。
- 是否需要大量调用 ML、数据处理或检索生态。
- 是否对并发、部署体积、启动速度和运维成本敏感。
- 是否涉及 sandbox、权限隔离、解析器或跨平台 CLI。
常见组合
| 组合 | 适合场景 |
|---|---|
| TypeScript + Python | 最常见。TypeScript 做产品界面和 API,Python 做 RAG、评测、数据处理和研究原型。 |
| TypeScript + Go | 产品层由 TypeScript 承担,Go 承担队列、调度、节点控制、工具网关和爬虫控制面。 |
| TypeScript + Rust | 产品层由 TypeScript 承担,Rust 做本地 CLI、sandbox、parser、runtime 或高性能组件。 |
| TypeScript + Python + Go | Agent 产品、模型实验、infra 控制面同时存在时的稳妥组合。 |
| TypeScript + Python + Go + Rust | 系统进入多平台、本地运行时、沙箱、安全执行和高性能工具阶段后再引入。 |
不建议的做法
- 不要因为 Python 生态强,就把产品 UI 和所有工具服务都写成 Python。
- 不要因为 TypeScript 适合产品,就忽略 Python 在 RAG、评测和模型实验中的效率。
- 不要过早用 Rust 重写业务逻辑,除非确实有运行时、安全或性能边界。
- 不要把 Go/Rust 当作协作者第一期必须精通的语言,它们应作为 AI infra 能力储备逐步补齐。
默认建议
如果没有额外约束,本站采用以下默认选型:
- 产品化 Agent 第一语言是 TypeScript。
- 模型、RAG、评测和数据处理第一语言是 Python。
- AI infra 服务、调度控制面和高并发工具服务优先 Go。
- 安全边界、本地 runtime、CLI、解析器和 sandbox 优先 Rust。
选型流程
可以把语言选型拆成六步:
- 确定模块边界:它是 UI、API、RAG、worker、gateway、runtime 还是 CLI。
- 确定失败代价:失败是展示错误、任务失败、数据损坏,还是安全事故。
- 确定运行环境:浏览器、Node.js、容器、GPU 机器、本地桌面、移动端或边缘节点。
- 确定生态依赖:是否需要特定 SDK、ML 库、解析器、队列、数据库或系统调用。
- 确定团队能力:是否有人能维护构建、测试、发布和线上排障。
- 确定接口契约:跨语言边界用 JSON Schema、OpenAPI、protobuf、事件流还是子进程协议。
如果第 6 步答不上来,就先不要引入新语言。跨语言本身不是问题,隐式契约才是问题。
反模式
| 反模式 | 为什么危险 | 替代方案 |
|---|---|---|
| 所有东西都写进 Python notebook | 原型快,但产品化、权限、并发和部署困难 | notebook 用于实验,服务和 UI 拆出去 |
| Web 产品后端和评测脚本共享大量业务状态 | UI 迭代会污染实验复现 | 用数据集、API 和任务记录隔离 |
| 过早引入 Go/Rust | 团队心智成本高,业务还没稳定 | 等边界、性能或安全需求明确后再引入 |
| 用子进程随意串语言 | 错误语义、超时和日志难统一 | 定义输入输出 schema 和超时协议 |
| 只按框架选语言 | 框架流行不等于系统边界适合 | 先按模块职责,再选框架 |
示例:Coding Agent 产品
一个 Coding Agent 可以这样切:
- TypeScript:Web UI、任务列表、终端输出展示、人工确认、GitHub 集成页面。
- TypeScript 或 Python:Agent 编排、工具 schema、任务状态机;取决于主框架和团队栈。
- Python:评测集、仓库分析实验、语义检索、报告生成。
- Go:远端 worker、队列消费、任务调度、仓库克隆服务、网关限流。
- Rust:本地 CLI、文件搜索、diff 解析、sandbox runner、跨平台插件宿主。
关键不是语言数量,而是每层是否可以独立测试、独立发布、独立回滚。
团队协作建议
- 第一阶段只要求所有协作者能读懂 TypeScript 和 Python 的核心实现。
- Go 和 Rust 页面面向 infra 方向协作者,不要求每个内容协作者立即精通。
- 文档示例优先给出小而完整的代码片段,不追求覆盖语言全部语法。
- 新增跨语言模块时,同步补充 README、测试命令和错误码约定。
- 语言页如果引用框架,优先说明“为什么这个框架适合这个边界”,不要只列工具名。
检查清单
- 是否能说清“这个模块为什么不用项目默认语言”。
- 是否为跨语言边界定义了稳定输入输出。
- 是否有统一的日志、trace id、错误码和超时策略。
- 是否能在没有生产依赖的情况下跑本地测试。
- 是否有从原型迁移到生产的退出条件,例如性能阈值、失败率、团队维护成本。