基于Harness与Langfuse构建企业级AI智能体:财务分析实战
2026/8/20 7:18:03 网站建设 项目流程

在构建企业级AI应用时,我们常常面临一个核心矛盾:如何将前沿的AI模型(如大语言模型)稳定、可靠、可观测地集成到复杂的业务流程中?尤其是在财务分析这类对准确性、可追溯性和合规性要求极高的领域。传统的“脚本+API调用”模式在开发效率、监控评估和迭代优化上捉襟见肘,导致项目难以规模化落地。

本文将围绕Harness架构Langfuse这两大AI工程化核心工具,手把手带你构建一个企业级的“财务分析智能体”项目。这不是一个简单的Demo,而是一个覆盖从智能体开发、流程编排、全面评估到生产部署全链路的实战教程。无论你是希望将AI能力引入现有系统的后端工程师,还是专注于AI应用落地的算法工程师,都能从中获得一套可直接复用的工程化方案。

1. 项目背景与核心概念解析

在深入代码之前,我们必须厘清几个关键概念,理解它们为何能解决企业级AI应用的痛点。

1.1 什么是AI工程化?

AI工程化是将机器学习/人工智能模型的开发、部署、监控和维护过程系统化、标准化和自动化的实践。它旨在弥合数据科学实验与生产级软件交付之间的鸿沟。对于基于大语言模型(LLM)的应用,工程化挑战尤为突出,包括:提示词(Prompt)管理、上下文窗口处理、多步骤推理(Agent)流程编排、成本控制、性能评估与迭代等。

1.2 Harness:AI智能体的编排与执行引擎

Harness在这里并非指持续交付工具Harness.io,而是指一个新兴的、专注于AI智能体(Agent)工作流编排的开源框架(注:根据网络热词,可能与DeepSeek等探索相关)。我们可以将其理解为一个专为AI设计的“工作流引擎”。它的核心价值在于:

  • 可视化/代码化编排:允许你通过拖拽或代码定义复杂的、多步骤的AI任务流程,例如“获取数据 -> 分析 -> 生成报告 -> 发送审核”。
  • 状态管理与回溯:自动维护智能体执行过程中的状态(State),方便调试和错误恢复。
  • 工具集成:便捷地集成外部工具(如计算器、数据库查询、API调用),扩展智能体的能力边界。
  • 抽象底层LLM:提供统一的接口调用不同的模型提供商(OpenAI, Anthropic, 本地模型等),降低耦合。

简单说,Harness让构建一个像“财务分析师”一样执行多步骤任务的智能体,变得像搭积木一样清晰可控。

1.3 Langfuse:LLM应用的观测与评估平台

Langfuse是一个开源的LLM应用观测平台。如果说Harness是“生产车间”,那么Langfuse就是“质量检测与监控中心”。它的核心功能包括:

  • 全链路追踪(Tracing):自动记录每次LLM调用的输入、输出、延迟、成本、token用量,并可视化整个调用链。
  • 提示词管理(Prompt Management):版本化管理和评估不同的提示词模板,实现A/B测试。
  • 评估与评分(Evaluation):支持基于规则(如格式检查)、模型(使用另一个LLM打分)或人工的反馈,对AI输出进行量化评估。
  • 数据分析看板:提供丰富的仪表盘,分析成本、延迟、评分趋势,定位问题。

在财务分析场景中,Langfuse能帮助我们回答关键问题:智能体生成的报告准确性如何?分析逻辑是否稳定?每次调用的成本是多少?

1.4 财务分析智能体:我们的实战目标

我们将构建一个智能体,它能够处理一份结构化的财务数据(如CSV格式的利润表),并完成以下任务:

  1. 数据解读:识别关键财务指标(营收、毛利率、净利润等)。
  2. 趋势分析:计算环比、同比增长率。
  3. 洞察生成:用自然语言总结财务状况,指出亮点与风险。
  4. 报告格式化:输出结构清晰的Markdown格式报告。

这个智能体将使用Harness来编排“数据读取 -> 指标计算 -> LLM分析 -> 报告生成”的流程,并利用Langfuse对每一次执行进行追踪、记录和评估。

2. 环境准备与项目初始化

我们将使用Python作为主要开发语言。请确保你的环境满足以下要求。

2.1 基础环境要求

  • 操作系统:macOS / Linux / Windows (WSL2推荐)
  • Python版本:3.10 或 3.11(建议使用3.11以获得最佳兼容性)
  • 包管理工具:pip 或 poetry
  • LLM API密钥:你需要一个OpenAI API密钥(或 Anthropic、Groq 等兼容OpenAI SDK的API密钥)用于调用模型。本文以OpenAI GPT-4o-mini为例。

2.2 创建项目并安装依赖

首先,创建一个新的项目目录并初始化虚拟环境。

mkdir finance-ai-agent && cd finance-ai-agent python -m venv venv # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate

接下来,创建requirements.txt文件,包含以下核心依赖:

# 核心AI与编排框架 openai>=1.0.0 # 假设我们使用一个名为 `ai-harness` 的模拟Harness框架包进行演示 # 注:当前Harness框架生态中有多个项目,如 `harness`,`agent-harness`等,此处为概念演示,我们使用一个简化的自制类。 langfuse>=3.0.0 # 数据处理与工具 pandas>=2.0.0 numpy>=1.24.0 # 环境变量管理 python-dotenv>=1.0.0 # 可选:Web框架(如需提供API接口) fastapi>=0.104.0 uvicorn>=0.24.0

安装依赖:

pip install -r requirements.txt

由于目前没有一个统一的、名为“Harness”的Python包,我们将模拟其核心编排思想,构建一个轻量级的Harness类。在真实项目中,你可以根据调研选择如Semantic Kernel,LangChain,AutoGen或新兴的harnessSDK。

2.3 配置环境变量

创建.env文件,存储敏感信息和配置:

# .env OPENAI_API_KEY=sk-your-openai-api-key-here LANGFUSE_SECRET_KEY=sk-lf-your-langfuse-secret-key LANGFUSE_PUBLIC_KEY=pk-lf-your-langfuse-public-key LANGFUSE_HOST=https://cloud.langfuse.com # 或你的自托管地址 # 项目配置 DEFAULT_LLM_MODEL=gpt-4o-mini

重要:请勿将.env文件提交到版本控制系统。确保它在.gitignore中。

2.4 初始化Langfuse客户端

在项目根目录创建config.py,用于初始化全局配置和客户端。

# config.py import os from dotenv import load_dotenv from langfuse import Langfuse # 加载环境变量 load_dotenv() class Config: OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") LANGFUSE_SECRET_KEY = os.getenv("LANGFUSE_SECRET_KEY") LANGFUSE_PUBLIC_KEY = os.getenv("LANGFUSE_PUBLIC_KEY") LANGFUSE_HOST = os.getenv("LANGFUSE_HOST") DEFAULT_LLM_MODEL = os.getenv("DEFAULT_LLM_MODEL", "gpt-4o-mini") @staticmethod def get_langfuse_client(): """初始化并返回Langfuse客户端,实现单例模式""" if not all([Config.LANGFUSE_PUBLIC_KEY, Config.LANGFUSE_SECRET_KEY]): print("警告: Langfuse 密钥未配置,追踪功能将禁用。") return None try: # 在生产环境中,建议配置更详细的初始化参数 langfuse_client = Langfuse( public_key=Config.LANGFUSE_PUBLIC_KEY, secret_key=Config.LANGFUSE_SECRET_KEY, host=Config.LANGFUSE_HOST, ) return langfuse_client except Exception as e: print(f"初始化Langfuse客户端失败: {e}") return None # 全局配置和客户端实例 config = Config() langfuse_client = config.get_langfuse_client()

3. 核心架构与模拟Harness引擎实现

我们将实现一个简化的Harness类,其核心思想是:将复杂的AI任务分解为多个可复用的“节点”(Node),并通过“边”(Edge)定义执行顺序和数据流

3.1 定义节点基类与上下文

首先,定义任务执行时的上下文(State)和节点的基类。

# harness/core.py from abc import ABC, abstractmethod from typing import Any, Dict, Optional, Callable import inspect class State(Dict[str, Any]): """任务执行状态上下文,是一个增强型字典。""" pass class Node(ABC): """Harness节点抽象基类。每个节点代表一个处理单元。""" def __init__(self, id: str, description: str = ""): self.id = id self.description = description @abstractmethod async def execute(self, state: State) -> State: """ 执行节点的核心逻辑。 参数: state: 当前执行状态,包含上游节点的输出。 返回: 更新后的状态。 """ pass def __repr__(self): return f"Node(id={self.id})"

3.2 实现具体功能节点

基于我们的财务分析场景,我们需要几种类型的节点:

  1. 工具节点(Tool Node):执行确定性操作,如读取文件、计算指标。
  2. LLM节点(LLM Node):调用大语言模型进行分析和生成。
  3. 条件节点(Condition Node):根据状态决定执行分支(本例暂不展开)。

