模型调用 3|怎样让程序可靠地接收模型输出?

假设你在做一个活动通知页面。模型负责从通知中提取报名截止日期,程序把日期、出处和原文填进页面。

模型生成正确答案以后,还有一段工作需要程序完成:从响应中取出回答,检查需要的字段,决定这份结果能否使用。如果生成中断、缺少字段,或者资料不足,页面也需要知道该显示什么。

这篇文章把这段接收过程接起来:先约定数据,再读取真实响应,最后让每份结果进入"已接受、拒收、待核对"中的一个状态。 我们用四次真实模型调用观察正常结果,再用明确标为人工构造的输入检查失败分支。

1. 先决定页面需要什么,再约定模型返回什么

教学资料是两份来自同一主办方、针对同一次读书会的通知。年份均为 2026 年:

程序分配的编号 通知与正文
D1 《读书会报名通知》,9 月 10 日发布:本次读书会报名将于2026年9月20日截止。
D2 《读书会报名调整通知》,9 月 16 日发布:本次读书会报名截止日期提前到2026年9月18日,原通知中的截止日期作废。

页面有"截止日期"和"依据"两个位置,因此让模型返回以下三个字段。字段就是数据中一个有名称的位置:

字段 接收约定 用途
deadline_date 日期字符串,格式为 YYYY-MM-DD 填写页面日期,供程序按日期比较
source_id 从本次资料编号中选择 找到程序已经保存的通知
quote 该通知中支持判断的连续原文 让核对者检查日期与依据

三个字段必须齐全,不接受额外字段。无法确定唯一有效日期时,三个值都填 null,表示没有可用的提取结果。它不能被解释成"活动没有截止日期"。这个简化约定适合当前的单日期页面;若需要分别展示冲突通知或部分已知信息,就要增加相应的数据表达。

我们使用 JSON 保存这些字段。JSON 用名称和值组织数据,程序可以按名称取值,例如读取 deadline_date,不必先从一段回答中识别哪个日期应该填进页面。资料编号由程序分配,模型只从给定编号中选择;通知名称等已有信息可以按编号取回。

这里先定义本例的使用条件:只有字段检查通过,并确认日期有有效通知支持,才把它填入页面的正式结果。 尚未核对的候选可以展示在核对区,但不标为已确认。本例选择人工对照两份通知;实际产品是否需要逐条人工核对,要根据用途和风险决定。

2. 看真实输出怎样对应这份接收约定

2026 年 9 月 19 日,我们通过已配置的 Responses API 兼容接口,分别要求自然语言回答和三字段 JSON 回答,各做两次独立调用。请求模型名和四次响应的 model 均为 gpt-6;这里按接口返回的标识记录,响应未提供可独立核实的底层模型快照。

四次都设置 reasoning.effort="high"max_output_tokens=4096stream=falsestore=false,未传 temperature,也未启用 JSON 模式或 JSON Schema 生成约束。各次重新提供相同通知,不带历史回答、标准答案或校验器代码,没有重试或筛选结果。

两组共有的任务指令是:

根据提供的通知,提取这次读书会唯一有效的报名截止日期,并提供依据。采用明确修改报名日期的通知,不仅凭发布时间选择。只使用本次资料;无法确定唯一有效日期时,不猜测。不要声称执行了报名或联系操作。

自然语言组追加:

请用自然语言简短回答,说明采用哪份通知,并引用支持判断的原文。无法确定时,说明具体缺口。

字段组追加:

只输出 JSON 对象,字段为 deadline_date、source_id、quote;日期使用 YYYY-MM-DD,出处使用给定编号,引文复制支持判断的连续原文。无法确定唯一有效日期时,三个字段都填 null。不要添加解释文字、Markdown 代码围栏或其他字段。

稳定任务与输出要求放在 instructions,两份通知和问题放在 input。问题相同:"这次读书会当前有效的报名截止日期是什么?"

自然语言第 1 次的完整回答是:

当前有效的报名截止日期是 2026年9月18日

采用 D2《读书会报名调整通知》,依据是其明确写道:"本次读书会报名截止日期提前到2026年9月18日,原通知中的截止日期作废。"因此,D1 中的9月20日已失效;判断依据是 D2 明确修改并废止原截止日期,而非仅因其发布较晚。

两次字段回答的文字完全相同,原样为:

json 复制代码
{"deadline_date":"2026-09-18","source_id":"D2","quote":"本次读书会报名截止日期提前到2026年9月18日,原通知中的截止日期作废。"}

