拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

AI财报分析提示词设计:防幻觉、强约束、可验算的落地方法

AI财报分析提示词设计:防幻觉、强约束、可验算的落地方法

简介:面向金融商贸从业者、投资者以及需要频繁阅读上市公司财报的分析师,这份《AI财报分析提示词推荐》PDF文档提供了一套可直接复制、修改的AI对话提示词方案。文档围绕整体分析、行业分析、杜邦分析法三大应用场景展开,不仅覆盖资产负债表、利润表、现金流量表的关键指标计算(如速动比率、资产负债率、应收账款周转率、存货周转率、净资产收益率、毛利率、净利润率、营收和净利润增长率),还引入同行业负债水平比较、存贷双高识别以及八种现金流组合研判,帮助使用者多维度判断企业安全性、管理层能力、盈利与成长能力、现金流质量及当前财务状态。资源包仅含1个PDF文件,压缩后约484KB,便于随手查阅与复用;截至当前已有185人浏览学习。得益于分步工作流、角色设定和输出格式约束,这份提示词可驱动AI按步骤提取数据、计算指标、解释结论,最终生成相对完整的财报分析报告,显著降低非财务背景用户的解读门槛,也适合作为个人或团队构建智能财报助手的起点。

1. AI财报分析提示词推荐:先堵住幻觉,再谈分析能力

做投研的人用大模型读财报,最常踩的不是模型看不懂,而是它看得太“懂”——把没有的增长率算出来,把错的同比口径说对,再一本正经写进结论里。我调试AI财报分析提示词的第一版,就让模型把某公司营业收入同比增速从真实的6.8%算成了17.3%,问题出在哪?出在提示词给了它自由发挥的余地。这篇笔记要讲的是,怎么设计一套财报分析提示词,让模型既能用又能信:包括基础版与分析师的进阶模板、多期数据喂法、长文本下的上下文工程,以及一套能交叉校验数字的验算器方案。适合正在做AI投研工具、财务自动分析或企业内部经营分析的人,照着就能落地。

2. 财报提示词怎么设计:角色、任务、数据、输出四层约束

2.1 为什么通用提示词在财报上跑不赢:任务结构化程度不同

通用提示词擅长写文案、列要点,因为那类任务本身就没有唯一答案。财报分析完全相反,它是一张坐标系锁死的任务:行项目名称是固定的(营业收入、营业成本、销售费用、净利润),数字必须分毫不差,口径一旦变了结论就翻车。把写公众号的提示词直接丢给模型读年报,等于让实习生不看会计准则就写分析报告,结果一定是自由发挥。

我早期做过的实验:同样的年报文本,用“请分析这家公司的财务状况”和用“请按下列表格结构逐项提取数字并计算三年同比”的两个提示词跑,后者的错误率明显低。原因不玄学——财报分析本质是信息抽取加口径计算,不是语言生成。所以提示词的核心任务不是“让模型说得更多”,而是“让模型少说、少猜、少发挥”。

2.2 四层约束拆解:每层都在锁死哪些自由度

第一层是角色约束。把模型定位成“财务分析助理”,不是“投资顾问”也不是“通用助手”。财报分析需要冷静的行项目核对,不需要投资建议的激情发挥。第二层是任务约束。明确交付物是什么:提取表格、计算指标、列风险点、列疑问清单,而不是一篇议论文。第三层是数据约束。要求模型只用喂进去的文本和表格里的数字,明确禁止调用训练记忆里的“相似公司数据”——这条特别重要,模型见过太多上市公司,极容易把A公司的营收安到B公司头上。第四层是输出约束。固定输出格式,比如Markdown表格、JSON或编号清单,并强制每个核心数字后面带来源行号。

这四层约束本质上是把自由生成问题,转换成信息抽取问题。参数上的配合也关键:回答温度(temperature)设到0,禁止采样随机;关闭联网检索,保证回答只基于你喂进去的上下文内容。

2.3 可抄作业的最小模板:基础版提示词与参数设置

我给团队常用的基础版提示词,长这样:

你是一名财务分析助理,只依据用户提供的财报文本和表格数据作答,禁止使用你的记忆补充任何公司数据。 任务: 1. 从给定文本中提取最近一个报告期的利润表关键行项目:营业收入、营业成本、销售费用、管理费用、研发费用、净利润。 2. 按“项目 | 报告期 | 金额(单位) | 同比变化(%) | 来源行号”输出为 Markdown 表格。 3. 计算毛利率、净利率,并标明计算式。 4. 列出你认为异常或需要进一步核实的 3 个点,每个点必须注明对应行号。 硬性要求: - 只允许使用文本中明确出现的数字,禁止推算缺失年份的数据。 - 每个数字后必须带来源行号,行号格式为 [L12]。 - 如果某项数据在文本中不存在,明确写“未提供”,不要猜测。 - 输出只包含上述表格和要点,不要额外给出投资建议。