让我们实现一个文件读取节点和一个指标计算节点。

# harness/nodes/tool_nodes.py import pandas as pd from ..core import Node, State import json class LoadCSVNode(Node): """加载CSV财务数据文件到状态中。""" def __init__(self, id: str, file_path_key: str = "file_path", output_key: str = "df"): super().__init__(id, description="加载CSV文件为DataFrame") self.file_path_key = file_path_key # 状态中文件路径的键名 self.output_key = output_key # 输出DataFrame的键名 async def execute(self, state: State) -> State: file_path = state.get(self.file_path_key) if not file_path: raise ValueError(f"状态中未找到文件路径键: {self.file_path_key}") try: df = pd.read_csv(file_path) state[self.output_key] = df state[f"{self.output_key}_shape"] = df.shape print(f"[{self.id}] 已加载文件: {file_path}, 形状: {df.shape}") except Exception as e: raise RuntimeError(f"[{self.id}] 加载CSV文件失败: {e}") return state class CalculateMetricsNode(Node): """计算基础财务指标。""" def __init__(self, id: str, df_key: str = "df", metrics_key: str = "basic_metrics"): super().__init__(id, description="计算财务指标(营收、毛利、净利等)") self.df_key = df_key self.metrics_key = metrics_key async def execute(self, state: State) -> State: df = state.get(self.df_key) if df is None or not isinstance(df, pd.DataFrame): raise ValueError(f"状态中未找到有效的DataFrame,键: {self.df_key}") # 假设CSV有特定列名,这里需要根据实际数据调整 # 示例列:`period`, `revenue`, `cost_of_goods_sold`, `operating_expenses`, `net_income` required_cols = ['period', 'revenue', 'cost_of_goods_sold', 'net_income'] if not all(col in df.columns for col in required_cols): raise ValueError(f"DataFrame缺少必要列,需要: {required_cols}") metrics = {} latest = df.iloc[-1] # 取最新一期数据 previous = df.iloc[-2] if len(df) > 1 else None metrics['latest_period'] = latest['period'] metrics['revenue'] = float(latest['revenue']) metrics['gross_profit'] = float(latest['revenue'] - latest['cost_of_goods_sold']) metrics['gross_margin'] = float(metrics['gross_profit'] / latest['revenue']) if latest['revenue'] != 0 else 0 metrics['net_income'] = float(latest['net_income']) metrics['net_margin'] = float(latest['net_income'] / latest['revenue']) if latest['revenue'] != 0 else 0 # 计算环比(如果数据足够) if previous is not None: metrics['revenue_qoq'] = float((latest['revenue'] - previous['revenue']) / previous['revenue']) if previous['revenue'] != 0 else 0 metrics['net_income_qoq'] = float((latest['net_income'] - previous['net_income']) / previous['net_income']) if previous['net_income'] != 0 else 0 state[self.metrics_key] = metrics print(f"[{self.id}] 计算完成基础指标: {json.dumps(metrics, indent=2, default=str)}") return state

接下来,实现一个与Langfuse深度集成的LLM节点。这个节点会将其调用过程自动记录到Langfuse。

