up readme

This commit is contained in:
jinli.yl 2025-07-15 19:48:52 +08:00
parent 7832f20d41
commit acb2262bb8
10 changed files with 0 additions and 1444 deletions

View file

@ -1 +0,0 @@
__version__ = "0.1.0"

View file

@ -1,81 +0,0 @@
#!/usr/bin/env python3
"""
金融分析师Agent使用示例
"""
import sys
from experiencemaker.utils.util_function import load_env_keys
load_env_keys("../../.env")
# 添加项目根目录到Python路径
# project_root = Path(__file__).parent.parent
# sys.path.insert(0, str(project_root))
sys.path.append(".")
from financial_agent import FinancialAgent
def main():
"""主函数"""
# 加载环境变量
load_env_keys()
# 初始实体列表
init_entity_list = [
"美元债务",
"美债利率",
"美元指数",
"工业金属银、铜、铝",
"黄金",
"稳定币",
"石油",
"能源",
"军工",
"海运",
]
# 创建金融分析师Agent
agent = FinancialAgent(
model_name="qwen-max-2025-01-25",
verbose=True
)
# 执行知识图谱构建
output_file = "金融知识图谱.jsonl"
stats = agent.execute(
init_entity_list=init_entity_list,
dump_file_path=output_file,
max_iter=5, # 减少迭代次数用于演示
search_strategy="mixed"
)
print("\n" + "=" * 50)
print("执行结果统计:")
print(f"总实体数: {stats['total_entities']}")
print(f"总关系数: {stats['total_relations']}")
print(f"新增关系数: {stats['new_relations']}")
print(f"迭代次数: {stats['iterations']}")
print("=" * 50)
# 查询示例
print("\n查询示例:")
query_results = agent.query_knowledge_graph("美元")
print(f"包含'美元'的关系数量: {len(query_results)}")
# 获取特定实体的关系
print("\n美元指数的关系:")
usd_relations = agent.get_entity_relations("美元指数")
for i, relation in enumerate(usd_relations[:3]): # 只显示前3个
print(f"{i + 1}. {relation}")
# 生成可视化图表
print("\n生成可视化图表...")
agent.visualize("financial_knowledge_graph.html")
print(f"\n知识图谱已保存到: {output_file}")
print("可视化图表已保存到: financial_knowledge_graph.html")
if __name__ == "__main__":
main()

View file