这段模板好在哪?它把自由度锁在几处:角色前面限定了“只依据给定文本”;任务里明确提取项和输出格式;硬性要求把“来源行号”变成强制项。这里的来源行号是整个方案的支点,后面做自动校验全靠它。

参数上,我一般在调用时设置:temperature=0,top_p=0.1,max_tokens=1500到2000。温度设为0意味着概率分布里每次都选最高概率词,模型不会随机换词,这对数字复述很关键。top_p再收紧一档,是在0温度的基础上进一步减少罕见词概率。max_tokens不建议低于1000,因为多期对比输出表格时,截断往往发生在表格尾部。

2.4 参数说明:温度、上下文注入与输出上限的取值依据

这里有一个容易忽略的点:提示词里提到的“行号”不是模型自己编的,是你在数据预处理时写在每行文本前的标记。换句话说,提示词设计必须和上游的数据管线配套,否则模型没法给出真实行号,只能编一个。这也是为什么我坚持把预处理脚本和提示词放在同一篇讲。

温度参数有一个反直觉的现象:把temperature降到0以后,模型反而会更频繁地输出“未提供”,因为它不再“尝试凑一个答案”。这在财报场景是好事,宁可说没有,不能编一个。如果你的使用场景里模型输出仍然有幻觉,先检查提示词里有没有“必须回答所有问题”这类话,这类指令会诱导模型补齐缺失值,和财务分析的需求正好相冲。

3. 多期对比与分析师版提示词:让模型按口径算而不是自由发挥

3.1 多期数据怎么喂:一张三年对比表比三段描述更可靠

单期财报分析的价值有限,真正做投研的人至少看三年。但大模型处理时间序列有个毛病:你喂一段话描述2022年营收,再喂一段描述2023年营收,它计算同比时很容易串行、漏数、甚至把两年的数字颠倒。

我的做法是用结构化的方式把三年数据压进提示词:同一张表格、同一套行项目、一年一列。人眼看起来可能有点挤,但对模型来说,这种并行结构比自然语言描述更不容易错。

以下为某公司近三年利润表关键数据(单位:亿元人民币): | 行项目 | 2023 | 2022 | 2021 | |--------|------|------|------| | 营业收入 | 218.3 | 189.7 | 152.4 | | 营业成本 | 148.2 | 130.5 | 105.8 | | 销售费用 | 19.4 | 17.8 | 14.2 | | 管理费用 | 10.6 | 9.4 | 8.1 | | 研发费用 | 15.9 | 14.2 | 11.5 | | 净利润 | 33.8 | 26.5 | 19.7 | 计算任务: 1. 分别计算营业收入、净利润的2023年同比变化率,保留一位小数,并写出计算式。 2. 计算2023年毛利率和净利率,并写出计算式。 3. 简要说明2023年相较2021年的两年复合增长率。

这里有个细节值得说:表格最后一行“净利润”,模型有时会把它理解成“归属于母公司股东的净利润”,实际年报里这两个数可能差好几亿。如果提示词里不写清楚,模型就会按训练记忆里的定义理解,而不是按你喂的数据。这种情况的防法是:在表格标题附近加一句“净利润=利润表净利润,非归母净利润,两者逻辑上有差异时以本表为准”。

3.2 计算口径声明:同比、环比、TTM与单季缺一不可

多期对比的大坑是口径不一致。年报里的同比可能是“本季度同比增长”,也可能是“年初至今累计同比增长”,模型不知道你说的是哪一种,它只会按字面意思算。这是我对AI财报分析提示词最深的血泪经验之一。

所以提示词里必须有口径声明段。我现在每个报告提示词都固定带一段:“以下指标均默认为单季口径。若为累计口径,请先在结果中注明‘累计’字样。TTM(滚动十二个月)口径,必须单独标出计算窗口,例如(2023Q2-2024Q1)。”这样模型每次输出指标时都带口径前缀,你后续使用才不会误读。

还有一个常见情况:你手头只有年度数据,但想对比季度趋势。这时提示词要明确写“只有年度数据,禁止推测季度分布,仅标注‘未提供季度明细’”。模型靠训练数据里类似公司的季节性模式去补季度分布的可能性很高,必须提前用指令封死。

3.3 分析师版提示词全文:带勾稽校验的输出协议

给分析师用,基础模板还不够,输出必须是可直接进投研底稿的结构。我常用的分析师版提示词如下:

你是有十年经验的财务分析师,只基于给定财报文本与表格工作,禁止补充任何外部数据。 分析范围:2021-2023年年度报告。 第一步:提取三年利润表、资产负债表、现金流量表关键行项目,按“行项目 | 2023 | 2022 | 2021 | 三年变化趋势”输出为Markdown表格。 第二步:计算以下指标,每个指标必须带计算式、口径、来源行号: - 毛利率 = (营业收入 - 营业成本) / 营业收入 - 净利率 = 净利润 / 营业收入 - 期间费用率 = (销售费用 + 管理费用 + 研发费用) / 营业收入 - 经营性现金流净利润比率 = 经营活动产生的现金流量净额 / 净利润 第三步:执行勾稽校验,并逐项给出结论: 1. 经营活动产生的现金流量净额与净利润差异是否超过20%,若超过,请指出差异方向。 2. 应收账款增速与营业收入增速的对比。 3. 存货增速与营业成本增速的对比。 第四步:输出结构 | 模块 | 内容 | |------|------| | 核心结论 | 不超过3点,每点附行号 | | 主要风险 | 不超过3点,每点附行号 | | 疑问清单 | 需要向公司确认的问题,不超过3个 | | 数据可信度 | 高/中/低,给出理由 |

这套模板不是单纯加了更多计算项,核心变化在第三步:勾稽校验。这是财务分析中“先验后评”的思路,让模型在做判断之前先执行一组可验证的等式比对。做完校验之后模型给出的风险点,比直接问“有什么风险”可靠得多——因为它需要先摆数据,再下结论。

3.4 输出协议:结论、风险、疑问与验算清单

第四步的输出结构是这套提示词的收口。这里我故意把“数据可信度”放在最后,让模型评估自己在数据提取过程中的把握程度。实操里,模型给“数据可信度:低”的时候,往往是因为它的来源行号对不上、或者年报里数字出现多口径。这时输出的风险点本身就成了一个值得复核的信号。

输出协议里还有一个隐性好处:如果你后面要接AI Agent做自动报告,这套结构化输出可以直接解析成JSON再入库。我一般是这样接的:提示词尾部加“若需要机器读取,将上述表格转为JSON,字段名为core_conclusion、risks、questions、confidence”,然后让大模型同时输出Markdown和JSON两段。不过要注意,一次让模型输出两遍内容会明显增加token消耗,如果上下文空间紧张,优先保表格,JSON可以后续二次生成。

4. 长文本下的上下文工程:年报PDF转提示词输入前先做预处理

4.1 先抽后喂:年报里哪些表格值得进上下文,哪些可以丢

一家上市公司的年报PDF少的几十页,多的三百页。直接把全量文本塞进提示词,不但浪费token,还会触发上下文窗口截断,模型读到后面忘了前面。财报分析常用的做法是“先抽后喂”:把年报里的核心章节摘出来,而不是全文进入。

我实际处理时,按优先级排这样几块:第三节“管理层讨论与分析”里的经营情况回顾,第四节“经营情况讨论与分析”里的行业与业务数据,财务报告部分三张主表(合并利润表、合并资产负债表、合并现金流量表),附注中的收入确认、应收账款、存货、商誉减值等关键注释。其他内容比如公司治理、股东名册、备查文件,基本不进上下文。

判断标准是一句话:凡是能直接产出数字的,优先;凡是帮助理解数字口径的,其次;凡是用来“感受公司风格”的文本,全部舍弃。这样操作下来,一个正常年报抽出的文本量控制在1到2万token以内,多数主流大模型窗口能装下。

4.2 分段检索式分析:让AI Agent先定位再精读

如果分析目标是整个行业几家公司的横向对比,单家全文喂法还是太浪费。更省的做法是分段检索式:把年报切段建立索引,先让AI Agent定位目标数字在哪一段,比如“搜索‘销售费用’”,再把命中的段落连同前后文送给模型精读。

这个思路本质上是把阅读任务拆成两层:第一层是检索层,负责“找到数字在哪”;第二层是分析层,负责“看到数字后做判断”。很多现成的AI Agent框架都支持这种流程,但直接用工具前,你要理解它的数据输入格式要求——检索层返回的段落如果太长,分析层仍然要截断。我一般把每段限制在400到600字以内,保证一个段落能完整覆盖一个行项目的“名称、数字、口径说明、附注标记”。

4.3 预处理脚本:裁剪年报文本,把关键表按行号喂给模型

下面这是我维护的一个裁剪脚本,核心功能是:读取年报纯文本,给每行加行号,抽取包含关键财务术语的段落,最后按顺序拼成一段带行号标记的文本,方便后面喂给提示词。

