BAML 是 Boundary 创建的一种语言,用于从无结构数据中生成干净、结构化的输出。Neo4j 是一种图形数据库,用于将数据以图形的方式存储——即节点及它们之间的关系。
在本文中,我将介绍如何扩展 BAML 的一个示例项目,将网页转换为图形表示,以快速填充 Neo4j 实例。
要求
工作流程
FastAPI
Boundary 提供了使用 BAML 从硬编码的简历中提取数据的简单 FastAPI 服务器示例代码。FastAPI 是一个很棒的框架,它包含一个交互式文档页面,允许你直接从浏览器中测试端点。
我最初对这个示例进行了分叉,并添加了一个实验性端点,用于从网页内容中提取实体和关系。这个端点接受一个 URL 字符串列表作为参数。
底层函数将调用 BAML 函数,从网页中提取数据,并将这些数据作为结构化 JSON 对象上传到 Neo4j 中。
@app.post("/url_to_graph")
async def extract_url_content(urls: list[str]):
"""General purpose conversion of contents from a list of urls to a graph"""
# 1. Prep html to text conversion
h = html2text.HTML2Text()
h.ignore_links = False
# 2. Extract text from each url
markdown_contents = []
for url in urls:
try:
response = requests.get(url)
response.raise_for_status()
html_content = response.text
markdown_content = h.handle(html_content)
markdown_contents.append(markdown_content)
except Exception as e:
markdown_contents.append(f"Error processing {url}: {str(e)}")
# 3. Composite the text
combined_markdown = "\n\n".join(markdown_contents)
# 4. Run BAML to get a Cytoscape graph JSON representation of text
json_output = b.GenerateCytoscapeGraph(combined_markdown)
json_str = str(json_output.model_dump_json())
json_dict = json.loads(json_str)
# 5. Upload the JSON data to Neo4j
finished = upload_cytoscape_to_neo4j(json_dict)
return {"finished": finished}
BAML
在结构上,当使用 BAML 时,会在根项目文件夹下添加两个子文件夹:baml_src 和 baml_client。
baml_client 文件夹中的内容是由活动的 VS Code 插件自动生成的,或者在更新 baml_src 文件夹中的任何 .baml 文件后,通过手动运行 baml cli generate 命令生成的。
baml_src 文件夹需要包含 main.baml 和 clients.baml 文件。clients.baml 文件包含了要使用的基础模型的规格说明,而 main.baml 文件则指定了配置选项。
注意:此处的版本号应与 CLI 版本相匹配,否则自动生成的 baml-client 内容将停止工作。
你添加的 .baml 文件将包含以下三个元素中的一个或多个,或全部三个:
BAML 函数是指定输入到输出定义、要使用的客户端模型以及 LLM(可能是指大型语言模型,Large Language Model)提示的地方。以下是 FastAPI 端点调用的函数,用于将 HTML 文本转换为结构化的图形数据。
模型类的定义方式与 Pydantic 类似,但更为简洁,而 Pydantic 是在其底层使用的。为了获得如下所示的结构化 JSON 输出:
{{
"elements": {
"nodes": [
{
"data": {
"id": "neo4j_graph_database",
"name": "Neo4j Graph Database",
"label": "product",
"description": "Self or fully-managed, deploy anywhere"
}
},
{
"data": {
"id": "neo4j_auradb",
"name": "Neo4j AuraDB",
"label": "product",
"description": "Fully-managed graph database as a service"
}
},
],
"edges": [
{
"data": {
"id": "edge_1",
"source": "neo4j_graph_database",
"target": "neo4j_auradb",
"label": "RELATED_TO"
}
}
]
}
}
以下是在 BAML 中可以使用的模型定义:
注意:目前,即使在不同的 .baml 文件中定义,BAML 的类和函数名也是全局范围的。此外,属性名称中目前不允许使用下划线前缀(例如:_id)。
Cytoscape
Cytoscape 是一个流行的开源平台,用于可视化图形(或网络)数据。它使用的 JSON 数据格式既简单又足够灵活,除了节点必需的 id 和 label 属性外,还支持其他附加数据。
Neo4j
Neo4j 是最受欢迎的图形数据库之一。它原生地使用 Cypher 查询语言来输入、操作和输出图形数据。因此,在这个演示中,我使用了官方支持的 neo4j bolt Python 包,在 cytoscape2neo4j.py 文件中上传 Cytoscape 格式的 JSON 数据。
upload_cytoscape_to_neo4j 函数。该函数会遍历源 JSON 数据中定义的每个节点和关系,并创建一个 Cypher 查询来为每个指定的节点创建一个节点,并为每个指定的边创建一个关系。
使用对象图形映射器(OGM)包(如 Neomodel)或设置 Apollo GraphQL 服务器是创建 JSON 和 Neo4j 之间输入桥梁的替代方法。
运行
完整的应用程序可以在这个公开的 Github 仓库中找到。按照安装和运行说明操作后,应该可以在任何浏览器的 localhost:8000/docs 上访问以下交互式文档。
还有一些其他实验性的端点,但本文讨论的是 /url_to_graph 选项。
要进行测试,请打开端点详细信息,点击“Try It Out(试用)”按钮,输入一个或多个有效的网页URL,然后点击“Execute(执行)”。
过一会儿,根据源网页的数量和大小,你有望得到一个 finished:true 的响应。
并且,在终端/控制台中,你应该会看到类似这样的内容:
...
---Parsed Response (class CytoscapeJSON)---Parsed Response (class CytoscapeJSON)---
{
"elements": {
"nodes": [
{
"data": {
"id": "neo4j_graph_database",
"name": "Neo4j Graph Database",
"label": "product",
"description": "Self or fully-managed, deploy anywhere"
}
},
{
"data": {
"id": "neo4j_auradb",
"name": "Neo4j AuraDB",
"label": "product",
"description": "Fully-managed graph database as a service"
}
},
{
"data": {
"id": "generative_ai",
"name": "Generative AI",
"label": "use_case",
"description": "Back your LLMs with a knowledge graph for better business AI"
}
}
],
"edges": [
{
"data": {
"id": "prod_use_case_1",
"source": "neo4j_graph_database",
"target": "generative_ai",
"label": "ENABLED_BY"
}
},
{
"data": {
"id": "prod_use_case_2",
"source": "neo4j_auradb",
"target": "generative_ai",
"label": "ENABLED_BY"
}
}
]
}
}
INFO: 127.0.0.1:63190 - "POST /url_to_graph HTTP/1.1" 200 OK
并且,在你的 Neo4j 控制台中,你应该会看到类似这样的内容: