在这里插入图片描述

还在把Chroma当临时列表用?从集合创建到安全删除,这6个致命暗坑踩中一个,你的RAG项目就可能“数据混乱、查询失真、误删跑路”!今天一次性把Chroma集合管理的底层逻辑掰开揉碎讲清楚,手把手教你搭好AI应用的“数据地基”。

🎯 Chroma集合管理实战

📦 认识Collection

✨ 创建集合

📝 更新集合

🗑️ 删除集合

🔍 数据边界

🛠️ 实战封装

Client与Collection关系

持久化路径配置

create_collection

get_or_create

配置embedding与metadata

modify方法

元数据更新策略

distance function变更方案

delete_collection

清空与删除区别

安全删除checklist

集合 vs 数据

add/update/upsert

CollectionManager类

异常与日志处理

文字目录

一、认识Collection:向量世界的“数据库表”

二、创建集合:命名与配置,一步错步步错

三、更新集合:metadata是唯一的“活口”

四、删除集合:delete与reset,天差地别

五、数据边界:集合的CRUD与数据的CRUD

六、实战封装:写一个健壮的CollectionManager


嗨,大家好呀,我是你的老朋友精通代码大仙。接下来我们一起学习 《大模型RAG生成式AI开发实战》79.[第8章 Chroma与开源模型] Chroma集合管理:创建、更新和删除

“万丈高楼平地起,一砖一瓦皆根基。”

这话放在RAG开发里,再贴切不过了。很多同学现在急着让大模型回答问题,网上抄两段代码,把数据“怼”进Chroma,Query跑通了,就觉得自己搞定了。可等项目稍微复杂一点,第二次运行程序,啪,一个Collection already exists报错糊在脸上;或者团队里来了新同事,拉了你的代码却查不出数据;再或者某天想清理下测试数据,一个手滑,整个知识库全军覆没……代码是跑通了,但底子虚得很,风吹草动就倒。

今天咱们不追风口,不聊虚的,就扎扎实实把Chroma的集合管理吃透。create、update、delete,这三个动作看似简单,里面的门道足够你调一下午的bug。坐稳了,学长带你看路。


一、认识Collection:向量世界的“数据库表”

Chroma作为当下最流行的开源向量数据库之一,它的核心组织单元就是Collection。你可以把它类比成MySQL里的表(Table),或者MongoDB里的集合(Collection)。但它又不太一样,它专门用来存放高维向量、原始文档和附加的元数据,三者绑在一起,为你的RAG检索提供弹药。

可很多新手第一次用的时候,完全没意识到这个“表”的分量。他们眼里,Chroma就是一个大号Python字典,甚至是一个临时变量,拿来存点东西图个方便。结果呢?灾难一个接一个。

你是不是也这样写过:

import chromadb

# 错误示范:默认Client,数据捉摸不定
client = chromadb.Client()
collection = client.create_collection("test")
collection.add(documents=["hello world"], ids=["1"])

第一次运行,看起来没问题。但你有没有想过,程序重启后,这个test集合还在不在?数据存在哪台机器的哪个目录下?如果你把代码发给同事,他电脑上为什么查不到这条数据?

坑就在这里。chromadb.Client()是一个轻量级的客户端,默认行为下数据可能是临时的,或者持久化到了一个你根本不知道的默认路径。等你换了个目录重新跑脚本,或者部署到服务器上,数据仿佛“人间蒸发”,你站在原地一脸懵。更乱的是,有些同学把PersistentClientHttpClientClient混着用,本地开发用一个,测试环境用另一个,路径配得五花八门,数据一会儿有一会儿没有,排查起来简直噩梦。

正确的认知应该是这样的:Client是你连接“向量数据库”的管道,而Collection是库里面一张张正式的表。表不是临时变量,它是有持久化身份的。

# 正确示范:明确指定持久化路径
import chromadb

client = chromadb.PersistentClient(path="./my_chroma_db")
collection = client.get_or_create_collection("test")

一旦你用了PersistentClient并显式声明了path,你的数据才真正落盘到./my_chroma_db这个目录里。把这个目录纳入你的项目结构或者Docker挂载卷管理,数据才算有了根。

🖥️ Client连接

📁 Collection A

📁 Collection B

📄 Documents原文

🔢 Embeddings向量

🏷️ Metadata元数据

📄 Documents原文

你看,Client像是一个数据库实例,Collection是里面的表,表里存着文档、向量和标签。这个层级关系不搞清楚,后面所有的create、update、delete都会乱了套。

小结:Collection不是内存里的临时字典,它是你RAG系统的数据根基。Client选不对,路径管不好,后面全白费。


二、创建集合:命名与配置,一步错步步错

client.create_collection(name="xxx"),就这么一行代码,很多新手觉得有手就行。但大仙我要告诉你,这一行里的坑,够你调一个下午。

第一个大坑,名字冲突。你写了个脚本,第一次运行,“yeah,成功了”。第二次运行,啪,一个异常甩你脸上:ValueError: Collection xxx already exists。你怎么办?我见过很多同学开始写try...except,捕获到异常再get_collection,代码绕来绕去跟意大利面条一样,丑不说,还容易漏掉其他异常。

第二个坑,忽略embedding_function。创建集合的时候不指定,后面add数据的时候也不传,全靠Chroma的默认配置。Chroma默认用的是all-MiniLM-L6-v2,输出维度384。但你如果项目里实际用的是BAAI/bge-large-zh或者OpenAI的Ada-002,维度完全不一样。更隐蔽的是,有些同学创建时不传,查询时却传了一个不同的embedding函数,结果向量空间对不上,搜出来的Top K全是错的,他还以为是大模型Prompt写得不好。

第三个坑,metadata空白。创建集合时metadata参数直接忽略,等你有五个、十个集合的时候,看着product_kb_v1product_kb_v2test_2024test_backup,你分得清谁是谁吗?团队协同时,队友看到你的集合名,完全不知道业务含义。

第四个坑,distance function,也就是hnsw:space。做语义搜索,余弦相似度(cosine)通常比欧氏距离(l2)更合理,但Chroma默认是l2。新手根本不知道这个配置藏在哪里,结果搜索出来的结果总是“感觉不太相关”。

看看这些错误示范,是不是似曾相识:

# 坑1:第二次运行必报错
coll = client.create_collection("my_docs")

# 坑2:隐式使用默认embedding模型,埋下维度炸弹
coll.add(documents=["长文本内容..."], ids=["1"])

# 坑3:没有任何业务标签,集合成了黑盒
coll = client.create_collection("abc")

# 坑4:不指定distance function,默认l2可能不适合语义搜索
coll = client.create_collection("semantic_search")

咱们工程化的做法是什么?一套“创建checklist”,每一步都显式声明,不留模糊地带。

第一,用get_or_create_collection代替create_collection。它如果存在就获取,不存在就创建,幂等、健壮,脚本跑多少次都不会炸。

第二,显式传入你项目要用的embedding_function。不要依赖默认配置,你把命运攥在自己手里。

第三,metadata里写清楚业务信息。{"project": "rag_demo", "version": "1.0", "owner": "大仙"},越多越好。

第四,根据业务场景选对hnsw:space。语义相似度首选cosine,明确写在metadata里。

from chromadb.utils import embedding_functions

# 明确指定embedding模型
ef = embedding_functions.SentenceTransformerEmbeddingFunction(
    model_name="BAAI/bge-large-zh"
)

# 幂等创建,配置一次到位
collection = client.get_or_create_collection(
    name="enterprise_kb",
    embedding_function=ef,
    metadata={
        "hnsw:space": "cosine",
        "description": "企业知识库主库",
        "created_at": "2025-01-15",
        "owner": "ai_team"
    }
)

这样做的好处是什么?你的代码可重复运行,你的集合自带“身份证”,你的向量相似度计算从根儿上就是对的。队友看你的代码,一眼就能明白这个集合是干嘛的,距离函数是什么,不用翻文档瞎猜。

开始创建集合

集合是否已存在

存在

不存在

使用 get_or_create

使用 create_collection

配置 embedding_function

注入 metadata 与 hnsw:space

返回可用的 Collection

小结:创建集合就是给房子打地基,名字、配置、元数据,一个都不能随便。


三、更新集合:metadata是唯一的“活口”

业务需求变了,集合配置是不是也能跟着改?带着关系数据库思维进来的同学,觉得“alter table”嘛,总有办法。但Chroma的Collection很特殊,它创建完之后,大部分属性就“冻住”了。

