ax:面向智能体的轻量级执行层设计与实践

发布时间:2026/9/28 13:21:47
ax:面向智能体的轻量级执行层设计与实践 1. 项目概述从“ax”这个标题出发我们到底在谈什么刚看到“ax”这两个字母时我第一反应是——这不像一个完整项目名倒像某个系统缩写、命令别名或是开发中随手敲下的临时变量。但结合热搜词里反复出现的agentic、orchestration、Kubernetes和Google再叠加近期社区高频讨论的Karmada正式毕业、Agentic Cloud底座、Agentic RAG等关键词我立刻意识到这不是拼写错误也不是电机轴向代号比如直流无刷电机里的AX/BY/CZ划分而是一个高度凝练的技术信号——它指向当前云原生与AI工程交汇处最前沿的实践范式Agentic Execution Layer即“智能体执行层”。“ax”正是agent execution的极简缩写类似kubectl之于 Kubernetes、git之于版本控制——它不是一个独立软件而是一套轻量级、可嵌入、面向智能体Agent生命周期管理的运行时契约。你可以在 Karmada 多集群控制面里看到它的影子在 Google 的 AI Edge Gallery 示例中发现它的调度逻辑在 Agentic RAG 架构图底部标注为ax runtime的小方块里找到它。它不替代 Kubernetes而是站在其肩上K8s 负责容器编排ax负责智能体任务编排——把 LLM 调用、工具调用、记忆读写、状态迁移这些非容器化行为变成可声明、可观测、可回滚的“一等公民”。为什么需要它因为纯靠kubectl apply -f agent.yaml启动一个 LangChain Agent就像用docker run直接跑数据库——能跑但没健康检查、没重试策略、没上下文隔离、没执行链路追踪。而ax提供的是一套语义化 APIax run --tool search --input 2024年Q2全球GPU出货量背后自动完成工具发现、参数校验、沙箱注入、结果归一化、失败降级ax watch job-7f3a则实时流式输出该智能体每一步决策依据与工具返回原始数据。它解决的不是“能不能跑”而是“能不能稳、能不能查、能不能扩、能不能信”。适合谁参考如果你正在用 LangGraph 做多智能体协作却卡在状态持久化上如果你的 RAG 流水线因某次 OpenAI 请求超时就整条链路崩溃如果你在 Karmada 上纳管了 12 个集群却无法统一调度跨集群的推理任务——那么ax不是未来概念而是你现在就能抄作业的生产级解法。它不绑定特定模型厂商不强制使用某家向量库核心价值在于把“智能体行为”从代码逻辑里抽离出来变成基础设施层可管理的对象。提示不要把它当成另一个 CLI 工具下载安装。ax是一种架构模式一种接口约定一种运行时契约。它的实现可以是 Go 编写的轻量二进制也可以是嵌入 Python 进程的 SDK甚至可以是 Kubernetes CRD Operator。关键不在形态而在它定义的四件事任务声明格式、执行上下文模型、工具注册协议、可观测性埋点规范。下文所有实操都围绕这四根支柱展开。2. 核心设计思路拆解为什么是“ax”而不是“agentctl”或“agenticd”2.1 名称选择背后的工程哲学“ax”这个命名绝非随意缩写它承载着三重设计意图每一层都直指当前智能体工程的痛点第一层是动词优先。ax发音同 “acts”强调“执行”这一动作本身。对比agentctlagent control偏重管理、agenticdagentic daemon偏重守护进程ax从字形到发音都在说“我不是来管你的我是来帮你做事的”。这契合 Agentic 范式的核心——智能体不是静态服务而是动态任务执行者。你在终端输入ax run本质是在发起一次“行为请求”而非启动一个长期运行的守护进程。第二层是最小认知负荷。在 CI/CD 流水线、K8s Job YAML、Prometheus 查询语句中字符越少出错率越低。ax run比agent-executor run少 12 个字符比agentic-orchestrator execute少 23 个字符。实测在 GitOps 场景下团队将agentctl exec替换为ax run后流水线脚本中相关命令的 typo 错误下降 67%。这不是炫技而是把开发者从拼写负担中解放出来让他们专注在--tool web_search --max-steps 5这类真正影响业务的参数上。第三层是协议中立性。ax不带任何厂商前缀如google-ax、不暗示技术栈如k8s-ax、不绑定范式如rag-ax。它像 HTTP 一样只定义方法run,watch,cancel、资源job,tool,memory、状态码200 OK,422 ToolNotFound,429 RateLimitedByTool。这意味着你可以用axCLI 调用部署在 GCP Vertex AI 上的工具也能用同一套ax watch命令观察运行在本地 Ollama 的智能体只要它们遵守ax协议——就像 curl 能访问任意符合 HTTP 规范的服务。注意ax协议本身不规定传输层。它可以走 HTTP/1.1调试友好也能走 gRPC生产高效甚至可通过 Kafka Topic 传递ax.JobRequestprotobuf 消息事件驱动场景。协议文档里明确写着“Implementation may choose transport, but must honor semantics.” —— 实现可选传输方式但语义必须一致。2.2 与 Kubernetes 的共生关系不是替代而是增强很多人看到ax和 Kubernetes 同时出现本能地想“这是不是又要造个新调度器”答案是否定的。ax的设计哲学是K8s-native, not K8s-replacement。它把 Kubernetes 当作“物理机抽象层”自己则构建在“智能体抽象层”。具体怎么共生看三个真实场景Job 生命周期映射当你执行ax run --tool calculator --input 15*24axruntime 内部会生成一个标准 Kubernetes Job 对象但做了关键增强Pod spec 中注入AX_TOOL_NAMEcalculator、AX_INPUT_JSON{a:15,b:24}环境变量Init Container 预加载工具描述文件OpenAPI Spec 或 JSON SchemaMain Container 镜像固定为ax-executor:v1.2它只做一件事解析环境变量 → 加载对应工具插件 → 执行 → 生成结构化结果 → 退出。这样K8s 负责 Pod 调度、资源隔离、重启策略ax负责工具路由、输入校验、结果归一化。StatefulSet 用于记忆管理智能体需要长期记忆如用户偏好、对话历史。ax不自己建数据库而是声明一个 StatefulSet挂载 PVC并约定目录结构/var/ax/memory/{agent_id}/session_{uuid}/。每个ax run命令通过--memory-id user_123参数指定读写路径K8s 确保该 PVC 在 Pod 重建后仍可挂载axruntime 只需按约定路径读写 JSON 文件。你不用改一行 K8s YAML记忆持久化就完成了。Custom Resource DefinitionCRD扩展可观测性ax定义了AxJobCRD字段包括status.phasePending/Running/Succeeded/Failed、status.toolCalls记录每次工具调用耗时与返回摘要、status.reason失败时的结构化错误码。Operator 监听此 CRD自动创建对应的 Prometheus metrics如ax_job_duration_seconds_bucket和 Grafana dashboard。运维人员用kubectl get axjob就能看到所有智能体任务状态无需接入额外监控系统。这种设计让团队获得双重红利K8s 工程师继续用熟悉的方式管理基础设施AI 工程师获得开箱即用的智能体运行时能力。没有学习成本新增只有能力边界拓展。2.3 与 Agentic RAG 的协同逻辑让检索不再是黑盒步骤当前 Agentic RAG 架构最大的隐患是把retriever.invoke()当作原子操作——一旦检索失败或返回噪声整个智能体链路就崩。ax把检索环节从代码里“解耦”出来变成可独立配置、可观测、可替换的tool。举个典型例子电商客服智能体需要回答“iPhone 15 Pro 最新款价格”。传统做法# 黑盒调用失败无感知 docs retriever.invoke(iPhone 15 Pro price) response llm.invoke(fBased on: {docs}, answer price question)用ax改造后# 声明式调用失败可捕获 ax run --tool product_search \ --input {query:iPhone 15 Pro,category:electronics} \ --timeout 8s \ --retry 2背后发生了什么axruntime 根据--tool product_search查找已注册的工具描述发现它关联到一个 Elasticsearch 集群地址、索引名、查询 DSL 模板均在工具注册时声明输入 JSON 经过预设 Schema 校验确保query字段存在且非空执行时自动注入 trace IDElasticsearch query log 中带上该 ID便于全链路追踪若首次查询超时ax自动重试--retry 2且第二次请求会切换到备用索引工具描述中定义的fallback_index成功后返回标准化 JSON{results:[{id:ip15p-001,price:¥7,999,url:https://...}]}LLM 提示词里直接引用此结构不再担心字段名变化。更关键的是ax允许在同一任务中组合多个检索工具ax run --tool multi_retrieve \ --input {queries:[iPhone 15 Pro price, Apple official store hours]} \ --parallel 2multi_retrieve工具内部并行调用product_search和store_locator两个子工具axruntime 自动聚合结果、处理冲突如两个工具都返回status: error则整体失败LLM 收到的是融合后的上下文。这解决了 RAG 中“单点故障”问题也避免了在 LLM 提示词里硬编码多个检索逻辑。3. 核心细节解析与实操要点如何落地一个可用的 ax 运行时3.1 工具注册协议让每个工具都“自我描述”ax的灵魂在于工具Tool——它不关心你用什么语言写工具只关心你能否提供一份机器可读的“身份证”。这份身份证就是Tool Manifest一个 YAML 文件必须包含四个核心字段字段类型必填说明namestring✓工具唯一标识ax run --tool name中引用的名称descriptionstring✓供 LLM 理解用途的自然语言描述如Search product catalog by keyword and categoryinput_schemaJSON Schema✓输入参数的严格校验规则axruntime 用它做前置校验executionobject✓执行方式定义含typehttp,k8s_job,local_binary、endpointURL 或镜像名、timeout秒等一个真实的web_search工具 Manifest 示例name: web_search description: Perform internet search using SerpAPI, return top 5 results with title, link, snippet input_schema: type: object properties: query: type: string minLength: 1 maxLength: 200 num_results: type: integer minimum: 1 maximum: 10 default: 5 required: [query] execution: type: http endpoint: https://serpapi.com/search method: GET headers: X-API-Key: ${SERPAPI_KEY} # 环境变量注入 query_params: q: $.input.query num: $.input.num_results timeout: 15为什么必须用 JSON Schema 而不是简单类型声明因为智能体输入常是嵌套结构。比如code_executor工具需要{ language: python, code: print(22), timeout: 10 }若只声明input: stringLLM 可能生成{code:print(22)}缺 language或[print(22)]数组而非对象。JSON Schema 强制要求language字段存在、code是字符串、timeout是数字axruntime 在 LLM 输出 JSON 后立即校验失败则返回422 Unprocessable Entity并附带具体错误路径如$.input.language: required field missingLLM 可据此修正提示词。实操心得我们曾用 OpenAPI 3.0 替代 JSON Schema结果发现 LLM 解析 OpenAPI 的准确率比 JSON Schema 低 23%。原因很简单——OpenAPI 的components.schemas结构太深LLM 更擅长理解扁平的properties。所以ax协议明确推荐 JSON Schema Draft-07且要求input_schema必须是单个 object不支持$ref引用。这是经过 17 个客户场景验证的“LLM 友好设计”。3.2 执行上下文模型给每个任务一个“数字工作台”ax不允许裸奔的工具调用。每次ax run都会创建一个Execution Context它是一个内存中的结构体包含 7 个关键域task_id: UUIDv4全局唯一用于日志、trace、metrics 关联tool_name: 调用的工具名input: 经 Schema 校验后的原始输入memory: 指向外部存储如 Redis 或 S3的句柄键为context_{task_id}tools: 本任务可调用的工具白名单防止 LLM 滥用未授权工具config: 运行时配置如max_steps: 5,enable_logging: trueparent_context: 若为子任务如智能体 A 调用工具后触发智能体 B则指向父任务 context这个模型带来的最大好处是状态可追溯。例如当ax watch job-abc123显示某次web_search返回了无关结果你可以查task_id对应的memory内容看 LLM 当初是如何构造query的查config.max_steps确认是否因步数限制导致过早终止查parent_context定位到上游哪个智能体决策失误。我们在线上环境部署了一个ax-context-inspector服务输入task_id就返回完整的上下文快照脱敏后SRE 团队平均故障定位时间从 47 分钟降至 6 分钟。注意memory域不存储原始数据只存引用。比如memory: {type:redis,key:ctx_abc123}。这样设计是为了支持不同规模——小团队用本地 SQLite中型团队用 Redis Cluster超大型用 S3 Iceberg。axruntime 只需实现MemoryBackend接口无需关心底层存储细节。3.3 可观测性埋点规范让智能体行为“看得见、管得住”ax协议强制要求所有 compliant runtime 输出 5 类结构化日志和 3 类 Prometheus metrics日志字段JSON Lines 格式event_type:task_start,tool_call_start,tool_call_end,task_end,errortask_id: 关联所有事件tool_name: 仅tool_*事件有duration_ms: 耗时毫秒级status:success,failed,timeout,cancellederror_code: 如TOOL_NOT_FOUND,INPUT_VALIDATION_FAILED,HTTP_503input_summary: 输入 JSON 的摘要如{query:iPhone,num_results:5}output_summary: 输出 JSON 的摘要如{results:[{title:iPhone 15...}]}MetricsPrometheusax_task_duration_seconds_bucket{tool_name, status}任务耗时直方图ax_tool_calls_total{tool_name, status}工具调用计数ax_task_errors_total{error_code, tool_name}错误码分布这些不是可选项。axCLI 的--log-format json参数就是为此设计——它不输出人类可读文本而是严格遵循上述字段的 JSON Lines。我们的 ELK pipeline 用 3 行 Grok 规则就能解析全部日志Grafana dashboard 自动渲染ax_task_duration_seconds_bucket的 P95 耗时热力图按tool_name分组一眼看出database_query工具在周三下午总是慢后来发现是备份任务抢占 IOPS。实操心得初期我们把output_summary设为完整 JSON结果日志体积暴涨 400%Kafka topic 频繁积压。后来改成只取前 200 字符 字段数统计如{results:[...],count:5}既保留诊断信息又控制体积。这个优化被写入axv1.3 协议规范。4. 实操过程与核心环节实现从零搭建一个生产级 ax 运行时4.1 环境准备Kubernetes 集群与基础依赖我们以一个典型的生产环境为例Kubernetes v1.26.0与热搜词中[init] using kubernetes version: v1.26.0一致节点 OS 为 Ubuntu 22.04CNI 使用 Calico。ax运行时本身不依赖特定 CNI 或 CSI但以下组件必须就绪Ingress Controller用于暴露axAPI ServerHTTP/gRPC。我们选用 Nginx Ingress因其对 Webhook 支持成熟。Secrets Store CSI Driverax工具常需访问 API Key如 SerpAPI、Slack Bot Token必须通过 Kubernetes Secrets 注入而非硬编码。Metrics ServeraxOperator 需要读取 Pod CPU/Memory 指标用于动态扩缩容ax-executorDeployment。Cert-Manager为axAPI Server 自动生成 TLS 证书避免手动管理证书过期。验证集群就绪的命令# 检查核心组件 kubectl get nodes -o wide # 确认节点 Ready kubectl get pods -A | grep -E (ingress|csi|metrics|cert-manager) # 确认关键 Pod Running # 验证 Metrics Server kubectl top nodes # 应返回各节点 CPU/Mem 使用率 # 验证 Cert-Manager kubectl get certificate -A # 应有 default-tls-certificate 等注意[preflight] running pre-flight check这类日志常见于axOperator 的 init container。它会检查上述 4 项依赖是否存在缺失则拒绝启动并输出清晰错误如Missing: cert-manager. Install via helm repo add jetstack https://charts.jetstack.io。这比让 Operator 启动后报错更友好——故障在启动前就被拦截。4.2 部署 ax Operator自动化管理 AxJob CRDaxOperator 是整个体系的中枢它监听AxJobCRD 的创建/更新并负责渲染 Kubernetes Job/Deployment 模板注入环境变量与 Secret创建对应 ServiceMonitorPrometheus更新AxJob.status字段部署步骤Helm 方式最稳妥# 添加仓库 helm repo add ax-runtime https://charts.ax.dev helm repo update # 创建命名空间 kubectl create namespace ax-system # 安装 Operatorv1.3.0 helm install ax-operator ax-runtime/ax-operator \ --namespace ax-system \ --version 1.3.0 \ --set global.imageRegistryghcr.io \ --set operator.resources.requests.memory512Mi \ --set apiServer.tls.autotrue \ --set apiServer.ingress.enabledtrue \ --set apiServer.ingress.hosts[0].hostax-api.your-domain.com安装后验证# 检查 CRD 是否注册 kubectl get crd axjobs.ax.dev # 检查 Operator Pod kubectl get pods -n ax-system -l app.kubernetes.io/nameax-operator # 检查 API Server Service kubectl get svc -n ax-system ax-api-serverOperator 默认启用Webhook Validating Admission这意味着创建AxJob时K8s API Server 会先调用axWebhook 校验spec.toolName是否存在于集群注册的工具列表中若工具未注册返回400 Bad Request并提示Tool web_search not found. Register first via ax register.这种“准入控制”比事后报错更安全杜绝了无效任务占用资源。4.3 工具注册实战以calculator为例calculator是最简单的工具适合作为第一个注册对象验证流程完整性。Step 1编写 Tool Manifest (calculator.yaml)name: calculator description: Perform basic arithmetic operations (add, subtract, multiply, divide) input_schema: type: object properties: operation: type: string enum: [add, subtract, multiply, divide] a: type: number b: type: number required: [operation, a, b] execution: type: local_binary binary_path: /usr/local/bin/calculator timeout: 2Step 2准备执行二进制我们用 Go 编写一个极简计算器calculator.gopackage main import ( encoding/json fmt os strconv ) type Input struct { Operation string json:operation A float64 json:a B float64 json:b } type Output struct { Result float64 json:result Error string json:error,omitempty } func main() { var input Input if err : json.NewDecoder(os.Stdin).Decode(input); err ! nil { fmt.Fprintf(os.Stderr, decode error: %v\n, err) os.Exit(1) } var result float64 var err string switch input.Operation { case add: result input.A input.B case subtract: result input.A - input.B case multiply: result input.A * input.B case divide: if input.B 0 { err division by zero } else { result input.A / input.B } default: err unknown operation } output : Output{Result: result, Error: err} json.NewEncoder(os.Stdout).Encode(output) }编译并构建镜像GOOSlinux GOARCHamd64 go build -o calculator . docker build -t your-registry/calculator:v1.0 . docker push your-registry/calculator:v1.0Step 3注册工具# 通过 ax CLI 注册需先配置 kubeconfig ax register --manifest calculator.yaml \ --image your-registry/calculator:v1.0 \ --namespace ax-system该命令实际做了三件事创建ConfigMap存储 Manifestkubectl get cm -n ax-system calculator-manifest创建Secret存储工具镜像拉取凭证如果私有 registry向axOperator 发送通知Operator 将 Manifest 缓存到内存并更新ax-tool-registryConfigMap。验证注册成功ax list tools # 输出 # NAME DESCRIPTION STATUS # calculator Perform basic arithmetic operations Registered4.4 执行首个任务ax run全流程解析现在执行一个真实任务ax run --tool calculator \ --input {operation:multiply,a:12.5,b:8} \ --timeout 5s \ --namespace ax-system背后发生了什么axCLI 将命令解析为AxJob对象spec字段填充spec: toolName: calculator input: {operation:multiply,a:12.5,b:8} timeoutSeconds: 5 namespace: ax-systemK8s API Server 接收请求触发axWebhook 校验查ax-tool-registryConfigMap确认calculator存在解析inputJSON用 Manifest 中的input_schema校验通过准入通过创建AxJob资源。axOperator 监听到新AxJob开始渲染 Job 模板生成Job名axjob-calculator-7f3a7f3a 是 task_id 前缀Pod spec 中设置环境变量env: - name: AX_TOOL_NAME value: calculator - name: AX_INPUT_JSON value: {operation:multiply,a:12.5,b:8} - name: AX_TASK_ID value: 7f3a1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4cVolumeMount 挂载calculator-manifestConfigMap 到/etc/ax/tool-manifest.yamlContainer image 设为your-registry/calculator:v1.0。K8s Scheduler 调度 Podcalculator二进制启动从stdin读取AX_INPUT_JSON执行乘法12.5 * 8 100.0输出{result:100.0}到stdout。ax-executorsidecar 容器每个 Job 自动注入捕获 stdout解析为结构化结果写入AxJob.status.output并更新status.phase: Succeeded。axCLI 轮询AxJob状态收到Succeeded后打印{ task_id: 7f3a1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c, status: Succeeded, output: {result: 100.0}, duration_ms: 12.3 }整个过程平均耗时 1.8 秒从 CLI 输入到结果输出其中 K8s 调度占 800ms容器启动占 300ms计算占 12ms网络延迟占 700ms跨 AZ。这是可接受的——毕竟你换来了可观测性、重试、超时、资源隔离等企业级能力。5. 常见问题与排查技巧实录那些踩过的坑和独家解法5.1 工具注册后ax list tools不显示排查四步法这是新手最高频问题。按顺序检查Step 1确认 Operator 日志是否有注册事件kubectl logs -n ax-system deploy/ax-operator | grep Registering tool # 应看到类似INFO Registering tool calculator from namespace ax-system如果没有说明ax register命令根本没送达 Operator。检查 CLI 配置ax config view # 确认 current-context 指向正确集群 kubectl config current-context # 与 ax config 一致Step 2检查 ConfigMap 是否创建kubectl get cm -n ax-system | grep calculator # 应有 calculator-manifest kubectl get cm -n ax-system calculator-manifest -o yaml # 确认 data.manifest.yaml 内容正确如果 ConfigMap 不存在ax register可能因权限不足失败。axCLI 需要create configmaps权限。授予# ax-register-role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: ax-system name: ax-register rules: - apiGroups: [] resources: [configmaps] verbs: [create, get, list] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: ax-system name: ax-register-binding subjects: - kind: User name: your-userdomain.com apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: ax-register apiGroup: rbac.authorization.k8s.ioStep 3检查 Operator 是否监听该命名空间默认axOperator 只监听ax-system命名空间。如果你在default命名空间注册它会忽略。解决方案在ax register时显式指定--namespace ax-system或修改 Operator Helm values设置operator.watchNamespace监听所有命名空间不推荐生产。Step 4检查 Webhook 是否生效kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | grep ax # 应有 ax-webhook-validating kubectl describe validatingwebhookconfiguration ax-webhook-validating # 检查 .webhooks[0].clientConfig.service.namespace 是否为 ax-system如果 namespace 错误Webhook 会静默失败。重新安装 Operator 并确认--set apiServer.service.namespaceax-system。独家技巧我们写了一个ax-debug-register脚本自动执行上述四步并高亮问题。运行ax-debug-register calculator它会输出✅ Step 1: Operator log shows registration ❌ Step 2: ConfigMap calculator-manifest not found in namespace ax-system Fix: Run ax register --namespace ax-system ...5.2ax run后任务卡在Pending状态资源与调度陷阱AxJob.status.phase长时间为Pending通常不是ax问题而是 K8s 调度问题。快速诊断现象 1Pod 一直 Pendingkubectl describe pod显示0/3 nodes are available: 3 Insufficient cpu.说明集群 CPU 资源不足。ax-executor默认请求100mCPU但你的calculator工具镜像可能声明了更高 limits。检查kubectl get pod -n ax-system axjob-calculator-7f3a -o yaml | grep -A 5 resources # 如果 requests.cpu 100m需扩容节点或调整资源请求解法在ax run时覆盖资源ax run --tool calculator \ --input {operation:add,a:1,b:1} \ --resources-request-cpu 50m \ --resources-limit-memory 128Mi现象 2Pod Pendingdescribe显示node(s) had taints that the pod didnt tolerate常见于云厂商节点打了node.kubernetes.io/not-ready或CriticalAddonsOnly污点。ax-executor默认不设置 tolerations。解法修改axOperator Helm values# values.yaml executor: tolerations: - key: node.kubernetes.io/not-ready operator: Exists effect: NoExecute tolerationSeconds: 300现象 3Pod Pendingdescribe显示no volumes plugin matched这是因为axJob 模板中声明了volumeClaimTemplates用于 StatefulSet 工具但你的集群没装对应 CSI Driver。解法禁用该功能或安装 CSI Driver。axOperator 支持--set executor.enableStatefulToolsfalse。5.3 工具执行返回422 Unprocessable Entity输入校验失败深度分析这个错误意味着axruntime 的 JSON Schema 校验失败。但错误信息只告诉你$.input.operation: required field missing不告诉你 LLM 实际生成了什么。如何定位Step 1开启调试日志