# harness/nodes/llm_nodes.py import openai from openai import OpenAI from ..core import Node, State from config import config, langfuse_client import json class LangfuseLLMNode(Node): """集成Langfuse追踪的LLM调用节点。""" def __init__(self, id: str, prompt_template: str, input_state_keys: Dict[str, str], # 例如 {"metrics": "basic_metrics", "df_summary": "df_summary"} output_key: str = "llm_response", model: str = None, system_prompt: str = "你是一个专业的财务分析师,请根据提供的数据进行客观、严谨的分析。" ): super().__init__(id, description="调用LLM并生成分析报告") self.prompt_template = prompt_template self.input_state_keys = input_state_keys # 映射:模板变量名 -> 状态中的键名 self.output_key = output_key self.model = model or config.DEFAULT_LLM_MODEL self.system_prompt = system_prompt self.client = OpenAI(api_key=config.OPENAI_API_KEY) async def execute(self, state: State) -> State: # 1. 从状态中提取数据,填充提示词模板 template_data = {} for var_name, state_key in self.input_state_keys.items(): if state_key not in state: raise ValueError(f"状态中缺少所需键 '{state_key}',用于模板变量 '{var_name}'") template_data[var_name] = state[state_key] try: user_prompt = self.prompt_template.format(**template_data) except KeyError as e: raise ValueError(f"提示词模板变量替换失败,缺少变量: {e}") # 2. 准备Langfuse追踪(如果客户端可用) trace = None generation = None if langfuse_client: trace = langfuse_client.trace( name=f"FinanceAnalysis-{self.id}", input={"system_prompt": self.system_prompt, "user_prompt_preview": user_prompt[:200]}, metadata={"node_id": self.id, "model": self.model}, ) generation = trace.generation( name="Financial Report Generation", model=self.model, model_parameters={"temperature": 0.2, "max_tokens": 1500}, input=[{"role": "system", "content": self.system_prompt}, {"role": "user", "content": user_prompt}], ) # 3. 调用OpenAI API try: response = self.client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": self.system_prompt}, {"role": "user", "content": user_prompt} ], temperature=0.2, max_tokens=1500, ) llm_output = response.choices[0].message.content # 4. 记录成功结果到Langfuse if generation: generation.end(output=llm_output) trace.update(output={"report": llm_output[:500]}) # 只记录预览 print(f"[{self.id}] LLM调用成功,结果已记录至Langfuse Trace: {trace.id}") else: print(f"[{self.id}] LLM调用成功 (Langfuse未启用)") # 5. 将结果存入状态 state[self.output_key] = llm_output # 也可以存储原始响应对象以备后用 state[f"{self.output_key}_raw"] = response except Exception as e: # 6. 记录失败信息到Langfuse if generation: generation.end(error=str(e)) trace.update(output={"error": str(e)}) print(f"[{self.id}] LLM调用失败: {e}") raise RuntimeError(f"LLM节点执行失败: {e}") from e finally: # 确保Langfuse客户端刷新数据 if langfuse_client: langfuse_client.flush() return state

3.3 实现Harness编排引擎

现在,我们将这些节点连接起来,构建一个简单的线性执行引擎。

# harness/engine.py from typing import List, Dict, Any from .core import Node, State import asyncio class Harness: """简单的线性工作流编排引擎。""" def __init__(self, name: str = "FinanceAgentHarness"): self.name = name self.nodes: List[Node] = [] self.state = State() def add_node(self, node: Node): """向工作流添加一个节点。""" self.nodes.append(node) return self # 支持链式调用 def set_initial_state(self, **kwargs): """设置工作流的初始状态。""" self.state.update(kwargs) async def run(self) -> State: """顺序执行所有节点。""" print(f"=== 开始执行工作流 [{self.name}] ===") current_state = self.state.copy() for i, node in enumerate(self.nodes): print(f"\n[{i+1}/{len(self.nodes)}] 执行节点: {node.id} ({node.description})") try: current_state = await node.execute(current_state) except Exception as e: print(f"!!! 节点 {node.id} 执行失败,工作流终止。错误: {e}") # 可以将错误状态记录到Langfuse if langfuse_client: langfuse_client.trace( name=f"HarnessError-{self.name}", input={"failed_node": node.id, "state_snapshot": str(current_state)}, output={"error": str(e)}, level="ERROR" ) langfuse_client.flush() raise print(f"\n=== 工作流 [{self.name}] 执行完成 ===") return current_state def visualize(self): """打印工作流的简单文本可视化。""" print(f"工作流: {self.name}") for i, node in enumerate(self.nodes): print(f" {i+1}. [{node.id}] -> {node.description}")

4. 完整实战:构建并运行财务分析智能体

现在,我们将所有部分组合起来,创建一个完整的可执行示例。

4.1 准备示例财务数据

创建一个示例CSV文件data/sample_finance_data.csv

period,revenue,cost_of_goods_sold,operating_expenses,net_income 2023-Q1,1000000,600000,250000,150000 2023-Q2,1200000,700000,280000,220000 2023-Q3,1100000,650000,260000,190000 2023-Q4,1300000,750000,300000,250000

4.2 定义提示词模板与工作流

创建主执行脚本main.py

