返回

Agent Harness 解析:概念与两种构建方式

RSS InfoQ (AI/数据工程) AI 逐段翻译 发布 2026-09-25 17:00 收录于 09-26

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

本文以金融助手 FinBot 为例,讲解 agent harness(智能体生产化所需的模型外围层)的开发与运维两层结构。文章对比 AWS AgentCore Harness(托管式 HaaS)与 Kubernetes 上 LangChain 配合 Agent Router(原 Envoy AI Gateway)的自管方案,比较二者在工具、记忆、模型访问、成本控制与可观测性上的处理差异,并讨论团队在控制权、成本与可移植性之间的取舍。指出真正的区别不在能力有无,而在于由谁运维、支付多少以及是否用控制换速度。

为什么值得关注:为 Data Agent 从 demo 走向生产提供了清晰的架构分层与托管/自管选型框架,对负责智能体落地的数据与平台工程团队有直接参考价值。

本文目录 22 节
  1. 要点
  2. 代理 = 模型 + 脚手架
  3. 脚手架的两半
  4. 构建它的两种方式
  5. 选择在光谱上的位置
  6. 演示:构建 FinBot,然后关注三项能力
  7. 构建智能体
  8. 统一模型访问
  9. 成本控制
  10. 可观测性
  11. 认识这两个技术栈
  12. 构建 FinBot:工具、MCP、记忆与检索
  13. 模型访问
  14. 在 AgentCore 上
  15. 自管理
  16. 成本控制
  17. 在 AgentCore 上
  18. 自管理
  19. 可观测性
  20. 在 AgentCore 上
  21. 自管理
  22. 总结

译文

AI 逐段翻译

要点

  • 演示与生产级代理之间的差距在于脚手架(harness):你围绕模型构建的一切,使其成为真正的产品。几乎没有什么是来自模型本身的,尽管这恰恰是你大部分工程时间实际投入的地方。
  • 脚手架分为两半:开发扩展了模型能做什么,而运维则在真实用户出现后让它持续运行。那运维的一半本质上就是换了顶帽子的 DevOps。
  • 脚手架即服务(HaaS)(如 AWS AgentCore)和自管理方案(如在 Kubernetes 上使用 LangChain 与 Agent Router(原 Envoy AI Gateway))为你提供相同的能力,所以真正的问题不在于你获得什么。而在于谁来运行它、你愿意付多少钱,以及你是用控制权换速度,还是用精力换可移植性。
  • 构建生产级代理更多是架构而非魔法:你决定产品必须做什么、什么样子算“好”,以及硬边界在哪里。然后把模型和脚手架当作工具来构建它。
  • 让脚手架生长,但不要给它镀金。从最小化开始,让技术栈随代理一起演进。价值来自任务被完成,而不是来自你在需要之前就构建好的镀金脚手架。

启动一个演示 AI 代理可能只需要一个下午。构建一个真正准备好投入生产的代理则完全是另一回事。

生产级代理必须保持在线、保持安全、控制成本,并给你足够的可见性,以便在它不可避免地出故障时弄清楚哪里出了问题。这些能力几乎都不来自模型。它来自你围绕模型构建的一切:记忆、工具访问、模型路由、护栏、成本控制,以及当你的代理开始行为异常时你翻查的追踪记录。

这一层就是我们所说的代理脚手架。

图 1. 演示 vs. 生产(来源:作者创建的图片)。

本文的其余部分将带你了解什么是代理脚手架及其两半:开发和运维。然后我们会看看团队如何选择自己管理什么,从完全托管的服务(脚手架即服务)到自管理技术栈。最后,我会以两种方式逐项能力构建同一个代理 FinBot。读完后,你将更好地理解如何利用本文介绍的脚手架能力来构建你的生产级代理。

代理 = 模型 + 脚手架

“代理脚手架”是一个今年才真正流行起来的概念,但其背后的工作一点也不新鲜。如果你去年就在构建代理,那你已经在做这件事了:把工具粘合在一起、手工调整提示词、加上重试和日志、在每次故障把某人吵醒后的第二天早上打补丁。新鲜的是这个过程有了名字。这个名字原来出奇地有用。它让你能把所有这些能力当作一件你有意设计的东西,而不是一抽屉的一次性修复。