四次都正常完成,并正确采用 D2 的 9 月 18 日。把保存的完整响应交给下文的接收程序,再对照通知作出核对决定,结果如下:

实际调用顺序 模型回答的日期与依据 三字段接收程序怎样处理
自然语言第 1 次 9 月 18 日,D2,引文准确 无法解析为 JSON,拒收为字段结果
字段第 1 次 2026-09-18D2,引文准确 自动检查通过,进入待核对;确认依据后变为已接受
自然语言第 2 次 9 月 18 日,D2,引文准确 无法解析为 JSON,拒收为字段结果
字段第 2 次 2026-09-18D2,引文准确 自动检查通过,进入待核对;确认依据后变为已接受

自然语言组完成了它收到的要求,可以直接用于文字展示;本例的字段接收程序需要另一种格式,因此不能把两次拒收计为模型答错。字段组则让程序可以直接按名称取值。这组实测体现的是输出方式与接收约定是否一致,没有显示日期判断正确率的提升,也不足以估计长期错误率。

如果所用接口支持生成格式约束,还可以在生成时约束输出。DeepSeek 的 JSON Output 官方示例用 JSON 输出参数配合提取指令,再通过 json.loads 读取结果。字段类型、必填项等约定也可以写成 JSON Schema,交给校验器或支持它的模型接口使用。生成约束能保证哪些条件,需要按具体接口核对;本次实测只使用文字要求,没有测试这些额外能力的收益。

3. 按顺序检查,让结果进入明确的处理状态

收到接口响应以后,程序依次解决三个问题。

第一,是否拿到了可用的完整回答? 响应中既有生成状态,也有模型生成的内容。应先确认生成正常完成,排除拒绝、空回答和未完成内容,再读取答案。流式返回需要等到最终状态;本例使用非流式响应。

第二,回答是否符合数据约定? 能解析为 JSON 只是开始。{"date":"2026-09-18"} 可以解析,却没有约定的三个字段。字段齐全后,还要检查值的类型、日期是否存在、出处编号是否属于本次资料,以及引文是否确实出现在对应通知中。这些条件可以由普通程序确定。

第三,已有证据是否足以接受这个候选? 三个值全为 null 时,进入资料核对,不输出截止结论。有候选日期时,本例先展示候选和两份原文,让核对者确认日期含义及通知效力,再决定接受或拒收。
#mermaid-svg-NHxyy8syT537BY1U{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NHxyy8syT537BY1U .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NHxyy8syT537BY1U .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NHxyy8syT537BY1U .error-icon{fill:#552222;}#mermaid-svg-NHxyy8syT537BY1U .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NHxyy8syT537BY1U .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NHxyy8syT537BY1U .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NHxyy8syT537BY1U .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NHxyy8syT537BY1U .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NHxyy8syT537BY1U .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NHxyy8syT537BY1U .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NHxyy8syT537BY1U .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NHxyy8syT537BY1U .marker.cross{stroke:#333333;}#mermaid-svg-NHxyy8syT537BY1U svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NHxyy8syT537BY1U p{margin:0;}#mermaid-svg-NHxyy8syT537BY1U .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NHxyy8syT537BY1U .cluster-label text{fill:#333;}#mermaid-svg-NHxyy8syT537BY1U .cluster-label span{color:#333;}#mermaid-svg-NHxyy8syT537BY1U .cluster-label span p{background-color:transparent;}#mermaid-svg-NHxyy8syT537BY1U .label text,#mermaid-svg-NHxyy8syT537BY1U span{fill:#333;color:#333;}#mermaid-svg-NHxyy8syT537BY1U .node rect,#mermaid-svg-NHxyy8syT537BY1U .node circle,#mermaid-svg-NHxyy8syT537BY1U .node ellipse,#mermaid-svg-NHxyy8syT537BY1U .node polygon,#mermaid-svg-NHxyy8syT537BY1U .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NHxyy8syT537BY1U .rough-node .label text,#mermaid-svg-NHxyy8syT537BY1U .node .label text,#mermaid-svg-NHxyy8syT537BY1U .image-shape .label,#mermaid-svg-NHxyy8syT537BY1U .icon-shape .label{text-anchor:middle;}#mermaid-svg-NHxyy8syT537BY1U .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NHxyy8syT537BY1U .rough-node .label,#mermaid-svg-NHxyy8syT537BY1U .node .label,#mermaid-svg-NHxyy8syT537BY1U .image-shape .label,#mermaid-svg-NHxyy8syT537BY1U .icon-shape .label{text-align:center;}#mermaid-svg-NHxyy8syT537BY1U .node.clickable{cursor:pointer;}#mermaid-svg-NHxyy8syT537BY1U .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NHxyy8syT537BY1U .arrowheadPath{fill:#333333;}#mermaid-svg-NHxyy8syT537BY1U .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NHxyy8syT537BY1U .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NHxyy8syT537BY1U .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NHxyy8syT537BY1U .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NHxyy8syT537BY1U .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NHxyy8syT537BY1U .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NHxyy8syT537BY1U .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NHxyy8syT537BY1U .cluster text{fill:#333;}#mermaid-svg-NHxyy8syT537BY1U .cluster span{color:#333;}#mermaid-svg-NHxyy8syT537BY1U div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NHxyy8syT537BY1U .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NHxyy8syT537BY1U rect.text{fill:none;stroke-width:0;}#mermaid-svg-NHxyy8syT537BY1U .icon-shape,#mermaid-svg-NHxyy8syT537BY1U .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NHxyy8syT537BY1U .icon-shape p,#mermaid-svg-NHxyy8syT537BY1U .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NHxyy8syT537BY1U .icon-shape .label rect,#mermaid-svg-NHxyy8syT537BY1U .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NHxyy8syT537BY1U .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NHxyy8syT537BY1U .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NHxyy8syT537BY1U :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否





