ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RAG+大语言模型解析A股年报:绿色全要素生产率统计建模与实证全流程

RAG+大语言模型解析A股年报:绿色全要素生产率统计建模与实证全流程 简介基于RAG技术与大语言模型的A股上市公司年报分析项目核心目标是评估人工智能对企业绿色全要素生产率的影响同时纳入企业融资约束异质性分析并针对模型设定与数据选择进行了稳健性检验。资源包共20个文件压缩后仅2.29MB包含Python脚本、Jupyter notebook、配置文件、说明文档及附赠材料脚本覆盖年报爬取、数据预处理、GPT评分与模型构建notebook展示数据处理、图表绘制与统计分析细节json与txt文件保存问题集及配置说明有助于快速部署调试。当前已有66人学习下载适合经济学、金融学及环境经济领域的研究者、量化分析爱好者。使用者可由此掌握从年报采集、RAG检索增强生成到统计建模的完整技术链路理解大语言模型在文本评分和变量构造中的实际应用并能基于代码灵活调整研究设定、复现结论或扩展到其他样本是一份兼顾方法示范与实操性的研究工具包。1. 用 RAG 读年报做统计建模这个项目到底解决什么问题做实证研究的人拿到这个标题第一反应多半是「用大语言模型读年报再拿结果跑回归」。这个判断大方向对但低估了真正的工作量。A股年报一年五千多份每份几十页到几百页人工读一遍再手工打分一个研究周期耗掉两三个月不夸张。把 RAG 技术和大语言模型组合起来本质上是把「读年报、抽取指标、形成面板数据」这一段从体力活变成可重复的流水线再把输出喂给统计模型做因果推断和稳健性检验。这套方案适合三类人做绿色金融、ESG 或企业创新方向的研究生和高校老师需要处理非结构化文本但不想逐份人工标注的量化分析师以及想在企业融资约束、绿色全要素生产率这类主题里找增量贡献的实证研究者。它的价值不在「用了大模型」这个噱头而在把「文本→结构化变量→回归结果→稳健性检验」整条链路打通。下面按我实际搭这套流程的经验拆成五个部分原理和整体架构、年报解析与 RAG 构建、统计建模与变量构造、稳健性检验与异质性分析、避坑清单与进阶验证。2. 为什么是 RAG 而不是直接让大模型读全文架构选型与落地框架2.1 直接塞全文给大模型为什么不行很多人第一次尝试时都走过这条路把一份年报 PDF 转成文本整段丢给大模型让它输出「绿色转型投入、环保补助、碳排放数据」。表面看可行实际跑一轮就翻车。原因有三个第一是上下文窗口的物理限制。一份 A 股年报动辄十万字以上主流开源模型的上下文窗口即便支持长文本塞进去之后检索和注意力计算都明显变慢成本按 token 计费时更是不划算。第二是无关信息干扰。年报里有大量董事会报告、公司治理、会计政策、审计意见等模板化内容真正和绿色全要素生产率相关的段落可能只占百分之几。全量输入会让模型被无关信息带偏抽取结果不稳定。第三是统计建模需要的是「可复现、可追溯」的结构化数据如果每次让模型读全文再自由发挥同一份年报跑两次可能给出不同数值这在实证研究里是致命伤——审稿人要求你提供数据来源和复现路径时根本交代不了。RAG 的核心思路是先检索、后生成。把年报切块、向量化、建索引查询时先召回最相关的片段再把片段拼进提示词让大模型作答。这样既控制了输入长度又让模型的回答有原文依据。更重要的是召回出来的片段可以保留「出处」方便事后核对和人工抽检。2.2 整体技术栈怎么选从轻量级到完整链路搭建这条流水线没有唯一标准答案取决于你手头的算力和预算。我一般把方案分成三档轻量级方案面向个人研究者用开源嵌入模型做向量化本地向量库存索引大模型调云端 API。开发语言选 Python框架用 LangChain 或 LlamaIndex 都行。成本低效果对大段中文年报来说已经够用。进阶方案适合实验室或小团队嵌入模型、向量库、大模型全部本地化用 FastAPI 包一层服务支持多人并发解析年报。完整方案面向需要批量处理数千份年报的场景引入任务队列、缓存层和增量索引解析失败的任务自动重试并记录日志。选型时有一条重要经验嵌入模型不要贪大。中文年报里大量术语是「环保投入」「排污费」「绿色专利」「碳排放权」这类固定搭配通用中文嵌入模型足够捕获语义相近的片段。大模型反而要选指令遵循能力强的——抽取任务依赖模型严格按输出格式返回指令遵循差的模型会给你夹带解释文字。2.3 流水线的五个环节解析、切块、索引、召回、抽取整条 RAG 流水线按顺序拆成五个环节每个环节都有必须注意的细节。文档解析环节把 PDF 转成文本。这一步的坑最多后面专章详述。切块环节决定召回质量。年报不是普通文章按固定字符数硬切会切断语义把「环保投入」和「同比增长」切成两个不相干的块。我常用的策略是优先按标题层级结构切找不到清晰标题时再按段落切段落过长时用滑动窗口重叠切。索引环节把切好的块做向量化写入向量库同时存原始文本和来源页码。召回环节根据查询语句检索最相关的块一般取 top-kk 设在 4 到 8 之间。抽取环节把召回的块拼进提示词模板让大模型输出结构化字段。提示词模板的设计直接决定抽取质量。一个能稳定工作的模板必须包含角色设定、任务描述、字段定义、输出格式要求、以及「如果原文没有提及输出 N/A」。不要允许模型自由发挥输出格式用 JSON 并给出字段名枚举值程序化解析时才不会两头踩坑。3. 把 A 股年报变成可查询的知识库解析、切块与 RAG 索引构建3.1 PDF 年报解析从下载到可处理文本A 股年报通常从巨潮资讯网下载格式是 PDF。第一步是把 PDF 转成文本这里推荐三套工具按场景选用。PDFplumber 适合版面规整、以文本为主的年报能按页面提取文字和表格保留相对位置信息。PyMuPDFfitz速度快适合批量处理但复杂版面可能丢内容。OCR 方案只在扫描版年报时用PaddleOCR 对中文支持较好但速度慢、耗资源。A 股年报绝大多数是文本型 PDF少数早期年报是扫描件建议第一次批量处理前先随机抽查十份确认没有扫描版混入。一个常见的坑是 PDF 里存在「文本抽取乱序」问题。年报是双栏排版时PDFplumber 按坐标输出的文字可能左右两栏穿插读取。解决方式是先按坐标排序再拼接文本。下面的代码演示了用 PDFplumber 提取并按 y 坐标排序文本的基本流程import pdfplumber def extract_text_by_page(pdf_path): pages_text [] with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: # 提取单词及其坐标 words page.extract_words( use_text_flowFalse, keep_blank_charsFalse, extra_attrs[size] ) # 按行聚合y 坐标相近的单词归为同一行 lines {} for w in words: key round(w[top], 0) lines.setdefault(key, []).append(w) # 按 y 坐标排序同一行内按 x 坐标排序 sorted_keys sorted(lines.keys()) page_lines [] for key in sorted_keys: line_words sorted(lines[key], keylambda w: w[x0]) page_lines.append( .join(w[text] for w in line_words)) pages_text.append(\n.join(page_lines)) return pages_text这段代码先按 top 坐标粗略分桶把同一水平线上的单词归到一行再对每行按 x 坐标从左到右排序。对双栏年报来说这个策略能显著改善乱序问题。参数方面round(w[top], 0) 的精度可以根据版面微调遇到行距较密的年报改成 2 或 3 更稳。要注意的是这种粗暴分桶在表格区域可能出错解决方式是后续根据表格特征单独处理或者接受一定的表格噪声——因为后续 RAG 检索和字段抽取主要依赖叙述性文本表格噪声影响可控。3.2 切块策略先按标题层级再考虑字符数年报有天然结构第三节「公司业务概要」、第四节「经营情况讨论与分析」、第五节「重要事项」等。利用这种结构切块比纯字符数切块质量高一个档次。先用正则或关键词定位一级标题再在标题范围内切分内容。切块时我会遵循三条规则块大小控制在 500 到 1000 字之间太大召回后拼进提示词的 token 开销高太小语义不完整相邻块之间保留 50 到 100 字重叠防止关键信息正好落在切分边界标题单独作为 metadata 保存便于召回后追溯来源章节。下面是一个按标题切块的示例用正则快速定位年报常见的章节标题import re def split_by_headings(text, min_chunk500, max_chunk1000, overlap80): # 匹配第X节或第X章形式的标题 heading_pattern re.compile( r(第[一二三四五六七八九十][节章节])[ ]*[^\n]{2,30}, re.MULTILINE ) matches list(heading_pattern.finditer(text)) chunks [] for i, m in enumerate(matches): start m.start() end matches[i 1].start() if i 1 len(matches) else len(text) section_text text[start:end].strip() heading m.group(0).replace(\n, )[:50] # 如果段落超长按字符窗口再切 if len(section_text) max_chunk: chunks.append({text: section_text, heading: heading}) else: # 滑动窗口切分并保留重叠 step max_chunk - overlap for j in range(0, len(section_text), step): piece section_text[j:j max_chunk] if len(piece) min_chunk: # 最后一段过短则并入前一段 chunks[-1][text] \n piece break chunks.append({text: piece, heading: heading}) return chunks这套切分逻辑里min_chunk 和 max_chunk 是核心参数。年报叙述性段落往往信息密度低切太小召回回来的片段讲不清前因后果切太大又让提示词过长。我实际跑下来600 到 800 字效果较稳。overlap 的作用是防止「环保投入比上年增长」这类关键句被一刀切断。另外 heading 字段非常重要——后续检索时可以用它做过滤条件比如只查「经营情况讨论与分析」这一节的片段召回精度会明显提升。3.3 向量化与索引构建嵌入模型和向量库的选择切好的块需要转成向量。嵌入模型的选择上中文场景下可以优先考虑 BGE 系列的中文模型它对中文长文本的语义匹配表现稳定预算充足且对效果有更高要求时再考虑商用的中文 embedding API。向量库方面轻量场景选 Chroma 或 FAISS 就够用需要多人协作、数据量上万份年报时再上 Milvus。构建索引的流程包括对每个块调用嵌入模型生成向量把向量、原文、标题、页码写入向量库建立 metadata 索引方便按年份、股票代码过滤。下面用 Chroma 演示一个最小可用的建库流程import chromadb from chromadb.utils import embedding_functions # 使用本地嵌入模型避免每次调用云端API embed_fn embedding_functions.SentenceTransformerEmbeddingFunction( model_nameBAAI/bge-base-zh-v1.5 ) client chromadb.PersistentClient(path./annual_report_db) collection client.get_or_create_collection( namea_share_reports, embedding_functionembed_fn, metadata{hnsw:space: cosine} ) # 批量写入切块 for idx, chunk in enumerate(chunks): collection.add( ids[f{stock_code}_{year}_{idx}], documents[chunk[text]], metadatas[{ stock_code: stock_code, year: year, heading: chunk[heading] }] )cosine 距离适合文本语义检索这是默认选择。id 的编码方式决定了后续能不能按股票和年份做增量更新——重复跑同一年份数据时用相同 id 写入会覆盖旧数据避免重复。这里有个细节嵌入模型固定之后不要频繁更换否则整个向量库的语义空间变了之前建的索引全部失效。如果要换模型宁可重建索引也别混着用。3.4 召回策略从 top-k 到带过滤条件的精确检索索引建好之后召回模块决定了大模型能看到哪些证据。最简单的召回是纯向量相似度取 top-k但对年报场景来说加 metadata 过滤的效果立竿见影。举例来说查询「企业当年的环保投入金额」时如果不过滤召回结果可能混入「环保投入计划」「环保投入占营业收入比例」等高度相似但语义不同的片段。加上 heading 过滤条件只从「经营情况讨论与分析」「重要事项」两个章节里召回噪声明显减少。def retrieve(query, k6, yearNone, stock_codeNone, heading_filterNone): where {} if year is not None: where[year] year if stock_code is not None: where[stock_code] stock_code if heading_filter is not None: where[heading] {$in: heading_filter} results collection.query( query_texts[query], n_resultsk, wherewhere if where else None ) return resultsk 值不是越大越好。k 太小可能漏掉关键证据k 太大把不相关的内容塞进上下文模型反而被干扰。我通常先取 6观察抽取结果如果模型频繁输出「未在原文中找到依据」再把 k 提到 8 或 10。另一种常见策略是同时跑两路召回一路纯向量检索一路按关键词过滤比如「环保」「绿色」「排放」两路结果合并去重后送入大模型。这种混合召回在年报抽取任务里表现优于单路检索。4. 从文本到变量用大模型抽取指标并构造绿色全要素生产率4.1 抽取字段清单先定研究设计再写提示词在调大模型之前先想清楚统计建模需要哪些变量。标题里涉及的核心是「人工智能对绿色全要素生产率的影响」那么至少需要四类字段绿色全要素生产率测算类期望产出营业收入、增加值、非期望产出碳排放量、污染物排放量、投入固定资产、员工人数、能源消耗。中介机制类企业融资约束SA 指数、KZ 指数相关字段、绿色技术创新环保专利数量。人工智能应用程度类年报中是否提及人工智能、数字化、智能化相关表述及具体应用场景。控制变量类企业规模、资产负债率、盈利能力、成立年限、产权性质等。4.2 用 RAG 抽取指标提示词模板与输出解析抽取环节的提示词模板是整条流水线里最值得反复调的部分。设计原则是给模型限定证据范围、限定输出字段、限定输出格式、要求逐项标注来源。下面给一个可直接改造的模板prompt_template 你是上市公司年报分析助手。请基于提供的年报片段回答以下问题。 年报片段 {document} 请抽取以下字段 1. 环保投入金额单位万元如未提及输出N/A 2. 碳排放量单位吨如未提及输出N/A 3. 绿色专利数量如未提及输出N/A 4. 是否提及人工智能技术应用是/否 5. 人工智能应用场景描述如未提及输出N/A 约束 - 严格基于年报片段回答不得自行推理补全 - 字段无法从片段中获得时输出N/A - 输出JSON格式格式如下 {环保投入金额: ..., 碳排放量: ..., 绿色专利数量: ..., 是否提及人工智能技术应用: ..., 人工智能应用场景描述: ...} 这段模板的关键在约束部分。第一句「严格基于年报片段回答」防止模型把常识当事实写进结果第二句「输出 N/A」保证缺失值能被统一处理第三句强制 JSON 格式让程序能稳定解析。缺失值处理对统计建模极为重要——如果模型自由发挥填充了不存在的数值面板数据里会混入系统性测量误差直接影响回归估计的一致性。输出解析也有讲究。大模型偶尔会输出不规范 JSON比如字段名多了空格、字符串里带了引号。解析时不要直接 json.loads先做一轮清洗去掉首尾的代码块标记、修正单双引号混用、提取第一个完整的 JSON 对象。解析失败的样本记录到日志里批量跑完后统一人工处理不要试图用更复杂的正则硬解。4.3 人工抽检与一致性校验统计建模的前提大模型抽取的结果不能直接进回归。我习惯每批跑完后按 10% 比例人工抽检核对模型输出的字段和原文片段是否一致。更重要的是做一致性校验同一份年报用不同 random seed 跑两次如果结果不一致说明提示词或温度参数有问题需要先修稳定再批量。温度参数在抽取任务里设为 0 或接近 0。温度控制的是输出随机性抽样类指标如「是否提及人工智能」用低温能显著提高可复现性。有研究者担心低温会不会影响模型理解能力实际测试下来对这类有明确原文答案的字段抽取温度和效果没有显著关系稳定压倒一切。4.4 构造绿色全要素生产率从抽取结果到模型输入字段抽取完后进入统计建模前的数据构造环节。绿色全要素生产率的主流测度方法有两种SBM 方向距离函数和 Malmquist 指数。两种方法都能处理非期望产出区别在于前者测度静态效率后者测度动态变化。面板数据齐全的情况下我更推荐用 SBM 计算静态效率再补 Malmquist 算变动趋势两者配合可以互相验证。数据构造阶段有一个细节容易被忽略投入产出变量的价格调整。跨年份的面板数据不做价格平减测出来的生产率变化可能只是价格波动。固定资产净值要用固定资产投资价格指数调整营业收入用 GDP 平减指数或行业价格指数调整。这一步不做后面的回归结果经不起审稿人推敲。把大模型抽取的文本指标和财务数据库的结构化指标合并时按股票代码和年份做 key 连接。年报文本数据是期末值财务数据也取对应年报期末口径合并前先处理重复记录——有些公司当年发布过更正年报PDF 源文件可能下载到两份要按发布时间取最新版。5. 统计建模人工智能对绿色全要素生产率的影响、异质性与稳健性检验5.1 基准回归模型固定效应还是系统 GMM研究对象是 A 股上市公司面板数据基准模型一般选双向固定效应。企业个体固定效应吸收不随时间变化的企业特征年份固定效应吸收宏观经济波动和行业政策冲击。模型设定如下import statsmodels.api as sm from linearmodels.panel import PanelOLS # 假设df是面板数据index为(股票代码, 年份) df df.set_index([stock_code, year]) exog_vars [ai_index, size, leverage, roe, growth, age, state_owned] exog sm.add_constant(df[exog_vars]) model PanelOLS( dependentdf[gtfp_sbm], exogexog, entity_effectsTrue, time_effectsTrue ) result model.fit(cov_typeclustered, cluster_entityTrue) print(result.params) print(result.pvalues)核心解释变量 ai_index 是人工智能应用程度指标可以由大模型抽取的「是否提及人工智能技术应用」和相关场景描述构造比如用 0-1 虚拟变量或按提及频次加总的强度指数。被解释变量 gtfp_sbm 是 SBM 方法测度的绿色全要素生产率。标准误聚类到企业层面这是面板回归的基本功。如果不聚类同一家企业不同年份的扰动项几乎必然相关t 统计量会被严重高估。cov_typeclustered 配合 cluster_entityTrue 做的事就是允许同一家企业内部任意相关、不同企业间独立这是常见且合理的设定。5.2 异质性分析融资约束分组与中介效应标题里明确写了「企业融资约束异质性分析」这块是研究增量的重要来源。逻辑链条是人工智能提升绿色全要素生产率可能需要前期投入购买智能设备、改造产线、培训员工而融资约束严重的企业拿不出这笔钱效果被压制。因此预期分组回归中融资约束低的企业里人工智能系数显著为正融资约束高的企业里系数不显著或明显更小。融资约束的测度常用 SA 指数。SA 指数的好处是只依赖企业规模和年龄两个外生性较强的变量比 KZ 指数对财务指标的内生性更小。分组时按 SA 指数的中位数或三分位数切分都可以。另一种做法是把融资约束作为交互项放进全样本回归比如df[ai_sa_interact] df[ai_index] * df[sa_index] exog_vars [ai_index, sa_index, ai_sa_interact, size, leverage, roe, growth, age]交互项显著为负说明融资约束确实抑制了人工智能对绿色全要素生产率的提升作用这比单纯分组回归更有说服力。同时可以补一个中介效应检验人工智能通过促进绿色技术创新绿色专利数间接提升绿色全要素生产率用三步法或 Bootstrap 检验都可以。异质性分析也可以按产权性质分组国有/非国有、按行业分组重污染行业/非重污染行业、按地区分组东部/中西部。但注意行业和地区分组会吸收掉部分时间固定效应的影响分析时要谨慎解读。5.3 内生性处理工具变量与滞后变量论文级的实证研究绕不开内生性讨论。反向因果是首要威胁绿色全要素生产率高的企业可能更有动力和财力去应用人工智能而不是人工智能带来了生产率提升。惯用处理方法是核心解释变量滞后一期或两期将当期 gtfp 与滞后 ai_index 回归缓解反向因果。也可以用系统 GMM把被解释变量滞后项和解释变量差分项作为工具变量。寻找外部工具变量比较困难常见做法是使用同行业或同地区其他企业人工智能应用程度的均值作为本企业的工具变量。合理性在于行业-地区层面的技术扩散会影响本企业的人工智能应用但不直接影响本企业的绿色全要素生产率排除通过行业共同冲击影响的情况这时需要控制行业-年份联合固定效应。工具变量回归结果要报告第一阶段 F 统计量。F 值小于 10 表明工具变量弱结果不可信。实操中如果 F 值勉强过 10再考虑补充 LIML 估计或弱工具变量稳健推断。5.4 稳健性检验清单换指标、换样本、换模型审稿人最关心的稳健性检验按以下顺序做替换被解释变量测度方法SBM 换成 Malmquist 指数或非期望产出用不同污染物口径重新测算。替换核心解释变量构造方式0-1 虚拟变量换成人工智能词频强度指数或用与人工智能直接相关的投入科目做连续变量。替换样本区间剔除金融危机年份或新冠疫情年份再跑一遍。剔除异常值对连续变量在 1% 和 99% 分位上缩尾处理防止极值点驱动结果。增加控制变量把公司治理指数、机构持股比例、分析师关注度加进回归。下面是一次典型稳健性检验的共现逻辑# 替换解释变量后的基准回归 df[ai_freq] df[ai_mention_count] / df[report_length] exog_vars [ai_freq, size, leverage, roe, growth, age] model_alt PanelOLS( dependentdf[gtfp_sbm], exogsm.add_constant(df[exog_vars]), entity_effectsTrue, time_effectsTrue ).fit(cov_typeclustered, cluster_entityTrue) # 缩尾处理后的数据 from scipy.stats import mstats for col in [gtfp_sbm, ai_freq, size, leverage, roe, growth]: df[col _winsor] mstats.winsorize(df[col], limits[0.01, 0.01])缩尾处理后重新回归重点观察核心系数的方向和显著性是否保持一致。每一条通过就在论文里写一句「结果保持稳健」哪一条不通过先别急着改数据回头检查变量构造逻辑——大多数不稳健的根源是测度方法有偏不是样本问题。5.5 统计模型跑完后结果解读的规范性回归结果输出要规范。系数要报告经济显著性而不是只看 p 值。比如 ai_index 的系数是 0.05要说明人工智能应用程度每提高一个标准差绿色全要素生产率大约提升多少个百分点用标准差换算。表格要报告观测值数量、R 方、企业数。用 estout 或 linearmodels 的结果导出功能整理成论文格式不要手工抄数字。6. RAG 与统计建模的避坑清单我踩过的五个典型坑6.1 PDF 解析出来的文本是乱码或大量缺字现象PDFplumber 提取后文本里出现大量空白、字形错乱尤其带特殊符号的表格区域。原因年报 PDF 大多不是纯文本流有些是排版软件生成的复合字体提取时字体映射出错表格线框也可能干扰文字识别。解决先用 pdfplumber 抽查三页文本质量。如果缺字严重换 PyMuPDF 再试仍不行就上 OCR。OCR 前先做图像预处理灰度化和二值化能明显提升准确率。也可以混合策略文本层可用的页面走文本提取文本层损坏的页面走 OCR再按页码拼接。6.2 标题切块命中不准确把章节切碎了现象正则匹配标题时把正文里出现的「第四节 经营情况讨论与分析」和「本节概述」都当成了章节边界导致切块混乱。原因年报里标题和正文引用容易混淆纯正则无法很好区分。有些标题在 PDF 里带编号但换行后编号和标题文字分离。解决改进正则要求标题独立成行且前后有空行匹配候选后再做一步验证检查该行是否以已知章节关键字公司业务概要、经营情况讨论与分析、重要事项等开头。拿 50 份年报做回归测试确认切分准确率后再批量跑。6.3 大模型抽取结果对同一份年报不稳定现象同一份年报、同一个提示词跑三次三次得到的「环保投入金额」不一样。原因温度参数没有设为 0或者提示词里没有明确「严格依据原文、不得推理」。也可能是召回片段不稳定——向量检索本身有随机性或者索引中存在重复片段。解决温度设为 0提示词加「严格依据片段」约束对召回结果固定 k 值和过滤条件。还有一个经验不要用「根据你的理解」这类开放式表述全部改成「请从以下片段中查找」。6.4 财务指标与文本指标合并后样本量大缩水现象年报文本抽取完了和财务数据库 merge 之后样本从五千多家企业变成八百家。原因股票代码格式不一致文本里是 000001.SZ财务库里是 1年份口径不一致年报期间和财年日期没对齐复牌状态或退市股票在文本库中存在但财务库中缺失。解决合并前统一股票代码格式为六位数字年份取年报对应会计期间。合并时先跑 inner join 检查丢失量再决定是否用 left join 补全文本侧信息。对缺失股票代码的样本把年报文件名或正文页眉的代码取出来做映射。6.5 回归结果显示核心系数不稳定现象基准回归 ai_index 系数显著为正但替换解释变量构造方式后不显著了。原因核心变量构造方式太粗糙。比如「是否提及人工智能」这个 0-1 变量只能捕捉企业是否提过不能反映应用程度。大量企业年报里顺带提一句「积极推进数字化转型」和真正有智能化产线投入的企业在 0-1 变量里没有区分。解决把变量改成强度和频度指标。用 RAG 召回时统计「人工智能」「机器学习」「智能工厂」等关键词在年报中的出现频率同时让大模型抽取具体应用场景人工抽检判断应用深度。单纯加词频也要小心这是文本类变量的通病弄不好会把年报写作风格的差异当成信号。最终解法是构造复合指标结合词频、场景描述和是否投入资金三个维度。7. 把这套流程跑顺的两个进阶技巧7.1 用人工样本校准大模型抽取质量批量跑大模型之前抽 30 份年报做人工标注覆盖不同行业和不同年报篇幅。将人工标注结果和大模型抽取结果对比计算每个字段的准确率和召回率。准确率低的字段优先调整提示词而不是换模型。比如「碳排放量」字段如果经常抽不到原因多半是年报原文表述五花八门——「二氧化碳排放量」「温室气体排放量」「碳排放量」召回阶段没把这些同义表述的片段都捞出来。解决方式是扩充查询词的近义表述一次跑多路召回。这里要强调一个容易被忽略的点人工标注样本不只是用来验证模型也是用来校准检索结果的。人工看 30 份年报时记录信息实际出现的位置和表述方式再对比 RAG 召回结果能清晰看到检索策略的盲区。RAG 系统的上限由召回决定大模型只是在已召回的片段上做抽取。召回漏了模型再强也白搭。7.2 用记录日志做整条链路的审计运行日志里记三样东西每份年报的解析耗时、切块数量、抽取成功与否。解析耗时异常偏长的多半是文件损坏或 OCR 介入切块数量偏离同类年报平均水平的检查标题切分逻辑抽取失败的查看提示词返回内容和对应片段来源。当日志里的失败模式多次指向同一类年报比如某家券商年报的独特排版考虑单独写规则处理。从经验来看大部分失败不是大模型本身的问题而是前面的解析或检索环节埋了雷。把日志做成可查询的批量处理完抽出失败样本统一修比在线调参数更高效。做完整条流水线后定下一条个人习惯每次跑新一批数据先复跑上批数据中 20 份已验证的旧年报确认重建索引后抽取结果没有漂移。这套做法在多次修改代码后救过我的数据质量希望你用到时也能省一轮从头来过的功夫。希望这篇基于 RAG 与大语言模型分析 A 股年报做绿色全要素生产率建模的完整链路拆解能帮你在自己的研究项目里少走几趟弯路。本文还有配套的精品资源点击获取
返回列表