下面介绍 add 方法 metadata 属性的一些规则:
metadatas 传递空字典立即报错,例如:
import chromadb
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1"], embeddings=[[1, 0, 0]], metadatas=[{}])运行代码,错误信息如下:
ValueError: Expected metadata to be a non-empty dict, got 0 metadata attributes in add.如果记录没有 metadata 要写,就别传这个参数,或者传 [None]:
import chromadb
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1"], embeddings=[[1, 0, 0]], metadatas=[None])或则,部分记录有 metadatas,部分记录没有:
import chromadb
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1", "e2"], embeddings=[[1, 0], [0, 1]], metadatas=[{"a": 1}, None])注意了,下面方式不支持:
{"author": {"name": "鲁迅"}} # 对象嵌套
{"tags": ["a", 1]} # 数组元素类型不一致
{"tags": []} # 空数组要表达嵌套就拍平:
{"author_name": "鲁迅", "author_id": 42}import chromadb
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1"], embeddings=[[1, 0]], metadatas=[{"a": None}])运行上面代码,抛出异常如下:
TypeError: argument 'metadatas': Cannot convert Python object to MetadataValue
注意,如果想表达"空",用空字符串、0,或者干脆不写这个 key。
下面自定义个函数,用来在写数据之前对 metadata 数据清洗一遍,尽量避免在运行时报错:
import chromadb
from datetime import date, datetime
def clean_metadata(md: dict | None) -> dict | None:
"""把 metadata 洗成 Chroma 能接受的样子"""
if not md:
return None
out = {}
for k, v in md.items():
# 如果值为 None,过滤掉
if v is None:
continue
# 如果值为 bool、int、float、str 基础类型,直接放行
if isinstance(v, bool) or isinstance(v, int) or isinstance(v, float) or isinstance(v, str):
out[k] = v
# 如果值为列表或元组
elif isinstance(v, (list, tuple)):
# 遍历列表,仅保留基础数据类型的元素
items = [x for x in v if x is not None and isinstance(x, (bool, int, float, str))]
if not items:
continue
# 数组元素必须同类型,取第一个元素的类型为准
t = type(items[0])
items = [x for x in items if type(x) is t]
if items:
out[k] = items
# 如果是日期类型,直接格式化为 ISO 标准
elif isinstance(v, (datetime, date)):
out[k] = v.isoformat()
# 否则转换为字符串
else:
out[k] = str(v)
return out or None
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(
ids=["q1",],
documents=[
"订单付款后多久发货?一般 48 小时内出库",
],
metadatas=[
clean_metadata({"category": "物流", "tags":None, "info": {"price":"27.9", "position":"四川"}}),
],
)
print(col.get(ids=["q1"]))
# 结果:
# {'ids': ['q1'], 'embeddings': None, 'documents': ['订单付款后多久发货?一般 48 小时内出库'],
# 'uris': None,
# 'included': ['metadatas', 'documents'], 'data': None,
# 'metadatas': [{'info': "{'price': '27.9', 'position': '四川'}", 'category': '物流'}]}运行示例,并没有因为我们将 metadatas 的 tags 设置为 None,以及 info 使用嵌套对象而报错,反而将 tags 剔除,将 info 转换成字符串。