确认成立
确认不成立
尚不能确定
收到响应
生成完成且有可用回答?
拒收当前结果,保留原因
JSON、字段和基础条件合规?
有候选日期?
待核对:检查或补充资料
待核对:展示候选及通知原文
已接受:填写页面结果

这个顺序使每次停止都有具体原因。生成未完成时,不进入 JSON 修补;字段错误时,不补一个默认日期;依据尚未确认时,也不会因为程序已经解析成功,就自动把候选变成正式结果。

"拒收"是停止使用当前结果,不代表整个任务永远无法完成。格式错误可以反馈具体问题后有限次重试;因输出预算耗尽而截断,需要调整预算或缩小单次输出范围后重新生成,不能原样反复重试。信息不足则要补充资料。DeepSeek 的 JSON Output 文档也提醒了输出截断及空内容的情况。

4. 把接收、检查和核对接成一个能运行的程序

示例用终端中的"页面结果"模拟页面填写,处理从一份已取得的响应开始。网络请求失败或 HTTP 状态异常时,应先处理接口错误,不把错误页面送入这个接收程序。

Responses API 的返回里,status 说明整次生成是否完成,output 存放输出条目;其中 output_text 内容块的 text 才是模型回答。模型按要求生成 JSON 时,这个 text 仍是一段文字,程序还要把它解析成字段。解析接口响应和解析回答中的 JSON,是两个不同步骤。

先保存 response.json。以下取自字段组第 1 次真实响应,只保留本例会读取的字段,字段值未改动;完整响应也可以直接交给程序处理:

json 复制代码
{
  "status": "completed",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "{\"deadline_date\":\"2026-09-18\",\"source_id\":\"D2\",\"quote\":\"本次读书会报名截止日期提前到2026年9月18日,原通知中的截止日期作废。\"}"
        }
      ]
    }
  ]
}

这里的反斜杠用于在外层 JSON 字符串里表示双引号。读入响应文件后,text 的实际值就是第 2 节那段三字段 JSON。

再把下面完整代码保存为 receive_result.py,使用 Python 3.10 或以上版本运行,不需要安装第三方包。DOCUMENTS 保存程序本来就持有的教学通知;核对时展示全部两份,避免只看到模型选中的那份。

python 复制代码
"""Receive a saved Responses API result. No network calls are made."""

import json
import sys
from datetime import date
from pathlib import Path


DOCUMENTS = {
    "D1": "本次读书会报名将于2026年9月20日截止。",
    "D2": "本次读书会报名截止日期提前到2026年9月18日,原通知中的截止日期作废。",
}
FIELDS = {"deadline_date", "source_id", "quote"}


def result(state, reason, candidate=None):
    return {"state": state, "reason": reason, "candidate": candidate}


def unique_object(pairs):
    obj = {}
    for key, value in pairs:
        if key in obj:
            raise ValueError("JSON 中有重复字段")
        obj[key] = value
    return obj


def reject_constant(value):
    raise ValueError("JSON 中有不允许的数值常量")


def parse_json(text):
    return json.loads(text, object_pairs_hook=unique_object,
                      parse_constant=reject_constant)