# main.py import asyncio import sys import os sys.path.append(os.path.dirname(os.path.abspath(__file__))) from harness.engine import Harness from harness.nodes.tool_nodes import LoadCSVNode, CalculateMetricsNode from harness.nodes.llm_nodes import LangfuseLLMNode # 1. 定义分析报告提示词模板 FINANCIAL_ANALYSIS_PROMPT = """ 你是一名资深财务分析师。请基于以下财务数据和分析指标,生成一份简洁、专业的财务分析报告。 **基础数据概览:** - 数据期间: {periods} - 总记录数: {record_count} **计算出的关键指标(最新一期 {latest_period}):** - 营业收入: {revenue:,.2f} - 毛利润: {gross_profit:,.2f} - 毛利率: {gross_margin:.2%} - 净利润: {net_income:,.2f} - 净利率: {net_margin:.2%} {trend_analysis} **请按以下结构组织报告:** 1. **核心业绩摘要**:用2-3句话总结本期核心财务表现。 2. **盈利能力分析**:分析毛利率和净利率的水平及其含义。 3. **增长趋势洞察**:结合环比数据,评论营收和利润的增长趋势。 4. **潜在风险与关注点**:基于数据,指出1-2个可能的风险或需要关注的方面。 5. **后续建议**:给出1-2条具体的后续分析或行动建议。 报告请使用Markdown格式,确保数据准确,分析客观。 """ async def main(): # 2. 初始化Harness工作流 harness = Harness(name="QuarterlyFinancialAnalysis") # 3. 添加节点,定义执行流水线 harness.add_node( LoadCSVNode(id="load_data", file_path_key="input_file", output_key="df") ).add_node( CalculateMetricsNode(id="calc_metrics", df_key="df", metrics_key="basic_metrics") ).add_node( LangfuseLLMNode( id="generate_report", prompt_template=FINANCIAL_ANALYSIS_PROMPT, input_state_keys={ "periods": "periods_summary", # 这些键需要从状态中获取 "record_count": "record_count", "latest_period": "latest_period", "revenue": "revenue", "gross_profit": "gross_profit", "gross_margin": "gross_margin", "net_income": "net_income", "net_margin": "net_margin", "trend_analysis": "trend_text", }, output_key="analysis_report", system_prompt="你是一个严谨、客观的财务分析师,擅长从数据中发现洞察并以结构化的方式呈现。", model="gpt-4o-mini" # 或 gpt-3.5-turbo ) ) # 4. 准备初始状态,并补充LLM节点需要的额外数据 # 注意:LLM节点需要的数据,有些需要前面的节点生成,有些需要我们从原始数据中提取并放入状态。 # 我们可以在运行前设置一部分,另一部分通过一个“数据准备节点”或直接在运行中计算后注入。 # 这里我们采用一个简单方法:在运行工作流前,先手动计算一些衍生数据放入状态。 # 更优雅的方式是创建一个 `PrepareForLLMNode`。 initial_state = { "input_file": "data/sample_finance_data.csv", } harness.set_initial_state(**initial_state) # 5. 可视化工作流 print("构建的工作流如下:") harness.visualize() # 6. 执行工作流 try: final_state = await harness.run() except Exception as e: print(f"\n工作流执行因错误中断: {e}") return # 7. 打印最终结果 print("\n" + "="*50) print("财务分析报告生成完成!") print("="*50) if "analysis_report" in final_state: print(final_state["analysis_report"]) else: print("未生成报告。最终状态:", final_state.keys()) if __name__ == "__main__": asyncio.run(main())

4.3 运行智能体并查看结果

在终端运行:

python main.py

你将看到类似以下的输出(具体内容因模型随机性而异):

构建的工作流如下: 工作流: QuarterlyFinancialAnalysis 1. [load_data] -> 加载CSV文件为DataFrame 2. [calc_metrics] -> 计算财务指标(营收、毛利、净利等) 3. [generate_report] -> 调用LLM并生成分析报告 === 开始执行工作流 [QuarterlyFinancialAnalysis] === [1/3] 执行节点: load_data (加载CSV文件为DataFrame) [load_data] 已加载文件: data/sample_finance_data.csv, 形状: (4, 5) [2/3] 执行节点: calc_metrics (计算财务指标(营收、毛利、净利等)) [calc_metrics] 计算完成基础指标: { "latest_period": "2023-Q4", "revenue": 1300000.0, "gross_profit": 550000.0, "gross_margin": 0.4230769230769231, "net_income": 250000.0, "net_margin": 0.19230769230769232, "revenue_qoq": 0.18181818181818182, "net_income_qoq": 0.3157894736842105 } [3/3] 执行节点: generate_report (调用LLM并生成分析报告) [generate_report] LLM调用成功,结果已记录至Langfuse Trace: 01JXXXXXX === 工作流 [QuarterlyFinancialAnalysis] 执行完成 === ================================================== 财务分析报告生成完成! ================================================== # 财务分析报告 ## 1. 核心业绩摘要 2023年第四季度,公司实现营业收入130万元,净利润25万元。毛利率为42.31%,净利率为19.23%,整体盈利能力保持稳健。 ## 2. 盈利能力分析 本期毛利率为42.31%,表明公司产品或服务具有较强的市场竞争力,成本控制有效。净利率达到19.23%,在扣除运营费用后,仍保持了较高的利润留存率,整体盈利结构健康。 ## 3. 增长趋势洞察 与第三季度相比,第四季度营收环比增长约18.18%,净利润环比增长约31.58%,增速显著。这反映出公司在年末可能采取了有效的市场策略或成本优化措施,推动了利润的更快增长。 ## 4. 潜在风险与关注点 1. **成本压力**:尽管毛利率可观,但需持续关注原材料或直接成本(销售成本)的变动,其占营收比例仍超过57%。 2. **增长可持续性**:本季度的强劲增长是否具有可持续性,还是受季节性因素影响,需要结合更多历史数据和业务背景判断。 ## 5. 后续建议 1. **深入分析成本结构**:建议对销售成本(cost_of_goods_sold)进行细分,识别可优化的具体环节。 2. **制定2024年季度预算**:基于2023年的增长趋势,为2024年各季度设定合理的营收与利润目标,并建立监控机制。

