
上个月陪一家做快消的团队做数据平台年度复盘会议室白板上贴满了需求卡片红黄绿三色里红色占了将近一半。排在最上面的几条是“华东区上周动销下滑原因拆解”“某新品铺货率和复购率交叉看一下”“帮我把近三个月渠道费用和销量做个相关性”。这些问题没有一条是标准报表能直接回答的但它们又确实是业务每天在问的东西。数据团队六个人两个人维护报表两个人接临时取数剩下两个在修数据质量一年下来真正做建模分析的时间不到三成。这就是 Data Agent 这两年会被反复提起的现实土壤——不是概念上有多新而是需求侧真的被长尾问题压得喘不过气。我理解的 Data Agent简单说就是一套以语言模型为推理内核、以企业数据资产为作业对象、以工具调用为执行手段的智能体系统。它跟几年前那波 Text-to-SQL 不是一回事跟 BI 工具里附带的自然语言查询也不是一回事。它要解决的核心问题是让业务方用自己习惯的话把问题讲清楚系统自己去找数据、拆任务、跑查询、验结果、给解释中间不需要人把问题翻译成 SQL、不需要人判断口径、不需要人逐条核对数字对不对。适合谁看如果你是数据平台负责人、做指标中台或 BI 建设的同学、正在评估 AI 落地场景的技术管理者或者单纯是每天被取数需求追着跑的分析师下面这些内容应该都能对上你的实际处境。1. 需求侧的真实压力为什么传统数据链路撑不住了1.1 长尾需求吃掉了数据团队的大部分产能先把账算清楚。一个中等规模企业的数据团队日常产出大致可以分成三类固定报表和看板、临时取数、专项分析。第一类有明确的需求方和固定的更新节奏做完了就自动跑第二类数量最多、单个体量最小、但最消耗人第三类数量少、价值高却常常因为前两类挤占时间而做不了。我见过的一个典型分布是固定报表维护占 30%临时取数占 45%专项分析占 25%。而这 45% 的临时取数里有相当比例是“上个月那个数再按渠道拆一下”“同样的口径换成本周”“把这张表加一个城市维度”这类变体需求。它们的技术难度并不高但每一条都要走“业务提需求—分析师理解—确认口径—写 SQL—核对—发结果”的完整链路平均周转两三天。长尾需求的本质矛盾在于单条价值低但总量巨大每条的边际成本降不下来因为都要人参与。Data Agent 切中的正是这一段。它不指望把专项分析也自动化掉而是把那些“有明确口径、有现成数据、只是需要换个切法”的需求接过去让人的时间回到真正需要判断力的地方。1.2 BI 的“固定报表”假设正在失效传统 BI 的底层假设是业务的问题是可以被提前枚举的。所以我们要做需求调研、要设计指标体系、要把常用的分析路径固化成看板和钻取。这套方法在业务稳定、竞争节奏慢的年代非常有效它把重复劳动沉淀成了资产。问题是现在的业务节奏不允许你慢慢枚举。一个新渠道上线两周就要评估效果一个促销策略三天就要复盘一个区域异常当天就要定位原因。等你把这个需求抽象成指标、建好模型、做好看板业务窗口已经过去了。更麻烦的是很多问题是“一次性的”做完这次就不会再问第二遍为它建一个看板的投入产出比极低。所以企业现在的状态很尴尬看板越建越多使用率越来越低需求响应越来越慢业务方越来越倾向于自己在Excel里土法炼钢。Data Agent 在这种缝隙里出现它提供的不是“又一个新的报表入口”而是“一个能接住一次性问题的临时分析员”。这个定位差异很关键它决定了你不能拿做 BI 的思路去做 Data Agent。1.3 数据资产越堆越多找数和懂数的成本反而在上升还有个更隐蔽的问题。大部分企业这几年数据平台建设没停过表数量从几百张涨到几千张指标从几十个涨到几百个。按理说资产变多了取数应该更容易但实际体验往往相反。原因在于资产的增长没有伴随“可理解性”的同步增长。一张表叫什么、字段什么含义、谁在用、口径和别的表是否一致、更新频率如何、有没有质量问题这些信息散落在文档、聊天记录、老员工脑子里。新人接手一个需求光是搞清楚“应该用哪张表”就要花掉大半天。人做这件事靠的是经验和问人而 Data Agent 做这件事靠的是元数据检索和语义理解。这就引出了一个很重要的判断Data Agent 的上限很大程度上不取决于模型有多强而取决于企业元数据和语义层的建设质量。这一点后面会反复提到因为它决定了项目是能落地还是只能做演示。2. Data Agent 的核心本质一条完整的“数据决策回路”2.1 它不是一个聊天框而是四层结构的组合很多人第一次接触 Data Agent看到的是一个输入框问一句话出来一个数字加一段解释。表面上确实像个聊天机器人但如果按聊天机器人的思路去设计做出来的东西一定不好用。我习惯把它拆成四层来看每一层解决不同的问题。第一层是交互层负责接收自然语言、澄清歧义、展示结果。这一层最容易被过度重视因为它最直观但它其实是最薄的一层。第二层是语义层负责把业务语言映射到数据语言。什么叫“动销”、什么叫“活跃用户”、什么叫“毛利率”这些词在每个人嘴里含义可能都不一样语义层的任务是把它们钉死成唯一可执行的定义包括计算公式、过滤条件、时间口径、维度组合规则。第三层是执行层负责把任务拆成步骤、选择合适的工具、填参数、跑查询、处理报错和重试。这一层是传统工程能力和模型推理能力的结合部。第四层是校验层负责检查结果是否合理、是否和问题对齐、能不能给出可追溯的解释。这一层最容易被忽略但它是决定“业务方敢不敢用”的关键。四层里交互层决定第一印象语义层决定准确率上限执行层决定能覆盖多复杂的问题校验层决定信任度。大部分失败的项目问题都出在语义层没做透却在交互层拼命优化体验。2.2 语义层才是真正的护城河我经常跟团队讲一句话Data Agent 的竞争不在模型在口径。模型能力是公共资源大家用的是相近的基础能力差距不会拉开太多但每家企业对“销售额”“有效订单”“活跃门店”的定义都是独有的把这套定义结构化、可执行化才是别人抄不走的东西。举个具体的例子。某零售企业问“上周销售额同比下降多少”。这句话里有四个需要定义的点销售额是含税还是不含税、是否扣除退货、上周是按自然周还是按业务周有些企业业务周从周日开始、同比是跟去年同周还是去年同日期。如果语义层没有把这四个点定死模型每次生成的 SQL 都可能在四个维度上做不同的选择导致同一个问题问三次得到三个答案。更麻烦的是这种不一致很难被立刻发现。数字看起来都“差不多”业务方拿去汇报过两周和财务对不上信任就崩了。所以我在做任何 Data Agent 项目时第一件事永远不是搭框架、调模型而是拉着业务和数据的人坐下来把前二十个高频问题涉及的口径一条条写清楚写成一个结构化的指标定义文件。这个文件长什么样后面第 4 节会给具体格式。这里先强调一点口径定义必须是机器可读的结构化描述不能是一段自然语言文档。自然语言文档可以给人看但模型读它的时候仍然要做一次理解理解就会有偏差。而结构化定义可以直接被程序解析、被工具调用、被校验逻辑引用这才是可靠的。2.3 与 Text-to-SQL、传统 BI 的边界对比这三者经常被混为一谈实际能力边界差别很大。用一个表说清楚。维度传统 BI 看板Text-to-SQL 工具Data Agent解决的问题已枚举的固定问题单轮取数问题多步、需要判断的分析问题输入形式点选筛选器一句话生成一段 SQL自然语言目标可多轮澄清处理复杂度低路径固定中单次生成高任务拆解加多工具协作口径保障建模时固化依赖 schema 和提示词依赖语义层加执行校验失败处理不涉及报错后人工改自动重试、换路径、降级结果可信度高可审计中需人工核对取决于校验层设计适用场景日常监控简单取数归因、对比、多表关联分析看这张表要抓住一个关键差异Text-to-SQL 的输出是 SQL成败取决于这一段 SQL 对不对Data Agent 的输出是结论成败取决于整个链路上的每一步是否正确。后者的问题空间大得多所以工程复杂度也高得多。如果只是把 Text-to-SQL 包一层对话界面就叫 Data Agent那基本会在真实场景里迅速翻车因为真实问题很少能一次查询解决。3. 技术逻辑拆解从一句人话到可信数字要过几道关3.1 上下文构建schema 剪枝与元数据检索把几千张表的 schema 全塞进上下文是最常见也最致命的做法。先不说 token 成本光是大量无关表名和字段名就会严重干扰模型判断导致它选错表、编字段、乱 join。正确做法是两级筛选。第一级是元数据检索把用户的问题向量化去检索表描述、字段注释、历史问答记录召回 top 20 左右的候选表。第二级是schema 剪枝对召回的表只保留相关字段同时带上字段类型、注释、枚举值样例、主外键关系。这里有个实操细节字段注释的质量直接决定召回质量。我见过太多企业的字段注释是“状态”“类型”“金额”这种等于没写。做 Data Agent 之前先把核心表的注释补一遍投入产出比极高通常补几十张核心表就能覆盖 80% 的高频问题。另外样例数据也很重要。比如一个字段注释写“渠道类型”取值是 1/2/3模型不可能知道 1 代表线上还是线下。但如果上下文里带上“1-线上2-线下3-经销商”它就能正确生成过滤条件。这类枚举映射建议直接从数据字典里抽别靠人写。# 上下文构建的简化示意 def build_context(question, retriever, schema_store, top_k20): # 第一级元数据召回 candidates retriever.search(question, top_ktop_k) # 第二级schema 剪枝只保留相关字段 pruned [] for table in candidates: fields schema_store.get_relevant_fields(table, question) pruned.append({ table: table.name, comment: table.comment, fields: [ { name: f.name, type: f.type, comment: f.comment, enum_sample: f.enum_sample, # 枚举映射非常关键 is_primary: f.is_primary, } for f in fields ], row_count_level: table.row_count_level, # 粗略量级帮模型判断是否要加过滤 }) return pruned注意row_count_level这个字段它是我踩坑之后加的。早期没放数据量信息模型经常对一张几十亿行的明细表做全表扫描查询直接超时。放一个“百万级/千万级/亿级”的粗略标注模型就会更倾向于先加时间过滤成功率明显提升。3.2 工具设计粒度、返回结构与错误语义Agent 的能力边界由工具集决定。工具设计得好不好比提示词写得好不好重要十倍。我总结了三条原则。第一工具粒度要匹配任务粒度不能太细也不能太粗。太细的例子是提供“执行SQL”“获取表结构”“获取字段注释”三个独立工具模型要完成一个简单查询得调五六次延迟高、出错点多。太粗的例子是只提供一个“回答问题”的黑盒工具模型没有中间控制权错了也没法纠正。我通常会给到四到六个工具指标查询、明细查询、维度枚举、数据分布探查、口径解释基本能覆盖大部分场景。第二返回结构要稳定且信息充分。工具返回不能是一坨自由文本要有明确的字段数据行、列名、单位、口径说明、查询耗时、是否有数据截断。同时要给模型留一个“提示位”比如“本次查询未加时间过滤结果可能包含历史数据”让模型在生成回答时能带上这个提醒。第三错误信息要写给人看也要写给模型看。数据库报错信息通常是“Unknown column xx in field list”这种模型拿到之后不一定知道怎么改。更好的做法是在工具层做一次错误翻译返回结构化的错误类型和建议动作比如{error_type: column_not_found, hint: 字段 xxx 不存在可用的相似字段有 aaa, bbb, retryable: true}。这个改动看着小实际能把自动重试的成功率提高一大截。{ tool: query_metric, description: 按指标口径查询聚合数据返回已按语义层定义计算好的结果, parameters: { metric_name: {type: string, description: 指标名必须来自指标清单}, dimensions: {type: array, items: {type: string}, description: 分组维度最多3个}, time_range: {type: object, description: 时间范围含 start 和 end格式 YYYY-MM-DD}, filters: {type: array, description: 过滤条件字段必须来自维度清单} }, returns: { rows: 结果数据, metric_definition: 本次使用的口径说明需在回答中体现, truncated: 是否因行数限制被截断, elapsed_ms: 查询耗时 } }把metric_definition作为返回值的一部分是个很有用的设计。模型在组织答案时会自然把口径带出来用户看到“按不含税、已扣退货的口径计算”对数字的信任度会明显不同。3.3 规划与执行为什么企业场景更适合“先规划后执行”Agent 的推理模式大致有两类。一类是边想边做走一步看一步根据每步结果决定下一步另一类是先出完整计划再逐步执行执行中遇到问题再局部调整。通用场景里第一种更灵活但在企业数据场景我更倾向第二种原因是可审计性。业务方问“为什么华东下滑”如果 Agent 的推理路径是随机的每次走的步骤都不一样出了问题你根本没法复盘。而先出计划再执行计划本身可以被记录、被展示、被人工干预这在企业环境里非常重要。具体实现上我会让模型先输出一个结构化的执行计划包含步骤序号、每步目的、依赖的前置步骤、调用的工具。计划生成后先做一次静态校验检查引用的指标是否存在、维度是否合法、步骤依赖是否有环。校验通过再进入执行。执行过程中的局部重规划也要有边界。比如某一步查询返回空结果可以让模型决定是放宽时间范围、换一个维度、还是直接告知用户无数据。但重试次数必须设上限我一般设 3 次超过就降级成“当前无法自动完成建议人工介入”并把已经跑过的步骤和中间结果一并展示出来方便人接手。这个降级路径经常被忽略但它决定了产品能不能用。完全自动化的系统一旦失败就是黑盒失败用户不知道发生了什么带降级路径的系统失败时至少能给出线索体验差距很大。3.4 结果校验让模型自己不相信自己生成式系统最大的风险是“看起来对”。数字整齐、解释流畅、格式漂亮但可能是错的。校验层就是用来对抗这种表面合理性的。我在实际项目里会做四类校验成本从低到高排列。第一类是结构校验检查返回是否为空、行数是否异常、数值是否为空值或负数、时间范围是否符合预期。这类校验纯靠规则成本几乎为零能拦掉相当一部分低级错误。第二类是一致性校验用不同路径算同一个数。比如用户问总销售额可以让 Agent 分别通过指标工具和明细表聚合算一次两个结果在容差范围内才算通过。这个做法会增加一次查询成本但对核心指标非常值得。第三类是量级校验把结果和历史同期、环比数据做对比偏离超过阈值就标记出来让模型在回答里主动说明“本次结果较上期波动较大建议核实”。这不是为了拦截而是为了提示。第四类是溯源校验要求每个结论都能对应到具体的查询和口径。实现方式是在工具返回里带上数据来源标识最终回答里以脚注形式呈现。用户点开能看到“这个数来自哪张表、什么口径、什么时候跑的”。这四类里第一类和第四类必须有第二类和第三类按指标重要程度选择性开启。全部开启会让延迟翻倍不划算。3.5 权限与安全绝不能交给 prompt 的那部分这一点必须单独强调。有些团队的做法是在系统提示词里写“你只能查询该用户有权限的数据”这等于没有权限控制。模型可以被诱导也可能因为理解偏差绕过限制。正确的做法是权限下沉到执行引擎。Agent 调用工具时工具层根据当前用户身份在生成的查询上强制附加行级过滤条件和列级脱敏规则这些规则由后端代码拼装模型完全不参与。模型甚至不需要知道有这回事它只管表达“我要查什么”。具体实现上我通常会在工具层维护一个权限上下文对象包含用户所属组织、可见的数据范围、被屏蔽的敏感字段。查询构造器在拼 SQL 时统一注入这些条件并且用参数化方式避免注入风险。同时所有查询走只读账号设置查询超时和返回行数上限避免一个失控的查询拖垮整个库。还有个容易被忽略的点结果聚合可能泄露明细。比如按小组聚合如果某个组只有一个人聚合结果就等于暴露了个人数据。这种情况需要在工具层做最小分组人数限制低于阈值的结果直接屏蔽或合并。这类规则一定要在代码里硬编码不能指望模型自觉。4. 落地实操跑通一个最小可用闭环4.1 第一步把指标和口径钉死我给一个可以直接抄的指标定义结构。核心是把“业务怎么理解”和“机器怎么执行”分开写前者给人看后者给程序用。metric: name: net_sales_amount display_name: 销售额净额 owner: 数据平台组 # 给业务看的说明 business_desc: 已完成销售确认、扣除退货与折扣后的金额不含税。 与财务报表中主营业务收入口径一致。 # 给机器执行的定义 expression: SUM(order_amount) - SUM(return_amount) base_table: dwd_order_detail grain: order # 时间口径 time_field: pay_time time_rule: 按支付时间归属跨月订单归入支付月 # 强制过滤 mandatory_filters: - order_status IN (paid, shipped, completed) - is_test_order 0 # 可用维度 dimensions: - region # 大区 - province # 省份 - channel_type # 渠道类型 - category_l1 # 一级品类 - brand # 品牌 # 校验规则 validation: min_value: 0 max_daily_amount: 50000000 # 单日上限超过需人工确认 compare_with: [gross_sales_amount] # 与毛销售额做量级对比这个结构有几个刻意设计。mandatory_filters把测试订单和无效状态排除掉避免每个使用者都要记一遍。time_rule明确跨期归属这是最容易扯皮的地方。validation里的上限值不是拍脑袋是从历史数据里取 P99 再上浮 20% 得到的超出就说明可能有问题。写完定义之后一定要做一件事拿它和历史报表对账。找三个月的历史数据用新定义跑一遍和现有报表逐日比对。差异超过 0.5% 就要查清楚原因。这一步不能省我见过太多项目上线后才发现口径和财务不一致返工成本极高。4.2 第二步注册工具附配置示例工具层的核心是把“能做什么”和“怎么安全地做”封装起来。下面是一个指标查询工具的注册配置用配置化的方式描述方便后续扩展。TOOLS [ { name: query_metric, description: 查询已定义指标的聚合结果。适用于同比、环比、分组对比类问题。, when_to_use: 问题涉及明确指标名和维度组合时优先使用, parameters: { metric_name: {type: string, required: True, enum: METRIC_REGISTRY.keys()}, dimensions: {type: array, max_items: 3, items: {type: string, enum: ALL_DIMENSIONS}}, time_range: {type: object, required: True}, filters: {type: array, required: False}, }, handler: handlers.metric_query, timeout_ms: 15000, max_rows: 500, }, { name: explore_data, description: 探查数据分布用于回答有哪些取值数据量大概多少这类前置问题。, when_to_use: 用户提到不熟悉的字段或需要确认数据是否存在时使用, parameters: { table: {type: string, enum: CORE_TABLES}, field: {type: string}, limit: {type: integer, default: 20}, }, handler: handlers.data_explore, timeout_ms: 10000, }, { name: explain_metric, description: 返回指标的口径定义、计算逻辑和注意事项。, when_to_use: 用户询问口径或回答中需要说明数据来源时使用, parameters: {metric_name: {type: string, required: True}}, handler: handlers.metric_explain, timeout_ms: 1000, }, ]注意when_to_use这个字段。它不是标准 JSON Schema 的一部分但对提升工具选择准确率很有帮助。模型在多个工具之间犹豫时一句明确的使用场景描述往往比详细的参数说明更管用。max_rows和timeout_ms是硬约束必须在工具层强制执行不能只写在提示词里。我一般会把超时设得比预期慢查询稍长一点超时后返回明确的错误类型让模型知道是超时而不是无数据。4.3 第三步写 Agent 主循环附代码主循环是整个系统的心脏。下面是一个经过简化的版本去掉了具体的模型调用细节重点看控制流。def run_agent(question, user_context, max_steps8, max_retry3): # 1. 构建上下文 schema_ctx build_context(question, retriever, schema_store) metric_ctx match_metrics(question, METRIC_REGISTRY) messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: render(question, schema_ctx, metric_ctx)}, ] # 2. 先出计划 plan llm_plan(messages) if not validate_plan(plan): return fallback(无法理解该问题请补充指标或时间范围, plan) # 3. 逐步执行 trace [] for step in plan.steps: retry 0 while retry max_retry: try: result call_tool( step.tool, step.params, user_context, # 权限在这里注入 ) result post_check(result, step) # 结构校验 trace.append({step: step, result: result}) break except ToolError as e: retry 1 if not e.retryable or retry max_retry: return fallback(f第{step.idx}步执行失败{e.hint}, trace) # 局部重规划让模型修正参数 step llm_revise(step, e, messages) # 4. 结果整合与一致性校验 answer_data merge_results(trace) if needs_cross_check(plan): answer_data cross_validate(answer_data, user_context) # 5. 生成回答强制带溯源信息 final llm_summarize(messages, answer_data, trace) return attach_citations(final, trace)有几个细节值得单独说。post_check这一步别看简单它承担的职责不少检查返回是否为空、数值是否在合理区间、是否发生截断、时间范围是否匹配问题。任何一项不通过都要么触发重试要么在最终回答里标注。cross_validate只对核心指标开启判断依据可以写在指标定义里比如标一个critical: true。全部开启会让整体延迟增加 40% 以上得不偿失。attach_citations是把 trace 里的信息转成脚注附在回答末尾。这个功能对建立信任的作用远超它增加的开发成本。4.4 第四步构造评测集别靠感觉验收Data Agent 最容易翻车的地方是验收。很多团队的做法是找几个人随便问几十个问题看着差不多就上线了。这种验收几乎没有意义因为问题分布和真实场景差太远而且没人会去问那些真正难的问题。我的做法是分层构造评测集每一层测不同的能力。层级测试目标样本量通过标准意图识别能否判断问题类型100准确率 ≥ 92%指标匹配能否选对指标和口径100准确率 ≥ 90%维度识别能否正确理解分组和过滤80准确率 ≥ 85%单步查询单次工具调用是否正确80成功率 ≥ 90%多步规划复杂问题能否正确拆解50成功率 ≥ 70%结果正确最终数字与人工答案一致60一致率 ≥ 95%降级处理无法回答时是否合理30合理率 ≥ 90%样本来源很重要。我的经验是三个渠道各占三分之一历史工单里真实提过的问题、业务方主动提供的“最难的问题”、以及从指标定义反向构造的边界问题。第三类最容易被忽略但恰恰最能暴露口径问题比如“闰年的二月销售额”“跨年订单归属”这类。评测要能持续跑最好做成回归测试。每次改提示词、换模型、调工具都跑一遍看指标有没有退化。这件事听起来重但比上线后被动救火轻得多。4.5 成本与延迟的现实调优理想状态下我们希望每个问题都走最强的模型、最多的校验、最完整的溯源。现实里要算账。一个中等复杂度的归因问题可能涉及 5 到 8 次模型调用和 3 到 5 次数据库查询。如果每次都走最强模型单次成本不低延迟也会到十几秒用户体验很差。我的调优顺序是这样的。先做模型分级意图识别、参数修正这类简单任务用轻量模型规划和总结用强模型。通常能省掉一半以上的推理成本准确率影响很小。再做缓存相同问题、相同口径、相同时间范围的查询结果缓存一段时间热点问题的命中率往往能到 20% 以上。最后做并行计划里没有依赖关系的步骤并行执行归因类问题的延迟能降三分之一。有个反直觉的经验延迟比成本更影响使用率。用户能接受一次查询花点钱但不能接受等二十秒。所以调优时优先砍延迟比如把非关键校验改成异步、把溯源信息延后加载。这些改动对准确率没影响但体验差别很大。5. 常见问题与排查技巧实录5.1 答非所问八成是语义层没做对最常见的现象是用户问“上个月新客贡献了多少销售额”Agent 返回了总销售额。排查下来问题往往不在模型而在于“新客”这个词没有定义。没有定义模型只能猜猜错了也合理。排查这类问题的顺序应该是先看用户的问题里有哪些业务词再看这些词在语义层里有没有对应定义最后看定义有没有被正确检索到。三步里任何一步断了都会导致答非所问。我的做法是维护一个“未定义词表”。每次出现答非所问如果是定义缺失导致的就记录下来定期清理。这个表在项目初期会很长两三个月后会明显缩短缩短的过程就是语义层逐步完善的过程。还有个技巧对高频业务词做同义词映射。比如“新客”“新增用户”“首购用户”可能指向同一个定义“GMV”“成交额”“交易额”也可能是一回事。把这些映射写进配置能显著减少歧义。5.2 数字幻觉模型永远不该自己算数这是最危险的问题因为它不容易被发现。表现是模型在回答里给出一个数字但这个数字不是工具返回的而是它自己推算出来的。比如工具返回了各渠道销售额模型在总结时写“合计约 1200 万”这个 1200 万可能是它心算的也可能是编的。彻底解决的办法只有一个所有数字必须来自工具返回模型的职责是组织和解释不是计算。实现上我在生成最终回答时会把工具返回的所有数值做一次提取然后校验回答里的每个数字是否都能在提取结果里找到对应。找不到的要么重新生成要么标注为“推算值”。对于确实需要二次计算的场景比如求占比、求增速不要让模型心算而是再调一次工具把计算逻辑放到代码里。多一次调用换来准确率很值。5.3 复杂问题一次性失败拆解粒度的问题“为什么华东下滑”这类问题失败率明显高于简单取数。原因通常是拆解粒度不对。拆得太粗一步查询根本算不出来拆得太细步骤太多中间任何一步出错都会导致整体失败。我摸出来的经验是单个步骤最好只包含一个工具调用和一个判断。比如“为什么下滑”应该拆成确认下滑事实查同比环比、定位到具体维度按渠道、品类、区域分别查、找出贡献最大的负向因子、针对该因子做下钻。四步每步一次查询中间可以插入判断。还有一个细节拆解出来的步骤要能独立失败。某一步查不到数据不应该让整个流程崩掉而应该标记为“该项无数据”继续走其他分支。最后汇总时说明哪些角度查了没结果这本身也是有价值的信息。5.4 问题速查表实际运维中遇到的高频问题整理成一张表出问题时照着查。现象可能原因排查动作解决方向选错表元数据检索召回不准看召回结果是否包含正确表补表注释调召回策略字段不存在schema 剪枝过度看剪枝后是否保留该字段放宽剪枝加相似字段提示数字对不上口径不一致对比指标定义与历史报表修定义做对账结果为空过滤条件过严看生成的时间范围和过滤加空结果处理引导放宽查询超时大表全扫描看是否缺少分区过滤加数据量提示强制时间条件回答冗长上下文塞太多看上下文构成压缩 schema精简历史重复问同一个问题会话上下文丢失看多轮状态管理补短期记忆权限报错权限注入位置不对看查询构造链路统一在工具层注入成本飙升大模型全量调用看调用分布分级路由加缓存回答自我矛盾多步结果未整合看最终汇总逻辑强制以工具返回为准这张表我一般会贴在项目群里新人上手第一周基本都会碰到其中三四个。把排查动作写清楚比反复口头解释效率高得多。最后分享两个我在实际项目里体会比较深的点。一个是关于节奏Data Agent 不适合大而全地推先选一条业务线、二十个高频问题、三张核心表做深跑通了再横向扩。我见过几个团队一上来就想覆盖全公司数据结果语义层做了一半就推不动了因为范围太大口径争议永远收不齐。另一个是关于预期管理一定要在项目早期就跟业务方说清楚这个系统能接住的是“有明确口径的问题”遇到需要判断的开放性问题它会给出线索但不会给结论。把边界讲在前面比上线后被质疑“怎么这个也不会”要好处理得多。