我不断回想的框架来自 Vivek Trivedy 的 代理脚手架的解剖:代理是模型加脚手架。换句话说:如果你不是模型,那你就是脚手架。汽车让这个想法一下子清楚了。

图 2. 代理 = 模型 + 脚手架(来源:作者创建的图片)。

模型是引擎。动力来自那里。但没有人会把一台光秃秃的引擎用螺栓固定在托盘上发给客户。底盘、刹车、仪表盘和安全带才让它成为你会让家人坐进去的东西。模型只是引擎;让它成为安全、可靠且使用愉悦的产品的一切,就是你围绕它构建的脚手架。

脚手架的两半

我的思考方式是,脚手架里的一切都归入两半。开发是扩展模型触达范围的东西:跨会话记忆、工具和 MCP、检索、提示词和编排。运维是真实用户出现后让这个东西可靠运行的东西:可观测性、评估、护栏、路由、漂移和成本监控、部署和扩展。

图 3. 脚手架的两半(来源:作者创建的图片)。

这里我想谨慎一点,因为看到这样一张不平衡的图,很容易得出模型几乎不重要的结论。这完全不对。模型做的是真正困难的认知工作。更强的模型会提升它上面的一切。要点更微妙:AI 代理不是一个模型,而是一个产品。构建一个好产品远不止是把模型包进一个 API,而那“远不止”的大部分就是脚手架。如果你以前运行过服务,其中很多也会让你感到熟悉:运维那一半本质上就是 DevOps,戴着顶新帽子。

构建它的两种方式

图 4. HaaS vs. 自管理(来源:作者创建的图片)。

早点了解一件事。两条路线是同一种东西:你构建代理并用于运行它的脚手架。在底层,它们持有相同的构建块:模型访问、检索、工具和 MCP、路由、护栏等。

不同之处在于这些块如何打包以及你如何与它们交互。HaaS 把每一个都放在你配置的托管 API 后面交给你;自管理则把各个部件交给你去接线和运行。这种差异决定了你多快能发布、你保留多少控制权,以及脚手架让你付出什么代价:一边是供应商账单,另一边是基础设施和工程时间。改变的不是部件。而是谁组装它们,以及它们坏掉时谁被叫醒。

维度 脚手架即服务自管理
它是什么由供应商运行的运行时,将整个脚手架(开发和运维)作为托管 API 暴露出来由 SDK 加开源组件组装而成的脚手架
你仍然拥有策略、预算、提示词、工具、评估同样的这些,外加部署、升级和待命值班
绑定于提供商的运行时和 API你选择并构建的技术栈
示例AWS AgentCore、Google Vertex AI Agent Engine、Azure AI Foundry Agent Service、LangGraph PlatformLangChain 或 LlamaIndex,加上 Agent Router(原 Envoy AI Gateway)或 LiteLLM,运行在 Kubernetes 上
最佳适用场景快速发布而不必拥有部署云无关部署,紧密掌控

选择在光谱上的位置

Harness 即服务位于一端,自管理位于另一端,许多团队落在中间的某个位置,这完全没问题。这里存在一个光谱;你想坐在哪里取决于几个考虑因素:

  • 团队能力——你能运营 Kubernetes、一个网关和轮值待命吗,还是你真的宁愿不要?
  • 现有的云承诺——已经全力投入 AWS,还是刻意采用多云?
  • 成本——可预测的供应商账单,还是基础设施加上运行它的工程时间?HaaS 更易预算;自管理在大规模时可能更便宜,既然无论如何你都要为运营它付费。
  • 治理——护栏、审计轨迹和数据路径是否必须位于你自己的边界内?一些企业必须在自己的 VPC 中运行所有这些。
  • 可移植性——一个供应商可以,还是你必须保持云无关?
  • 预期规模——你愿意为服务它而运行多少运维面。
  • 对运维复杂性的容忍度——你真的想与集群、升级和偶尔的凌晨 3 点告警共处吗?

演示:构建 FinBot,然后关注三项能力

FinBot 是一个小型智能体,它在两个构建中都是相同的场景。用户提出一个财务问题:“总结第三季度收入”。FinBot 从文档存储中拉取该季度的文件,将数字交给代码解释器,调用模型撰写摘要,然后回答。