4.4 在Langfuse平台查看追踪详情

  1. 登录你的Langfuse账户(云服务或自托管)。
  2. 进入“Traces”页面,你应该能看到一条名为FinanceAnalysis-generate_report的追踪记录。
  3. 点击进入,可以看到完整的追踪详情:
    • 输入:系统提示词和用户提示词(预览)。
    • 输出:生成的完整报告。
    • 元数据:节点ID、使用的模型。
    • 分析:Token使用量、成本、延迟。
  4. 你可以在“Prompts”部分管理你的提示词模板,并进行版本对比。
  5. 在“Evaluations”部分,可以基于本次输出创建评估(例如,让另一个LLM从“专业性”、“数据准确性”维度打分)。

5. 企业级评估平台搭建与AI工程化实践

仅仅生成报告和记录追踪是不够的。企业级应用需要系统化的评估、监控和迭代能力。下面我们利用Langfuse构建一个简单的评估流程。

5.1 定义自动化评估指标

我们可以为财务报告定义几个自动化评估维度:

  1. 格式合规性:报告是否包含要求的5个部分?(基于规则)
  2. 数据保真度:报告中引用的数字是否与输入数据一致?(基于LLM或规则)
  3. 专业性评分:报告的语言是否专业、客观?(基于LLM)

我们在项目中创建一个新的模块evaluation/evaluator.py

# evaluation/evaluator.py import re from typing import Dict, Any from langfuse import Langfuse from config import langfuse_client class ReportEvaluator: def __init__(self): self.client = langfuse_client def evaluate_format(self, report: str, required_sections: list) -> Dict[str, Any]: """评估报告格式是否包含所有必需章节。""" score = 100 feedback = [] missing_sections = [] for section in required_sections: # 简单检查章节标题是否存在于报告中 pattern = rf'^#+\s*{section}|^#+\s*\d+\.\s*{section}' if not re.search(pattern, report, re.IGNORECASE | re.MULTILINE): missing_sections.append(section) score -= 20 # 每缺一个章节扣20分 if missing_sections: feedback.append(f"报告缺少以下必需章节: {', '.join(missing_sections)}") else: feedback.append("报告格式完整,包含所有必需章节。") return { "score": max(0, score), "feedback": "; ".join(feedback), "details": {"missing_sections": missing_sections} } async def evaluate_data_fidelity(self, trace_id: str, original_metrics: Dict, report: str) -> Dict[str, Any]: """使用LLM评估报告中的数据是否与原始指标一致。""" if not self.client: return {"score": -1, "feedback": "Langfuse客户端未初始化,无法进行评估。"} # 从Langfuse获取该Trace的完整生成记录 # 注意:Langfuse Python SDK目前可能不直接支持通过ID查询Trace,这里为演示逻辑。 # 实际应用中,你可能需要在生成时保存更多上下文,或使用Langfuse API。 # 此处简化为直接调用一个新的LLM进行评估。 from openai import OpenAI from config import config client = OpenAI(api_key=config.OPENAI_API_KEY) evaluation_prompt = f""" 你是一个严谨的数据审计员。请对比以下两组信息: **【原始财务指标】**: {original_metrics} **【生成的财务分析报告】**: {report} 请判断报告中引用的核心数据(如营业收入、毛利率、净利润、增长率等)是否与原始指标**完全一致**。 注意:报告可能对数字进行格式化(如添加千分位逗号)或使用近似表述(如“约42%”),这不算错误。 请只检查是否存在**事实性矛盾**(例如,原始数据是130万,报告写成120万)。 请按以下格式回答: 一致性结论: [是/否] 得分: (0-100分,100分为完全一致) 不一致详情: [如果结论为“否”,请列出具体不一致的数据点;否则写“无”] """ try: response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": evaluation_prompt}], temperature=0, max_tokens=500, ) result_text = response.choices[0].message.content # 简单解析结果(实际应用需更健壮的解析) score = 100 feedback = "数据一致性评估完成。" if "一致性结论: 否" in result_text: score = 50 # 假设不一致则给50分 feedback = "检测到报告中的数据与原始指标存在潜在不一致。" # 可以将此次评估也记录到Langfuse,关联到原始Trace if self.client and trace_id: self.client.score( trace_id=trace_id, name="data_fidelity", value=score, comment=feedback, ) return {"score": score, "feedback": feedback, "details": result_text} except Exception as e: return {"score": -1, "feedback": f"数据一致性评估失败: {e}"} def log_evaluation_to_langfuse(self, trace_id: str, evaluation_name: str, score: float, comment: str = ""): """将评估分数记录到Langfuse对应的Trace上。""" if self.client and trace_id: try: self.client.score( trace_id=trace_id, name=evaluation_name, value=score, comment=comment, ) print(f"[评估已记录] Trace: {trace_id}, 指标: {evaluation_name}, 分数: {score}") except Exception as e: print(f"记录评估分数到Langfuse失败: {e}")