第一个误区,想改集合名。collection.modify(name="new_name"),一运行,报错。Chroma目前不支持重命名集合!你只能删掉重建。这个限制让很多新手措手不及:“我就改个名字而已,至于吗?”至于,因为集合名是底层索引和持久化文件的命名依据。

第二个误区,想改distance function。发现搜索效果不好,怀疑是l2的锅,于是想collection.modify(metadata={"hnsw:space": "cosine"})。大仙我告诉你,这招没用!hnsw:space在集合创建时就固化到HNSW索引结构里了,modify改metadata影响不了底层向量的度量方式。你改了metadata里的字符串,但索引算法不会因此重建,搜索逻辑还是老的。

第三个误区,以为modify是“合并更新”。比如原来metadata是{"description": "知识库"},你调用modify(metadata={"status": "deprecated"}),以为结果是两者合并。错!Chroma的modify(metadata=...)是直接替换整个metadata字典!原来的description直接丢了,等你下次想读描述信息,返回None,你还得回头排查是不是哪里误删了。

第四个误区,层级混淆。试图通过collection.update()来修改集合配置。醒醒,collection.update()这个API更新的是数据记录(documents、embeddings、metadatas),不是集合本身的属性!这完全是两个层级。

# 错误1:试图改名,直接抛异常
collection.modify(name="new_name")

# 错误2:试图修改distance function,只是自欺欺人
collection.modify(metadata={"hnsw:space": "cosine"})

# 错误3:误以为modify是合并,结果是覆盖
# 假设原有metadata包含description和version
collection.modify(metadata={"status": "deprecated"})
# 现在metadata只剩status了,其他全丢!

# 错误4:用update改集合配置,层级错误
collection.update(ids=["1"], metadatas={"key": "val"}) # 这是改数据记录

那正确的姿势是什么?首先要摆正心态,Chroma Collection的设计哲学是“创建时定型”,这保证了向量索引的稳定性和一致性。你能改的,只有metadata,而且必须“先读后写”,在Python层面手动合并。

# 步骤1:读取现有metadata
existing_meta = collection.metadata or {}

# 步骤2:在Python层面合并,而不是覆盖
existing_meta.update({
    "status": "archived",
    "archived_at": "2025-06-01",
    "reason": "业务线调整"
})

# 步骤3:写回
collection.modify(metadata=existing_meta)

那如果我真的要改name或distance function怎么办?没有捷径,只能走“数据迁移”的正路。流程是:用新名字、新配置创建一个新集合 -> 从旧集合把所有数据get出来 -> 用新的embedding_function处理(如果换了模型)-> add到新集合 -> 确认无误后删除旧集合。虽然麻烦,但这是保证数据一致性的唯一方式。

def safe_update_metadata(collection, updates: dict):
    """安全更新集合metadata,避免误删旧数据"""
    meta = collection.metadata or {}
    meta.update(updates)
    collection.modify(metadata=meta)
    return collection

# 使用
safe_update_metadata(
    collection, 
    {"reviewed": "true", "owner": "team_a", "priority": "high"}
)

collection.modify

✅ 可修改: metadata键值对

❌ 不可改: name

❌ 不可改: hnsw:space

❌ 不可改: embedding维度约束

小结:modify不是万能补丁,它是专门用来打业务标签的。想动集合的根基属性?请走“新建+迁移”的正规流程。


四、删除集合:delete与reset,天差地别

有创建就有删除。但删除这个操作,在Chroma里是“高危动作”,新手在这里摔跟头的概率极高。

最惨烈的坑,叫client.reset()。有些同学看了API文档,发现有个reset方法,以为是“重置某个集合”或者“清空当前集合数据”,啪一点,整个世界安静了。reset()是清空整个Chroma实例的所有数据!所有集合,所有向量,所有文档,灰飞烟灭。如果你在正式环境里来这么一下,那真的是“删库跑路”的节奏,救都救不回来。

第二个坑,删除不存在的集合。代码里写client.delete_collection("tmp"),但这个名字之前根本没创建过,或者已经被别的进程删了,结果抛出一个异常。如果你没做异常处理,整个服务直接崩掉,一个删除操作把主流程全带垮了。

第三个坑,混淆“删数据”和“删集合”。collection.delete()是把集合里的文档记录清空,但集合这个“表”本身还在;client.delete_collection("name")是把整张表从数据库里抹掉。你想清空数据却删了表,或者想删表却只是一条条删数据,效率和心理预期都差得很远。

