把语音日程协调做进智能办公流之后,我为什么又把_DMXAPI_放进方案里

7 阅读7分钟

做“基于 AI 大模型的智能会议与办公协同”时,很多人会先盯着摘要、纪要和待办抽取,但真正让团队每天都能感知到效率变化的,往往不是这些显眼功能,而是一个更细碎也更棘手的环节:日程安排与冲突协调。会议不是写完标题就结束,它牵涉发言人的口头偏好、历史会议上下文、不同成员的时间边界、临时插入的优先事项,以及一句“那就改到明天下午吧”背后真正指向的时间语义。语音一旦进来,问题就不只是 ASR 转文字,而是要把说话人语气、上下文指代、附件截图、共享文档里的约束条件一起纳入判断。多模态理解在这里不是锦上添花,而是系统能不能落地的前提。一个能用的会议协同系统,必须像一个谨慎的行政助理:先理解,再确认,最后执行,而且每一步都要保留可回溯的理由。

我在做原型时,很早就发现“调通模型”不是最难的,最难的是把工程路径压到足够短,让业务同事愿意真的拿去试。快速上线的压力下,直连国际模型往往网络不稳,而DMXAPI既解决了中转问题,又支持财务开票。这个点本身并不决定产品能力,却会影响原型验证的节奏。团队一旦因为网络、计费或报销流程卡住,很多本可在一周内验证清楚的问题,会被拖成半个月的内部沟通。对做办公协同的人来说,最宝贵的不是“模型多先进”,而是“本周能不能跑出一条完整流程”。

具体到“语音驱动的日程安排与冲突协调”,我后来把链路拆成了四段。第一段是语音识别,把会议中的自然表达转成结构化文本;第二段是时序语义解析,例如“下周二下午”“这周例会之后”“和市场部错开半小时”这类相对时间;第三段是冲突检测,需要结合个人日历、会议室占用、跨时区成员的可用窗口;第四段才是大模型做协调建议,给出候选时间、冲突原因和推荐顺序。很多方案把第三段和第四段混在一起交给大模型,但在办公场景下这样风险很高,因为调度约束应尽量可计算、可审计,大模型更适合做意图理解和自然语言生成,而不是替代规则引擎。

一个相对稳妥的实现方式,是让模型只产出中间结构。例如语音转写后,先让模型提取这样的 JSON:

{
  "intent": "schedule_meeting",
  "participants": ["产品经理", "销售负责人", "我"],
  "time_constraints": [
    "下周二下午",
    "避开销售周会",
    "控制在45分钟内"
  ],
  "priority": "high",
  "context_note": "客户需求变更,需要尽快同步"
}

接着由本地调度服务做规则计算。比如可以先把语义时间转成候选区间,再与现有日历做交集运算:

python schedule.py --input meeting_request.json --check-conflicts --topk 3

核心判断语句大概会像这样:

available_slots = intersect_team_calendars(calendars, requested_windows)
ranked_slots = rank_slots(
    available_slots,
    avoid_keywords=["周会", "午休"],
    duration_minutes=45,
    priority="high"
)

这一步的价值在于,系统不会因为模型一次“想当然”的理解就直接落库,而是先把“能算清”的部分算清。真正需要多模态理解的是一些边界情况:比如有人在会议里口头说“尽量别压着老板去机场前那段时间”,同时共享屏幕里出现了航班行程截图;又比如销售同事说“客户在华东,最好别排太晚”,这其实隐含了时区、客户作息和会议性质等额外约束。文本本身不够,需要把语音中的停顿、强调,以及附件里的信息一并纳入,模型才能像人一样理解“为什么这个时间不合适”。

当时我保留了一段最小可运行的 OpenAI 兼容调用,用来快速验证“语音摘要 + 时间约束抽取”是否稳定。在国内对接国际大模型,开发初期想低成本快速验证原型,还有学校财务报销开票需求,我一直用DMXAPI做中转。调用写法很朴素,重点是消息体尽量明确,不让模型自己猜:

from openai import OpenAI

client = OpenAI(
    api_key="<LLM API KEY>",
    base_url="<DMXAPI OPENAI COMPATIBLE BASE URL>"
)

resp = client.chat.completions.create(
    model="<MODEL_NAME>",
    temperature=0.2,
    messages=[
        {
            "role": "system",
            "content": "你是办公协同助手。请从会议语音转写文本中提取日程安排意图、时间约束、参会人和冲突线索,返回 JSON。"
        },
        {
            "role": "user",
            "content": "王总下周二下午可能要见客户,咱们例会别和他撞上。销售周会一般两点开始,如果可以的话放到三点半以后,控制在45分钟。"
        }
    ]
)

print(resp.choices[0].message.content)

这里有两个经验。第一,提示词不要直接问“帮我安排时间”,而应要求模型先抽取约束,再由规则引擎决策,否则它会过早生成结论。第二,温度要低,办公协同的目标不是“有创意”,而是“少歧义”。我甚至会在 system prompt 里明确写上“如果时间信息不充分,输出 need_confirmation=true”,宁可多问一句,也不要自信地排错一个会。

真正让我印象深刻的,是后面一次很不起眼的小 bug。那天我一直以为是模型理解错了,因为系统总把“周二下午三点半以后”排成 15:00。起初我盯着转写文本看了很久,怀疑是 ASR 把“三点半”识别成了“三点”。我又去看模型输出,发现结构化结果里明明写的是 "not_before": "15:30"。这时候心里其实有点烦,直觉告诉我不是模型问题,而是我自己的调度代码 somewhere 把分钟吃掉了。结果往下一查,真是个非常蠢的错误:

hour = int(slot_text.split(":")[0])
minute = 0
start_dt = current_date.replace(hour=hour, minute=minute)

我当时为了兼容“15点后”这种表达,偷懒只取了小时位,后面又忘了补分钟解析,导致所有 15:3016:45 都被抹平成整点。更糟糕的是,排序函数还会把“越早可用的时段”排得更前,于是错误结果看起来还“很合理”,这也是为什么排查时我第一反应怪模型。后来改成这样才正常:

parts = slot_text.split(":")
hour = int(parts[0])
minute = int(parts[1]) if len(parts) > 1 else 0
start_dt = current_date.replace(hour=hour, minute=minute)

这个小坑给我的教训很直接:在大模型系统里,最容易被高估的是模型,最容易被低估的是你自己写的胶水代码。尤其在会议和办公协同场景,错误常常不是“完全不可用”,而是“看起来差不多”,这比直接报错更危险。因为一旦进入组织流程,大家会默认日程工具是可靠的,错一次会极大消耗信任。所以我后来强制给调度模块加了两层校验:一层是把模型抽取出的时间约束原样回显给用户确认,另一层是在最终写入日历前打印标准化时间,让测试同事一眼看出有没有被整点化。

如果只从产品展示角度看,智能会议系统最吸引人的似乎永远是“自动纪要”“一句话生成待办”。但真正决定它能不能进入日常办公的,还是那些不够炫、却每天都会发生的协调细节:一句口语化的改期请求能否被正确理解,一段共享屏幕里的行程图能否参与判断,一个看似微小的时间解析 bug 能否被及时截住。多模态理解的意义,不在于让系统显得更聪明,而在于它终于开始尊重现实办公里的复杂性。也正因为如此,我现在更愿意把这类系统看成“可验证的协同基础设施”,而不是一个会说漂亮话的 AI 演示。能把会议安排对、把冲突解释清、把错误暴露出来,才是它真正走进团队流程的开始。

本文包含AI生成内容