5.2 集成评估到主工作流

修改main.py,在工作流执行后自动触发评估。

# 在 main.py 的 main() 函数末尾,打印报告后添加: # ... 原有打印报告的代码 ... # 8. 执行自动化评估 if "analysis_report" in final_state and langfuse_client: print("\n" + "="*50) print("开始自动化报告评估...") print("="*50) evaluator = ReportEvaluator() report = final_state["analysis_report"] # 评估1:格式合规性 required_sections = ["核心业绩摘要", "盈利能力分析", "增长趋势洞察", "潜在风险与关注点", "后续建议"] format_result = evaluator.evaluate_format(report, required_sections) print(f"格式评估得分: {format_result['score']}/100 - {format_result['feedback']}") # 记录分数到Langfuse (需要trace_id) trace_id = "从final_state或全局变量中获取" # 实际需要从LLM节点执行时获取并传递 # evaluator.log_evaluation_to_langfuse(trace_id, "format_compliance", format_result['score']) # 评估2:数据保真度 (异步) # 需要获取原始指标和trace_id # original_metrics = final_state.get('basic_metrics', {}) # fidelity_result = await evaluator.evaluate_data_fidelity(trace_id, original_metrics, report) # print(f"数据一致性评估得分: {fidelity_result['score']}/100 - {fidelity_result['feedback']}") print("自动化评估完成。请登录Langfuse平台查看详细追踪与评分。")

5.3 构建评估看板与持续迭代

在Langfuse平台上,你可以:

  1. 创建Dashboard:监控“报告生成延迟”、“平均格式得分”、“数据一致性得分”等核心指标。
  2. 设置警报:当评估分数低于阈值(如格式分<80)时,发送通知。
  3. Prompt版本管理:在Langfuse的“Prompts”中迭代你的FINANCIAL_ANALYSIS_PROMPT,并对比不同版本生成报告的质量。
  4. 人工反馈集成:在生成的报告旁提供“拇指向上/下”按钮,收集人工反馈,并将其作为评估信号。

通过这一套组合,你就建立了一个“开发(Harness) -> 运行 -> 观测与评估(Langfuse) -> 迭代优化”的完整AI工程化闭环。

6. 常见问题与排查思路

在实际部署和运行中,你可能会遇到以下问题:

问题现象可能原因排查思路与解决方案
运行时报ModuleNotFoundError: No module named 'harness'自定义的harness模块路径未正确加入Python路径。1. 确保在项目根目录下运行脚本。
2. 在main.py开头使用sys.path.append添加项目根目录,或使用PYTHONPATH环境变量。
3. 检查__init__.py文件是否存在于harness/harness/nodes/目录下。
Langfuse追踪未显示在控制台1. API密钥错误或未配置。
2. 网络问题。
3. Langfuse客户端初始化失败。
1. 检查.env文件中的LANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEY是否正确。
2. 检查config.pyget_langfuse_client方法的错误打印。
3. 尝试在代码中暂时禁用Langfuse,确认基础功能正常。
LLM节点调用超时或报错1. OpenAI API密钥无效或余额不足。
2. 网络连接问题。
3. 模型名称错误或不可用。
1. 在OpenAI平台验证API密钥状态和额度。
2. 尝试使用curlopenai库的简单测试脚本确认API连通性。
3. 确认model参数是有效的模型名(如gpt-3.5-turbo)。
提示词模板格式化报KeyErrorinput_state_keys中定义的键在节点执行时,状态中不存在。1. 仔细检查input_state_keys的映射关系。确保上游节点(如CalculateMetricsNode)的输出键与映射中state_key一致。
2. 在LangfuseLLMNode.execute方法开始处打印state.keys()进行调试。
财务指标计算逻辑错误CSV文件列名与代码中required_cols不匹配,或数据格式非数值。1. 打印加载后的DataFramecolumnsdtypes进行确认。
2. 在CalculateMetricsNode中添加更严格的数据类型校验和转换。
评估分数未关联到Tracetrace_id未正确传递到ReportEvaluator1. 修改LangfuseLLMNode,在执行成功后,将trace.id存入state(如state['trace_id'] = trace.id)。
2. 在工作流最终状态中将trace_id传递给评估器。

7. 最佳实践与工程化建议

将此类AI智能体项目投入生产环境,需要遵循以下工程化实践:

7.1 项目结构与代码组织

  • 清晰的模块化:正如本文所示,将引擎、节点、配置、评估逻辑分离。nodes/目录下可按功能进一步细分,如tools/,llms/,conditions/
  • 配置外部化:所有API密钥、模型参数、文件路径、提示词模板都应通过.env或配置中心(如Apollo)管理,严禁硬编码。
  • 依赖管理:使用requirements.txtpyproject.toml精确锁定依赖版本,避免环境差异导致运行失败。

7.2 提示词工程与管理

  • 版本控制:将提示词模板存储在代码库或Langfuse等专用平台中,并进行版本控制。每次修改都应记录原因和预期效果。
  • 变量化与验证:像本文一样,使用明确的变量占位符({variable}),并在填充前验证状态中是否存在对应数据,避免运行时错误。
  • 系统提示词设计:系统提示词(system_prompt)是塑造AI行为的关键。它应明确角色、任务边界、输出格式和禁忌。

7.3 可观测性与监控

  • 全链路追踪:务必为每个LLM调用、关键工具调用记录追踪。除了输入输出,还应记录延迟、Token用量和成本。
  • 定义业务指标:在Langfuse中创建与业务价值直接相关的评估指标(Score),如“报告格式合规分”、“数据准确分”、“用户满意度分”。通过看板持续监控。
  • 设置警报:对错误率、高延迟、成本突增、评估分下降设置阈值告警。

7.4 错误处理与韧性

  • 节点级容错:每个Nodeexecute方法应有完善的try-except,捕获可能异常,并决定是向上抛出终止流程,还是记录错误后返回降级结果。
  • 重试与退避:对于LLM API调用等可能因网络或速率限制失败的操作,实现带指数退避的重试机制。
  • 状态快照与回滚:复杂的Harness引擎应支持将执行状态持久化,在失败时可以从上一个成功节点恢复,而不是从头开始。

7.5 安全与合规

  • 数据脱敏:财务数据高度敏感。在将数据发送给外部LLM API前,必须进行严格的脱敏处理(如替换真实公司名、金额缩放)。对于极高敏感数据,考虑使用本地模型。
  • 权限控制:确保只有授权用户能触发智能体工作流,并能访问生成的报告和原始数据。
  • 审计日志:所有智能体的触发、输入、输出、执行人、时间都应记录到不可篡改的审计日志中,满足合规要求。

7.6 性能与成本优化

  • 缓存策略:对于相同输入可能产生相同输出的LLM调用或计算节点,考虑引入缓存(如Redis),显著降低成本和延迟。
  • 模型选型:并非所有任务都需要最强大的模型。对于数据提取、格式转换等简单任务,可使用更小、更快的模型(如gpt-3.5-turbo)。
  • 异步执行:如果工作流中节点间没有强依赖,可以将其设计为异步并行执行,缩短整体耗时。

通过本文的实战,你不仅学会了一个财务分析智能体的构建,更掌握了一套基于Harness架构思想与Langfuse评估平台的AI工程化落地方法论。这套方法论可以平移到客服、营销、运维、代码生成等几乎所有AI智能体应用场景。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询