当 Demis Hassabis 站到 Google 更全局的位置时,科技圈关注的不只是个人职级变化,而是前沿 AI 研究与产品商业化之间的平衡。这种平衡行为并不只发生在巨头公司里。任何要把 AI 功能落到生产环境的开发团队,都会面对类似的选择题:模型选多大,成本能承受多少,是追最新研究还是保稳定可用,Agent 要开放多少能力才不会失控。下面这些内容,围绕 AI 工程实践中最容易被忽视的几层平衡展开。
这篇文章不打算评论公司人事,而是把“AI 平衡行为”翻译成工程问题。你会看到模型选型、Agent 开发、AI 幻觉治理、部署运维和排错链路中,哪些决策决定了项目是停留在 Demo,还是能真正支撑业务。
1. 大公司组织架构调整背后,是 AI 工程的三大张力
1.1 为什么“研究与产品”的平衡会成为焦点
DeepMind 与 Google AI 的整合,在行业讨论中一直是一个高频话题。观点文章喜欢用“Hassabis 的新角色”作为引子,说明一个核心矛盾:一个以顶会论文和前沿探索为基因的研究团队,如何与一个以发布节奏、用户增长和收入为目标的商业产品部门协同。
这种讨论之所以成立,是因为两边的工作评价体系完全不同。研究团队追求的是上限,是“模型能不能做到以前做不到的事”;产品团队追求的是下限,是“功能在千万用户访问时会不会崩、回答会不会出错、延迟能不能接受”。当一个人同时对两边负责,所有冲突都会集中到决策层。
如果你在大厂或创业公司做过 AI 项目,会发现这不是公司政治,而是工程现实。研发说“换更大的模型效果更好”,运维说“当前 GPU 资源扛不住并发”,产品说“用户等不了 5 秒”,测试说“这次回答又和上次不一样”。所有声音都是对的,但必须有人做取舍。
1.2 从组织平衡到工程平衡:三组矛盾
把组织层面的讨论往下拆,会得到三组在代码和配置里真实存在的矛盾。
| 矛盾 | 研究/前沿导向 | 产品/工程导向 | 典型表现 |
|---|---|---|---|
| 能力选择 | 追求最新模型、最大参数量 | 追求可复现、可维护的稳定输出 | 模型版本频繁更换,测试集反复失效 |
| 资源成本 | 为了上限可以接受高成本 | 单位请求成本必须可控 | Token 消耗失控,账单暴涨 |
| 安全约束 | 希望模型能力完全释放 | 必须限制输出范围和权限 | Agent 工具调用越权,内容不合规 |
这三组矛盾不是理论。模型选型时要遇到,Agent 设计时要遇到,内容审核和权限控制时还要遇到。理解它们,等于理解了 AI 工程化的大框架。
1.3 普通开发者的“平衡行为”在哪里
小团队没有大公司的组织问题,但技术决策上一样要平衡。比如:
- 调用一个能力很强的闭源 API,还是部署一个可控但效果稍弱的开源模型。
- 让 Agent 自动执行工具,还是每次执行前都人工确认。
- 给模型完整的上下文窗口,还是用 RAG 只塞相关片段。
- 追求零人工干预,还是保留一个兜底审核环节。
这些决定看似琐碎,却决定了系统是“演示时惊艳”还是“上线后稳定”。后面的内容会按一条主线把这些决策串起来:模型选择、Agent 开发、幻觉治理、部署运维、排查修复。
2. 模型选择先想清楚:你要的是“研究成果”还是“生产可用”
2.1 模型选型三件套:效果、成本、延迟
很多团队选模型只看 benchmark 分数,这是第一个坑。生产环境里,效果只是三个约束之一。真正要同时看的是:
- 效果:在你自己业务数据上的表现,而不是公开榜单上的分数。
- 成本:单次请求的 Token 消耗、调用费用,长期跑下来是否可承受。
- 延迟:P50 和 P95 响应时间,用户可感知的等待时间。
三者的关系通常是这样:模型越大,效果越好,但成本和延迟也越高。你能做的是找一个“够用”的平衡点,而不是“最强”的模型。
| 选型维度 | 关注点 | 常用评估方式 | 错误做法 |
|---|---|---|---|
| 效果 | 业务场景准确性、格式遵循 | 自建评测集,跑回归对比 | 只看公开榜单 |
| 成本 | 单次请求费用、月账单 | 压测平均 Token 数,估算规模 | 上线前不测算 |
| 延迟 | 用户等待时间、并发吞吐 | P50/P95 压测,长尾分析 | 只测一次单请求 |
一个更常见的场景是:同一套业务,读操作和写操作用不同模型。例如标题生成、摘要提取这类简单任务用轻量模型,复杂推理或代码生成用更强模型。这比把所有流量都打到最大模型上更省钱,也更容易控制延迟。
2.2 开源自建和托管 API 的取舍
“要不要自己部署模型”是一个经常被问错的问题。正确的问法是:你的团队有没有能力维护推理服务。
托管 API 的好处是省心,不用管 GPU、扩容、模型文件;代价是数据要出域,成本按调用量累积,而且模型行为可能随版本变化。开源模型自建的好处是数据可控、单次调用边际成本低;代价是硬件投入大,推理性能调优需要专门能力,版本升级和兼容性也要自己维护。
| 对比项 | 托管 API | 自建开源模型 |
|---|---|---|
| 部署门槛 | 低,几行代码调用 | 高,需要推理服务和 GPU 资源 |
| 数据隐私 | 取决于服务条款 | 数据留在自己环境 |
| 单位成本 | 按 Token/请求计费 | 主要是硬件和电费,量大时更省 |
| 模型可控性 | 依赖服务方版本策略 | 可以固定版本、自己微调 |
| 运维成本 | 几乎为零 | 监控、扩容、日志、回滚都要做 |
这里的建议是:初创项目、快速验证阶段优先用托管 API;当调用量稳定、数据合规要求变高时,再把高频路径切到自建模型。不要一开始就把精力耗在部署上。
2.3 用接口抽象隔离模型变化
无论选哪种模型,代码里都不要直接写死某个厂商的 SDK。下面是一个最小抽象示例,用统一接口封装不同 Provider,后续换模型时只需要新增实现。
from dataclasses import dataclass @dataclass class ModelConfig: provider: str model_name: str max_tokens: int = 1024 temperature: float = 0.1 class LLMClient: def __init__(self, config: ModelConfig): self.config = config def chat(self, messages: list[dict]) -> str: if self.config.provider == "openai_compatible": return self._call_openai_compatible(messages) if self.config.provider == "local": return self._call_local(messages) if self.config.provider == "custom": return self._call_custom(messages) raise ValueError(f"unknown provider: {self.config.provider}") def _call_openai_compatible(self, messages): # 这里放 OpenAI 兼容接口的调用逻辑 pass def _call_local(self, messages): # 这里放本地推理服务的调用逻辑 pass def _call_custom(self, messages): # 这里放内部中转服务的调用逻辑 pass关键不是实现多少 Provider,而是把“业务代码”和“模型供应商”解耦。模型升级、替换、迁移时,业务侧不需要改逻辑,只改配置和新增适配层。这会成为后期做灰度发布和多模型容灾的基础。
3. Agent 开发的核心不是“让模型多聪明”,而是“给模型多少权限”
3.1 Agent 为什么成为 AI 应用的标配
单个模型只能回答,Agent 可以做事情。它的价值在于把模型的语言理解能力,与工具、API、数据库、业务流程连接起来。比如用户说“帮我查一下最近的订单状态”,Agent 先判断要调用订单查询工具,再提取参数,拿到结果后组织成自然语言回答。
这也是“AI Agent 开发”在工程实践里越来越重要的原因。但 Agent 带来的不仅仅是能力提升,还引入了一个新的风险面:模型在决定调用什么工具、传什么参数,一旦权限边界没设好,可能执行出开发者没有预期的操作。
3.2 最小工具调用闭环:Tool Call 的整个链路
一个最小 Agent 必须完成五步:识别意图、生成工具调用参数、执行工具、把结果送回模型、生成最终回答。下面是一个简化示例,模拟天气查询。
import json def get_weather(city: str) -> str: # 实际项目里应该调用真实天气服务 return f"{city} 当前晴天,气温 26 度" TOOL_SCHEMA = { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的当前天气", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名,例如 北京" } }, "required": ["city"] } } } def run_agent(query: str, llm_client) -> str: messages = [ {"role": "system", "content": "你是天气助手。根据用户问题决定是否调用工具。"}, {"role": "user", "content": query} ] response = llm_client.chat_with_tools(messages, tools=[TOOL_SCHEMA]) if response.tool_calls: call = response.tool_calls[0] args = json.loads(call.function.arguments) # 执行工具 tool_result = get_weather(args["city"]) # 把工具结果追加到对话,再让模型总结 messages.append(response.message) messages.append({ "role": "tool", "tool_call_id": call.id, "content": tool_result }) final_response = llm_client.chat(messages) return final_response.content return response.content这个流程里有三个容易出问题的地方:一是模型输出的 tool call 参数可能不是合法 JSON;二是工具执行可能抛异常;三是工具结果返回后模型可能仍然回答错误。工程化时,这三步都要加异常处理和校验。
3.3 Agent 权限边界和失败兜底
Agent 越强大,越需要约束。一个只读天气工具和一个能操作数据库、发送邮件、执行命令的工具,风险等级完全不同。不要把所有工具一股脑暴露给模型。
| Agent 风险 | 典型场景 | 缓解手段 |
|---|---|---|
| 工具越权 | 模型调用了无权限接口 | 工具注册表上做权限标记,服务端校验 |
| 参数注入 | 用户通过提示词诱导改变工具参数 | 对工具参数做类型、范围、枚举校验 |
| 误操作 | 连续调用多个副作用工具 | 高风险工具增加二次确认或人工审批 |
| 供应链 | 工具返回的数据被恶意构造 | 对工具返回内容做序列化校验和长度限制 |
建议早期把 Agent 设计成“建议式”:模型只给出应该调用哪个工具和参数,真正执行前由人工或固定规则确认。等线上跑稳了,再逐步放开自动执行,同时保留完整审计日志和紧急熔断开关。
4. AI 幻觉和内容合规,是同一个问题的两面
4.1 AI 幻觉是什么,为什么只靠提示词压不住
AI 幻觉是指模型生成的内容看起来合理,但事实错误、无中生有。常见原因包括训练数据不完整、上下文信息不足、模型为了“自洽”会补全不存在的细节。
很多人试图通过提示词压制幻觉,比如在 system prompt 里写“不要编造事实”。这在简单场景里有效,但在复杂任务中并不可靠。因为模型本质上是概率生成,没有真正区分“知道”和“不知道”的能力。提示词可以改变输出风格,但不能确保事实正确。
工程上控制幻觉,要从外部约束和验证入手。
4.2 用 RAG 和事实校验约束输出
RAG(检索增强生成)是目前最实用的手段:先检索相关资料,再让模型基于资料生成。它不要求模型记住所有知识,只要求它理解给定资料。
def verify_with_source(answer: str, source_docs: list[str]) -> bool: sources_text = "\n".join([f"[{i+1}] {doc}" for i, doc in enumerate(source_docs)]) prompt = f"""请判断下面的回答是否完全基于给定资料。 如果回答中的关键结论都能在资料中找到依据,输出 PASS。 如果回答中包含资料里没有的事实或推测,输出 FAIL。 资料: {sources_text} 回答: {answer} 判断结果:""" result = judge_llm.predict(prompt) return result.strip().upper() == "PASS"这里的校验模型可以用一个更便宜的模型,不一定和生成模型同一个。流程上,先生成回答,再校验,校验不通过就换一种方式回答,比如“资料中没有找到相关信息”。成本会增加一些,但换来的确定性是值得的。
4.3 面向用户的内容审核要当作安全组件
任何面向用户的内容,都不应该只依赖模型本身。你的产品可能有自己的内容规范,模型并不天然知道你允许什么、禁止什么。工程上通常做三层过滤:
- 输入侧过滤:对用户输入做长度、类型、关键词、格式校验。
- 输出侧过滤:对模型输出做关键词、分类模型、审核 API 检测。
- 人工兜底:高风险场景保留人工复核或举报入口。
审核模块要像日志和监控一样,作为基础设施接入,而不是后补。它应该返回结构化结果:是否通过、命中的规则、风险类型、触发位置,这样后续排查和迭代才有数据支撑。
5. 从 Demo 到生产:模型部署和可观测性
5.1 学习环境和生产环境的差异
很多 AI 项目死在“本地能跑”到“线上稳定”之间。本地 Notebook 调试和生产环境部署是完全两套思路。
| 维度 | 学习/开发环境 | 生产环境 |
|---|---|---|
| 模型文件 | 放在本地目录 | 镜像化、版本化管理 |
| 依赖 | 本机 conda/pip | 锁定版本,可重复构建 |
| 并发 | 单用户调试 | 压测后配置自动扩缩容 |
| 日志 | print 输出 | 结构化日志、链路追踪 |
| 故障 | 重启即可 | 需要监控、告警、回滚 |
| 成本 | 不关注 | 按次计费、资源配额 |
生产环境至少要补上三件事:配置外置化(模型地址、API Key、参数不写死在代码里)、健康检查接口、优雅退出机制。
5.2 一个最小容器化部署示例
无论模型是部署在本机还是通过 API 调用,业务服务先容器化是可行的第一步。下面是一个最小 Dockerfile,用于打包一个 FastAPI 推理服务。
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . ENV MODEL_CACHE_DIR=/models ENV API_TIMEOUT=30 EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]这里的关键点是:ENV MODEL_CACHE_DIR和API_TIMEOUT不应该在构建时写死,而是在启动容器时注入。这样不同环境(测试、预发、生产)可以复用同一个镜像,只改环境变量。模型文件如果很大,建议挂载外部存储,而不是打进镜像。
5.3 日志、监控、回滚和成本治理
上线后最该看的是三个面板:模型调用量、错误率、Token 消耗。尤其 Token 消耗,这是 AI 应用最容易失控的成本项。
| 指标 | 建议监控粒度 | 异常信号 |
|---|---|---|
| 平均 Token/请求 | 按天、按功能 | 某个功能突然翻倍 |
| 错误率 | 按分钟、按状态码 | 4xx/5xx 突增 |
| 延迟 P95 | 按小时 | 持续走高说明并发瓶颈 |
| 内容审核命中率 | 按天 | 输出侧风险明显上升 |
| 模型版本占比 | 按天 | 灰度流量和回滚观察 |
回滚策略同样重要。模型升级不像普通代码,行为变化往往是非预期的。上线前要把旧模型保留一段时间,新模型使用小流量灰度,出现质量下降或成本异常时能迅速切回旧版本。
6. AI 工程实践的高频坑与排查链路
6.1 三个高频坑
第一个坑:输出不稳定。现象是同样的输入,每次回答都不一样,测试用例时好时坏。常见原因是temperature设置过高,或者没有用seed等采样参数。解决办法是按场景区分参数:分类、抽取任务用低温度,创意生成任务才调高温度。
第二个坑:上下文超限。现象是请求报错提示context length exceeded,或者长对话越来越慢。常见原因是把整段历史全部塞给模型。解决办法是做上下文裁剪、摘要压缩,或者改用 RAG 只放相关片段。
第三个坑:Tool Call 解析失败。现象是模型返回的工具调用参数不是合法 JSON,或者参数类型不符合预期。常见原因是直接信任模型输出。解决办法是在解析时做容错,例如用流式解析、补充说明、重试一次;同时给工具参数做严格校验。
6.2 从现象到根因的排查顺序
AI 系统排查和传统系统不太一样,建议按下面顺序查:
- 输入是否正确:消息格式、角色字段、上下文长度是否符合模型要求。
- 配置是否生效:temperature、max_tokens、top_p 是否被代码覆盖。
- 模型是否选对:当前模型是否适合这个任务,是否被系统自动降级到了弱模型。
- 提示词是否稳定:同一提示词在不同模型版本下行为差异是否明显。
- 工具链路是否正常:工具有没有抛异常、返回内容有没有被截断。
- 审核或过滤层是否误杀:输出是否被规则拦截,但开发环境没有相同规则。
- 资源水位是否健康:延迟变高、超时增多时检查 GPU 利用率、连接池和限流。
6.3 排查清单
| 问题现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 回答前后不一致 | 采样参数不合理 | 固定 seed、降低 temperature | 按场景调整参数 |
| 长文本报错 | 上下文超限 | 查看请求上下文 token 数 | 截断、压缩、RAG |
| 工具调用失败 | 模型输出非法参数 | 打印原始 tool_call 内容 | 加 JSON 容错和重试 |
| 偶发超时 | 并发或慢查询 | 看 P95 延迟和连接池 | 增加超时控制和限流 |
| 审核误拦截 | 规则过粗 | 查看审核命中的规则明细 | 细化规则和放行逻辑 |
| 成本突增 | 请求量或 Token 膨胀 | 按功能维度拆分 Token 报表 | 设置预算告警和配额 |
这份清单可以贴在项目文档里,每次线上问题按照它过一遍,能省去很多猜测时间。
7. 把“平衡”落地成工程规范
7.1 项目启动前写清目标:研究 Demo 还是线上功能
给团队定一个方向比写代码更重要。项目初期先回答四件事:
- 这是内部验证,还是要长期运维的外部功能。
- 允许的最大单次调用成本和月成本是多少。
- 回答错误会造成什么影响,需要多高的兜底级别。
- 模型升级时,是接受行为变化,还是必须固定版本。
目标不同,后面的技术决策会完全不同。研究 Demo 可以用最新模型、不做监控;线上功能则要求稳定、可回滚、可观测。
7.2 定义“不做什么”和“人工兜底”边界
AI 工程最常见的错误是过度承诺。面对需求时最好明确:哪些场景 AI 不做、哪些场景 AI 只做辅助、哪些场景必须人工复核。给模型画边界,不是限制能力,而是让能力落在可控范围内。
7.3 可落地的工程规范:从接口抽象到分级发布
建议把下面的规范写进团队文档:
- 所有模型调用走统一接口层,禁止业务代码直接拼接供应商 SDK。
- 所有在线调用必须有超时、重试和熔断。
- 所有高风险操作在 Agent 工具层做权限校验。
- 所有模型输出先过审核层再返回用户。
- 所有模型版本变更走灰度发布,预留回滚通道。
- 所有 Token 消耗按功能维度记录,便于成本分析。
这些规范不复杂,但能在关键时候救项目一命。
7.4 给新手的下一步
如果你刚接触 AI 工程,不要一上来就追求“全自动化 Agent”或“大规模自部署”。建议按这个顺序练习:先调通一个模型 API,封装统一调用接口;再加一个工具调用,理解 Tool Call 链路;然后接数据库或搜索,做一次 RAG 应用;最后补上监控、审核和回滚。每一步都跑通再进入下一步。
AI 应用开发和传统软件开发最大的区别,是系统的行为不再完全由代码决定,模型本身会带来不确定性。所以工程的本质不是消除不确定性,而是设计一套机制,在不确定性存在的前提下依然让系统稳定、可靠、可解释。这也是 Google、DeepMind 那些大组织在讨论的平衡,最终落到每个开发者代码里的样子。