真正的要点是,将其投入生产并不在于选择一个更聪明的模型。而在于你在它周围构建了什么。一个出色的模型可以整天推理,但仅凭它自己,它不会记住上一轮,不会触及文件,不会在失控循环变成账单之前阻止它,也不会在它出故障时告诉你出了什么问题。所有这些都是一个 harness,包裹在这一条请求路径周围;我将沿着同一条路径追踪两个构建,每一侧都按相同规格编写,但使用各自技术栈所鼓励的惯用法。

一个真正的 harness 有许多活动部件(回到那两半),没有一篇文章能承载全部。我将从每一半中挑选几个:首先,FinBot 本身如何构建,然后是三项运维能力,根据我的经验,它们比其他任何东西都更快地决定生产就绪性。护栏、评估、提示编排、部署与扩展,以及多智能体工作流没有出现在这里;这是一个真实的缺口,而不是一个整洁的边界,因为把演示一路带到生产意味着也要处理这些。以下是我所挑选的每一项为何重要,以便选项 1 和选项 2 能够专注于各自如何交付它。

构建智能体

开发这一半,缩小到 FinBot 真正需要的东西:系统提示、它能触及的工具(一个用于文件的 MCP 服务器,以及一个运行 MCP 代码执行服务器的容器)、对这些文件的检索,以及跨轮次的记忆。这是两个技术栈感觉最不同的地方。一边是一个配置对象,另一边是一组你部署并版本化的进程。

统一模型访问

每个供应商都有自己的 SDK、认证和响应格式。自托管模型会带来更多。你想要一个前门,这样添加一个模型、金丝雀发布一个新模型或故障转移到另一个供应商,都是配置变更而不是应用变更。你的供应商密钥集中存放在一个地方,而不是散布在每个服务中。

成本控制

一个有缺陷的循环或一个粗心的功能可能使 token 用量激增,变成失控的账单。你需要计量、预算和达到限制时的优雅行为,例如停止循环的硬上限,或继续服务的回退,而不是意外的账单。

可观测性

智能体是一个黑匣子,多个供应商会让情况更糟。如果没有对提示-工具-响应链以及延迟和成本的单一视图,你就无法调试它,更不用说调优它了。

现在,同一个智能体和同样的三项能力,以两种方式构建。

认识这两个技术栈

在讲能力之前,我们将快速了解每个构建实际上由什么组成。两者交付相同的模块,但它们以不同方式打包,而打包方式正是接下来几节的内容。

图 5. AgentCore Harness 架构(来源:作者创建的图片)。

Amazon Bedrock AgentCore 为你提供生产原语(Runtime、Memory、Identity、Gateway、Observability、Code Interpreter 和 Browser),而 AgentCore Harness 是位于其上的一层托管层,将“把这些原语全部连接起来”变成“填写一些配置”。你通过两个调用 CreateHarness 和 InvokeHarness 描述智能体是什么,harness 会在底层连接这些原语,每个会话一个 Firecracker microVM、托管内存、身份和自动追踪。

当配置走到尽头时,一条命令将 harness 导出为可编辑的 Strands 代码,并在同一运行时上运行。配置用于乏味的百分之八十,代码用于真正特定于你的百分之二十。

图 6. 使用 Agent Router(原 Envoy AI Gateway)的 FinBot(来源:作者创建的图片)。

自管理构建将 FinBot 作为你自己集群上的普通 LangChain 智能体,并将 harness 的模型访问这一半交给请求路径上的一个网关。

Agent Router(原 Envoy AI Gateway)是一个基于 Envoy Proxy 和 CNCF Envoy Gateway 构建的开源网关,面向 GenAI 流量:一个兼容 OpenAI 的端点位于许多供应商之前,基于 token 的速率限制、路由和故障转移、可观测性,以及一个 ext_proc 扩展钩子,控制平面和数据平面清晰分离。请求路径很容易追踪。FinBot 向网关发出一个 OpenAI 风格的调用。数据平面(Envoy Proxy 加上一个 ext_proc服务)对其进行认证、按模型路由、运行护栏、统计 token,并在请求到达提供商之前注入上游凭证。一个由控制器组成的控制平面会监视你的 Kubernetes CRD,并通过 xDS 下发配置。这一切都运行在你自己的集群上,且没有任何一部分绑定到某个云。任何 Kubernetes 都可以(EKS、GKE、AKS 或本地部署)。