@ -1,345 +0,0 @@
"""
金融分析师Agent主类
"""
import datetime
import json
import re
from typing import List, Dict
from loguru import logger
from experiencemaker.enumeration.role import Role
from experiencemaker.model import OpenAICompatibleBaseLLM
from experiencemaker.schema.trajectory import Message
from experiencemaker.tool import CodeTool, DashscopeSearchTool
from knowledge_graph import KnowledgeGraphBuilder
from schema import FinancialRelation
class FinancialAgent:
"""金融分析师Agent"""
def __init__(self, model_name: str = "qwen-max-2025-01-25", verbose: bool = True):
"""初始化金融分析师Agent"""
self.llm = OpenAICompatibleBaseLLM(model_name=model_name)
self.search_tool = DashscopeSearchTool()
self.code_tool = CodeTool()
self.tools = [self.search_tool, self.code_tool]
self.verbose = verbose
# 知识图谱构建器
self.knowledge_graph = KnowledgeGraphBuilder()
# 系统提示词
self.system_prompt = """你是一个专业的金融分析师,专门负责分析金融市场中各种实体之间的逻辑关系。
你的任务:
1. 通过搜索发现多个实体之间的逻辑关系
2. 不断补充新的实体到实体列表中
3. 将多跳的实体关系拆分成多个单跳的实体关系
实体关系格式:
{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向、负向、中性",
"reasoning": "实体1和实体2是通过什么样的逻辑影响到实体3和实体4",
"source": "来源",
"confidence": "置信度(0-1)",
"timestamp": "时间戳",
}
请确保:
- 关系描述准确、具体
- 置信度合理评估
- 来源信息完整
- 时间戳格式:YYYY-MM-DD HH:MM:SS
- 多跳关系要拆分成多个单跳关系
"""
def _search_entity_relations(self, entity_list: List[str]) -> List[FinancialRelation]:
"""搜索实体间的关系"""
if self.verbose:
logger.info(f"Searching relations for entities: {entity_list[:5]}...")
# 构建搜索查询
entities_str = "、".join(entity_list[:5]) # 限制实体数量
query = f"请分析以下金融实体之间的关系:{entities_str}。请详细说明它们之间的逻辑关系,包括正向、负向或中性的影响关系。"
# 使用搜索工具
try:
search_result = self.search_tool.execute(query=query)
if self.verbose:
logger.info(f"Search completed, result length: {len(str(search_result))}")
except Exception as e:
logger.error(f"Search failed: {e}")
return []
# 使用LLM分析搜索结果并提取关系
analysis_prompt = f"""
基于以下搜索结果,请分析金融实体之间的关系:
搜索结果:
{search_result[:10000]}
当前实体列表:
{entity_list[:100]}
请提取出实体间的关系,格式如下(JSON格式):
{{
"relations": [
{{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向/负向/中性",
"reasoning": "详细的分析逻辑",
"source": "信息来源",
"confidence": 0.8
}}
],
"new_entities": ["新实体1", "新实体2"]
}}
请确保:
1. 关系描述准确具体
2. 置信度在0-1之间
3. 如果发现新的相关实体,请添加到new_entities中
4. 只返回JSON格式,不要其他内容
5. 多跳关系要拆分成多个单跳关系
"""
messages = [
Message(role=Role.SYSTEM, content=self.system_prompt),
Message(role=Role.USER, content=analysis_prompt)
]
try:
response = self.llm.chat(messages, self.tools)
# 尝试解析JSON响应
content = str(response.content)
json_match = re.search(r'\{.*\}', content, re.DOTALL)
if json_match:
data = json.loads(json_match.group())
relations = []
for rel_data in data.get("relations", []):
try:
relation = FinancialRelation(
input_entities=rel_data["input_entities"],
output_entities=rel_data["output_entities"],
relation=rel_data["relation"],
reasoning=rel_data["reasoning"],
source=rel_data["source"],
confidence=rel_data["confidence"],
timestamp=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
relations.append(relation)
except Exception as e:
logger.exception(f"Failed to create relation: {e}, data: {rel_data}")
# 添加新实体
for new_entity in data.get("new_entities", []):
self.knowledge_graph.entities.add(new_entity)
if self.verbose:
logger.info(
f"Extracted {len(relations)} relations and {len(data.get('new_entities', []))} new entities")
return relations
except Exception as e:
logger.error(f"Error parsing LLM response: {e}")
if self.verbose:
logger.error(f"Response content: {response.content if 'response' in locals() else 'No response'}")
return []
def _search_specific_entity_pairs(self, entity_pairs: List[List[str]]) -> List[FinancialRelation]:
"""搜索特定实体对之间的关系"""
all_relations = []
for pair in entity_pairs:
if len(pair) < 2:
continue
query = f"请分析{pair[0]}和{pair[1]}之间的金融关系,包括它们如何相互影响,以及对其他金融实体的影响。"
try:
search_result = self.search_tool.execute(query=query)
analysis_prompt = f"""
基于搜索结果,分析{pair[0]}和{pair[1]}之间的关系:
搜索结果:
{search_result[:800] if isinstance(search_result, str) else str(search_result)[:800]}
请提取关系,格式如下(JSON格式):
{{
"relations": [
{{
"input_entities": ["{pair[0]}", "{pair[1]}"],
"output_entities": ["影响实体1", "影响实体2"],
"relation": "正向/负向/中性",
"reasoning": "详细分析",
"source": "来源",
"confidence": 0.8
}}
]
}}
只返回JSON格式。
"""
messages = [
Message(role=Role.SYSTEM, content=self.system_prompt),
Message(role=Role.USER, content=analysis_prompt)
]
response = self.llm.chat(messages, self.tools)
content = str(response.content)
json_match = re.search(r'\{.*\}', content, re.DOTALL)
if json_match:
data = json.loads(json_match.group())
for rel_data in data.get("relations", []):
try:
relation = FinancialRelation(
input_entities=rel_data["input_entities"],
output_entities=rel_data["output_entities"],
relation=rel_data["relation"],
reasoning=rel_data["reasoning"],
source=rel_data["source"],
confidence=rel_data["confidence"],
timestamp=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
all_relations.append(relation)
except Exception as e:
logger.warning(f"Failed to create relation: {e}")
except Exception as e:
logger.error(f"Error searching pair {pair}: {e}")
return all_relations
def _generate_entity_pairs(self, entity_list: List[str], max_pairs: int = 10) -> List[List[str]]:
"""生成实体对用于搜索"""
pairs = []
entities = list(entity_list)
# 生成所有可能的二元组合
for i in range(len(entities)):
for j in range(i + 1, len(entities)):
pairs.append([entities[i], entities[j]])
if len(pairs) >= max_pairs:
break
if len(pairs) >= max_pairs:
break
return pairs
def execute(self, init_entity_list: List[str], dump_file_path: str, max_iter: int = 10,
search_strategy: str = "mixed") -> Dict:
"""
执行金融知识图谱构建
Args:
init_entity_list: 初始实体列表
dump_file_path: 输出文件路径
max_iter: 最大迭代次数
search_strategy: 搜索策略 ("general", "pairs", "mixed")
Returns:
执行结果统计
"""
logger.info(f"Starting financial knowledge graph construction with {len(init_entity_list)} initial entities")
# 1. 初始化实体列表
self.knowledge_graph.entities = set(init_entity_list)
# 2. 加载历史数据
self.knowledge_graph.load_from_jsonl(dump_file_path)
# 3. 迭代搜索
iteration = 0
total_new_relations = 0
while iteration < max_iter:
iteration += 1
logger.info(f"Iteration {iteration}/{max_iter}")
new_relations_count = 0
if search_strategy in ["general", "mixed"]:
# 通用搜索
entity_list = list(self.knowledge_graph.entities)
relations = self._search_entity_relations(entity_list)
for relation in relations:
if self.knowledge_graph.add_relation(relation):
new_relations_count += 1
if search_strategy in ["pairs", "mixed"] and iteration % 2 == 0:
# 实体对搜索
entity_list = list(self.knowledge_graph.entities)
entity_pairs = self._generate_entity_pairs(entity_list, max_pairs=5)
relations = self._search_specific_entity_pairs(entity_pairs)
for relation in relations:
if self.knowledge_graph.add_relation(relation):
new_relations_count += 1
total_new_relations += new_relations_count
logger.info(f"Added {new_relations_count} new relations in iteration {iteration}")
# 检查是否还有新的关系可以添加
if new_relations_count == 0:
logger.info("No new relations found, stopping iteration")
break
# 保存中间结果
self.knowledge_graph.export_to_jsonl(dump_file_path)
# 4. 保存最终结果
self.knowledge_graph.export_to_jsonl(dump_file_path)
# 5. 生成统计信息
stats = self.knowledge_graph.get_entity_statistics()
stats["new_relations"] = total_new_relations
stats["iterations"] = iteration
logger.info(f"Financial knowledge graph construction completed!")
logger.info(f"Total entities: {stats['total_entities']}")
logger.info(f"Total relations: {stats['total_relations']}")
logger.info(f"New relations added: {total_new_relations}")
return stats
def query_knowledge_graph(self, query: str) -> List[FinancialRelation]:
"""查询知识图谱"""
# 简单的关键词匹配查询
query_lower = query.lower()
results = []
for relation in self.knowledge_graph.relations:
# 检查输入实体、输出实体、推理过程是否包含查询关键词
all_text = " ".join([
" ".join(relation.input_entities),
" ".join(relation.output_entities),
relation.reasoning,
relation.source
]).lower()
if query_lower in all_text:
results.append(relation)
return results
def get_entity_relations(self, entity: str) -> List[FinancialRelation]:
"""获取特定实体的所有关系"""
return self.knowledge_graph.find_related_entities(entity)
def visualize(self, output_path: str = "financial_knowledge_graph.html"):
"""生成可视化图表"""
self.knowledge_graph.visualize_graph(output_path)

View file

@ -1,238 +0,0 @@
"""
金融知识图谱构建器
"""
import hashlib
import json
import os
from typing import List, Set, Dict
from schema import FinancialRelation
class KnowledgeGraphBuilder:
"""金融知识图谱构建器"""
def __init__(self):
"""初始化知识图谱构建器"""
self.entities: Set[str] = set()
self.relations: List[FinancialRelation] = []
self.relation_hashes: Set[str] = set() # 用于去重
self.entity_aliases: Dict[str, Set[str]] = {} # 实体别名映射
def _generate_relation_hash(self, relation: FinancialRelation) -> str:
"""生成关系的哈希值用于去重"""
content = f"{sorted(relation.input_entities)}_{sorted(relation.output_entities)}_{relation.relation}_{relation.reasoning}"
return hashlib.md5(content.encode()).hexdigest()
def add_relation(self, relation: FinancialRelation) -> bool:
"""添加关系,如果重复则返回False"""
relation_hash = self._generate_relation_hash(relation)
if relation_hash in self.relation_hashes:
return False
self.relation_hashes.add(relation_hash)
self.relations.append(relation)
# 添加新实体到实体列表
for entity in relation.input_entities + relation.output_entities:
self.entities.add(entity)
return True
def add_entity_alias(self, main_entity: str, aliases: List[str]):
"""添加实体别名"""
if main_entity not in self.entity_aliases:
self.entity_aliases[main_entity] = set()
for alias in aliases:
self.entity_aliases[main_entity].add(alias)
self.entities.add(alias)
def get_entity_aliases(self, entity: str) -> Set[str]:
"""获取实体的所有别名"""
for main_entity, aliases in self.entity_aliases.items():
if entity in aliases or entity == main_entity:
return aliases | {main_entity}
return {entity}
def find_related_entities(self, entity: str, max_depth: int = 2) -> List[FinancialRelation]:
"""查找与指定实体相关的所有关系"""
related_relations = []
visited_entities = set()
entities_to_check = {entity}
for depth in range(max_depth):
current_entities = entities_to_check.copy()
entities_to_check.clear()
for relation in self.relations:
# 检查关系是否涉及当前实体
relation_entities = set(relation.input_entities + relation.output_entities)
if relation_entities & current_entities:
related_relations.append(relation)
# 添加新的实体到下一轮检查
entities_to_check.update(relation_entities - visited_entities)
visited_entities.update(current_entities)
if not entities_to_check:
break
return related_relations
def get_entity_statistics(self) -> Dict:
"""获取实体统计信息"""
return {
"total_entities": len(self.entities),
"total_relations": len(self.relations),
"unique_relations": len(self.relation_hashes),
"entity_aliases": len(self.entity_aliases)
}
def export_to_jsonl(self, file_path: str):
"""导出到JSONL文件"""
# os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
for relation in self.relations:
f.write(json.dumps(relation.to_dict(), ensure_ascii=False) + '\n')
def load_from_jsonl(self, file_path: str):
"""从JSONL文件加载"""
if not os.path.exists(file_path):
return
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line:
data = json.loads(line)
relation = FinancialRelation.from_dict(data)
self.add_relation(relation)
def export_to_networkx_format(self) -> Dict:
"""导出为NetworkX可用的格式"""
nodes = []
edges = []
# 添加节点
for entity in self.entities:
nodes.append({
"id": entity,
"label": entity,
"type": "entity"
})
# 添加边
for i, relation in enumerate(self.relations):
for input_entity in relation.input_entities:
for output_entity in relation.output_entities:
edges.append({
"source": input_entity,
"target": output_entity,
"relation": relation.relation,
"reasoning": relation.reasoning,
"confidence": relation.confidence,
"source_info": relation.source,
"timestamp": relation.timestamp
})
return {
"nodes": nodes,
"edges": edges,
"metadata": self.get_entity_statistics()
}
def visualize_graph(self, output_path: str = "financial_knowledge_graph.html"):
"""生成可视化图表(HTML格式)"""
try:
import plotly.graph_objects as go
import networkx as nx
# 创建NetworkX图
G = nx.DiGraph()
# 添加节点
for entity in self.entities:
G.add_node(entity)
# 添加边
for relation in self.relations:
for input_entity in relation.input_entities:
for output_entity in relation.output_entities:
G.add_edge(
input_entity,
output_entity,
relation=relation.relation,
confidence=relation.confidence
)
# 使用spring布局
pos = nx.spring_layout(G, k=1, iterations=50)
# 创建边轨迹
edge_x = []
edge_y = []
edge_text = []
for edge in G.edges(data=True):
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
edge_text.append(f"{edge[0]} → {edge[1]} ({edge[2]['relation']})")
edge_trace = go.Scatter(
x=edge_x, y=edge_y,
line=dict(width=0.5, color='#888'),
hoverinfo='text',
text=edge_text,
mode='lines')
# 创建节点轨迹
node_x = []
node_y = []
node_text = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
node_text.append(node)
node_trace = go.Scatter(
x=node_x, y=node_y,
mode='markers+text',
hoverinfo='text',
text=node_text,
textposition="top center",
marker=dict(
showscale=True,
colorscale='YlGnBu',
size=10,
color=[],
line_width=2))
# 设置节点颜色
node_adjacency_list = []
for node in G.nodes():
node_adjacency_list.append(len(list(G.neighbors(node))))
node_trace.marker.color = node_adjacency_list
# 创建图形
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
title='金融知识图谱',
showlegend=False,
hovermode='closest',
margin=dict(b=20, l=5, r=5, t=40),
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
)
fig.write_html(output_path)
print(f"知识图谱已保存到: {output_path}")
except ImportError:
print("需要安装 plotly 和 networkx 来生成可视化图表")
print("运行: pip install plotly networkx")

View file

@ -1,46 +0,0 @@
"""
金融实体关系的schema定义
"""
from dataclasses import dataclass
from typing import List
@dataclass
class FinancialRelation:
"""金融实体关系的数据结构"""
input_entities: List[str]
output_entities: List[str]
relation: str # "正向", "负向", "中性"
reasoning: str
source: str
confidence: float
timestamp: str
def __post_init__(self):
"""初始化后的验证"""
if not isinstance(self.confidence, (int, float)) or not 0 <= self.confidence <= 1:
raise ValueError("confidence must be a float between 0 and 1")
if self.relation not in ["正向", "负向", "中性"]:
raise ValueError("relation must be one of: 正向, 负向, 中性")
def to_dict(self):
"""转换为字典格式"""
return {
"input_entities": self.input_entities,
"output_entities": self.output_entities,
"relation": self.relation,
"reasoning": self.reasoning,
"source": self.source,
"confidence": self.confidence,
"timestamp": self.timestamp
}
@classmethod
def from_dict(cls, data: dict):
"""从字典创建实例"""
return cls(**data)
def __str__(self):
return f"{self.input_entities} -> {self.output_entities} ({self.relation}, 置信度: {self.confidence})"

View file

@ -1,171 +0,0 @@
# 金融分析师Agent
一个智能的金融分析师Agent,能够通过搜索和分析构建金融知识图谱,发现金融实体之间的逻辑关系。
## 功能特性
- 🔍 **智能搜索**: 使用大模型和搜索工具发现金融实体关系
- 🧠 **知识图谱构建**: 自动构建和更新金融知识图谱
- 🔗 **关系分析**: 分析正向、负向、中性关系
- 📊 **可视化**: 生成交互式知识图谱可视化
- 🔄 **迭代优化**: 支持多轮迭代,不断丰富知识图谱
- 📝 **数据导出**: 支持JSONL格式导出
## 安装
1. 克隆项目并安装依赖:
```bash
pip install -r financial_agent/requirements.txt
```
2. 设置环境变量:
```bash
export OPENAI_API_KEY="your_openai_api_key"
export OPENAI_BASE_URL="your_openai_base_url"
export DASHSCOPE_API_KEY="your_dashscope_api_key"
```
## 快速开始
### 基本使用
```python
from financial_agent import FinancialAgent
# 创建Agent
agent = FinancialAgent(model_name="qwen-max-2025-01-25")
# 初始实体列表
init_entities = ["美元债务", "美债利率", "美元指数", "黄金", "石油"]
# 执行知识图谱构建
stats = agent.execute(
init_entity_list=init_entities,
dump_file_path="金融知识图谱.jsonl",
max_iter=10,
search_strategy="mixed"
)
print(f"构建完成!总实体数: {stats['total_entities']}, 总关系数: {stats['total_relations']}")
```
### 运行示例
```bash
python financial_agent/example.py
```
## 核心组件
### FinancialAgent
主要的金融分析师Agent类,负责:
- 搜索和分析金融实体关系
- 构建和更新知识图谱
- 提供查询接口
### FinancialRelation
金融实体关系的数据结构:
```python
{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向、负向、中性",
"reasoning": "关系推理过程",
"source": "信息来源",
"confidence": "置信度(0-1)",
"timestamp": "时间戳"
}
```
### KnowledgeGraphBuilder
知识图谱构建器,提供:
- 关系去重和验证
- 实体别名管理
- 图谱查询和统计
- 可视化生成
## 配置选项
### 搜索策略
- `"general"`: 通用搜索,分析多个实体间的关系
- `"pairs"`: 实体对搜索,专注于特定实体对
- `"mixed"`: 混合策略,结合两种方法
### 模型配置
支持多种大模型:
- `qwen-max-2025-01-25`
- `qwen3-32b`
- 其他OpenAI兼容模型
## 输出格式
### JSONL文件格式
每行一个JSON对象,包含完整的金融关系信息:
```jsonl
{"input_entities": ["美债利率", "美元债务"], "output_entities": ["美元指数"], "relation": "负向", "reasoning": "美债利率上升和美元债务增加会导致美元走弱", "source": "金融分析报告", "confidence": 0.85, "timestamp": "2024-01-15 10:30:00"}
{"input_entities": ["石油价格", "美元指数"], "output_entities": ["通胀预期"], "relation": "正向", "reasoning": "石油价格上涨和美元走弱会推高通胀预期", "source": "经济分析", "confidence": 0.78, "timestamp": "2024-01-15 10:31:00"}
```
### 可视化输出
生成交互式HTML图表,支持:
- 节点拖拽
- 关系查看
- 缩放和平移
- 悬停信息显示
## API参考
### FinancialAgent.execute()
执行知识图谱构建:
```python
def execute(self, init_entity_list: List[str], dump_file_path: str,
max_iter: int = 10, search_strategy: str = "mixed") -> Dict
```
### FinancialAgent.query_knowledge_graph()
查询知识图谱:
```python
def query_knowledge_graph(self, query: str) -> List[FinancialRelation]
```
### FinancialAgent.get_entity_relations()
获取特定实体的关系:
```python
def get_entity_relations(self, entity: str) -> List[FinancialRelation]
```
## 使用场景
1. **金融研究**: 自动发现金融市场中的实体关系
2. **投资分析**: 分析投资标的之间的相互影响
3. **风险管理**: 识别风险传导路径
4. **政策分析**: 分析政策对市场的影响机制
## 注意事项
1. **API限制**: 注意搜索API的调用频率限制
2. **数据质量**: 建议对生成的关系进行人工验证
3. **成本控制**: 大模型调用会产生费用,注意控制迭代次数
4. **环境配置**: 确保正确配置API密钥和基础URL
## 贡献
欢迎提交Issue和Pull Request来改进项目!
## 许可证
MIT License

View file

@ -1,77 +0,0 @@
entity_list = [
"美元债务",
"美债利率",
"美元指数",
"工业金属银、铜、铝",
"黄金",
"稳定币",
"石油",
"能源",
"军工",
"海运",
]
"""
现在初始状态你有以下的实体列表:
美元债务
美债利率
美元指数
工业金属银、铜、铝
黄金
稳定币
石油
能源
军工
海运
你有一个大模型调用的Client
from experiencemaker.model import OpenAICompatibleBaseLLM
你有两个工具:
1. 代码执行工具
from experiencemaker.tool import CodeTool
2. web search工具
from experiencemaker.tool import DashscopeSearchTool
请你根据以上内容,设计一个金融分析师的Agent,并给出Agent的代码。
Agent的任务:
1. 通过不断的搜索,发现多个实体之间的逻辑关系,例如“美债利率高”、“美元债务高”会让美元变弱,从而导致“美元指数”变弱。
2. 同时通过不断的搜索,不断的补充新的实体到**实体列表**。
3. 多跳的实体关系,可以拆成多个单跳的实体关系。
实体关系的schema如下:
{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向、负向、中性",
"reasoning": "实体1和实体2是通过什么样的逻辑影响到实体3和实体4",
"source": "来源",
"confidence": "置信度",
"timestamp": "时间戳",
}
最后这些schema的list会变成一个jsonl文件,文件名是:
金融知识图谱.jsonl
```python
class FinAgent(object):
def execute(self, init_entity_list: list[str], dump_file_path: str, max_iter: int = 100):
# init_entity_list 是初始的实体列表
# dump_file_path 是最终的jsonl文件路径
# max_iter 是最大迭代次数
# 1. 初始化实体列表
# 2. 读取dump_file_path中历史的金融知识图谱(如果有),加载到内容
# 2. 迭代搜索,不断更新已有的知识图谱,不断补充新的知识图谱,不断增加新的实体(和已有的语义去重)
# 3. 迭代到max_iter次,或者没有新的知识图谱可以补充,则停止迭代, 保存到dump_file_path中
pass
```
帮忙把整个project写一下
"""

View file

@ -1,294 +0,0 @@
#!/usr/bin/env python3
"""
金融分析师Agent测试脚本
"""
import json
import os
import datetime
from typing import List, Dict, Set
from dataclasses import dataclass
import hashlib
import re
from experiencemaker.model import OpenAICompatibleBaseLLM
from experiencemaker.tool import CodeTool, DashscopeSearchTool
from experiencemaker.schema.trajectory import Message
from experiencemaker.enumeration.role import Role
@dataclass
class FinancialRelation:
"""金融实体关系的数据结构"""
input_entities: List[str]
output_entities: List[str]
relation: str # "正向", "负向", "中性"
reasoning: str
source: str
confidence: float
timestamp: str
class FinancialAgent:
"""金融分析师Agent"""
def __init__(self, model_name: str = "qwen-max-2025-01-25"):
"""初始化金融分析师Agent"""
self.llm = OpenAICompatibleBaseLLM(model_name=model_name)
self.search_tool = DashscopeSearchTool()
self.code_tool = CodeTool()
self.tools = [self.search_tool, self.code_tool]
# 存储实体和关系
self.entities: Set[str] = set()
self.relations: List[FinancialRelation] = []
self.relation_hashes: Set[str] = set() # 用于去重
# 系统提示词
self.system_prompt = """你是一个专业的金融分析师,专门负责分析金融市场中各种实体之间的逻辑关系。
你的任务:
1. 通过搜索发现多个实体之间的逻辑关系
2. 不断补充新的实体到实体列表中
3. 将多跳的实体关系拆分成多个单跳的实体关系
实体关系格式:
{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向、负向、中性",
"reasoning": "实体1和实体2是通过什么样的逻辑影响到实体3和实体4",
"source": "来源",
"confidence": "置信度(0-1)",
"timestamp": "时间戳",
}
请确保:
- 关系描述准确、具体
- 置信度合理评估
- 来源信息完整
- 时间戳格式:YYYY-MM-DD HH:MM:SS
"""
def _generate_relation_hash(self, relation: FinancialRelation) -> str:
"""生成关系的哈希值用于去重"""
content = f"{sorted(relation.input_entities)}_{sorted(relation.output_entities)}_{relation.relation}_{relation.reasoning}"
return hashlib.md5(content.encode()).hexdigest()
def _add_relation(self, relation: FinancialRelation) -> bool:
"""添加关系,如果重复则返回False"""
relation_hash = self._generate_relation_hash(relation)
if relation_hash in self.relation_hashes:
return False
self.relation_hashes.add(relation_hash)
self.relations.append(relation)
# 添加新实体到实体列表
for entity in relation.input_entities + relation.output_entities:
self.entities.add(entity)
return True
def _load_existing_relations(self, file_path: str):
"""加载已存在的关系数据"""
if not os.path.exists(file_path):
return
try:
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line:
data = json.loads(line)
relation = FinancialRelation(**data)
self._add_relation(relation)
print(f"Loaded {len(self.relations)} existing relations from {file_path}")
except Exception as e:
print(f"Error loading existing relations: {e}")
def _save_relations(self, file_path: str):
"""保存关系到文件"""
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
for relation in self.relations:
f.write(json.dumps(relation.__dict__, ensure_ascii=False) + '\n')
print(f"Saved {len(self.relations)} relations to {file_path}")
def _search_entity_relations(self, entity_list: List[str]) -> List[FinancialRelation]:
"""搜索实体间的关系"""
# 构建搜索查询
entities_str = "、".join(entity_list[:5]) # 限制实体数量
query = f"请分析以下金融实体之间的关系:{entities_str}。请详细说明它们之间的逻辑关系,包括正向、负向或中性的影响关系。"
# 使用搜索工具
search_result = self.search_tool.execute(query=query)
# 使用LLM分析搜索结果并提取关系
analysis_prompt = f"""
基于以下搜索结果,请分析金融实体之间的关系:
搜索结果:
{search_result[:1000] if isinstance(search_result, str) else str(search_result)[:1000]} # 限制长度
当前实体列表:
{entity_list[:10]} # 限制显示数量
请提取出实体间的关系,格式如下(JSON格式):
{{
"relations": [
{{
"input_entities": ["实体1", "实体2"],
"output_entities": ["实体3", "实体4"],
"relation": "正向/负向/中性",
"reasoning": "详细的分析逻辑",
"source": "信息来源",
"confidence": 0.8
}}
],
"new_entities": ["新实体1", "新实体2"]
}}
请确保:
1. 关系描述准确具体
2. 置信度在0-1之间
3. 如果发现新的相关实体,请添加到new_entities中
4. 只返回JSON格式,不要其他内容
"""
messages = [
Message(role=Role.SYSTEM, content=self.system_prompt),
Message(role=Role.USER, content=analysis_prompt)
]
response = self.llm._chat(messages, self.tools)
try:
# 尝试解析JSON响应
content = str(response.content)
json_match = re.search(r'\{.*\}', content, re.DOTALL)
if json_match:
data = json.loads(json_match.group())
relations = []
for rel_data in data.get("relations", []):
relation = FinancialRelation(
input_entities=rel_data["input_entities"],
output_entities=rel_data["output_entities"],
relation=rel_data["relation"],
reasoning=rel_data["reasoning"],
source=rel_data["source"],
confidence=rel_data["confidence"],
timestamp=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
relations.append(relation)
# 添加新实体
for new_entity in data.get("new_entities", []):
self.entities.add(new_entity)
return relations
except Exception as e:
print(f"Error parsing LLM response: {e}")
print(f"Response content: {response.content}")
return []
def execute(self, init_entity_list: List[str], dump_file_path: str, max_iter: int = 5):
"""
执行金融知识图谱构建
Args:
init_entity_list: 初始实体列表
dump_file_path: 输出文件路径
max_iter: 最大迭代次数
"""
print(f"Starting financial knowledge graph construction with {len(init_entity_list)} initial entities")
# 1. 初始化实体列表
self.entities = set(init_entity_list)
# 2. 加载历史数据
self._load_existing_relations(dump_file_path)
# 3. 迭代搜索
iteration = 0
new_relations_count = 0
while iteration < max_iter:
iteration += 1
print(f"Iteration {iteration}/{max_iter}")
# 搜索实体间关系
entity_list = list(self.entities)
relations = self._search_entity_relations(entity_list)
# 添加新关系
added_count = 0
for relation in relations:
if self._add_relation(relation):
added_count += 1
new_relations_count += added_count
print(f"Added {added_count} new relations in iteration {iteration}")
# 检查是否还有新的关系可以添加
if added_count == 0:
print("No new relations found, stopping iteration")
break
# 保存中间结果
if iteration % 2 == 0:
self._save_relations(dump_file_path)
# 4. 保存最终结果
self._save_relations(dump_file_path)
print(f"Financial knowledge graph construction completed!")
print(f"Total entities: {len(self.entities)}")
print(f"Total relations: {len(self.relations)}")
print(f"New relations added: {new_relations_count}")
return {
"entities": list(self.entities),
"relations": [rel.__dict__ for rel in self.relations],
"total_entities": len(self.entities),
"total_relations": len(self.relations),
"new_relations": new_relations_count
}
def main():
"""主函数"""
from experiencemaker.utils.util_function import load_env_keys
# 加载环境变量
load_env_keys()
# 初始实体列表
init_entities = [
"美元债务",
"美债利率",
"美元指数",
"黄金",
"石油",
]
# 创建Agent并执行
agent = FinancialAgent()
result = agent.execute(
init_entity_list=init_entities,
dump_file_path="test/金融知识图谱.jsonl",
max_iter=3 # 减少迭代次数用于测试
)
print("=" * 50)
print("构建完成!")
print(f"总实体数: {result['total_entities']}")
print(f"总关系数: {result['total_relations']}")
print(f"新增关系数: {result['new_relations']}")
print("=" * 50)
if __name__ == "__main__":
main()

View file

@ -1,191 +0,0 @@
#!/usr/bin/env python3
"""
简化的金融Agent测试脚本
"""
import os
import sys
import json
from pathlib import Path
# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
# 模拟环境变量(如果没有设置的话)
if not os.getenv("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = "test_key"
if not os.getenv("OPENAI_BASE_URL"):
os.environ["OPENAI_BASE_URL"] = "http://localhost:8000/v1"
if not os.getenv("DASHSCOPE_API_KEY"):
os.environ["DASHSCOPE_API_KEY"] = "test_key"
from financial_agent.schema import FinancialRelation
from financial_agent.knowledge_graph import KnowledgeGraphBuilder
def test_schema():
"""测试FinancialRelation schema"""
print("测试FinancialRelation schema...")
# 创建测试关系
relation = FinancialRelation(
input_entities=["美债利率", "美元债务"],
output_entities=["美元指数"],
relation="负向",
reasoning="美债利率上升和美元债务增加会导致美元走弱",
source="金融分析报告",
confidence=0.85,
timestamp="2024-01-15 10:30:00"
)
print(f"创建的关系: {relation}")
print(f"转换为字典: {relation.to_dict()}")
# 测试验证
try:
invalid_relation = FinancialRelation(
input_entities=["实体1"],
output_entities=["实体2"],
relation="无效关系", # 应该报错
reasoning="测试",
source="测试",
confidence=0.5,
timestamp="2024-01-15 10:30:00"
)
except ValueError as e:
print(f"验证错误(预期): {e}")
print("Schema测试通过!\n")
def test_knowledge_graph():
"""测试KnowledgeGraphBuilder"""
print("测试KnowledgeGraphBuilder...")
# 创建知识图谱
kg = KnowledgeGraphBuilder()
# 添加关系
relation1 = FinancialRelation(
input_entities=["美债利率", "美元债务"],
output_entities=["美元指数"],
relation="负向",
reasoning="美债利率上升和美元债务增加会导致美元走弱",
source="金融分析报告",
confidence=0.85,
timestamp="2024-01-15 10:30:00"
)
relation2 = FinancialRelation(
input_entities=["石油价格", "美元指数"],
output_entities=["通胀预期"],
relation="正向",
reasoning="石油价格上涨和美元走弱会推高通胀预期",
source="经济分析",
confidence=0.78,
timestamp="2024-01-15 10:31:00"
)
# 添加关系
kg.add_relation(relation1)
kg.add_relation(relation2)
# 添加实体别名
kg.add_entity_alias("美元指数", ["USD Index", "DXY"])
# 测试统计
stats = kg.get_entity_statistics()
print(f"知识图谱统计: {stats}")
# 测试查询
usd_relations = kg.find_related_entities("美元指数")
print(f"美元指数相关关系数量: {len(usd_relations)}")
# 测试导出
test_file = "test_knowledge_graph.jsonl"
kg.export_to_jsonl(test_file)
print(f"知识图谱已导出到: {test_file}")
# 测试加载
new_kg = KnowledgeGraphBuilder()
new_kg.load_from_jsonl(test_file)
print(f"加载后的实体数量: {len(new_kg.entities)}")
# 清理测试文件
if os.path.exists(test_file):
os.remove(test_file)
print("KnowledgeGraphBuilder测试通过!\n")
def test_mock_agent():
"""测试模拟的Agent(不调用真实API)"""
print("测试模拟Agent...")
# 创建模拟的搜索结果
mock_search_result = """
根据最新金融分析,美债利率上升和美元债务增加会对美元指数产生负面影响。
当美债利率上升时,投资者会要求更高的收益率,这可能导致美元走弱。
同时,美元债务的增加也会增加市场对美元贬值的担忧。
"""
# 模拟LLM响应
mock_llm_response = {
"relations": [
{
"input_entities": ["美债利率", "美元债务"],
"output_entities": ["美元指数"],
"relation": "负向",
"reasoning": "美债利率上升和美元债务增加会导致美元走弱",
"source": "金融分析报告",
"confidence": 0.85
}
],
"new_entities": ["美联储政策", "市场情绪"]
}
print(f"模拟搜索结果: {mock_search_result[:100]}...")
print(f"模拟LLM响应: {json.dumps(mock_llm_response, ensure_ascii=False, indent=2)}")
# 测试关系创建
try:
relation = FinancialRelation(
input_entities=mock_llm_response["relations"][0]["input_entities"],
output_entities=mock_llm_response["relations"][0]["output_entities"],
relation=mock_llm_response["relations"][0]["relation"],
reasoning=mock_llm_response["relations"][0]["reasoning"],
source=mock_llm_response["relations"][0]["source"],
confidence=mock_llm_response["relations"][0]["confidence"],
timestamp="2024-01-15 10:30:00"
)
print(f"成功创建关系: {relation}")
except Exception as e:
print(f"创建关系失败: {e}")
print("模拟Agent测试通过!\n")
def main():
"""主测试函数"""
print("=" * 50)
print("金融Agent测试开始")
print("=" * 50)
try:
test_schema()
test_knowledge_graph()
test_mock_agent()
print("=" * 50)
print("所有测试通过!")
print("=" * 50)
except Exception as e:
print(f"测试失败: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()