资讯动态

工具向LLM报告数据的格式选型:JSON、Markdown还是CSV?

发布时间:2026/8/28 23:50:25 来源:尧图企业网站定制
如果你正在写一个 AI Agent、RAG 应用或工具类服务大概率会遇到一个很具体的问题工具已经把数据拿回来了怎么把这些数据塞给 LLM它才能看得懂、答得准、而且不烧太多 tokenHacker News 上有一个经典提问“What is a good format for a tool to report data to a LLM?” 翻译过来就是工具向 LLM 报告数据时到底该用什么格式这个问题不是简单的“JSON 还是 Markdown”二选一。它牵扯到上下文窗口利用率、模型对结构化信息的理解能力、多工具结果聚合、批量任务稳定性、以及后续接口维护成本。本文就围绕这个问题展开先给结论再给对比最后给一套可以直接用的格式化工具代码和测试流程。核心结论没有万能格式但有决策框架。数据量大、机器消费优先用 JSON面向阅读和生成报告优先用 Markdown纯表格批量数据用 CSV/TSV简单状态上报用纯文本 key-value。真正要花心思的是如何把原始数据裁剪成“模型友好”的结构。1. 核心能力速览LLM 数据报告格式的关键维度在选格式之前先建立一个评估框架。根据实际 LLM 应用开发经验一份“模型友好”的工具报告应该满足以下五个维度维度说明对 LLM 的影响结构化程度数据是否分层、是否有明确边界结构化越高模型定位信息越容易Token 开销格式符号占用的 token 比例格式符号越多有效信息密度越低可读性人类能否快速检查影响调试效率和错误定位机器可解析性能否被脚本、下游工具直接消费影响接口对接和自动化容错性数据缺失、嵌套过深时是否抗干扰影响长上下文稳定性围绕这五个维度实际部署时还要关注三个额外项上下文窗口是否够用、批量任务数据是否分页、以及数据中是否包含敏感信息需要脱敏。2. 主流格式横向对比JSON、Markdown、纯文本、CSV、XML下面把最常用的五种格式放在同一张表里对比。这里的 token 开销是相对概念不是绝对数字实际以你选用的模型分词器为准。格式结构化程度Token 开销人类可读性机器可解析性典型场景JSON高中高一般高API 结果、Function Calling、MCP 工具输出Markdown中高中高一般报告生成、文档摘要、表格数据纯文本 key-value中低高低系统状态、日志摘要、简单设备上报CSV / TSV中低一般高批量表格数据、数据库导出、批量任务结果XML高高一般高复杂文档、需要强分隔符的场景2.1 JSON接口对接首选但要注意层级深度JSON 是工具和 LLM 之间最常用的格式尤其是配合 Function Calling 和 MCP 时。绝大多数模型在预训练阶段见过大量 JSON对 {key: value} 这种结构有很好的理解能力。但 JSON 有两个明显问题第一个问题是 token 开销。键名、引号、花括号、冒号、逗号都会占用 token。一个 1000 行的小型 JSON可能 30% 左右的 token 花在纯格式符号上。数据量越大这个损耗越明显。第二个问题是嵌套层级。如果工具返回的对象嵌套超过三四层模型在长上下文中定位信息的能力会下降。常见的表现是模型明明看到了某个字段但回答时引用了错误的值。给一个相对稳妥的 JSON 示例{ product_id: SKU-88421, status: out_of_stock, warehouse: [ {city: 上海, available: 0, eta_days: 3}, {city: 广州, available: 12, eta_days: 1} ], last_updated: 2025-01-15T08:30:0008:00 }这个结构层级不超过三层字段名简短时间用了 ISO 8601 格式模型理解起来几乎没有障碍。2.2 Markdown适合生成报告和给模型“阅读”Markdown 的优势在于模型对它的理解非常好。表格、标题、列表这些 Markdown 元素天然带有语义模型可以快速区分“这是标题”“这是表格”“这是强调”。如果你的场景是让 LLM 基于工具数据生成摘要、日报、分析文档Markdown 比 JSON 更合适。原因很简单目标输出是 Markdown 时输入也用 Markdown格式转换损耗最小。## 库存报告 | 商品 | 状态 | 可用库存 | 预计补货 | | --- | --- | --- | --- | | SKU-88421 | 缺货 | 0 | 3 天 | | SKU-91023 | 正常 | 12 | 1 天 |这里要提醒一点Markdown 表格的大数字列建议用千分位分隔比如 12,000避免模型把 12000 和 12,000 混淆。2.3 纯文本 key-value省 token但别让语义靠猜纯文本是最省 token 的格式也是 LLM 最早被用于处理日志时常见的输入格式。它的缺点是机器解析性弱如果键名设计得不够清晰模型很容易产生歧义。适合纯文本 key-value 的场景是传感器数据、系统状态、进程心跳、简单的任务执行结果。device_idgw-02 statusonline temperature36.5 battery82% last_sync2025-01-15T08:30:0008:00这种格式的 token 开销非常低。如果单条记录很短甚至可以把几十条记录拼在一个上下文里。要注意的是如果数据里包含数组、嵌套结构纯文本就不够用了。不要硬用文本表达树形结构那样反而增加模型理解难度。2.4 CSV / TSV批量数据的压缩方案当你需要向 LLM 报告一批相同结构的数据时CSV 或 TSV 是最划算的方案。比如一次查询返回 200 条订单记录用 JSON 会非常长用 CSV 可以压缩很多。order_id,customer_id,amount,status 20250115001,C1001,299.00,paid 20250115002,C1002,59.90,pendingCSV 的注意事项字段里如果包含逗号、换行、中文标点必须正确转义。更稳妥的选择是 TSV用制表符分隔比逗号对转义的要求低一些。2.5 XML需要强分隔符时再考虑XML 的 token 开销最大日常 LLM 应用中一般不推荐。但在一些 agent 场景下如果模型的指令遵循能力不够稳定XML 标签可以提供非常明确的分隔边界帮助模型区分“工具输出开始”和“工具输出结束”。tool_result field namestatusonline/field field namelatency_ms84/field /tool_result如果工具输出的数据本身来自 XML 格式的旧系统也可以先转成 XML 报告 LLM减少格式转换的中间步骤。但如果是新建项目JSON 通常更合理。3. 场景化格式选型不同 LLM 应用该选什么格式格式选择不能脱离场景。同样是“报告数据给 LLM”API 调用、RAG 检索、日志分析、批量任务汇总对格式的需求完全不同。3.1 Function Calling / MCP 工具结果用 JSONFunction Calling 是模型直接驱动工具执行工具结果最终要回到模型上下文中。这个场景几乎不用犹豫直接用 JSON。原因有三个第一机器可解析性最强第二与 MCP 的 JSON-RPC 协议天然兼容第三模型对 Function Call 返回的 JSON 结构经过了大量指令微调理解准确率最高。格式参考{ tool: fetch_weather, status: success, data: { city: 杭州, temperature_c: 18, humidity_pct: 65 } }注意不要为了展示给模型看再加一层冗长的包装比如重复的提示话术。Function Calling 的结果直接给数据即可解释性文字放在 system prompt 里。3.2 数据库查询结果CSV 比 JSON 更实用从数据库查出来的结果是典型的二维表结构。直接用 JSON 数组会把列名重复很多次token 浪费严重。更适合的方式是转成 CSV 或 TSV表头保留列名数据行紧凑排列。region,revenue,orders 华东,126500.00,320 华南,98200.00,275 华北,74300.00,198如果行数特别多比如超过 50 行建议先做聚合再决定是否截断。LLM 对超长表格的尾部数据感知力较弱中间部分也有被忽略的可能。3.3 日志与可观测性数据纯文本 key-value 优先日志分析场景里单条日志本身就是 key-value 或字符串。直接拼接日志原文是最省事的做法但要注意日志级别过滤。把所有 debug 日志都丢给模型既浪费 token 又稀释重点。推荐做法先按 error、warn、info 级别过滤再把关键字段抽成 key-value 文本。levelerror servicepayment-api error_codeTIMEOUT latency_ms3200 request_idreq-88423.4 RAG 检索结果带来源标记的 Markdown 列表RAG 场景下工具向 LLM 报告的是检索到的文档片段。这里有两个要求一是保留来源信息否则模型无法给出引用二是保留原文上下文不要截断到语义断裂。Markdown 列表是适合的格式之一[来源 1] 项目 2025 年规划文档第 3 节 平台将支持批量任务队列和回调通知机制 [来源 2] 技术方案评审记录第 7 节 批量任务默认并发数为 4可通过配置调整这种方式把内容与来源绑定在一起模型生成回答时可以自然带出引用。3.5 Agent 多工具结果聚合统一 JSON envelopeAgent 场景里一次任务可能会调用多个工具每个工具都有各自的返回结果。如果直接拼接模型很难区分哪些数据属于哪个工具。更稳定的做法是为所有工具统一包装一个 JSON envelope包含工具名、调用序号、状态和数据{ tool_calls: [ { seq: 1, tool: search_products, status: success, data: [...] }, { seq: 2, tool: get_stock, status: success, data: [...] } ] }seq 字段非常重要。模型需要知道工具调用的先后顺序尤其是当后一个工具的输入依赖前一个工具的输出时。3.6 批量任务结果汇总先统计再明细最后样本批量任务里一个任务可能处理几百条数据。如果全部丢给 LLM上下文会迅速膨胀。规范的汇总顺序是总览统计成功数、失败数、平均耗时、错误类型分布。失败明细列出失败的记录 ID 和原因。成功样本抽样几条作为格式参考。batch_idB20250115001 total120 success115 failed5 avg_latency_ms1200这种方式既覆盖全局又保留了模型做归因分析的样本。4. 数据预处理与 Schema 设计格式之外的硬功夫确定了格式之后真正决定 LLM 输出质量的是数据预处理。下面列出六条高频规则都是实际开发中踩过坑后总结出来的。4.1 字段名要语义化不要用缩写模型对缩写词的理解能力参差不齐。字段名尽量用完整单词比如 user_available_balance 比 bal 好payment_status 比 ps 好。如果必须用缩写第一次出现时把全称写进 system prompt。4.2 统一单位与量纲温度、金额、距离、时间这些字段必须明确单位。模型看到数字 35 时不知道是摄氏度还是华氏度。格式上建议字段名后面直接带单位比如 temperature_c、amount_usd、distance_km。4.3 时间统一为 ISO 8601时间格式不加限制是 LLM 推理出错的高发原因。2025/01/15、01-15-2025、Jan 15 2025 这些格式混在一起模型容易混淆。全链路统一使用 ISO 8601即 YYYY-MM-DDTHH:MM:SS08:00是最稳妥的约定。4.4 空值不要用 null、none、None 混用同一个字段有时是 null有时是 none有时是空字符串这对模型是一种干扰。建议全链路统一用 nullJSON 场景或留空CSV/文本场景并在报告说明中补充一句“null 表示数据缺失”。4.5 数组长度要控制数组越长模型越容易“看丢”中间内容。保守的做法是数组元素不超过 30 条。超过 30 条时先做分页摘要或者让 LLM 分批处理。4.6 长文本要给出摘要锚点如果某个字段是长文本不要整段塞进 JSON 字段里。模型对长文本中间部分感知较弱。更合理的做法是{ content_summary: 合同第三页关于违约责任的部分共 8 条, content_excerpt: 第 3.2 条乙方逾期交货超过 10 个自然日甲方有权解除合同。, content_offset: 3 }这样既保留了关键信息又避免了长文本消耗过多 token。5. 代码示例统一格式化工具下面给出一套 Python 格式化工具用于把 Pandas DataFrame 或字典列表转换成不同格式的 LLM 报告文本。实际部署时可以直接嵌入到自己的数据处理链路中。import json import csv from io import StringIO from typing import List, Dict, Any class LLMReportFormatter: 把工具数据转成 LLM 友好的报告格式 staticmethod def to_json(data: List[Dict[str, Any]], ensure_ascii: bool False, indent: int 2) - str: JSON 格式用于 Function Calling 和机器对接 return json.dumps( data, ensure_asciiensure_ascii, indentindent, defaultstr ) staticmethod def to_markdown_table(data: List[Dict[str, Any]]) - str: Markdown 表格用于报告生成和文档摘要 if not data: return (empty) headers list(data[0].keys()) lines [ | | .join(headers) |, | | .join([---] * len(headers)) | ] for row in data: values [ str(row.get(h, )).replace(|, \\|) for h in headers ] lines.append(| | .join(values) |) return \n.join(lines) staticmethod def to_csv(data: List[Dict[str, Any]], delimiter: str \t) - str: CSV/TSV 格式用于批量数据 if not data: return output StringIO() if delimiter \t: writer csv.DictWriter( output, fieldnameslist(data[0].keys()), delimiter\t, lineterminator\n ) else: writer csv.DictWriter( output, fieldnameslist(data[0].keys()), lineterminator\n ) writer.writeheader() writer.writerows(data) return output.getvalue() staticmethod def to_key_value(data: Dict[str, Any]) - str: 纯文本 key-value 格式用于简单状态上报 lines [] for key, value in data.items(): lines.append(f{key}{value}) return \n.join(lines)使用示例report_data [ {order_id: 20250115001, amount: 299.00, status: paid}, {order_id: 20250115002, amount: 59.90, status: pending}, ] formatter LLMReportFormatter() json_report formatter.to_json(report_data) print(json_report) md_report formatter.to_markdown_table(report_data) print(md_report) csv_report formatter.to_csv(report_data, delimiter\t) print(csv_report)这个工具的核心价值是同一份数据根据需要切换输出格式不污染上游数据结构。批量任务中可以在每条任务执行完毕后调用这个工具生成中间报告再决定是否交给 LLM。6. 接口 API 与上下文管理报告数据如何进入 LLM格式选好之后下一个问题是数据如何进入 LLM 请求。这里涉及单次请求、流式交互、缓存和 MCP 接入。6.1 单次请求把报告放在 user message 还是 system message工具报告数据本质上属于“外部上下文”不应该混入 system prompt。system prompt 放的是固定指令和格式要求工具报告应该放在 user message 中作为本次任务的实际输入。一个典型的请求结构{ model: your-llm-model, messages: [ { role: system, content: 你是库存管理助手。根据工具报告回答用户问题。 }, { role: user, content: 工具报告\n json_report }, { role: user, content: 请分析哪些商品需要补货并给出建议顺序。 } ], temperature: 0.2 }注意工具报告和用户问题最好分成两条 user message不要拼接在一条里。这样模型能清晰区分哪些是数据、哪些是任务指令。6.2 流式输出长报告要分段进入如果工具报告特别长一次塞进上下文可能导致模型在输出中段开始遗漏信息。更稳妥的做法是分两轮第一轮先给摘要让模型确认理解了整体结构。 第二轮再给明细针对具体问题推理。这也是 RAG 场景里“先检索再阅读最后回答”的常规做法。6.3 MCP 工具输出协议如果你的工具通过 MCPModel Context Protocol接入 LLM工具结果默认就是 JSON-RPC 格式。这里要注意MCP 工具返回结果时建议用一个固定 schema把所有工具的输出统一成同样的外层结构避免每个工具一套返回风格。MCP 工具返回结果外层结构示例{ content: [ { type: text, text: {\status\: \success\, \count\: 42} } ], isError: false }如果 isError 为 true模型会进入错误处理分支。因此工具内部所有业务异常都要显式捕获不要直接抛给模型。6.4 缓存与重放同一份工具报告如果被多个 LLM 请求引用可以考虑缓存结构化结果、减少重复格式化。批量任务中每一条记录格式化成一次文本后存到本地后续请求直接复用能显著减少 CPU 和 token 计数开销。7. 性能与成本观察怎么判断格式选得对不对格式选型是否合理不能靠感觉。部署后要建立三个观察指标。第一个是 token 消耗。同一份数据用不同格式计算 token 数。可以采用 tiktokenOpenAI 生态或对应模型的分词器来统计。如果 JSON 比 Markdown 多消耗的 token 超过 40%且当前场景不是机器对接就可以考虑换 Markdown。# 以 OpenAI tiktoken 为例实际请按模型选择 tokenizer import tiktoken encoder tiktoken.get_encoding(cl100k_base) def count_tokens(text: str) - int: return len(encoder.encode(text)) json_tokens count_tokens(json_report) csv_tokens count_tokens(csv_report) print(fJSON tokens: {json_tokens}) print(fCSV tokens: {csv_tokens})注意不同模型的分词器不同token 数字只代表当前测试结论。中文环境下字符不代表 token必须实际编码后统计。第二个是模型回答准确率。可以准备一组固定任务分别用 JSON 和 Markdown 报告同一份数据统计回答正确率。这个测试需要在 prompt 完全一致的前提下进行否则无法归因。第三个是出错的成本。格式导致的错误通常是“模型引用错误字段”“模型忽略某一行”“模型把数字拼错”。在批量任务里这种错误率需要控制在可接受范围内否则就要换格式或调整 prompt。8. 常见问题与排查方法最后给出一份 LLM 数据报告格式在实际调用中容易踩的坑以及对应排查方式。问题现象可能原因排查方式解决方案模型回答引用了错误的字段值JSON 嵌套层级过深或字段名歧义检查报告是否超过 4 层嵌套扁平化结构字段名加前缀区分模型忽略了表格中间的行Markdown 表格数据量过大观察数字、总行数拆分成多次请求或先聚合输出中数字拼错CSV 中大数字未加分位符检查原始数据格式使用千分位分隔或统一为字符串中文乱码或标点异常编码不一致或转义错误检查 JSON ensure_ascii 设置统一使用 UTF-8避免重复转义空值被模型当成 0null 与 0 混用查看报告里空值字段统一 null 表示缺失并在 prompt 中说明时间被模型理解错多种时间格式混用检查报告中的时间字段统一 ISO 8601批量任务中部分输出为空上下文长度超限被截断检查请求的 tokens 数增加分页或摘要层模型重复引用同一工具结果Agent 多工具结果未加序号查看请求中的 tool_calls给每个工具结果加 seq 字段API 调用超时报告数据量过大观察接口耗时压缩格式、减小 payload、流式输出工具返回 isError 但模型继续正常回答MCP 返回结果没有错误状态捕获工具异常并显式设置 isError在工具层做兜底不让异常直接进入模型9. 最佳实践与安全边界数据报告给 LLM 并不是“塞得越多越好”。下面几条是长期维护 LLM 应用时的工程建议。9.1 最小上下文原则除非任务必须否则不要把所有工具结果都传给模型。先问自己一个问题LLM 完成这个任务真正需要哪些字段把无关字段在工具层过滤掉比模型自己“忽略”更可靠。9.2 敏感数据脱敏工具报告里如果有用户手机号、身份证、地址、密钥必须在上报前脱敏。LLM 应用的数据链路可能经过第三方 API也可能被模型训练日志记录。不要寄希望于 prompt 里的“不要泄露”要直接在数据层抹掉。9.3 工具权限最小化LLM 应用经常出现“工具权限过大”的问题。一个只读查询工具被模型误用于执行写操作或者一个删除接口没有二次确认都是严重的工程事故。工具暴露给 LLM 前必须限定操作范围和频率写操作加确认机制。9.4 版权与隐私合规如果工具报告的数据来自用户上传的文档、图片、音视频必须确认有合法授权。涉及人脸、声音、肖像的内容在上报给 LLM 前要做额外权限校验。商用场景下还要检查训练数据合规条款。9.5 批量任务要加日志和重试批量任务中每一轮“数据 - 格式化 - LLM 推理”都可能有偶发失败。建议为每批数据记录原始数据 hash、格式版本、LLM 请求摘要、返回结果状态。失败任务重试时优先复用已格式化的中间报告而不是重新读取原始数据。10. 总结与下一步工具向 LLM 报告数据本质上是一个“上下文工程”问题。格式选型只是入口真正影响效果的是数据裁剪能力、字段命名一致性和上下文长度的预算管理。如果只记一条经验我会选这个先确定 LLM 后续要做什么再反推格式。机器对接场景定 JSON报告生成场景定 Markdown批量数据定 CSV/TSV简单状态定纯文本。不要在一开始就套一个“万能格式”那是把问题推迟到了后面。下一步建议做三件事用文中的 formatter 工具把你现有的工具输出格式化成不同格式统计 token 差距。固定 20 条测试数据用不同格式各跑一轮 LLM 推理对比回答准确率。给批量任务加上“统计 明细 样本”三层报告结构观察上下文占用是否下降。格式问题解决了后面接 MCP、接 RAG、接 Function Calling 都会顺畅很多。建议收藏备用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价