别被提示词优化困住!用DSPy.GEPA把Prompt做成可演进的工程(万字长文)

写给正在落地 AI 产品的工程师。一些代码直接可改造复用;另一些,是我踩坑后的经验之谈。
写给正在落地 AI 产品的工程师。一些代码直接可改造复用;另一些,是我踩坑后的经验之谈。
为什么是 DSPy.GEPA,而不是“再手搓一次提示”
DSPy是一个2024年5月修猫曾反复推荐给大家的一个AI程序,您有兴趣的话可以翻一下之前关于DSPy的文章。毋庸置疑,DSPy.GEPA接下来会成为很多AI应用的Prompt优化器,当然最有可能成为众多AI应用程序中的一个优化模块。在国庆期间OpenAI的新产品Agentkit中就有用到DSPy.GEPA。读这篇文章不过是早了解一下,因为您迟是需要了解一下的。
- 反思 + 文本反馈,不止分数:GEPA 支持指标函数返回“分数 + 自然语言原因”,反思模型由此定位“错在哪”,再定向改写子模块的提示;样本效率高、rollouts 少也能稳步提升。
- Pareto 维护多样性,而非只盯全局最优:在验证集上形成前沿集合,避免早停或陷入局部最优,适合多目标/多约束业务场景。具体您可以看下上一篇《Agent多步误差咋破?看下GEPA,反思自进化+帕累托前沿,超过DSPy的MIPROv2(在新窗口打开)》其实,GEPA的论文也是DSPy主创团队的Paper,您有兴趣的话可以仔细阅读一下~
- 模块级演化 + 系统合并:不仅优化一个“大提示”,而是针对具体模块产生候选,并在需要时“合并/交叉”出系统级的更优组合。
- 可观测、可审计、费用可控:完整 trace、与 MLflow 的良好集成;每一次改动与得分都能复盘,工程上可依赖。
关于与代理框架的协同:十一期间,OpenAI 的 AgentKit 发布,明确支持以工程化方式组织代理与工具链,开发者表示已经将 GEPA 这类提示优化器接入到 AgentKit 的开发流程中(作为反思/调优阶段)。如果您使用的类似 AgentKit 之类的流程类的无代码开发工具未内置 GEPA,也可以通过适配器把 Agent 的决策逻辑包装成一个 DSPy 模块,用 GEPA 优化其提示与子策略,二者职责清晰、边界分明。
我会在文中展示 dspy.GEPA 的两种基础用法:
- 模式 A(产品化 UI 优化器):给项目加一层 UI,让团队“点一点就能对比/优化各个模块的 prompt”;配合 MLflow/日志,适合持续 A/B 与迭代,这个优化出来的提示可以用于各种环境。
- 模式 B(程序内联):直接用 DSPy.GEPA 写 AI 程序,把优化环节内嵌到开发流水线与单元评测里。我推荐模式B,这样看起来,会随着反馈数据的增加,提示词也会被自动优化。
与 OpenAI AgentKit 协同的适配骨架
不依赖 AgentKit 内置支持,也能把 GEPA 接入到代理开发中。核心是把“代理的策略/指令模板”封装为 DSPy 模块:
# 把 Agent 的一步决策包装成 DSPy.Module,便于 GEPA 优化其指令
classAgentStep(dspy.Signature):
context: str = dspy.InputField()
reply: str = dspy.OutputField()
classAgentModule(dspy.Module):
def__init__(self):
# 用 CoT 包一层,使 GEPA 能在指令层面演化
self.policy = dspy.ChainOfThought(AgentStep)
defforward(self, context: str):
# 在这里桥接到 AgentKit:把 policy 产出的回复/意图,交给 AgentKit runtime 执行
# action = agentkit.act(context, hint=self.policy_instructions) # 伪代码
out = self.policy(context=context)
return dspy.Prediction(reply=out.reply)
# metric 以任务成功率、工具调用正确率或安全规则为准则,返回分数+文字反馈
reflector = dspy.LM(model='gpt-5', temperature=1.0, max_tokens=32000)
gepa = dspy.GEPA(metric=metric, reflection_lm=reflector, auto='medium')
optimized_agent = gepa.compile(AgentModule(), trainset=train_tasks, valset=val_tasks)
实际工程里,metric可以基于端到端任务成功(工具调用、输出格式、策略合规)产生可解释的反馈文本;AgentKit 继续负责工具与环境调用,GEPA 负责“让策略指令更聪明”。
项目的核心目标
- 把“提示调参”升级为“反思驱动的工程循环”:观测 → 反馈 → 生成候选 → 评估 → 选择/合并。
- 让反馈不仅是分数,还有原因(自然语言),并且精确到子模块;这样模型知道“错在哪、该怎么改”。
- 通过 Pareto 前沿维持多样性,避免只追单一全局最优导致早停或卡住。
- 在有限预算下(metric 调用数或完整评估次数)给您稳定、可复现的迭代收益。
这和“AI 控制研究”的目标意外地一致:我们需要可控、可迁移的策略,而不是一次性调好的咒语。LessWrong 上那篇关于“提示优化推动 AI 控制研究”的文章说得很实在——人工手改提示太慢、可迁移性差;把反馈变成优化面,研究速度和可重复性会不一样。
两种基础用法:UI 优化器 vs. 程序内联
模式 A(给项目加 UI,做 Prompt 优化与对比):
- 适合团队/运营同学参与,通过 Web UI 选择数据子集、触发一次 GEPA 运行、对比不同候选提示在关键指标上的表现;
- 结合track_stats=True与 MLflow,保留每次演化的提示文本与评测曲线;
- 提示与数据逐步沉淀到版本库,成为“可复盘”的资产。
import gradio as gr
# 假设已定义 program/train_set/val_set 与上文 metric/reflector
gepa = dspy.GEPA(metric=metric, reflection_lm=reflector, auto='light', track_stats=True, log_dir='./ui_runs')
defrun_once(sample_size:int=50):
# 选一个子集做快速迭代(UI 模式强调“快试快看”)
subset = train_set[:sample_size]
new_prog = gepa.compile(program, trainset=subset, valset=val_set)
# 返回关键信息用于页面展示
scores = new_prog.detailed_results.val_aggregate_scores ifhasattr(new_prog, 'detailed_results') else []
returnf"candidates={len(scores)}; best={max(scores) if scores else 'n/a'}"
demo = gr.Interface(fn=run_once, inputs=gr.Number(value=50, label='train subset size'), outputs="text")
demo.launch()
模式 B(程序内联,用 GEPA 写 AI 程序):
- 把业务流程拆成多个 DSPy 模块(签名明确的输入/输出),GEPA 面向模块级别自动演化提示;
- 单元评测与回归数据可直接转成 GEPA 的反馈(分数 + 文字说明);
- 更适合持续集成/交付(CI/CD)与自动化评审流水线。
小提示:如果您要在 AgentKit 的代理里用 GEPA,修猫建议把“策略/指令模板”封装为一个 DSPy.Module,然后通过桥接函数把代理的调用上下文映射为该 Module 的输入;GEPA 会在这个模块上反思与演化提示,而 AgentKit 维持工具/环境交互。
工程上下文:把“反思”这件事做得可观测
- 模型与温度:推理模型可以普通,反思模型建议偏强(文档中推荐dspy.LM(model='gpt-5', temperature=1.0, max_tokens=32000)这类)。
- 追踪与日志:DSPy 的 trace 会标注每个子模块的执行;MLflow 集成可以将 GEPA 的优化过程、提示版本、模块调用可视化。
- 反馈来源:单元校验、JSON Schema、约束检查器、业务规则、甚至 LLM‑as‑a‑judge 的文字说明,统统变成“反馈文本”。
- 预算与并行:auto/max_metric_calls/max_full_evals明确资源上限;num_threads控制并发;reflection_minibatch_size决定每步反思使用的样本数。
GEPA 的优势和劣势
适用场景(Works Well):
- 任务是开放式、模糊的,或者客观上存在多个“足够好”的答案;
- 您更关心语义一致或行为一致,而不是严格的逐字完全匹配;
- 具备较强的反思模型(reflection LLM),能够理解反馈、概括规律并改写指令。
不太适用(Makes Less Sense):
- 任务非常简单,或者只有唯一且明确的标准答案(无需演化就能稳定命中);
- 缺少可靠的语义度量/评测器(只有“对/错”而没有“为什么”时,反思空间很小);
- 希望极快地“一把梭”完成一次性优化(GEPA 是迭代式的,追求稳健改进而非秒回)。
GEPA 的“甜蜜区间”(Sweet Spots):
- 专业领域:
- 数学:多步骤求解与自校验;
- 医疗:以安全为前提的医学推理与解释;
- 法律:合同分析与合规性验证;
- 安全:漏洞检测与修复建议;
- 金融:风险评估与与监管口径对齐。
- 质量关键型应用:当准确性、可解释性与可审计性比极致速度更重要时;例如教育内容生成、专业咨询、监管合规、安全关键系统。
- 有限数据:只有 3–10 个高质量示例、领域知识主要靠专家口述时,GEPA 借助“分数+文字反馈”依然能推进优化;也适合专业领域的快速成型。
- 多目标优化:在“准确性+安全+合规”或“性能+可解释+效率”等多指标场景,Pareto 前沿能避免只追单一最优而丢掉互补策略。
何时考虑替代方案:
- 简单、通用型任务:基础问答、简单分类、通用对话代理,传统(或更轻量)的优化器通常已经够用;
- 大数据量场景(100+ 训练样本):更偏向统计学习/微调或批量式的启发式优化,收益/成本比可能更高;
- 资源受限:
- 内存/模型:通常需要一个推理模型 + 一个反思模型;
- 时间:一次有效优化往往要 3–5 分钟甚至更久(视预算与模型而定);
- 计算:比单轮提示调参更密集。可用auto/max_metric_calls/max_full_evals控制预算。
实操建议:有好的语义指标就用起来(哪怕是 LLM‑as‑a‑judge),并把失败原因写清楚;没有就先做最小可用的“反馈器”(validator/test/logs→文字),再上 GEPA。
决策清单(5 分钟自检)
- 使用 GEPA 的信号(满足≥3 条,倾向选 GEPA)
- 任务存在多解或语义等价答案,严格精确匹配并不关键
- 能提供语义型指标或 LLM‑as‑a‑judge,并能输出“为什么”
- 需要在多个目标间权衡(准确性/安全/合规/效率)
- 可提供强一些的反思模型(或能申请到相应配额)
- 数据较少(3–10 个高质量样本起步),但专家能写出规则/校验
- 需要过程可观测、可审计、可复盘(MLflow/trace)
- 暂不使用 GEPA 的信号(≥2 条为真,考虑更轻方案)
- 任务极其简单、答案唯一明确、无需演化
- 没有可用的语义指标或无法给出可解释反馈
- 一次性“立刻”拿到结果更重要(而非稳健迭代)
- 有 100+ 标注样本,更适合微调/统计学习
- 资源受限(只允许一个模型、时间/算力紧张)
- 推荐行动
- 若语义指标缺失,先做最小可用“反馈器”:把单测/Schema/日志转成文本原因
- 从 Program 内联模式起步;确有需求再搭 UI 优化器
- 先跑 light 预算,观测 Pareto 前沿的多样性再加大预算
主要组成部分(您关心的接口)
- dspy.GEPA(metric, *, auto|max_full_evals|max_metric_calls, reflection_minibatch_size=3, candidate_selection_strategy='pareto', reflection_lm=..., skip_perfect_score=True, use_merge=True, ...)
- 只需设置一种预算:auto或max_metric_calls或max_full_evals。
- candidate_selection_strategy='pareto'保持多策略共存;也可设'current_best'追当前最强。
- use_merge=True时,会把不同谱系的强项模块合并,常见于多模块流水线有互补优势时。
- GEPAFeedbackMetric(指标协议)
- 签名:metric(gold, pred, trace=None, pred_name=None, pred_trace=None) -> float | {'score': float, 'feedback': str}
- 支持模块级反馈:GEPA 优化某个模块时会传入pred_name/pred_trace,您就能给定向建议。
- 没有文本反馈时,GEPA 会自动把分数转成一句话;但强烈建议给出可操作的自然语言原因。
- DspyGEPAResult(详细结果)
- candidates, parents, val_aggregate_scores, val_subscores, per_val_instance_best_candidates, ...
- best_outputs_valset(当track_best_outputs=True时)可直接拿到每个任务的最优输出。
案例:企业结构化抽取
任务:输入是一封有关设施支持的邮件,要抽出三类信息——
- 紧急程度:low|medium|high
- 情感:positive|neutral|negative|mixed|unclear
- 多标签类别:如cleaning_services_scheduling, routine_maintenance_requests, ...
先给一个基线 DSPy 程序(3 个子模块,各自 Chain‑of‑Thought),随后我们用 GEPA 自动演化提示,减少您手改的时间。
# 1) 配置推理模型(示例用小模型,可替换为您的供应商)
import dspy
lm = dspy.LM(model="openai/gpt-4.1-nano", temperature=1)
dspy.configure(lm=lm)
# 2) 定义签名与模块
from typing importList, Literal
classFacilitySupportAnalyzerUrgency(dspy.Signature):
"""Read the provided message and determine the urgency."""
message: str = dspy.InputField()
urgency: Literal['low','medium','high'] = dspy.OutputField()
classFacilitySupportAnalyzerSentiment(dspy.Signature):
"""Read the provided message and determine the sentiment."""
message: str = dspy.InputField()
sentiment: Literal['positive','neutral','negative','mixed','unclear'] = dspy.OutputField()
classFacilitySupportAnalyzerCategories(dspy.Signature):
"""Read the provided message and determine all applicable categories."""
message: str = dspy.InputField()
categories: List[Literal[
"emergency_repair_services",
"routine_maintenance_requests",
"quality_and_safety_concerns",
"specialized_cleaning_services",
"general_inquiries",
"sustainability_and_environmental_practices",
"training_and_support_requests",
"cleaning_services_scheduling",
"customer_feedback_and_complaints",
"facility_management_issues",
]] = dspy.OutputField()
classFacilitySupportAnalyzerMM(dspy.Module):
def__init__(self):
self.urgency_module = dspy.ChainOfThought(FacilitySupportAnalyzerUrgency)
self.sentiment_module = dspy.ChainOfThought(FacilitySupportAnalyzerSentiment)
self.categories_module = dspy.ChainOfThought(FacilitySupportAnalyzerCategories)
defforward(self, message: str):
u = self.urgency_module(message=message)
s = self.sentiment_module(message=message)
c = self.categories_module(message=message)
return dspy.Prediction(urgency=u.urgency, sentiment=s.sentiment, categories=c.categories)
program = FacilitySupportAnalyzerMM()
反馈设计:越“像人评审”,GEPA 越知道往哪改
“分数 + 文本理由”让反思 LLM 抓到症结。比如:
- 紧急程度:错在“把礼貌用语当成高优先级信号”。
- 情感:错在“把常规致谢误判为正向情绪”。
- 类别:错在“把 HVAC 的预约当成清洁安排(应判为 routine_maintenance_requests)”。
下面是一份可直接复用的指标函数。它会为每个子模块给出定向反馈(若 GEPA 传入pred_name),否则给出程序级反馈;并把三项任务合成一个 0–1 的平均分。
import json
from typing import Optional
ALLOWED_CATEGORIES = {
"emergency_repair_services",
"routine_maintenance_requests",
"quality_and_safety_concerns",
"specialized_cleaning_services",
"general_inquiries",
"sustainability_and_environmental_practices",
"training_and_support_requests",
"cleaning_services_scheduling",
"customer_feedback_and_complaints",
"facility_management_issues",
}
SENTIMENTS = {"positive","neutral","negative","mixed","unclear"}
URGENCIES = {"low","medium","high"}
def_safe_list(x):
return x ifisinstance(x, list) else []
defmetric(gold: dspy.Example,
pred: dspy.Prediction,
trace: Optional["DSPyTrace"] = None,
pred_name: Optional[str] = None,
pred_trace: Optional["DSPyTrace"] = None):
# gold.answer 约定为 JSON 字符串:{"urgency":..., "sentiment":..., "categories": {...或列表...}}
try:
gold_obj = json.loads(gold["answer"]) ifisinstance(gold["answer"], str) else gold["answer"]
except Exception:
# 数据脏的情况,给出温和的降级
gold_obj = {"urgency": None, "sentiment": None, "categories": []}
# 归一化 gold categories(既兼容字典,也兼容列表)
g_c = gold_obj.get("categories", [])
ifisinstance(g_c, dict):
gold_categories = sorted([k for k, v in g_c.items() if v])
else:
gold_categories = sorted([c for c in _safe_list(g_c) if c in ALLOWED_CATEGORIES])
# 取 pred 输出
p_u = getattr(pred, "urgency", None)
p_s = getattr(pred, "sentiment", None)
p_c = sorted([c for c in _safe_list(getattr(pred, "categories", [])) if c in ALLOWED_CATEGORIES])
# 逐项打分
s_u = 1.0if p_u in URGENCIES and p_u == gold_obj.get("urgency") else0.0
s_s = 1.0if p_s in SENTIMENTS and p_s == gold_obj.get("sentiment") else0.0
# 类别:F1 更稳妥,这里示例按严格一致;也可以用 Jaccard/F1
s_c = 1.0if p_c == sorted(gold_categories) else0.0
score = (s_u + s_s + s_c) / 3.0
# 文本反馈(模块定向 or 程序级)
hints = []
# 紧急程度
if s_u < 1:
hints.append(
"紧急程度:避免把礼貌性的“尽快”“感谢”当成高优先级;只有出现安全隐患、业务中断、近期限时,才提升到 high/medium。")
# 情感
if s_s < 1:
hints.append(
"情感:普通礼貌与求助语气通常是 neutral;只有出现明确赞扬/抱怨/挫败感时才判 positive/negative/mixed。")
# 类别
if s_c < 1:
if"routine_maintenance_requests"in gold_categories and"cleaning_services_scheduling"in p_c:
hints.append("类别:把 HVAC 等维护预约当成清洁安排了,应改为 routine_maintenance_requests。")
else:
hints.append("类别:仅选择文本明确支持的条目;不要外推隐含意图,也不要使用未在白名单中的标签。")
# 拼装反馈
feedback = "\n".join(hints) if hints else"各子任务判断合理。"
# 如果 GEPA 正在优化具体模块,尽量给定向建议
if pred_name:
feedback = f"[{pred_name}] 优化建议:\n" + feedback
return {"score": float(score), "feedback": feedback}
用 GEPA 让提示“自己进步”
# 反思模型建议用强一些的(示例名仅占位,替换成您的可用模型)
reflector = dspy.LM(model='gpt-5', temperature=1.0, max_tokens=32000)
gepa = dspy.GEPA(
metric=metric,
reflection_lm=reflector,
auto='medium', # 或改为 max_metric_calls / max_full_evals
reflection_minibatch_size=3,
candidate_selection_strategy='pareto',
use_merge=True,
track_stats=True,
log_dir='./gepa_logs'
)
optimized = gepa.compile(program, trainset=train_set, valset=val_set)
GEPA 在每次迭代会:
- 从 Pareto 前沿抽样一个候选与一个小批次;
- 收集该候选的执行轨迹与反馈,定位到某个模块;
- 用反思 LLM 产出新指令;
- 若小批次上提升,再在验证集评估并更新候选池;
- (可选)对不同行系的强项模块做合并/交叉。
您在日志里会看到类似“为urgency_module.predict生成了新指令”的片段;这些文本就是被优化后的“提示”,而不是手改一堆 prompt 片段。
把 MLflow 串起来:过程可见、结果可复盘
import mlflow
mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("DSPy")
# 自动记录 GEPA 编译、评估与 Trace
mlflow.dspy.autolog(
log_compiles=True,
log_evals=True,
log_traces=True
)
我建议在团队里固定开启 autologging。谁在什么数据上优化过、提示怎样演化、哪一次回退值得保留,MLflow 都能直接回答。出了回归,也能快速 bisect。
进阶选项与何时使用
- component_selector='round_robin':模块很多且数据分布不均时,避免某些模块长期得不到关注。
- instruction_proposer(高级):需要多模态(如图像+文本)、更细粒度约束或接入外部知识库时,用自定义 proposer 扩展生成逻辑。
- add_format_failure_as_feedback:输出偶发格式错(JSON 崩掉)时,把格式化失败也注入反馈里,反思模型会学会“别再犯”。
- use_merge / max_merge_invocations:当不同候选在不同子任务上各有千秋时,让系统级表现进一步抬升。
常见坑与我推荐的规避法
- 反馈太笼统:只给分不说因,反思就会“胡改”。最少要指出错在“判据”,而不是只说“错了”。
- Val 集过窄:Pareto 容易被“记住固定样本”骗到;请确保验证集覆盖关键决策边界。
- 长上下文成本:反思 LLM 的上下文里请只塞“决定性信息”(错误段落、关键日志、失败校验),别把整段流水账堆进去。
- 模块边界不清:Signature 要明确输入/输出,预测目标单一。否则定位不到“哪个模块需要改”。
最小可运行脚本(串起来看更有感觉)
import dspy, json, random
from typing importList, Literal
# 1) 配置推理与反思模型
base_lm = dspy.LM(model="openai/gpt-4.1-nano", temperature=1)
reflector = dspy.LM(model='gpt-5', temperature=1.0, max_tokens=32000)
dspy.configure(lm=base_lm)
# 2) 定义任务模块
classUrg(dspy.Signature):
message: str = dspy.InputField()
urgency: Literal['low','medium','high'] = dspy.OutputField()
classSent(dspy.Signature):
message: str = dspy.InputField()
sentiment: Literal['positive','neutral','negative','mixed','unclear'] = dspy.OutputField()
classCats(dspy.Signature):
message: str = dspy.InputField()
categories: List[str] = dspy.OutputField()
classApp(dspy.Module):
def__init__(self):
self.u = dspy.ChainOfThought(Urg)
self.s = dspy.ChainOfThought(Sent)
self.c = dspy.ChainOfThought(Cats)
defforward(self, message: str):
u, s, c = self.u(message=message), self.s(message=message), self.c(message=message)
return dspy.Prediction(urgency=u.urgency, sentiment=s.sentiment, categories=c.categories)
program = App()
# 3) 构造一个玩具数据集(真实项目用您自己的数据与切分)
data = [
dspy.Example({
"message": "Please adjust cleaning schedule to Tue/Fri; no urgency.",
"answer": json.dumps({
"urgency": "low",
"sentiment": "neutral",
"categories": ["cleaning_services_scheduling"]
})
}).with_inputs("message"),
]
train_set = data
val_set = data
# 4) 指标函数(可替换为上文完整版 metric)
ALLOWED_CATEGORIES = {"cleaning_services_scheduling"}
SENTIMENTS = {"positive","neutral","negative","mixed","unclear"}
URGENCIES = {"low","medium","high"}
defmetric(gold, pred, trace=None, pred_name=None, pred_trace=None):
g = json.loads(gold["answer"]) ifisinstance(gold["answer"], str) else gold["answer"]
p_u = getattr(pred, "urgency", None)
p_s = getattr(pred, "sentiment", None)
p_c = [c for c in (getattr(pred, "categories", []) or []) if c in ALLOWED_CATEGORIES]
s_u = 1.0if p_u == g.get("urgency") else0.0
s_s = 1.0if p_s == g.get("sentiment") else0.0
s_c = 1.0ifsorted(p_c) == sorted(g.get("categories", [])) else0.0
score = (s_u + s_s + s_c) / 3.0
fb = []
if s_u < 1: fb.append("紧急程度判据使用不当;仅在安全/中断/近期限时时提升等级。")
if s_s < 1: fb.append("情感标签与语气不符;礼貌语气通常为 neutral。")
if s_c < 1: fb.append("类别选择不严;只选文本明确支持的类别。")
txt = (f"[{pred_name}]\n"if pred_name else"") + "\n".join(fb or ["判断合理。"])
return {"score": float(score), "feedback": txt}
# 5) GEPA 编译
gepa = dspy.GEPA(metric=metric, reflection_lm=reflector, auto='light', track_stats=True)
optimized = gepa.compile(program, trainset=train_set, valset=val_set)
# 6) 使用优化后的程序
out = optimized(message="Need to adjust cleaning to Tue/Fri; everything is fine.")
print(out)
结尾小结(不“喊口号”,说两句实话)
- 如果您已经有一套验证与日志,就差“把原因说清楚”,GEPA 立刻能用起来;
- 如果您还在手改提示、不断回归,不妨试试把“约束与错误”变成文字反馈;
- 如果您的目标是可控、可复现、可迁移的策略,那么把提示“做成工程”,确实更稳。
项目作者把这条路打通了,剩下的就是把它放进您的流水线里。
引用链接:
[1]:https://dspy.ai/tutorials/gepa_facilitysupportanalyzer/
文章来自于“Al修猫Prompt”,作者“Al修猫Prompt”。
相关主题
读完之后
加入 AINRK 交流群
了解加入交流群的方式,与更多 AI 从业者交流。