这些示例运行在 EKS 上,位于 Bedrock 前面。如果你把整个技术栈迁移到另一个云(例如,位于 Vertex 前面的 GKE),这就是云无关性为你带来的好处:FinBot 的代码及其调用的端点不会改变。你需要重新配置的是底层,包括后端 schema、模型标识符、凭证、工作负载身份和部署配置。

构建 FinBot:工具、MCP、记忆与检索

方案 1 在 AWS AgentCore 上运行 FinBot,这是一个由供应商运行的 harness 运行时;方案 2 在你自己集群上的 Agent Router 后面,用 LangChain 运行同一个代理。两者都需要同样的四样东西:系统提示、它可触及的工具、对申报文件的检索,以及跨轮次的记忆。在 AgentCore 上,它们是单次控制平面调用中的字段:

import boto3
control = boto3.client("bedrock-agentcore-control")
runtime = boto3.client("bedrock-agentcore")
harness = control.create_harness(
    harnessName="finbot",
    executionRoleArn=ROLE_ARN,
    systemPrompt=[{"text": "You are FinBot, a finance assistant."}],
    model={"bedrockModelConfig": {
        "modelId": "us.anthropic.claude-sonnet-4-6",
        "apiFormat": "converse_stream"}},
    tools=[
        {"type": "agentcore_code_interpreter", "name": "code"},
        {"type": "remote_mcp", "name": "filings",
         "config": {"remoteMcp": {"url": "https://mcp.internal/filings"}}},
    ],
    memory={"managedMemoryConfiguration": {
        "strategies": ["SEMANTIC", "SUMMARIZATION"],
        "eventExpiryDuration": 60}},
)
resp = runtime.invoke_harness(
    harnessArn=harness["harnessArn"],
    runtimeSessionId=SESSION_ID,
    messages=[{"role": "user", "content": [{"text": "Summarize Q3 revenue."}]}],
)

检索并不是 harness 自己的字段:Amazon Bedrock 知识库会作为一个 Gateway 连接器目标出现,并像任何其他工具一样被挂载。在自管理的情况下,同样的四个构建块由你部署并版本化的独立组件组装而成:

from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_core.tools.retriever import create_retriever_tool
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from psycopg_pool import AsyncConnectionPool
from psycopg.rows import dict_row

model = ChatOpenAI(model="finbot", base_url="http://ai-gateway/v1", api_key="unused",
                   default_headers={"x-ai-eg-model": "finbot"})

async def build_agent():                                  # once, at startup
    pool = AsyncConnectionPool(DB_URI, open=False, 
    	kwargs={"autocommit": True, "row_factory": dict_row})
    await pool.open()                                     # long-lived, shared
    checkpointer = AsyncPostgresSaver(pool)
    await checkpointer.setup()                            # migration: run once, not per request
    mcp = MultiServerMCPClient({"filings": {"url": "http://filings-mcp:8000/mcp",
                                            "transport": "http"},
                                "code":    {"url": "http://code-sandbox:8000/mcp",
                                            "transport": "http"}})
    tools = [*await mcp.get_tools(),
             create_retriever_tool(vector_store.as_retriever(search_kwargs={"k": 4}),
                                   name="search_filings",
                                   description="Search quarterly filings.")]
    return create_agent(model, tools,
                        system_prompt="You are FinBot, a finance assistant.",
                        checkpointer=checkpointer)

async def answer(agent, question, session_id):            # per request
    return await agent.ainvoke(
        {"messages": [{"role": "user", "content": question}]},
        {"configurable": {"thread_id": session_id}})      # memory keyed by session

这些是同样的四个构建块和同样的请求路径。在一侧,它们是配置对象中的字段;在另一侧,它们是具有自身生命周期的进程,其中 runtimeSessionId 与 thread_id 就是两个标识符之间的全部差异。

模型访问

为每个提供商创建一个统一入口,这样添加模型、金丝雀发布新模型或故障转移都只是配置变更,而不是应用变更。

在 AgentCore 上

