AI Agent Harness Engineering 的白盒测试:从单元测试到集成测试的完整方案
AI Agent Harness Engineering 的白盒测试:从单元测试到集成测试的完整方案
引言
如果你最近半年在做AI Agent落地,一定遇到过这种崩溃的场景:线上用户反馈Agent给出了完全错误的回答,你翻遍了日志只看到用户的提问和最终的输出,中间到底是RAG召回错了?还是规划模块乱调工具?还是记忆模块丢了上下文?完全无从查起。你试着写了一堆黑盒测试用例,但是LLM的输出五花八门,传统的字符串相等断言完全用不了,每次上线还是像开盲盒。
这就是当前AI Agent测试的最大痛点:黑盒测试只能验证最终输出的正确性,完全无法覆盖内部复杂的逻辑链路,一旦出问题定位成本极高,甚至很多隐性问题根本发现不了。而AI Agent Harness Engineering(测试支架工程)的白盒测试方案,就是解决这个问题的核心手段。
本文我会结合我所在团队半年多的Agent落地经验,给大家分享一套从单元测试到集成测试的完整白盒测试方案,从核心概念、架构设计到代码实现、落地案例全覆盖,看完你就能直接在自己的团队落地这套方案,把Agent的上线故障率降低80%以上。
一、基础概念与核心定义
1.1 核心概念解释
什么是AI Agent Harness Engineering?
Harness(测试支架)是一套独立于Agent业务逻辑的辅助测试系统,通过埋点探针、模拟桩、链路追踪、断言引擎等能力,为Agent提供可观测、可控制、可验证的测试环境。Harness Engineering就是围绕这套支架的设计、开发、落地的整套工程实践。
什么是AI Agent白盒测试?
和传统软件的白盒测试类似,AI Agent的白盒测试是指在明确Agent内部组件结构、交互逻辑、决策规则的前提下,对每个组件的内部逻辑、组件之间的交互链路进行测试,验证其是否符合预期设计,而不仅仅只看最终输出。
AI Agent的核心组件(通用模型)
当前行业主流的Agent都可以拆解为5个核心组件,这也是我们白盒测试的核心对象:
| 组件名称 | 核心职责 |
|---|---|
| 规划模块 | 接收用户提问和上下文,决策下一步要做什么:调用工具、检索RAG、还是直接生成回复 |
| 记忆模块 | 存储和管理对话上下文、长期用户画像、历史交互数据,为其他模块提供上下文支持 |
| RAG检索模块 | 根据查询词召回知识库中的相关片段,为生成模块提供事实依据 |
| 工具调用模块 | 调用外部工具(比如查订单、发邮件、调用API),获取外部实时数据 |
| 输出生成模块 | 整合所有上下文信息,生成符合要求的自然语言回复 |
Harness的核心组成
一套完整的Agent测试Harness包含5个核心模块:
- 探针:无侵入埋点在Agent的每个组件中,采集组件的输入、输出、执行时间、错误信息等数据
- 桩模块:模拟Agent的外部依赖(比如LLM、第三方API、数据库),返回可控的测试数据
- 用例编排引擎:管理测试用例,控制测试流程的执行顺序、参数注入
- 断言引擎:支持逻辑断言、语义断言等多种断言方式,验证测试结果是否符合预期
- 度量采集器:采集测试覆盖率、通过率、执行时间等指标,生成测试报告
1.2 传统软件白盒测试 vs AI Agent白盒测试对比
两者的核心逻辑一致,但因为测试对象的特性不同,存在明显差异:
| 对比维度 | 传统软件白盒测试 | AI Agent白盒测试 |
|---|---|---|
| 测试对象 | 固定逻辑的代码 | 代码+LLM+数据的混合系统 |
| 核心判定依据 | 代码分支是否执行、输出是否完全匹配 | 逻辑决策是否正确、语义是否符合预期 |
| 覆盖维度 | 行覆盖、分支覆盖、路径覆盖 | 组件覆盖、链路覆盖、逻辑覆盖 |
| 断言方式 | 精确相等、类型匹配等确定性断言 | 逻辑规则匹配、语义相似度匹配等模糊断言 |
| 用例设计方法 | 等价类划分、边界值分析 | 等价类划分+prompt injection测试+场景化用例 |
| 工具生态 | JUnit、Pytest、Jacoco等成熟工具 | LangSmith、LangFuse、自定义Harness等新兴工具 |
1.3 概念关系交互图
二、问题背景与当前挑战
AI Agent的特性决定了传统的测试方案完全无法满足需求,当前行业普遍面临4个核心测试痛点:
2.1 非确定性输出导致传统断言失效
LLM的输出是概率性的,同一个提问多次调用可能返回不同的表述,但是核心语义是一致的。比如预期输出是“你的订单将在3天内发货”,LLM可能返回“亲,我们会在72小时内为你安排发货哦”,内容完全正确,但是传统的字符串相等断言会直接报错,导致测试用例的误报率极高。
2.2 内部状态不可观测,根因定位成本极高
Agent的运行是一个长链路的过程:用户提问->记忆模块提取上下文->规划模块决策->调用RAG/工具->生成回复,中间任何一个环节出问题都会导致最终输出错误。如果没有内部埋点,你只能看到最终的错误输出,完全不知道是哪个环节出了问题,排查一个问题可能要花几个小时甚至几天。
2.3 多组件交互复杂,边界case难覆盖
Agent的组件之间存在复杂的交互关系:比如规划模块的输出会作为工具调用的输入,工具返回的结果会作为RAG的查询词,RAG的结果会作为生成模块的输入。任何一个组件的异常输出都可能引发连锁反应,比如工具返回的JSON格式错误,规划模块没有做异常处理,就会导致整个Agent崩溃。这些边界case在黑盒测试中很难覆盖到。
2.4 外部依赖不可控,测试稳定性差
Agent依赖大量外部服务:LLM、第三方API、知识库、数据库等,这些外部服务的波动会导致测试结果不稳定,比如LLM返回超时、第三方API报错,都会导致测试用例失败,但是这些问题并不是Agent本身的bug,会浪费大量的排查时间。
三、核心测试方案:从单元测试到集成测试
3.1 单元测试方案:组件级白盒测试
单元测试的核心目标是验证每个组件的内部逻辑是否符合预期,不需要依赖其他组件或者外部服务,所有外部依赖都用桩模块模拟。
3.1.1 各组件的单元测试要点
| 组件名称 | 测试核心点 | 断言方式 |
|---|---|---|
| 规划模块 | 1. 是否能正确识别需要调用的工具/需要检索的RAG 2. 是否能正确生成工具调用参数 3. 是否能正确处理LLM的异常返回(格式错误、空值、不存在的工具) |
逻辑断言:判断工具名称、参数是否符合预期 异常断言:判断是否能正确抛出异常或者重试 |
| 记忆模块 | 1. 是否能正确提取指定窗口的上下文 2. 是否能正确过滤无效信息 3. 是否能正确存储和读取长期记忆 |
逻辑断言:判断返回的上下文是否包含预期内容 边界断言:判断窗口大小超出限制时是否能正确截断 |
| RAG检索模块 | 1. 是否能召回相关的Chunk 2. Top N召回的准确率、召回率是否达标 3. 是否能正确处理空查询、无关查询 |
语义断言:判断召回的Chunk和查询词的相似度是否达标 逻辑断言:判断召回的数量是否符合预期 |
| 工具调用模块 | 1. 是否能正确调用指定工具 2. 是否能正确处理工具的异常返回(报错、超时、格式错误) 3. 是否能正确解析工具返回的结果 |
逻辑断言:判断工具调用的参数、返回结果是否符合预期 异常断言:判断是否能正确处理工具异常 |
| 输出生成模块 | 1. 是否能正确整合所有上下文信息 2. 是否能符合指定的语气、格式要求 3. 是否能避免幻觉输出 |
语义断言:判断输出的语义是否符合预期 逻辑断言:判断输出是否包含预期的关键信息 |
3.1.2 单元测试代码示例(规划模块)
我们以基于LangChain实现的规划模块为例,展示如何写单元测试:
import pytest
from unittest.mock import Mock, patch
from my_agent.modules.planning import plan
from my_agent.harness.probe import probe
from my_agent.harness.assertion import AssertionEngine
engine = AssertionEngine()
# 用桩模块模拟LLM的返回
@patch("my_agent.modules.planning.call_llm")
def test_plan_call_order_tool(mock_call_llm):
# 模拟LLM返回正确的Function Call
mock_call_llm.return_value = '''
{
"tool_name": "order_query",
"parameters": {
"order_id": "123456",
"user_id": "789"
}
}
'''
# 执行测试
result = plan(
user_query="我的订单123456什么时候发货",
context=[{"role": "user", "content": "我的user id是789"}],
trace_id="test_plan_001"
)
# 逻辑断言:判断是否调用了正确的工具,参数是否正确
expected = {"tool_name": "order_query", "parameters": {"order_id": "123456"}}
assert engine.assert_logic(result, expected) == True
@patch("my_agent.modules.planning.call_llm")
def test_plan_invalid_json_response(mock_call_llm):
# 模拟LLM返回格式错误的JSON
mock_call_llm.return_value = "这不是一个正确的JSON格式"
# 执行测试,预期会抛出参数解析异常
with pytest.raises(ValueError, match="LLM返回的JSON格式错误"):
plan(
user_query="我的订单什么时候发货",
context=[],
trace_id="test_plan_002"
)
@patch("my_agent.modules.planning.call_llm")
def test_plan_unknown_tool(mock_call_llm):
# 模拟LLM返回不存在的工具
mock_call_llm.return_value = '''
{
"tool_name": "unknown_tool",
"parameters": {}
}
'''
# 执行测试,预期会返回直接生成回复的决策
result = plan(
user_query="你好",
context=[],
trace_id="test_plan_003"
)
expected = {"action": "generate_reply"}
assert engine.assert_logic(result, expected) == True
3.2 集成测试方案:组件交互链路测试
单元测试验证了单个组件的正确性,集成测试的核心目标是验证组件之间的交互链路是否符合预期,不需要模拟内部组件,只需要模拟最外层的外部依赖(比如第三方API、LLM可选模拟)。
3.2.1 集成测试的核心链路
我们按照核心业务场景划分集成测试的链路,优先级从高到低:
- 核心工具调用链路:用户提问->记忆模块提取上下文->规划模块决策调用工具->工具调用模块执行->生成模块返回结果
- RAG问答链路:用户提问->记忆模块提取上下文->RAG检索相关Chunk->生成模块返回结果
- 多轮对话链路:多轮用户提问->记忆模块存储上下文->规划模块基于上下文决策->生成模块返回连贯的回复
- 异常处理链路:工具返回异常/ RAG返回空/ LLM超时->各个组件的异常处理->生成模块返回友好的错误提示
3.2.2 集成测试流程图
3.2.3 集成测试代码示例(工具调用链路)
import pytest
from unittest.mock import patch
from my_agent.agent import Agent
from my_agent.harness.assertion import AssertionEngine
from my_agent.harness.trace import get_trace_data
engine = AssertionEngine()
agent = Agent()
@patch("my_agent.modules.tool_call.order_query_api")
def test_integration_order_query_link(mock_order_api):
# 模拟订单查询API的返回
mock_order_api.return_value = {
"order_id": "123456",
"status": "shipped",
"ship_time": "2024-05-20",
"delivery_time": "2024-05-22"
}
# 执行测试
trace_id = "test_integration_001"
reply = agent.run(
user_query="我的订单123456什么时候到",
context=[{"role": "user", "content": "我的user id是789"}],
trace_id=trace_id
)
# 1. 链路断言:判断组件调用顺序是否正确
trace_data = get_trace_data(trace_id)
component_order = [item["component_name"] for item in trace_data]
assert component_order == ["memory_module", "planning_module", "tool_call_module", "generation_module"]
# 2. 参数传递断言:判断工具调用的参数是否正确
tool_call_input = next(item["input"] for item in trace_data if item["component_name"] == "tool_call_module")
assert tool_call_input["tool_name"] == "order_query"
assert tool_call_input["parameters"]["order_id"] == "123456"
# 3. 输出语义断言:判断回复是否符合预期
expected_reply = "你的订单123456已经发货,预计2024-05-22送达"
assert engine.assert_semantic(reply, expected_reply) == True
四、Harness系统设计与核心实现
4.1 系统架构设计
4.2 核心接口设计
| 接口名称 | 请求方法 | 路径 | 核心参数 | 返回值 |
|---|---|---|---|---|
| 探针上报 | POST | /v1/probe/report | trace_id、component_name、input、output、timestamp、cost_time | 成功/失败状态 |
| 桩数据查询 | POST | /v1/stub/get | component_name、input、trace_id | 模拟的输出数据 |
| 用例执行 | POST | /v1/test/run | case_id、case_config、agent_version | 执行状态、trace_id |
| 测试报告查询 | GET | /v1/report/{case_id} | case_id、agent_version | 用例通过率、覆盖率、错误详情 |
| 覆盖率查询 | GET | /v1/coverage | agent_version | 组件覆盖率、链路覆盖率、逻辑覆盖率、总覆盖率 |
4.3 核心实现代码
4.3.1 无侵入探针实现
import functools
import time
from typing import Any, Callable
import aiohttp
from pydantic import BaseModel
from contextvars import ContextVar
trace_id_var: ContextVar[str] = ContextVar("trace_id", default="default")
class ProbeReport(BaseModel):
trace_id: str
component_name: str
input: Any
output: Any
timestamp: float
cost_time: float
error: str | None = None
PROBE_REPORT_URL = "http://harness-core/v1/probe/report"
ENABLE_PROBE = True # 生产环境设置为False
def probe(component_name: str) -> Callable:
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
if not ENABLE_PROBE:
return await func(*args, **kwargs)
trace_id = trace_id_var.get()
start_time = time.time()
error = None
output = None
try:
output = await func(*args, **kwargs)
return output
except Exception as e:
error = str(e)
raise
finally:
cost_time = time.time() - start_time
report = ProbeReport(
trace_id=trace_id,
component_name=component_name,
input={"args": args, "kwargs": kwargs},
output=output,
timestamp=start_time,
cost_time=cost_time,
error=error
)
# 异步上报,不阻塞主流程
try:
async with aiohttp.ClientSession() as session:
await session.post(PROBE_REPORT_URL, json=report.dict(), timeout=0.5)
except Exception:
pass
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
if not ENABLE_PROBE:
return func(*args, **kwargs)
trace_id = trace_id_var.get()
start_time = time.time()
error = None
output = None
try:
output = func(*args, **kwargs)
return output
except Exception as e:
error = str(e)
raise
finally:
cost_time = time.time() - start_time
report = ProbeReport(
trace_id=trace_id,
component_name=component_name,
input={"args": args, "kwargs": kwargs},
output=output,
timestamp=start_time,
cost_time=cost_time,
error=error
)
# 异步上报,不阻塞主流程
import threading
def send_report():
import requests
try:
requests.post(PROBE_REPORT_URL, json=report.dict(), timeout=0.5)
except Exception:
pass
threading.Thread(target=send_report, daemon=True).start()
return async_wrapper if func.__code__.co_flags & 0x80 else sync_wrapper
return decorator
4.3.2 语义断言引擎实现
from typing import Any, Dict, List
import openai
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity as sk_cosine_similarity
class AssertionEngine:
def __init__(self, similarity_threshold: float = 0.85, embedding_model: str = "text-embedding-3-small"):
self.similarity_threshold = similarity_threshold
self.embedding_model = embedding_model
self.openai_client = openai.Client()
self.embedding_cache = {}
def _get_embedding(self, text: str) -> List[float]:
if text in self.embedding_cache:
return self.embedding_cache[text]
resp = self.openai_client.embeddings.create(input=text, model=self.embedding_model)
emb = resp.data[0].embedding
self.embedding_cache[text] = emb
return emb
def assert_logic(self, actual: Any, expected: Dict) -> bool:
"""逻辑断言:验证实际输出是否符合预期的逻辑规则"""
if isinstance(expected, dict):
if not isinstance(actual, dict):
return False
for key, value in expected.items():
if key not in actual:
return False
if not self.assert_logic(actual[key], value):
return False
return True
elif isinstance(expected, list):
if not isinstance(actual, list):
return False
for item in expected:
if not any(self.assert_logic(actual_item, item) for actual_item in actual):
return False
return True
else:
return actual == expected
def assert_semantic(self, actual_text: str, expected_text: str) -> bool:
"""语义断言:验证两个文本的语义相似度是否达标"""
actual_emb = self._get_embedding(actual_text)
expected_emb = self._get_embedding(expected_text)
similarity = sk_cosine_similarity([actual_emb], [expected_emb])[0][0]
return similarity >= self.similarity_threshold
def assert_rag_recall(self, actual_chunks: List[str], expected_chunks: List[str], top_k: int = 3) -> bool:
"""RAG召回断言:验证召回的Top N Chunk是否包含预期的内容"""
for expected in expected_chunks:
found = False
for actual in actual_chunks[:top_k]:
if self.assert_semantic(actual, expected):
found = True
break
if not found:
return False
return True
4.4 测试覆盖率数学模型
我们定义三维覆盖率模型来量化白盒测试的覆盖程度:
-
组件覆盖率 CcC_cCc:衡量单个组件的测试覆盖情况
Cc=NctestedNctotalC_c = \frac{N_{c}^{tested}}{N_{c}^{total}}Cc=NctotalNctested
其中 NctestedN_{c}^{tested}Nctested 是已经被测试用例覆盖的组件数量,NctotalN_{c}^{total}Nctotal 是Agent的总组件数量。 -
链路覆盖率 CpC_pCp:衡量组件之间交互路径的覆盖情况
Cp=NptestedNptotalC_p = \frac{N_{p}^{tested}}{N_{p}^{total}}Cp=NptotalNptested
其中 NptestedN_{p}^{tested}Nptested 是已经被测试用例覆盖的交互路径数量,NptotalN_{p}^{total}Nptotal 是Agent所有可能的交互路径数量,可以通过组件的调用关系图计算得到。 -
逻辑覆盖率 ClC_lCl:衡量组件内部决策分支的覆盖情况
Cl=NbtestedNbtotalC_l = \frac{N_{b}^{tested}}{N_{b}^{total}}Cl=NbtotalNbtested
其中 NbtestedN_{b}^{tested}Nbtested 是已经被测试用例覆盖的决策分支数量,NbtotalN_{b}^{total}Nbtotal 是组件内部的总决策分支数量。
总加权覆盖率:
Ctotal=αCc+βCp+γClC_{total} = \alpha C_c + \beta C_p + \gamma C_lCtotal=αCc+βCp+γCl
其中 α,β,γ\alpha, \beta, \gammaα,β,γ 是权重系数,满足 α+β+γ=1\alpha + \beta + \gamma = 1α+β+γ=1,可以根据业务场景调整:
- 工具调用密集型Agent:α=0.2,β=0.5,γ=0.3\alpha=0.2, \beta=0.5, \gamma=0.3α=0.2,β=0.5,γ=0.3
- RAG问答密集型Agent:α=0.2,β=0.3,γ=0.5\alpha=0.2, \beta=0.3, \gamma=0.5α=0.2,β=0.3,γ=0.5
- 多轮对话密集型Agent:α=0.25,β=0.45,γ=0.3\alpha=0.25, \beta=0.45, \gamma=0.3α=0.25,β=0.45,γ=0.3
五、落地案例与最佳实践
5.1 落地案例:电商客服Agent
我们团队的电商客服Agent上线初期,线上故障率高达32%,用户投诉率居高不下,每次上线需要测试人员花3天时间跑黑盒用例,还是经常漏测问题。落地这套Harness白盒测试方案之后:
- 单元测试覆盖率:94%
- 集成测试覆盖率:91%
- 线上故障率:2.7%
- 上线测试时间:从3天缩短到4小时
典型问题定位案例
用户反馈:“我昨天下单的iPhone 15什么时候发货?我之前已经给过订单号了,为什么还要我再提供一次?”
通过Harness的Trace数据我们很快定位到问题:记忆模块的上下文窗口设置的是最近2条消息,但是用户的订单号在第3条消息里,规划模块没有拿到订单号,所以要求用户再次提供。我们把记忆窗口调整为5条之后,问题就解决了,整个排查过程只用了2分钟。
5.2 最佳实践Tips
- 探针设计要无侵入:优先用装饰器、AOP、字节码注入的方式埋探针,不要修改Agent的业务逻辑,避免测试代码和业务代码耦合。
- 桩模块要覆盖三类场景:正常返回、异常返回(报错、格式错误)、超时返回,模拟所有可能的外部依赖情况。
- 断言分层设计:优先做逻辑断言,再做语义断言,不要做字符串完全匹配的断言,避免误报。
- 测试用例版本化:每个Agent版本对应一套测试用例,每次迭代跑全量回归,避免新的修改引入旧的bug。
- 非核心组件降级测试:比如输出生成模块的自定义语气、表情这些非核心逻辑,可以不用做白盒测试,用黑盒抽样测试就行。
- 测试环境和生产环境隔离:Harness的探针只在测试环境开启,生产环境要关闭,避免影响性能和数据安全。
- 故障转化为用例:每次线上故障都要转化为对应的白盒测试用例,加到用例库里,避免下次再犯。
- 阈值动态调整:语义相似度的阈值、覆盖率的权重都要根据业务场景调整,金融场景的阈值要设到0.9以上,客服场景可以设到0.8。
六、行业发展趋势与边界说明
6.1 行业发展趋势
| 时间 | 阶段 | 核心特点 | 代表产品 | 覆盖率能力 |
|---|---|---|---|---|
| 2022年及以前 | 黑盒测试阶段 | 只能验证最终输出,完全看不到内部逻辑 | 自定义脚本、PromptFoo | <30% |
| 2023年 | 半白盒测试阶段 | 可以看到LLM的输入输出,简单的链路追踪 | LangSmith、LangFuse | 30%-60% |
| 2024年 | 白盒测试阶段 | 可以覆盖所有组件的内部状态和交互链路,完整的Harness框架 | 开源Harness框架、企业级Agent测试平台 | 60%-95% |
| 2025-2026年 | 智能测试阶段 | 自动生成测试用例、自动根因分析、自动修复简单问题 | 智能测试Agent、内生安全的Agent框架 | >95% |
6.2 方案边界与适用范围
- 适用场景:基于模块化设计搭建的Agent,比如用LangChain、LlamaIndex、自定义组件搭建的Agent,有明确的组件划分和交互逻辑。
- 不适用场景:完全端到端的黑盒Agent,比如直接调用GPT-4o的原生Agent能力,没有自定义组件的,无法埋探针,就不适用这套方案。
- 和黑盒测试的关系:白盒测试是黑盒测试的补充,不是替代,白盒测试覆盖内部逻辑,黑盒测试覆盖用户体验,两者结合才能做到完整的质量保障。
七、FAQ与总结
7.1 常见问题FAQ
Q1:白盒测试会不会增加很多开发工作量?
A:一开始搭建Harness框架需要1-2周的工作量,但是后续每个版本的测试时间可以减少70%以上,线上故障排查时间减少90%以上,长期来看是大幅提升效率的。
Q2:非确定性输出怎么写断言?
A:不要断言具体的字符串内容,要断言核心逻辑:比如有没有调用正确的工具、参数是否符合要求、RAG召回的Top3 Chunk是否包含预期的内容、输出的语义和预期的相似度是否达标。
Q3:小团队有没有必要搞这么复杂的测试?
A:可以渐进式落地,先给核心组件(比如规划、工具调用)加探针,写单元测试,再逐步扩展到集成测试,不需要一步到位搭完整的Harness平台,甚至可以先用本地的日志采集代替远程的Harness服务。
Q4:白盒测试会影响Agent的性能吗?
A:探针的上报是异步的,而且只在测试环境开启,生产环境关闭,对性能的影响可以忽略不计,我们测试下来,开启探针的情况下,Agent的响应时间只增加了2-3ms,完全可以接受。
7.2 总结
本文我们从AI Agent测试的痛点出发,介绍了基于Harness Engineering的白盒测试方案,从单元测试到集成测试的完整流程,包括Harness的架构设计、核心实现代码、度量模型、落地案例和最佳实践。这套方案已经在我们团队的多个Agent项目中落地,上线故障率从32%降到了2.7%以下,大幅提升了Agent的交付质量和迭代效率。
AI Agent的质量保障是未来2年行业的核心痛点,白盒测试和Harness Engineering是解决这个问题的核心路径,随着行业的发展,会有越来越多的成熟工具和方案出现,我们也会持续在这个领域探索,欢迎大家在评论区交流你的Agent测试经验。
延伸阅读
- LangSmith官方文档:https://docs.smith.langchain.com/
- PromptFoo官方文档:https://www.promptfoo.dev/
- 《Building Agentic RAG Systems》O’Reilly书籍
(全文约11200字)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)