Context Contract 协议

Go 后端与 Python AI Service 之间的上下文传递协议。显式定义字段、类型和语义,确保换模型、换 Provider、换 LangGraph 节点时前后端仍然稳定。

#type / concept #status / evergreen #tech / ai #tech / architecture

[!info] related notes

Context Contract 协议

Context Contract 是 Go 后端与 Python AI Service 之间关于上下文传递的显式协议。它定义了”每一轮 LLM 调用,Go 端应该传什么、Python 端应该收到什么”,确保换模型、换 Provider、换 LangGraph 节点时前后端仍然稳定。

为什么需要

没有 Context Contract 时,常见的问题是:

  1. Go 随便传,Python 随便收 — Go 端只传 messages []ChatMessage,Python 端自己决定怎么用
  2. 隐式依赖 — Python 端假设 Go 端会传某种格式,但没有文档或类型定义
  3. 耦合紧密 — 换一个 LangGraph 节点,Go 端也要改
  4. 无法独立测试 — Python 端无法脱离 Go 端做集成测试

Context Contract 把这些变成显式的、可版本化的、可测试的接口。

协议结构

{
  "session_id": "conv_0197...",
  "turn_id": "turn_0197...",
  "user_message": "我膝盖有下坠感",
  "context": {
    "recent_messages": [
      {"role": "user", "content": "...", "turn_id": "...", "timestamp": "..."},
      {"role": "assistant", "content": "...", "turn_id": "...", "timestamp": "..."}
    ],
    "conversation_summary": "用户主诉膝盖下坠感,已收集持续时间约一周...",
    "consultation_state": {
      "stage": "collecting_details",
      "chief_complaint": "膝盖下坠感",
      "body_parts": ["膝盖"],
      "symptoms": ["下坠感"],
      "duration": "一周",
      "aggravating_factors": ["走路"],
      "pain_level": null,
      "swelling": null,
      "trauma": null,
      "red_flags": [],
      "missing_slots": ["pain_level", "swelling", "trauma"],
      "last_question": "是否伴随疼痛或肿胀?",
      "pending_answer_for": ["pain", "swelling"]
    },
    "user_profile": {
      "age": 35,
      "gender": "male",
      "exercise_habit": "每周跑步3次",
      "known_limitations": []
    },
    "retrieved_knowledge": [
      {
        "title": "膝关节不稳定常见原因",
        "content": "可能与股四头肌控制、髋膝踝力线、韧带损伤相关...",
        "source": "kb_001",
        "relevance_score": 0.92
      }
    ]
  },
  "meta": {
    "context_version": "1.0.0",
    "token_budget": 8000,
    "included_message_count": 6,
    "summary_version": 2
  }
}

字段语义

顶层字段

字段类型必填说明
session_idstring会话 ID
turn_idstring本轮 turn ID
user_messagestring当前用户输入(最新一条)
contextobject上下文包
metaobject元数据

context 字段

字段类型必填说明
recent_messagesarray最近 N 轮原始消息(已过滤)
conversation_summarystring早期对话摘要(长对话时才有)
consultation_stateobject结构化问诊状态
user_profileobject用户画像(跨会话)
retrieved_knowledgearray知识库检索结果

meta 字段

字段类型说明
context_versionstring协议版本号,用于兼容性管理
token_budgetint本轮上下文的 token 预算上限
included_message_countint实际包含的消息数量
summary_versionint摘要版本号(0 = 无摘要)

版本管理

Context Contract 应该有版本号。当字段有 breaking change 时:

v1.0.0 → v1.1.0  // 新增字段(向后兼容)
v1.x.x → v2.0.0  // 删除或重命名字段(不兼容)

Python 端应该检查 meta.context_version,如果不兼容则返回错误而不是静默忽略。

Go 端实现

type ContextContract struct {
    SessionID  string              `json:"session_id"`
    TurnID     string              `json:"turn_id"`
    UserMessage string             `json:"user_message"`
    Context    ContextBundle       `json:"context"`
    Meta       ContextContractMeta `json:"meta"`
}

type ContextContractMeta struct {
    ContextVersion       string `json:"context_version"`
    TokenBudget          int    `json:"token_budget"`
    IncludedMessageCount int    `json:"included_message_count"`
    SummaryVersion       int    `json:"summary_version"`
}

Python 端接收

from pydantic import BaseModel
from typing import Optional

class ChatMessage(BaseModel):
    role: str
    content: str
    turn_id: str
    timestamp: str

class ConsultationState(BaseModel):
    stage: str
    chief_complaint: Optional[str]
    body_parts: list[str]
    symptoms: list[str]
    duration: Optional[str]
    pain_level: Optional[str]
    missing_slots: list[str]
    last_question: Optional[str]
    pending_answer_for: list[str]

class ContextBundle(BaseModel):
    recent_messages: list[ChatMessage]
    conversation_summary: Optional[str]
    consultation_state: ConsultationState
    user_profile: Optional[dict]
    retrieved_knowledge: list[dict]

class ChatRequest(BaseModel):
    session_id: str
    turn_id: str
    user_message: str
    context: ContextBundle
    meta: dict

与直接传 messages 的对比

维度只传 messagesContext Contract
结构化状态模型每轮重新推理显式传入,模型直接读取
消息过滤Go 随便传Contract 定义过滤规则
知识库结果每轮全量或不传按需动态注入
用户画像不传或散落各处结构化传入
可测试性难以独立测试Contract 可 mock
可演化性改一处影响多处版本化管理
创建于 2026/6/30 更新于 2026/7/15