def check_candidate(text):
    try:
        data = parse_json(text)
    except ValueError as error:
        raise ValueError("回答不是符合约定的 JSON") from error
    if not isinstance(data, dict) or set(data) != FIELDS:
        raise ValueError("必须恰好包含三个约定字段")
    if all(value is None for value in data.values()):
        return None
    if not all(isinstance(value, str) and value.strip()
               for value in data.values()):
        raise ValueError("三个值应都是非空字符串,或全部为 null")
    try:
        deadline = date.fromisoformat(data["deadline_date"])
    except ValueError as error:
        raise ValueError("截止日期不是有效日期") from error
    if deadline.isoformat() != data["deadline_date"]:
        raise ValueError("截止日期必须使用 YYYY-MM-DD")
    source_id = data["source_id"]
    if source_id not in DOCUMENTS:
        raise ValueError("出处不在本次资料中")
    if data["quote"] not in DOCUMENTS[source_id]:
        raise ValueError("引文不是该通知的连续原文")
    return data


def receive_response(response):
    if not isinstance(response, dict):
        return result("拒收", "响应应是 JSON 对象")
    if response.get("status") != "completed":
        return result("拒收", "响应尚未正常完成,请检查完成状态及原因")
    output = response.get("output")
    if not isinstance(output, list):
        return result("拒收", "响应缺少输出列表")

    texts = []
    for item in output:
        if not isinstance(item, dict):
            return result("拒收", "输出条目结构异常")
        if item.get("type") == "reasoning":
            continue  # 推理条目不作为最终回答。
        if item.get("type") != "message" or item.get("role") != "assistant":
            return result("拒收", "本任务只接收助手回答消息")
        if item.get("status") != "completed":
            return result("拒收", "回答消息尚未完成")
        content = item.get("content")
        if not isinstance(content, list):
            return result("拒收", "回答内容结构异常")
        for part in content:
            if not isinstance(part, dict):
                return result("拒收", "回答内容块结构异常")
            if part.get("type") == "refusal":
                return result("拒收", "模型拒绝了本次请求")
            if part.get("type") != "output_text" or not isinstance(part.get("text"), str):
                return result("拒收", "本任务只接收文字回答")
            texts.append(part["text"])

    text = "".join(texts)
    if not text.strip():
        return result("拒收", "需要非空、完整的回答")
    try:
        candidate = check_candidate(text)
    except ValueError as error:
        return result("拒收", str(error))
    if candidate is None:
        return result("待核对", "模型未给出日期,需要核对资料或补充信息")
    return result("待核对", "字段检查通过,需要核对日期含义与通知效力", candidate)


def finish_review(received, decision):
    # 决定来自核对当前候选的调用方,不从模型回答读取。
    if received["state"] != "待核对" or received["candidate"] is None:
        return received
    if decision == "y":
        return result("已接受", "依据已核对,可填入通知页面", received["candidate"])
    if decision == "n":
        return result("拒收", "核对发现日期或依据不成立")
    return received  # 尚未确定时保留待核对状态。


def main():
    if len(sys.argv) != 2:
        sys.exit("用法:python receive_result.py response.json")
    try:
        response = parse_json(Path(sys.argv[1]).read_text(encoding="utf-8"))
    except (OSError, ValueError):
        sys.exit("拒收:无法读取响应文件,或文件不是有效 JSON。")

    received = receive_response(response)
    if received["candidate"] is not None:
        print("待核对候选:", json.dumps(received["candidate"], ensure_ascii=False))
        for source_id, body in DOCUMENTS.items():
            print(f"{source_id}:{body}")
        print("请核对:日期是否抄对、引文是否支持日期、是否有通知将其作废。")
        decision = input("核对成立输入 y,不成立输入 n,尚不能确定直接回车:").strip().lower()
        received = finish_review(received, decision)

    print(f"处理结果:{received['state']};{received['reason']}")
    if received["state"] == "已接受":
        data = received["candidate"]
        print(f"页面结果:截止日期 {data['deadline_date']};依据 {data['source_id']}")


if __name__ == "__main__":
    main()

在这两个文件所在目录运行:

powershell 复制代码
python receive_result.py response.json

程序先显示待核对的候选以及 D1、D2。对照原文可以确认:D2 明确修改了报名日期,并废止 D1 的旧日期。输入 y 后,应得到:

text 复制代码
处理结果:已接受;依据已核对,可填入通知页面
页面结果:截止日期 2026-09-18;依据 D2