第四个坑,删除后继续使用旧引用。集合被delete_collection之后,你之前拿到的collection对象变量还在内存里挂着。你顺手又调了个collection.query(),这时候报的错可能让你摸不着头脑:“这个集合怎么突然没了?”其实是你拿着“野指针”在操作,对象还在,但底层数据文件和元数据已经被清除了。

# 灾难级操作:清空整个Chroma实例的所有数据!
client.reset()

# 错误:删不存在的集合,程序崩溃
client.delete_collection("ghost_collection")

# 错误:删了集合后继续使用旧引用
client.delete_collection("my_coll")
collection.query(query_texts=["test"]) # 报错!集合已不存在

咱们工程里必须有一套“安全删除协议”。

第一,永远不要随便调用client.reset()。除非你在做单元测试,且环境完全隔离,否则把这行代码从你的脑子里删除。

第二,删除前做存在性检查。client.list_collections()返回集合对象列表,先判断名字在不在里面,再动手。

第三,严格区分场景。清空集合内数据用collection.delete(where={})或者按ID删;删除整张表用client.delete_collection()

第四,删除后置空引用,避免后续代码误用。

def safe_delete_collection(client, name: str):
    """安全删除指定集合,不存在则静默跳过"""
    existing_names = [c.name for c in client.list_collections()]
    if name not in existing_names:
        print(f"集合 {name} 不存在,无需删除")
        return False
    
    client.delete_collection(name)
    print(f"集合 {name} 已安全删除")
    return True

# 使用
safe_delete_collection(client, "outdated_kb")

# 如果只是想清空数据(慎用!)
# collection.delete(where={}) # 这会删除集合内所有数据,但表结构保留

需要清理数据

删除整个集合?

否: 只删数据

collection.delete

集合存在?

存在

不存在

client.delete_collection

记录日志并跳过

置空引用

结束

小结:删除一时爽,误删火葬场。多写三行检查代码,能救你一下午的加班。


五、数据边界:集合的CRUD与数据的CRUD

讲到这里,有些同学可能已经有点晕了。集合有add吗?有delete吗?数据也有add,也有delete。这层级关系到底怎么分?这一节咱们就彻底划清边界,别再拿错工具。

很多新手看着Chroma的API,觉得collection.add()是在“给集合增加属性”,这是完全错误的理解。add是往集合里加数据记录(行)。还有的兄弟,想修改某条数据的向量,结果去翻collection.modify,找不到相关参数,就开始怀疑人生。更有甚者,id重复了,collection.add()直接抛出DuplicateIDError,他不知道有upsert这个“存在就更新,不存在就插入”的神器,硬是在业务层写了一堆if-else去判断id是否存在,代码臃肿得像裹脚布。

另外,collection.update()也有明确限制:它只能更新已经存在的id。如果你传入一个不存在的id,它不会帮你自动创建,而是可能报错或者静默失败(取决于版本),导致你以为数据更新了,实际库里没有。

# 错误:id重复导致崩溃
collection.add(ids=["doc_1"], documents=["内容A"])
collection.add(ids=["doc_1"], documents=["内容B"]) # DuplicateIDError!

# 错误:试图update不存在的id
collection.update(ids=["ghost_id"], documents=["不存在的内容"])

# 错误:把数据update当成集合配置update
collection.update(ids=["1"], metadatas={"key": "val"}) # 这是改数据行的metadata

把这两层API刻进脑子里,以后就不会乱了。

集合管理层(Schema级别),操作的是“表”本身:

  • client.create_collection
  • client.get_or_create_collection
  • client.delete_collection
  • collection.modify(metadata=...)

数据操作层(Record级别),操作的是表里的“行”:

  • collection.add
  • collection.upsert
  • collection.update
  • collection.delete
  • collection.query
  • collection.get

正确使用姿势:

  • 批量导入数据且id可能重复时,无脑用upsert。它是add和update的合体,是数据同步的利器。
  • 明确要追加全新数据,且保证id唯一时,用add
  • 要修改已有记录的文档或向量时,用update,但要确保id存在。
  • 查询时,query是按向量相似度排序,get是按条件精确获取。
# 正确:upsert 避免重复问题,适合定时同步任务
collection.upsert(
    ids=["doc_1", "doc_2", "doc_3"],
    documents=["新内容A", "新内容B", "新内容C"],
    metadatas=[{"src": "web"}, {"src": "pdf"}, {"src": "docx"}]
)