命名模型是配置,并且你可以按调用覆盖它。在底层,AgentCore 处理 Bedrock、OpenAI、Gemini 以及任何兼容 LiteLLM 的提供商,能够在会话中途切换提供商而不丢失上下文,并将第三方密钥保存在 AgentCore Identity 的令牌保管库中。模型字段是四个(bedrockModelConfig、 openAiModelConfig、 geminiModelConfig、 liteLlmModelConfig)的联合,可在 harness 上设置,并可按调用覆盖:

resp = runtime.invoke_harness(
    harnessArn=harness["harnessArn"],
    runtimeSessionId=SESSION_ID,
    model={"openAiModelConfig": {"modelId": "gpt-4o"}},   # swap provider per call
    messages=[{"role": "user", "content": [{"text": "Summarize Q3 revenue."}]}],
)

自管理

Agent Router 暴露一个兼容 OpenAI 的端点,并将模型别名映射到后端,提供商凭证保存在网关处:

kind: AIGatewayRoute
spec:
  rules:
    - matches:
        - headers: [{ name: x-ai-eg-model, value: finbot }]
      backendRefs:
        - name: bedrock-claude
          modelNameOverride: us.anthropic.claude-sonnet-4-6   # alias -> real model id
---
kind: AIServiceBackend            # translate OpenAI schema -> Bedrock
spec: { schema: { name: AWSBedrock } }

FinBot 将普通客户端指向那一个端点,且永远看不到提供商密钥;切换模型或提供商只是它发送的别名不同。凭证留在网关处。对于 Bedrock,这意味着一个由 EKS Pod Identity 或 IRSA 支持的 AWSCredentials 策略,因此集群中不会存在静态密钥:

apiVersion: aigateway.envoyproxy.io/v1beta1
kind: BackendSecurityPolicy
spec:
  targetRefs:
    - {group: aigateway.envoyproxy.io, kind: AIServiceBackend, name: bedrock-claude}
  type: AWSCredentials         	# Bedrock uses AWS auth
  awsCredentials:
	region: us-east-1          	# credentials via EKS Pod Identity or IRSA

两者都为你提供一个统一入口。AgentCore 的是一个 API,你用不同的配置对象调用它;网关的是一个你部署的路由。差异体现在提供商密钥所在的位置:AgentCore Identity 的令牌保管库,或者你通过 Pod Identity 或 IRSA 附加到网关的 IAM 角色。

成本控制

成本控制是一个阻止失控循环的硬上限,以及一个你可以在账单到来之前真正执行的预算。

在 AgentCore 上

AgentCore 直接应对失控循环故障,提供按调用的硬上限(maxIterations,默认 75;maxTokens;timeoutSeconds),以及用于成本分配的标签和 CloudWatch 中的 token 指标:

aws bedrock-agentcore-control update-harness \
  --harness-id "finbot-UuFdkQoXSL" \
  --max-iterations 50 --max-tokens 8192 --timeout-seconds 1800

自管理

网关按请求成本计量 token。这里,按用户的每日 token 预算设置在模型上,从响应中扣费。一旦用完,网关会用 HTTP 429 拒绝后续请求(尽管名字叫 limit.requests,它其实是一个 token 预算):

kind: AIGatewayRoute
spec:
  llmRequestCosts:
    - { metadataKey: llm_total_token, type: TotalToken }
  rules:
    - matches: [{ headers: [{ name: x-ai-eg-model, value: finbot }] }]
      backendRefs: [{ name: bedrock-claude }] 
---
kind: BackendTrafficPolicy               
spec:
  rateLimit:
    global:
      rules:
        - clientSelectors: [{ headers: [{ name: x-user-id, type: Distinct }] }]
          limit: { requests: 5000000, unit: Day }
          cost: 
        	request:  { from: Number, number: 0 }
        	response: { from: Metadata, metadata: { namespace: io.envoy.ai_gateway, key: llm_total_token } }

AgentCore 限制代理,而网关限制流量。一个在调用中途停止循环,另一个在租户的 token 预算用完后拒绝下一个请求。只有第二个知道租户是什么。

可观测性

这是提示-工具-响应链的一个视图,并附有延迟和成本。

在 AgentCore 上

这一项几乎免费。每次 AgentCore 调用都会自动将跟踪、日志和指标发送到 CloudWatch(即模型调用、工具调用和记忆操作)的一个视图中。只需要一个账户级前置条件;之后每次调用都会被跟踪:

# one-time, account level
aws logs put-resource-policy --policy-name MyResourcePolicy \
  --policy-document file://xray-to-logs.json   # logs:PutLogEvents for xray.amazonaws.com
aws xray update-trace-segment-destination --destination CloudWatchLogs

一个设置采样百分比的索引规则是可选的。

要了解这为你省去了什么,可以将其与你自行对代理进行插桩进行比较。在运行时之外托管时,你设置 AGENT_OBSERVABILITY_ENABLED、OTEL_PYTHON_DISTRO 和 OTEL_PYTHON_CONFIGURATOR,并用 opentelemetry-instrument 包装启动命令。将你自己的容器带到 AgentCore Runtime,运行时设置它自己的 ADOT 默认值,只留下 opentelemetry-instrument 包装器。通过 AgentCore CLI 部署,它会在打包时添加插桩,因此你也不需要该包装器。harness 开发者这些都不用写。

自管理

Agent Router 按照 OpenTelemetry 语义约定发出 GenAI 指标(token 使用量、首 token 时间和 token 间延迟),并由 Prometheus 抓取:

scrape_configs:
  - job_name: envoy-ai-gateway
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_container_port_name]
        regex: "metrics|aigw-admin"
        action: keep
# exposed GenAI metrics (OTel semconv):
#   gen_ai.client.token.usage
#   gen_ai.server.time_to_first_token

因此,你在事故中真正要问的两个问题(谁在消耗 token,谁慢)各自只需一个查询。标准指标名称使它们在提供商之间可移植:

sum(gen_ai_client_token_usage_sum{gateway_envoyproxy_io_owning_gateway_name="finbot"})
  by (gen_ai_request_model, gen_ai_token_type)

指标回答了多少和有多慢。至于实际发生了什么,你需要跟踪,而形态很简单:两个生产者、一个收集器和一个后端。

图 7。两个生产者、一个收集器、一个后端(来源:作者创建的图片)。

两者都通过 OTLP 发出相同的 gen_ai.* 词汇,这正是它们跨度能够对齐的原因。插桩和后端仍然是独立选择:Langfuse、Phoenix 和 OpenLIT 各自都同时提供 LangChain SDK 和后端,因此你可以用一种进行插桩,用另一种进行存储。在网关上,将 ext-proc 指向收集器:

kind: GatewayConfig
spec:
  extProc:
    kubernetes:
      env:
        - { name: OTEL_EXPORTER_OTLP_ENDPOINT, value: "http://otel-collector:4317" }
        - { name: AI_GATEWAY_TRACING_SEMCONV,  value: "gen_ai" }   # gen_ai.* span names

这些跨度覆盖请求路径上的模型调用。循环的其余部分(工具调用、代理的控制流、提示组装)永远不会离开进程,因此需要对应用进行插桩。OpenLIT 只需一行,并遵循相同的约定:

import openlit
openlit.init(otlp_endpoint="http://otel-collector:4318")   # once, at startup

OpenTelemetry 项目也自带了自己的 LangChain 插桩,在撰写本文时仍处于 beta 阶段。无论采用哪种方式,有一件事会让所有人都措手不及:消息内容默认是关闭的,所以如果你希望提示词本身出现在追踪中,就要在两端都设置 OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY,并且要考虑到一旦这样做之后,哪些人能够读取它们。

把两者都指向同一个收集器,你就得到了从提示词到工具再到响应的链路。当你自带代码时,这正是 AgentCore Runtime 所要求的同一项插桩工作;而 harness 是唯一能为你追踪整个循环的选项。

总结

本文介绍了 agent harness 的概念,并介绍了构建它的两种方式:使用 Harness-as-a-Service 的托管方式,以及自管理方式。我们在 FinBot 中只演示了 harness 的一小部分能力,其余部分就留给你去探索了。

无论你选择哪条路径,构建和运行 agent 最终都会归结为同样的节奏,而且它更多是架构,而不是魔法。你知道产品需要做什么、什么算“好”,以及硬边界在哪里。模型带来推理能力;harness 提供控制,把这种推理变成你真正可以交付的东西。你定义结果并设定边界,而工具则在边界之内完成工作。

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存