如果当前候选不能确认,直接回车就保留"待核对";确认不成立时输入 n,程序拒收,且不会输出页面结果。三个值全为空时没有可供确认的日期,程序也不会询问是否接受。

代码中的职责是连续的:receive_response 检查完成状态并取出文字,check_candidate 检查字段和基础条件,finish_review 接收对当前候选的核对决定。最后只有 state 为"已接受"时,才执行填写页面的分支。

其中 y 必须来自调用方对当前候选的核对,不能从模型生成的"已确认"字段读取。本例的终端输入只是这个决定的最小实现;实际页面还需要把核对动作绑定到当时看到的候选和资料。代码负责执行核对决定,核对者的判断质量仍需单独保障,不能无条件传入 y 来跳过核对。

parse_json 还主动拒绝重复字段及 NaN 等非标准数值,避免默认解析行为扩大接收范围。Python 的 JSON 文档说明了这些默认行为。代码直接表达了本例的少量字段规则,没有实现通用 Schema 校验器;遇到不同接口的响应结构,需要先按该接口约定调整提取部分。

5. 验证每个出口,并明确接受之后可以做什么

两份真实 JSON 响应重放后,都经历了"字段检查通过 → 待核对 → 对照通知确认 → 已接受"。只有成功路径还不够检查接收程序,因此还需要人为改变输入,观察其他分支。

下面全部是人工构造的程序测试条件,不是本次模型调用中出现过的错误;每行独立从有效的字段响应开始修改:

改变的条件 程序应停在哪里 后续怎样处理
整次响应状态改为 incomplete,即使文字看起来完整 完成状态检查,拒收 查看原因;若预算耗尽,调整预算或范围后重做
内容块改为 refusal 回答提取,拒收 呈现拒绝状态,不当成截止日期
回答文字缺少结束括号 JSON 解析,拒收 处理生成失败,不自动补括号使用
删除 source_id 字段检查,拒收 指出缺少的字段,不静默补默认值
日期改为 2026-02-30,或出处改为 D9 日期或出处检查,拒收 指出不满足的具体条件
三个字段全为 null 待核对资料,无候选可接受 检查输入及资料,必要时补充;不能按无截止日期处理
改成 D1、9 月 20 日及 D1 的真实原文 自动检查通过,停在待核对 查看 D2 可发现旧日期已作废,核对后拒收
保留正确候选,但暂不作核对决定 待核对 不填写正式结果;确认后再继续

旧通知这个条件说明了为什么需要明确检查范围:日期存在、编号存在、引文也存在,但这些检查没有判断"这项安排是否仍然有效"。本次真实模型已经把这层关系判断对了;人工样本只检验程序有没有把未经确认的候选直接放行。

对通知页面,本例的"已接受"表示:响应正常完成,字段符合约定,核对者确认资料支持这个日期。它允许填写日期与依据。如果用途改为自动创建提醒,还要明确具体时刻、时区及用户是否同意保存;只有日期的通知不能自动补出这些条件。

可靠接收最终要落实到程序的行为:读到约定的数据才能继续,遇到不合规结果有明确原因,依据不足时保留待核对状态,满足当前用途的条件后才使用结果。模型的实际表现由真实调用记录说明,接收程序的处理能力则通过这些具体分支验证。

相关推荐
科创致远1 小时前
科创致远 ESOP 系统深度评测:从参数解析到 ROI 实战验证
大数据·人工智能·制造·精益工程
CAIE研习社1 小时前
从“会聊天”到能落地:光伏、风电运维里的AI怎么用?
大数据·人工智能
TAN-90°-1 小时前
Deep Learning for Computer Vision——Generative Models 2
人工智能·深度学习·神经网络·算法·目标检测·机器学习·计算机视觉
洞见新研社1 小时前
豆包手机发售,AI代理进入“终端”竞赛
人工智能·ai
QC777LX1 小时前
中文专业在AI行业的新岗位:从Prompt到人文训练
人工智能
知几蜗牛1 小时前
2.8万亿参数上云之后,Kimi K3的门槛变低了吗
人工智能
sarasuki1 小时前
工具设计的坏味道:什么样的定义会让模型乱调
人工智能·agent·设计
jingli91 小时前
微信自动回复怎么设置?重复问题怎么自动回答——私域FAQ自动应答搭建全流程(关键词匹配+知识库+语义AI,2026实操版)
人工智能·自动化·用户运营
Ai_easygo2 小时前
AI下半场_09_CSDN版_Agent安全攻防
人工智能