第 6 章 第一周的技术选型

苏州合昇精密重工,海外业务部,会议室。项目第八天。

合昇的整机出口主要走东南亚——新加坡总仓、吉隆坡、曼谷、雅加达、胡志明市,五个站点共 48 名驻外服务工程师。三年前他们把 MES、CRM、工单系统迁到了 AWS 新加坡区。董事会十一月底要看工单 Agent 上线效果。

CTO 周明远把投影仪打开,手里捏着三家 ISV 的标书。”他们都说自己用 RAG + Agent。你们准备怎么做?我下周一要给董事会拍板。”

陈雪是售后系统的业务方,她不抬头:”我只关心 95% 的派工准确率。架构图我看不懂。”

顾建国是 IT 主管,他更直接:”我只关心这个东西能不能跑在我们现有 AWS 账号里、不要再开第二条供应商关系。审计去年才搞定一遍。”

会议预计三十分钟。我得在一张纸上回答五个问题:模型放哪、用谁、怎么调用、谁来编排、怎么验证。三个人的问题都得给出答案。


把”技术选型”拆成可独立决策的维度

很多 FDE 第一周翻车,是因为把”技术栈”当成一个整体来讨论。会议室里讨论”我们用 LangChain 还是 LangGraph”——讨论不出结果,因为这个问题本身没意义。在你确定模型在哪、用谁之前,编排框架是不能选的。

我习惯把它拆成五个维度,从下到上:

        ┌────────────────────────────────────────────────┐
        │ D5  评估 / 可观测                              │  ← 第 8 章
        │     怎么知道它在变好还是变坏                   │
        └────────────────────┬───────────────────────────┘
                             │
        ┌────────────────────┴───────────────────────────┐
        │ D4  编排                                       │  ← 本章 6.4 节
        │     谁把 prompt、tool、retry、log 串起来       │
        └────────────────────┬───────────────────────────┘
                             │
        ┌────────────────────┴───────────────────────────┐
        │ D3  调用模式                                   │  ← 第 7 章
        │     RAG / Tool use / Agent / 微调              │
        └────────────────────┬───────────────────────────┘
                             │
        ┌────────────────────┴───────────────────────────┐
        │ D2  模型选型                                   │  ← 本章 6.2、6.3
        │     哪一个 / 哪几个                            │
        └────────────────────┬───────────────────────────┘
                             │
        ┌────────────────────┴───────────────────────────┐
        │ D1  托管面                                     │  ← 本章 6.1
        │     模型部署在哪、数据走哪条链路               │
        └────────────────────────────────────────────────┘

D1 决定 D2 的可选范围(区域里有什么模型)。D2 决定 D4 的复杂度(如果一个 Haiku 就能解决 95% 的工单,你不需要多 agent 编排)。所以这五维不是平行关系,是有先后的。

会议三十分钟,我会把 D1、D2、D4 锁定,D3 和 D5 留给后续两章。


6.1 D1:在客户现有的 AWS 账号里把第一条调用链跑通

我让顾建国把现行的 AWS 账号架构图拿出来。一张可读性很差的 draw.io 图,但够用:

  • 主 region:ap-southeast-1(新加坡)
  • VPC:双 AZ,私有子网跑 ECS(CRM、MES)和 RDS
  • 出网走 NAT;只有 SaaS 集成走外部白名单
  • IAM 用 Identity Center 接 Okta SSO
  • 没用 Bedrock,也没开过模型访问

第一周的 D1 不是”挑 Bedrock 还是 SageMaker”——是把客户现有的账号配置打通到能跑第一条 Converse 调用。这步常常被低估。

具体做了三件事:

第一件,开通 Bedrock 模型访问。Bedrock 默认对每个账号是关的,每个模型要单独申请。新加坡区 Anthropic 的 Claude 4.5 系列一申请就过,4.6 系列要走 cross-region inference profile(跨区到 us-west-2 或 us-east-1),需要客户审批”流量是否允许跨 region”。顾建国走了一次 30 分钟的内部流程批了。