# 正确:先确认存在再update,或者直接upsert
result = collection.get(ids=["doc_1"])
if result and result["ids"]:
    collection.update(ids=["doc_1"], documents=["已修正内容"])

Client对象

集合管理层

数据操作层

create_collection

delete_collection

modify metadata

add / upsert

update / delete

query / get

小结:集合是房子,数据是家具。装修房子和搬动家具,工具箱不一样,别拿锤子去切菜。


六、实战封装:写一个健壮的CollectionManager

前面五个要点,咱们把坑都踩了一遍。但在真实项目里,你不能每次操作都写这么多防御性代码,太丑了,也容易复制粘贴出错。这时候就需要一个统一的管理层,把集合的生命周期封装起来。

我见过太多项目,Chroma的操作代码跟业务逻辑搅在一起。A文件里PersistentClient(path="./db"),B文件里又初始化一次,路径还写成了./data,结果数据分裂成两份。集合名字到处硬编码,"chat_history"这个字符串在八个文件里出现了十几次。删除操作裸奔,没有任何日志,出了问题没法追溯。异常处理更是没有,一旦Chroma文件被锁或者路径权限不对,整个后端服务直接500错误。

咱们要写的是这样一个类:它统一管理Client连接,封装幂等创建、安全更新、安全删除,还带日志记录。

import logging
import chromadb
from chromadb.api.models.Collection import Collection
from chromadb.utils import embedding_functions


class ChromaCollectionManager:
    def __init__(self, persist_dir: str = "./chroma_data"):
        """初始化时固定持久化路径,避免全项目到处new Client"""
        self.client = chromadb.PersistentClient(path=persist_dir)
        self.logger = logging.getLogger(self.__class__.__name__)
    
    def get_collection(self, name: str, ef=None) -> Collection | None:
        """获取集合,不存在则返回None,不抛异常"""
        try:
            return self.client.get_collection(name=name, embedding_function=ef)
        except Exception as e:
            self.logger.warning(f"获取集合 {name} 失败: {e}")
            return None
    
    def safe_create(self, name: str, ef=None, metadata: dict = None) -> Collection:
        """幂等创建集合,自动注入默认配置"""
        default_meta = {
            "hnsw:space": "cosine",
            "created_by": "ChromaCollectionManager",
            "version": "1.0"
        }
        if metadata:
            default_meta.update(metadata)
        
        try:
            coll = self.client.get_or_create_collection(
                name=name,
                embedding_function=ef,
                metadata=default_meta
            )
            self.logger.info(f"集合 {name} 准备就绪,meta={default_meta}")
            return coll
        except Exception as e:
            self.logger.error(f"创建集合 {name} 异常: {e}")
            raise
    
    def update_metadata(self, name: str, updates: dict) -> Collection:
        """安全更新metadata,自动合并而非覆盖"""
        coll = self.get_collection(name)
        if not coll:
            raise ValueError(f"集合 {name} 不存在,无法更新元数据")
        
        current = coll.metadata or {}
        current.update(updates)
        coll.modify(metadata=current)
        self.logger.info(f"集合 {name} 元数据已更新: {updates}")
        return coll
    
    def safe_delete(self, name: str) -> bool:
        """安全删除集合,不存在则跳过,不抛异常"""
        existing = [c.name for c in self.client.list_collections()]
        if name not in existing:
            self.logger.info(f"集合 {name} 不存在,跳过删除")
            return False
        
        try:
            self.client.delete_collection(name)
            self.logger.warning(f"集合 {name} 已删除")
            return True
        except Exception as e:
            self.logger.error(f"删除集合 {name} 失败: {e}")
            return False
    
    def list_collections(self) -> list:
        """返回所有集合名称,方便调试和监控"""
        return [c.name for c in self.client.list_collections()]

大仙我给你逐行讲讲为什么这么设计。

__init__里固定PersistentClient,这样全项目数据落盘位置统一,不会出现A模块写./db、B模块写./data的分裂惨剧。get_collection做了try-except,获取不到就返回None,绝不把异常往上抛,让业务层自己决定怎么处理。