import re def load_report_text(path): with open(path, 'r', encoding='utf-8') as f: return f.readlines() def add_line_numbers(lines): return [f"[L{i+1}] {line.strip()}" for i, line in enumerate(lines)] KEY_TERMS = [ '营业收入', '营业成本', '销售费用', '管理费用', '研发费用', '净利润', '经营活动产生的现金流量净额', '应收账款', '存货', '毛利率', '净利率', '商誉', '合同负债' ] def extract_relevant_blocks(lines, max_lines=800): numbered = add_line_numbers(lines) relevant = [] for i, line in enumerate(numbered): if any(term in line for term in KEY_TERMS): start = max(0, i - 2) end = min(len(numbered), i + 3) block = numbered[start:end] if block not in relevant: relevant.extend(block) if len(relevant) >= max_lines: break return '\n'.join(relevant) def estimate_tokens(text): # 粗略估算:中文平均每个字约0.6-0.7 token,英文单词约1.3 token cn_chars = len(re.findall(r'[\u4e00-\u9fff]', text)) other_chars = len(text) - cn_chars return int(cn_chars * 0.7 + other_chars / 4) if __name__ == '__main__': lines = load_report_text('annual_report.txt') result = extract_relevant_blocks(lines) print(f'抽取段落行数: {len(result.splitlines())}') print(f'估算token数: {estimate_tokens(result)}')

这段脚本的逻辑是:先给原文每行加行号标记[L12]这样的前缀,然后按财经术语命中的位置截取前后几行,保证上下文完整。extract_relevant_blocks里做了去重,防止相邻两个术语命中的段落重复拼接。estimate_tokens是一个粗估函数,中文按每字0.7个token估算,英文按每4个字符1个token估算,目的是让你在调上下文窗口大小时有数,不必真实切分token。

使用时有几个参数要按需调。一个是max_lines=800,代表最多保留800行有效内容,如果你要分析三年年报横向对比,建议调到1200到1500。另一个是KEY_TERMS,名单越长抽取越全面,但噪声也越多,我建议先跑一次看输出的段落,再删掉干扰项。还有start/end窗口的大小,当前取前后各2行,适合财务报表这种“一行一个行项目”的结构,如果遇到管理层讨论里成段的内容,建议扩到前后各5行。

预处理脚本输出的是纯文本,接下来把它接进提示词即可。在拼接时有一个顺序约定:先放提示词主体,再放“以下是带行号的财报文本”,最后放数据文本。模型对后置文本的注意力相对强,把关键数据放后面更稳妥。

5. 避坑:财报分析提示词最常见的5个翻车现场

5.1 数字幻觉:毛利率被模型算成41.37%,原文只有38.2%

现象:提示词要求计算毛利率,模型的输出看起来“细节齐全”,还写了计算式:(218.3 - 127.9) / 218.3 = 41.37%,但原文营业成本那条明确写的是148.2亿元。原因:模型在长文本中定位“营业成本”时,抓错了一个邻近数字(可能是某个分产品成本的片段),然后基于错误数字完成了计算。解决:一是提示词里强制每步计算前先列出“数据来源行号”,例如“营业成本[L88]”;二是在预处理脚本里将关键行项目“数字前不带任何其他数字”作为前处理规则,比如单独把利润表抽成表格再让模型算。自那以后我的模板里所有计算项必须带[Lxx]来源。

5.2 同比口径错位:把累计数当成了单季数

现象:某公司一季报里写“营业收入同比增长15%”,模型直接把这个数当成“2024年第一季度单季同比”,然后与年报里“2024年全年同比”放到一起比较,得出完全错误的增长趋势结论。原因:中文财报里“同比”二字经常匹配到“年初至今同比”而不是“单季同比”,模型按语义默认了单季。解决:在提示词开头写死“所有指标必须是单季口径,如果不确定是累计还是单季,输出‘口径不明’”,并且要求模型先标注口径再给数字。这个参数没有固定写法,但这句话必须出现在每个分析模板的前三行内。

5.3 勾稽关系对不上:经营现金流比净利润高就该起疑

现象:模型在风险清单里写“经营现金流为负,可能存在资金链风险”,可原始数据里经营现金流明明是正数,且比净利润高出一大截。原因:模型在输出前没有做“利润表-现金流量表”交叉核对,凭训练记忆里的“现金流为负=风险”模板生成了结论。解决:把勾稽校验直接写进提示词的执行步骤里,让模型输出“经营现金流与净利润的差异率”这个中间结果,再基于差异率判断风险方向。差异率超过20%才提示关注,而不是看到负值就预警——经营现金流为负不等于风险,还要看是扩张性支出还是经营性恶化,模型不应该自动跳过这个区分。

5.4 会计政策变更没发现:计提比例变了,模型还在用老口径

现象:公司把应收账款坏账计提比例从5%调整到10%,模型分析风险时完全没有提,反而判断“应收账款质量良好”。原因:提示词没有指定模型去读会计政策章节,模型只在报表主表里找数字,而会计估计变更写在附注里。解决:在分析师版提示词第三步里增加一条“检查附注中应收款项坏账准备计提比例的年度变化;若存在变更,指出对应行号,并标记“口径调整”到风险清单”。如果你的提示词体系里没有这一步,模型永远看不到附注里的变化。

5.5 输出截断与格式崩坏:JSON断了一半,Markdown表格错行

现象:输出到第9行表格时突然中断,JSON解析直接报错;有时表格列数不齐,模型漏写了某列数据。原因:max_tokens设得过小,模型在输出尾部被强行切断;还有一种情况是上下文太长时,模型在“注意力滑坡”阶段丢失了表格的列对齐信息。解决:测算输出长度——一张3年×10行项目的表格大约需要800到1000个token,风险清单再占300到500。把max_tokens放到2000以上,JSON模式单独一次生成,不与表格同请求。如果API支持response_format: json_object,单独开一个JSON请求更干净。实战中我倾向分两次调用:第一次取表格与分析,第二次把第一次的结论作为输入,再生成机器可读JSON。

6. 加一道验算器:让AI输出带行号引用,再用脚本交叉核验

前面所有提示词设计,都在为这一步铺路:让模型的每个关键数字都挂在某个行号上,然后用脚本反向验证。这是我从多次数据事故里逼出来的习惯——AI输出进入底稿之前,必须过一遍验算器,把这个当成工作流的一环,而不是可选项。

6.1 数字引用约束:在提示词里强制输出行号

提示词里我始终保存着这样一句:“任何一个关键数字后面必须标注来源行号,如[L88]。行号代表数字在该文本中首次出现的准确位置。如果数字无法定位到具体行号,则在该数字旁标注‘#未定位’,不要省略。”这个约束连着用几次以后,模型会形成一种稳定的带引用输出习惯。

6.2 交叉核验脚本:用原文反向验证AI给出的数字

下面这段脚本做的是:读取原始财报文本和AI输出的JSON,逐个检查AI给的关键数字是否真的出现在它引用的行号附近。如果数字不在行号位置,说明模型可能编造了引用。

import json import re def verify_citations(report_text, ai_json_path): with open(report_text, 'r', encoding='utf-8') as f: lines = f.readlines() with open(ai_json_path, 'r', encoding='utf-8') as f: data = json.load(f) issues = [] for item in data.get('key_figures', []): value = str(item.get('value', '')) line_no = item.get('line_no') if not line_no: issues.append(f"{item.get('name')}: 缺少行号") continue # 行号提取,例如 [L12] -> 12 match = re.search(r'L(\d+)', str(line_no)) if not match: issues.append(f"{item.get('name')}: 行号格式错误 {line_no}") continue idx = int(match.group(1)) - 1 if idx >= len(lines): issues.append(f"{item.get('name')}: 行号超出范围 L{idx + 1}") continue line_text = lines[idx] digits = re.sub(r'[^\d.]', '', value) if digits and digits not in re.sub(r'[^\d.]', '', line_text): issues.append(f"{item.get('name')}: 数字 {value} 未出现在 L{idx + 1} 附近") return issues if issues else ['全部引用校验通过'] if __name__ == '__main__': problems = verify_citations('annual_report.txt', 'ai_output.json') for p in problems: print(p)

脚本逻辑不算复杂:先按行号从原文里取出那一行,再从该行文本中抽出数字与AI报的数字做包含性比较。如果数字不在该行,就把{name}: 数字未出现在 L{idx + 1}记为异常。参数上注意两点:key_figures这个字段名要和你的提示词输出协议保持一致,如果不叫这个名,脚本读不到任何内容;比较时去掉了小数点前后的格式差异,但如果原文里是“218.3亿”,AI输出“218.3”,校验也能通过,因为只抽数字字符比对。

这是我这套提示词方案里最后的防线,也是我吃了哑巴亏以后总结出的经验。最开始我不做验算,直接拿AI分析结果写投研纪要,结果被数字来源折腾得不轻,从那以后所有AI报出的关键数字必须能顺着行号找回原文。这个习惯看起来多花几分钟,但它能挡住九成以上的幻觉输出。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表