第二件,配 Bedrock VPC endpoint。ECS 跑在私有子网,要么走 NAT 调 Bedrock 公网端点,要么开 VPC endpoint。顾建国坚持走 endpoint,理由是流量不出 VPC、可以接 endpoint policy 限制 modelId。我支持这个,因为它顺带把第一道安全护栏立了。

第三件,跑通一次 hello world 调用。真的就是 boto3.client('bedrock-runtime').converse(...) 调一次 haiku,看返回。这步看着没必要,但它能在第二天 demo 之前把所有”凭证 / endpoint / 模型 ID / IAM policy”的坑一次性踩干净。第一次跑我就撞到了两个坑(见 6.3)。

D1 锁定的不是”哪条供应商路线”,是”客户账号里下游所有 D2-D5 工作的网络/IAM/quota 已经准备好”。这一步做完,工单 Agent 才有地基。

后面的章节会用到的两个 Bedrock 能力,提前在这里说一句,避免到时候临时学。一个是 2025 年 11 月扩展的服务等级——除默认 Standard 外,新增 Priority(实时优先,价高)、Flex(latency-tolerant,半价)、以及 Reserved(1/3 月承诺包,固定 TPM)。生产实时调用走 Priority,批量评估走 Flex,可预测高 QPS 场景考虑 Reserved。另一个是 2026 年 1 月把 prompt cache 从 5 分钟扩到 1 小时——对工单这种”系统 prompt 长、用户输入短”的场景帮助很大。两个都是上线后慢慢用的,第一周不用现在配。


6.2 D2:用谁的模型

我从来不在选型会议上回答”哪个模型最好”。这个问题没有答案——它取决于你的数据。

但合昇会议室里,周明远问的就是这个问题。我手里有什么?十条客户工单。