safe_create里强制默认hnsw:space为cosine,同时允许业务层通过metadata覆盖,既规范又灵活。get_or_create_collection保证脚本的幂等性,跑一百次也不会因为“已存在”而崩溃。

update_metadata里一定先get再合并,避免直接覆盖。这个坑前面第三节讲过,很多新手在这里把旧metadata全丢了,Manager类帮你兜底。

safe_delete里先做list校验,宁可多一次查询,也不让delete_collection的异常抛到业务层。每个操作都带日志,出了事翻日志就知道是哪个集合在哪一步出了错。

使用示例:

manager = ChromaCollectionManager(persist_dir="./my_kb")

# 创建
ef = embedding_functions.DefaultEmbeddingFunction()
coll = manager.safe_create("product_qa", ef=ef, metadata={"owner": "ai_team"})

# 更新标签
manager.update_metadata("product_qa", {"status": "active", "env": "production"})

# 查看所有集合
print(manager.list_collections())

# 安全删除
manager.safe_delete("product_qa")

你看,业务代码里再也不用关心Chroma的底层异常了,只需要调用语义清晰的方法名。这就是封装的力量,把复杂度关进笼子里,把简洁留给业务。

ChromaCollectionManager

__init__ 初始化Client

safe_create 幂等创建

update_metadata 合并更新

safe_delete 存在性检查

list_collections 监控

注入 embedding_function

默认 hnsw:space + 业务metadata

小结:好代码是管出来的,好集合也是。一个Manager类,能让你少写80%的重复代码,多规避90%的低级错误。


写在最后

今天我们聊了Chroma集合管理的完整生命周期。从认识Collection的本质,到创建时的命名与配置陷阱,再到更新时的“不可变性”限制,删除时的安全红线,以及集合CRUD与数据CRUD的边界划分,最后给了一个工程化的封装方案。

你会发现,Chroma虽然上手简单,几行代码就能跑起来,但要把它稳稳地用在生产环境,这些细节一个都省不得。学RAG、学大模型,很多人只关注Prompt怎么写、模型怎么调,却忽视了数据层的基本功。但大仙我这么多年看下来,真正拉开差距的,往往就是这些“地基”上的功夫。集合管理搞扎实了,你的RAG系统才能稳如老狗,不会因为一个名字冲突、一次误删、一个distance function选错就全线崩盘。

编程之路不易,但每一步踏实的成长都算数。别怕麻烦,把这些代码片段敲一遍,踩一遍坑,它们就会变成你自己的肌肉记忆。保持好奇,持续学习,你不仅能跑通Demo,更能hold住生产级项目。咱们下节见!

关注私信备注:“资料代找获取”,全网计算机学习资料代找:例如:
《课程:2026 年多模态大模型实战训练营》
《课程:AI 大模型工程师系统课程 (22 章完整版 持续更新)》
《课程:AI 大模型系统实战课第四期 (2026 年开课 持续更新)》
《课程:2026 年 AGI 大模型系统课 23 期》
《课程:2026 年 AGI 大模型系统课 21 期》
《课程:AI 大模型实战课 8 期 (2026 年 2 月最新完结版)》
《课程:AI 大模型系统实战课三期》
《课程:AI 大模型系统课程 (2026 年 2 月开课 持续更新)》
《课程:AI 大模型全阶课程 (2025 年 12 月开课 2026 年 6 月结课)》
《课程:AI 大模型工程师全阶课程 (2025 年 10 月开课 2026 年 4 月结课)》
《课程:2026 年最新大模型 Agent 开发系统课 (持续更新)》
《课程:LLM 多模态视觉大模型系统课》
《课程:大模型 AI 应用开发企业级项目实战课 (2026 年 1 月开课)》
《课程:大模型智能体线上速成班 V2.0》
《课程:Java+AI 大模型智能应用开发全阶课》
《课程:Python+AI 大模型实战视频教程》
《书籍:软件工程 3.0: 大模型驱动的研发新范式.pdf》
《课程:人工智能大模型系统课 (2026 年 1 月底完结版)》
《课程:AI 大模型零基础到商业实战全栈课第五期》
《课程:Vue3.5+Electron + 大模型跨平台 AI 桌面聊天应用实战 (2025)》
《课程:AI 大模型实战训练营 从入门到实战轻松上手》
《课程:2026 年 AI 大模型 RAG 与 Agent 智能体项目实战开发课》
《课程:大模型训练营配套补充资料》

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