Context Contract 协议
Go 后端与 Python AI Service 之间的上下文传递协议。显式定义字段、类型和语义,确保换模型、换 Provider、换 LangGraph 节点时前后端仍然稳定。
#type / concept
#status / evergreen
#tech / ai
#tech / architecture
[!info] related notes
- 所属 MOC: Context Engineering MOC
- 核心概念: Context Engineering
- 组装层: Context Builder 模式
- 状态定义: 问诊状态 Schema
- 相关设计: 前后端共享类型契约
Context Contract 协议
Context Contract 是 Go 后端与 Python AI Service 之间关于上下文传递的显式协议。它定义了”每一轮 LLM 调用,Go 端应该传什么、Python 端应该收到什么”,确保换模型、换 Provider、换 LangGraph 节点时前后端仍然稳定。
为什么需要
没有 Context Contract 时,常见的问题是:
- Go 随便传,Python 随便收 — Go 端只传
messages []ChatMessage,Python 端自己决定怎么用 - 隐式依赖 — Python 端假设 Go 端会传某种格式,但没有文档或类型定义
- 耦合紧密 — 换一个 LangGraph 节点,Go 端也要改
- 无法独立测试 — 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_id | string | ✅ | 会话 ID |
| turn_id | string | ✅ | 本轮 turn ID |
| user_message | string | ✅ | 当前用户输入(最新一条) |
| context | object | ✅ | 上下文包 |
| meta | object | ✅ | 元数据 |
context 字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| recent_messages | array | ✅ | 最近 N 轮原始消息(已过滤) |
| conversation_summary | string | ❌ | 早期对话摘要(长对话时才有) |
| consultation_state | object | ✅ | 结构化问诊状态 |
| user_profile | object | ❌ | 用户画像(跨会话) |
| retrieved_knowledge | array | ❌ | 知识库检索结果 |
meta 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| context_version | string | 协议版本号,用于兼容性管理 |
| token_budget | int | 本轮上下文的 token 预算上限 |
| included_message_count | int | 实际包含的消息数量 |
| summary_version | int | 摘要版本号(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 的对比
| 维度 | 只传 messages | Context Contract |
|---|---|---|
| 结构化状态 | 模型每轮重新推理 | 显式传入,模型直接读取 |
| 消息过滤 | Go 随便传 | Contract 定义过滤规则 |
| 知识库结果 | 每轮全量或不传 | 按需动态注入 |
| 用户画像 | 不传或散落各处 | 结构化传入 |
| 可测试性 | 难以独立测试 | Contract 可 mock |
| 可演化性 | 改一处影响多处 | 版本化管理 |