第六天我拉了陈雪和王师傅(资深维修工程师),让他们各自从历史工单里挑十条”最有代表性”的。两个人挑出来的有重合也有差异,我把并集二十条做了去重,最后留下十条:

  • 五条机械组、五条电气组(覆盖两大派工去向)
  • 至少一条是新人会派错的(陈雪指认 T-2018)
  • 至少一条是带方言/口语化描述(”老师傅说那个不行了”——王师傅给的)
  • 至少一条是带报警代码(ALM 4501报警 1042

每条由陈雪和王师傅双盲打标,两人意见不一致的,陈雪决断。十条标完,三十分钟。

这十条就是 eval-v0。它太小,跑不了任何科学结论,但它够用——够用来在会议室拍板”我们 primary 用谁”。

样本两条:

{"id": "T-2025-Q4-0142",
 "ticket": "客户报修:JG-A6 五轴加工中心,X 轴定位异常,加工件公差超差 0.08mm,已发现 X 轴伺服电机过热报警 1042。请求工程师上门。",
 "expected_team": "电气组",
 "expected_fault_type": "伺服系统"}

{"id": "T-2025-Q4-2018",
 "ticket": "新来的徒弟操作:他说屏幕上显示 ALM 4501 报警动不了。我看了一下是冷却液液位低。我让他加了冷却液还是报警。是不是传感器坏了?",
 "expected_team": "电气组",
 "expected_fault_type": "传感器"}

完整十条在仓库 demos/ch6-stack/data/eval-v0.jsonl


6.3 在客户的数据上跑一遍

第七天,我跑了一次基准。Bedrock 上四个候选:claude-haiku-4-5、claude-sonnet-4-6、claude-opus-4-6、amazon nova-pro。每个模型对每条工单调用三次。

跑这一次踩了两个坑,值得记下来。

第一个坑:Anthropic 的模型在 Bedrock 上不能直接用 on-demand 模型 ID。第一次跑,所有 Claude 都返回:

ValidationException: Invocation of model ID anthropic.claude-opus-4-6
with on-demand throughput isn't supported. Retry your request with the
ID or ARN of an inference profile that contains this model.

这是 Bedrock 推 cross-region inference 之后的硬要求。Claude 模型必须走 us.anthropic.claude-opus-4-6 这种带 region 前缀的 inference profile id。Nova 两条路都行,但为了一致我也走 profile。

MODELS = {
    "claude-haiku-4-5":  "us.anthropic.claude-haiku-4-5-20251001-v1:0",
    "claude-sonnet-4-6": "us.anthropic.claude-sonnet-4-6",
    "claude-opus-4-6":   "us.anthropic.claude-opus-4-6",
    "nova-pro":          "us.amazon.nova-pro-v1:0",
}

合昇主 region 是新加坡,但这次基准我跑在 us-east-1,因为四个候选模型在 us-east-1 都直接可用。新加坡区当时还没全部开放,要走跨区 inference profile。这一步的目的是先确认”哪个模型够用”——区域可用性是落地时再做的二次 fit check。客户那边我也是这么解释的。

第二个坑:Claude 4.6 系列在 Converse API 上不再接受 temperature

ValidationException: `temperature` is deprecated for this model.

老的脚本写 inferenceConfig={"temperature": 0.0} 就直接挂掉。改成按模型分支:

def inference_config(model_id):
    cfg = {"maxTokens": 200}
    if "4-6" not in model_id:
        cfg["temperature"] = 0.0
    return cfg

这两个坑我都不是查文档发现的,是上手跑才撞到的。这就是为什么在客户那边的网络上,第一周必须把 hello world 端到端跑一遍。

调用主体很简单:

client = boto3.client("bedrock-runtime", region_name="us-east-1")

def call(model_id, ticket):
    t0 = time.perf_counter()
    resp = client.converse(
        modelId=model_id,
        messages=[{"role": "user",
                   "content": [{"text": PROMPT.format(ticket=ticket)}]}],
        inferenceConfig=inference_config(model_id),
    )
    return {
        "text": resp["output"]["message"]["content"][0]["text"],
        "in_tokens": resp["usage"]["inputTokens"],
        "out_tokens": resp["usage"]["outputTokens"],
        "elapsed_ms": (time.perf_counter() - t0) * 1000,
    }

完整代码:仓库 demos/ch6-stack/scripts/bench.py

跑出来的数字(每模型 30 次调用):

模型 派工准确率 故障类型准确率 P50 延迟 P90 延迟 $/1k 工单
claude-haiku-4-5 100% 40% 784ms 918ms $0.37
claude-sonnet-4-6 93% 40% 1340ms 1997ms $1.10
claude-opus-4-6 100% 40% 966ms 2383ms $5.63
nova-pro 90% 40% 498ms 536ms $0.27

我把这张表打印出来带进会议室。陈雪扫了一眼:”为什么故障类型全是 40%?四个模型一样?”

这是个好问题。四个候选在故障类型上全部 40%——这种”齐刷刷卡同一个数”的情况几乎肯定是 eval 设计问题,不是模型能力问题。我后来回去看:陈雪打标用的是”伺服系统”,模型经常输出”伺服电机”。语义相同,字符串不同。这个问题第 8 章会展开,它不是这次选型会议要解决的,但要承认它存在。

派工准确率上 haiku 100% 看起来最好,但十条样本的 ±10% 误差范围里,四个候选其实都接近达标。十条数据告诉我的是”四个候选都进入候选池”,不是”haiku 比 opus 强”。要分高下需要二百条以上。

真正能让我做决策的是延迟和成本:

  • nova-pro 的 P90 是 0.5 秒,opus-4-6 是 2.4 秒。差五倍。调度员从”瞬时反应”变成”等一下”,体感差异很大。
  • 单价 nova-pro $0.27 vs opus-4-6 $5.63(每千单)。日均 230 单 × 365 天 ≈ 8.4 万单/年,年化分别是 $23 和 $473。

合昇的工单 95% 是简单分诊。我没必要为每一条都用 opus。最终方案我推荐 primary + fallback:

primary:   claude-haiku-4-5  (95% 简单工单)
fallback:  claude-opus-4-6   (5% 复杂工单)

升级条件: 工单字数 > 200 OR 包含报警代码 OR 客户等级 = A

混合成本: 0.95 × $0.37 + 0.05 × $5.63 = $0.63 / 1k 工单
混合延迟: 0.95 × 0.92s + 0.05 × 2.4s   = 0.99s

这个方案比 all-in opus 便宜 9 倍,比 all-in haiku 贵 70%,但准确率上限拿到了 opus 的水平。

6 个月前实现这个 primary+fallback 自己得写一段路由逻辑。Bedrock 在 2026 年 5 月推了 Advanced Prompt Optimization and Migration Tool,能自动跑跨模型 A/B 并出延迟成本对比。如果你做的是和 6.3 节一模一样的实验,可以省掉一些手工活。但教学上我还是建议自己写一遍 bench.py——你需要知道每一行在做什么,工具是后来的事。

回到会议室。我把这张表念给周明远,他点头:”这种依据我能给董事会讲。”陈雪问:”五个百分点的复杂工单走 opus,会不会加错条件,简单工单也走过去?”我说:”Ch7 那个升级路由我写完了我们再过一遍。”顾建国问:”这个 inference profile 跨区的事,新加坡能拉回来吗?”我说:”能。Bedrock 现在新加坡区的 Claude 4.5 全系都开了,4.6 走 cross-region。我们落地前再跑一次区域 fit check,区别主要是延迟,不影响选型逻辑。”

D2 锁定。


6.4 D4:什么时候你不需要框架

第二天周明远找过来:”我让团队先看了下 LangGraph,听说挺好的。我们要不要直接上?”

我说不要。原因不是 LangGraph 不好,而是合昇这一期不需要它。

我用过的 agent 项目,第一周引入框架的,六个月后客户工程师能独立维护的,比例不到一半。框架不是没价值,是它的价值要等到项目复杂度真的需要它了才显现。在那之前,引入框架等于给客户加了一层学习负担和一类排错盲区。

我把 agent 编排分成三层:

Level 0:直接 boto3,自己写 dispatcher 两百行 Python。状态都在请求级别,每次调用从头算。日志走 CloudWatch Logs,metric 自己埋。能做的事:分诊、路由、简单 RAG、tool use。

Level 1:轻量 agent SDK(Strands、LangGraph、AutoGen) 五百行。框架帮你管对话栈、tool 调用 trace、retry。能做的事:上面所有的,加多步规划、tool 链。

Level 2:托管 agent 平台(AgentCore) 一千多行加一堆配置。平台管 session、policy、observability。能做的事:长会话(小时-天级别)、跨团队协作、复杂审批流。

合昇的工单 30 分钟内闭环、单 agent 单 tool(调 KB 检索)、第一期只有一个团队改代码。这是教科书级别的 Level 0 场景。我让团队第一期写 200 行直写,6 个月后视情况再升级。

这个判断我用三个信号来核:

满足两条以上 → 才考虑 Level 2 (AgentCore):

  A. 单个用户的会话状态需要跨 8 小时以上
     例: agent 等客户上传一份文档, 6 小时后客户传了, agent 接着干

  B. agent 调用 5 个以上工具, 其中至少一个需要管理员审批
     例: 备件下单要主管批, agent 暂停在那里等

  C. 4 个以上团队同时在改同一个 agent
     例: 售后/销售/IT 各接了 tool, 互相之间需要 policy 隔离

合昇三条都不满足。这是我建议 Level 0 的工程依据,不是凭直觉。

如果有一天合昇满足了——比如二期接入了备件下单流程(出现 B 信号),又把销售也接进来(出现 C 信号)——那我会重新评估。AgentCore 这一年做了很多扎实的工作,截至 2026 年 5 月一共 11 个能力(FAQ 上的官方清单):

  • Runtime——serverless 部署 agent / MCP server,8 小时长任务、bi-directional streaming、session 隔离、VPC 接入
  • Gateway——REST API / Lambda / 现有 MCP server 一键转成 MCP-compatible tool
  • Memory——跨 session 上下文存储
  • Browser——云端浏览器,agent 操作网站
  • Code Interpreter——沙箱跑 Python/JS/TS
  • Identity——接 Cognito / Okta / Entra ID,agent 凭证管理
  • Observability——Trace、debug、CloudWatch GenAI dashboard 一体
  • Evaluations——LLM-judge + 代码 evaluator、五种评估模式(online/on-demand/batch/dataset/simulation)。Ch8 展开。子能力 Optimization (preview) 从生产 trace 自动生成 prompt / tool description 改进建议 + A/B 验证,Ch13 展开
  • Policy——Cedar 自然语言 policy authoring、tool 调用层守门(不同于 Bedrock Guardrails 的内容守门)
  • Agent Registry(preview)——企业内部发布 / 审批 / 发现 agent / tool / MCP server 的中心目录。Ch15 展开
  • Payments(preview)——x402 协议,agent 付费访问 SaaS / paid APIs / MCP。本书不展开

合昇二期我用上了其中 5 项:Runtime、Gateway、Identity、Observability、Evaluations。Browser/Code Interpreter 用不上(没那种工作流),Policy 因为 14 个工具自己写规则就够了,Registry 和 Payments 是 preview 不进生产路径,Memory 因为我们的会话不需要跨 session 持久化。

判断逻辑很重要——AgentCore 11 项不是清单式”全部都要用”,而是”按需采用”。每一项的引入都对应一个具体的工程理由。三期合昇集团多 BU 协同时 Registry 才会变成必选项;金融客户做需要主管审批的工作流时 Policy 才会变成必选项。第一期 Level 0 的判断仍然是默认起点。

如果你想知道每一项的细节边界,仓库 research/whats-new-2026.md 整理了 2025-11 到 2026-05 的所有更新;research/agentcore-2026-features.md 是 11 项能力的逐项要点。


6.5 会议室里的产物

回到第一周那个三十分钟会议。最后我交给周明远的是一张 A4:

合昇精密重工 · 海外工单 Agent v1 选型决断
─────────────────────────────────────────

D1 托管:    AWS ap-southeast-1 (现有账号)
            Bedrock VPC endpoint + Identity Center 已就绪
            Claude 4.5 系列原生; 4.6 走 cross-region inference

D2 模型:    primary  claude-haiku-4-5
            fallback claude-opus-4-6  (字数>200 / 含报警码 / A 客户)
            预估     $0.63/1k 工单, P50 1 秒, 派工准确率 ≥ 95%

D3 模式:    Prompting + 长 system prompt(含报警代码全表),不上 agent (Ch 7)

D4 编排:    boto3 + 200 行 dispatcher                    (本章 6.4)
            6 个月后视 A/B/C 信号决定是否升级

D5 评估:    eval-v0 (10 条) → eval-v1 (200 条)            (Ch 8)
            上线前必须做的 4 件事见 Ch 8

锁定到:    2026-08-23 (三个月)                          周明远 ____
                                                        陈雪    ____
                                                        顾建国  ____

签字栏三个名字签了。这张纸接下来三个月是我的护身符——每次有人问”为什么不用 opus”、”为什么不上 agent”,我把这张纸拿出来。三个人都在上面签过字。


这一章踩过的坑

按时间顺序:

第三天,我在没看 IAM 架构图的情况下就开始写 bench 脚本,凭证用的是我自己的 AWS 账号。第五天顾建国把客户账号架构图推过来,我才发现 endpoint policy 限制只允许特定 modelId,我之前的脚本到客户账号上一行跑不了。第一周第一天就要拿到客户账号架构图

第六天,我让陈雪一个人打 eval 标。她当时表示”差不多就行”。后来我才知道她对电气组报警代码不熟,T-2018 那条她标错过。eval 标注必须双盲,最好业务方 + 一线工程师。

第七天,我跑 bench 时直接抄了 6 个月前的脚本,撞进了 inference profile 和 temperature 两个坑,浪费 40 分钟。第一周必须把每个候选模型在客户网络环境下端到端跑通一次——不是看 README,是真跑。

第八天,会议室里我差点说”haiku 准确率 100% 比 opus 还高”。如果不是临进会议室前再看一眼数据想到 ±10% 误差,我就把这句话说出去了。十条样本能告诉你 4 个候选都达标,不能告诉你谁更好


下一章

D3 还没解决:RAG、Tool use、Agent、微调,哪个?

合昇有 5000 份 PDF(产品手册 + 历史工单库 + 维修知识库),周明远的直觉是”先做个 RAG”。这是不是对的?这就是下一章。

← Part III 导读 · 上一章:从需求到 SOW 与评估集 · 下一章:RAG / Fine-tune / Agent 决策树 →


Source on GitHub. CC-BY-SA 4.0.

This site uses Just the Docs, a documentation theme for Jekyll.