在实际的 AI Agent 项目里,有一个比模型选型更隐蔽的问题:模型本身没有业务上下文。Odyssey Framework 要解决的,正是这个问题——给 AI 提供它需要的业务上下文,让大模型从“什么都懂一点”变成“懂你这家公司的用户、订单、规则和边界”。这篇文章会把这套思路拆开,从一个客服问答场景出发,先讲清楚业务上下文为什么重要,再带你实现一个最小可运行的上下文装配链路,最后给出参数配置、排查方法和生产环境建议。
如果你正在做智能客服、企业知识库问答、RAG 应用或者 AI Agent 后端,读完这篇文章后,可以明确回答三个问题:上下文到底要装什么、从哪里来、怎么安全地交给模型。
1. 先用一个具体场景理解“业务上下文”到底缺什么
1.1 一个客服 Agent 的真实困境
假设你要做一个电商客服 Agent。用户发来一句很常见的消息:
“我这个订单为什么还没发货?你们怎么这么慢?”
这句话单看没有任何业务信息。模型不知道用户是谁,不知道用户说的“这个订单”对应哪个订单号,不知道订单在哪个仓库,不知道当前物流节点,也不知道企业承诺的发货时效。
如果直接把这句话发给大模型,模型只能给出非常通用的回答,比如“很抱歉给您带来不便,我们正在催促仓库尽快发货”。这种回答不是不能用,但它没有解决问题的实际价值。用户真正想知道的,是他的订单会在什么时候发货、为什么会延误、有没有办法优先处理。
Odyssey Framework 的核心思想,就是把回答这个问题需要的背景信息提前准备好,再交给模型。这个背景信息就是“业务上下文”。
模型需要哪些上下文,可以拆成几类:
| 上下文类型 | 具体内容 | 缺了会怎样 |
|---|---|---|
| 用户上下文 | 用户ID、姓名、会员等级、所属租户 | 无法区分用户,无法做个性化答复 |
| 订单上下文 | 订单号、状态、金额、下单时间、预计发货时间 | 不知道用户问的是哪一笔订单 |
| 业务规则 | 发货时效、会员优先规则、退款规则 | 回答内容可能与公司实际政策冲突 |
| 工具上下文 | 可调用的 API、查询参数、操作权限 | 模型无法主动查物流、改地址 |
| 会话上下文 | 用户刚才问了什么、已经回答过什么 | 多轮对话经常重复提问或前后矛盾 |
1.2 为什么“把资料都塞进 Prompt”不可行
很多团队刚开始做 AI 应用时,第一个想法是:把用户数据、商品信息、公司制度全部拼进 Prompt 里,模型不就有上下文了吗?
这个思路方向没错,但直接拼接在真实项目里走不通,原因有四条。
第一是 token 天花板。企业级数据量远远超过模型上下文窗口。一个中型电商的订单表可能有几千万行,员工的权限列表可能也有几十万条,不可能一次性塞入。
第二是权限风险。不同用户能看到的数据不同。如果系统把所有用户的订单、所有内部备注都拼进 Prompt,模型即使不主动泄露,也很可能在回答中引用到其他用户的内容。权限过滤必须在模型调用之前完成。
第三是数据时效。订单状态、物流轨迹、库存数量都在实时变化。把静态文本拼进 Prompt,用户问第二次时数据就过期了。
第四是排障困难。所有信息混在一大段文本里,模型回答错了,你很难判断是哪条上下文导致的。你需要的是每条上下文都可追踪、可过滤、可审计。
1.3 Odyssey Framework 的核心思路:把上下文变成一条装配管线
Odyssey Framework 没有把这些信息当作“一段文本”去管理,而是把它当作一条“上下文装配管线”(Context Pipeline)。
一次请求进入系统后,框架会按固定流程处理:
- 识别当前用户和会话。
- 从数据库、接口、缓存中加载用户信息、订单信息、权限信息。
- 根据用户问题,补充相关的业务规则和可调用工具。
- 执行权限过滤,删除当前用户无权看到的数据。
- 按优先级剪裁上下文长度。
- 把最终结构化上下文渲染成模型输入。
这样做最直接的好处是,你不是在“尝试写一个更好的 Prompt”,而是在“搭建一套可编程、可测试、可观测的业务上下文系统”。这也是 Odyssey Framework 这个名字想表达的意思:模型像一位进入陌生业务现场的访问者,框架负责给它准备好地图、资料和边界规则。
2. 理解 Odyssey 的上下文编排模型
2.1 五个核心组件
Odyssey Framework 的上下文编排模型可以归纳为五个核心组件,下面用一张表说明每个组件的作用和常见实现方式。
| 组件 | 职责 | 常见实现方式 |
|---|---|---|
| Context Loader | 从数据库、Redis、外部服务加载原始数据 | SQL 查询、HTTP 调用、RPC 调用、缓存读取 |
| Business Rule Engine | 把企业线下规则转成模型可理解的约束 | 规则表、配置文件、Python 函数 |
| Tool Registry | 注册 Agent 可以调用的工具和方法 | JSON Schema、OpenAPI 描述、函数注册表 |
| Session Memory | 保存当前会话的关键信息,避免重复查询 | Redis、内存缓存、向量数据库 |
| Policy Filter | 负责脱敏、权限校验、租户隔离 | 装饰器、中间件、独立过滤层 |
在实际项目中,大多数团队会把前三个组件做得很重,却忽视了 Policy Filter。这是很危险的。因为模型本身没有判断数据边界的能力,你给它的上下文越多,它越容易把不该展示的数据“顺手”放进回答里。
2.2 一次请求的上下文装配流程
整个装配流程可以在代码里描述成下面这样。这不是可运行代码,而是用来说明执行顺序的伪代码。
request(user_id, query) -> 解析请求,得到 user_id、session_id、raw_query -> 并行加载基础上下文 user_context = load_user(user_id) session_context = load_session(session_id) -> 根据 query 意图加载业务数据 orders = load_orders(user_id) inventory = load_inventory(order_ids) -> 注入业务规则 rules = build_business_rules(user_context, orders) -> 注册工具 tools = register_tools(["query_logistics", "apply_refund"]) -> 执行 Policy Filter filtered = apply_policy(user, orders, tools, current_user_id) -> 渲染成模型输入 prompt = render_prompt(filtered) -> 调用模型 reply = call_llm(prompt) -> 记录审计日志 write_audit_log(user_id, filtered, reply)这个顺序很重要,尤其要注意:Policy Filter 必须放在渲染 Prompt 之前。一旦数据进入 Prompt,模型就有可能把它输出到回答里,届时再拦截就晚了。
3. 环境准备和最小项目结构
3.1 技术栈和依赖
为了让整条链路可运行,下面会用一个最小示例来演示。示例采用 Python 技术栈,因为 Python 在 AI 工程领域生态最成熟,调试也直观。
| 依赖 | 用途 |
|---|---|
| Python 3.11+ | 运行环境 |
| FastAPI | 提供 HTTP 接口 |
| uvicorn | 启动 Web 服务 |
| pydantic | 定义上下文数据结构 |
| pydantic-settings | 读取环境变量 |
| openai | 调用 OpenAI 兼容接口 |
如果原始项目没有给出明确版本,落地前要先确认本地 Python 版本和 pip 源。下面这份requirements.txt可以用于快速搭建:
fastapi>=0.110.0 uvicorn>=0.29.0 pydantic>=2.6.0 pydantic-settings>=2.2.0 openai>=1.30.03.2 项目目录结构
推荐使用下面的目录结构。它把数据加载、业务规则、权限过滤和 Prompt 渲染拆开,方便后续替换真实数据源。
odyssey-mini/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 入口 │ ├── config.py # 配置读取 │ ├── models.py # 上下文数据模型 │ ├── loaders.py # 数据加载器 │ ├── business_rules.py # 业务规则 │ ├── policy.py # 权限过滤 │ ├── pipeline.py # 上下文装配管线 │ └── prompt.py # Prompt 渲染 ├── requirements.txt └── .env.example3.3 环境变量和配置
创建一个.env.example文件,把可能变化的参数都放在里面。示例项目没有配置 OpenAI Key 时也能运行,以便先验证上下文装配逻辑;配置 Key 后再接入真实模型。
LLM_API_KEY= LLM_BASE_URL= LLM_MODEL=gpt-4o-mini CONTEXT_TIMEOUT_MS=2000 MAX_CONTEXT_CHARS=6000 ENABLE_POLICY_FILTER=true CACHE_TTL_SECONDS=60对应的config.py实现如下:
from pydantic_settings import BaseSettings class Settings(BaseSettings): llm_api_key: str = "" llm_base_url: str = "" llm_model: str = "gpt-4o-mini" context_timeout_ms: int = 2000 max_context_chars: int = 6000 enable_policy_filter: bool = True cache_ttl_seconds: int = 60 class Config: env_file = ".env" settings = Settings()这里把配置集中在一个类里,后续调整上下文超时、长度上限时,不用改动业务代码。
4. 动手实现一个最小上下文装配链路
4.1 定义上下文数据模型
上下文的结构越清晰,后面的权限过滤和 Prompt 渲染就越容易。这里用 pydantic 定义UserContext、OrderInfo和BusinessContext。
from enum import Enum from typing import Literal, Optional from pydantic import BaseModel, Field class UserLevel(str, Enum): NORMAL = "normal" VIP = "vip" class UserContext(BaseModel): user_id: str name: str level: UserLevel tenant_id: str email: str = "" class OrderInfo(BaseModel): order_id: str user_id: str status: str amount: float created_at: str estimated_ship_at: str item_title: str = "" class BusinessContext(BaseModel): user: Optional[UserContext] = None orders: list[OrderInfo] = Field(default_factory=list) business_rules: list[str] = Field(default_factory=list) tool_schemas: list[dict] = Field(default_factory=list) raw_query: str = ""数据模型要尽量窄,只保留模型回答必需的关键字段。不要把整张订单表的所有列都塞进去,字段越多,越容易泄露内部信息。
4.2 实现数据加载器
loaders.py里实现用户信息和订单信息的加载。示例中用 mock 数据代替真实数据库,生产环境可以替换为 SQL、HTTP 或 RPC 调用。
import asyncio from models import OrderInfo, UserContext, UserLevel async def load_user(user_id: str) -> UserContext: # 生产环境替换为数据库查询或用户中心 API await asyncio.sleep(0.01) return UserContext( user_id=user_id, name="张明", level=UserLevel.VIP, tenant_id="tenant_001", email="zhangming@example.com", ) async def load_orders(user_id: str) -> list[OrderInfo]: # 生产环境替换为订单服务 SDK 或 SQL 查询 await asyncio.sleep(0.02) return [ OrderInfo( order_id="SO202507130001", user_id=user_id, status="paid", amount=1299.00, created_at="2025-07-13 10:20:00", estimated_ship_at="2025-07-15 18:00:00", item_title="人体工学椅", ) ]两个加载函数都声明为async,并且内部有模拟耗时。这样在装配管线里可以用asyncio.gather并行执行,减少整体响应时间。
4.3 实现业务规则注入
业务规则不能只写在产品文档里,必须变成模型可以读取的结构化文本。下面是一个最简单的规则构造器:
from models import OrderInfo, UserContext, UserLevel SHIPMENT_RULES = [ "已支付订单默认在 48 小时内发货。", "VIP 用户订单优先安排发货。", "偏远地区配送时间可能延长 1 到 2 天。", ] def build_business_rules(user: UserContext, orders: list[OrderInfo]) -> list[str]: rules = list(SHIPMENT_RULES) if user.level == UserLevel.VIP: rules.append("本次咨询用户是 VIP,答复时可以告知优先处理通道。") if any(order.status == "paid" for order in orders): rules.append("当前存在已支付但未发货订单,需要先说明发货时间承诺,再提供查询物流入口。") return rules这里的关键点在于,业务规则和商品数据是分开管理的。因为规则常变,而历史订单数据基本不变。把规则抽成独立模块后,运营修改发货策略时,只需要改一处。
4.4 实现权限过滤
权限过滤是整个上下文装配链路里最不能省的一步。下面实现两个最基本的动作:数据越权校验和邮箱脱敏。
from models import BusinessContext, UserContext def apply_policy(ctx: BusinessContext, current_user_id: str, is_admin: bool = False) -> BusinessContext: if not is_admin and ctx.user is not None and ctx.user.user_id != current_user_id: raise PermissionError("user context mismatch") if ctx.user is not None: ctx.user.email = mask_email(ctx.user.email) # 非管理员只能看到自己的订单 if not is_admin: ctx.orders = [order for order in ctx.orders if order.user_id == current_user_id] return ctx def mask_email(email: str) -> str: if "@" not in email: return email local, domain = email.split("@", 1) visible = local[:2] if len(local) > 2 else local return f"{visible}***@{domain}"实际项目中,Policy Filter 还要处理更多场景,比如租户隔离、角色权限、内部成本字段删除等。这里只演示最核心的逻辑:进入 Prompt 之前,把不该出现的数据直接去掉。
4.5 装配管线、Prompt 渲染和模型调用
pipeline.py是整条链路的编排入口。它先并行加载用户和订单,再注入业务规则,然后执行权限过滤,最后渲染 Prompt。
import asyncio import time from business_rules import build_business_rules from config import settings from loaders import load_orders, load_user from models import BusinessContext from policy import apply_policy from prompt import render_prompt async def build_context(user_id: str, query: str) -> BusinessContext: start = time.perf_counter() user, orders = await asyncio.gather( load_user(user_id), load_orders(user_id), ) ctx = BusinessContext(user=user, orders=orders, raw_query=query) ctx.business_rules = build_business_rules(user, orders) if settings.enable_policy_filter: ctx = apply_policy(ctx, current_user_id=user_id) ctx.tool_schemas = [ { "name": "query_logistics", "description": "查询订单物流轨迹", "parameters": {"order_id": "string"}, } ] elapsed_ms = (time.perf_counter() - start) * 1000 print( f"[context] build finished, " f"sources=user,orders,business_rules,tool_schemas, elapsed_ms={elapsed_ms:.1f}" ) return ctx def call_llm(prompt: str) -> str: if not settings.llm_api_key: return "(未配置 LLM_API_KEY,已跳过真实模型调用。上下文装配成功,接下来模型会基于订单信息和发货规则回答。)" from openai import OpenAI client = OpenAI( api_key=settings.llm_api_key, base_url=settings.llm_base_url or None, ) response = client.chat.completions.create( model=settings.llm_model, messages=[{"role": "system", "content": prompt}], temperature=0.2, ) return response.choices[0].message.content async def chat(user_id: str, query: str) -> str: ctx = await build_context(user_id, query) prompt = render_prompt(ctx) print(prompt) return call_llm(prompt)prompt.py负责把BusinessContext渲染成最终发给模型的文本。
from models import BusinessContext def render_prompt(ctx: BusinessContext) -> str: user = ctx.user order_lines = "\n".join( f"- 订单 {order.order_id}:状态 {order.status}," f"金额 {order.amount},下单时间 {order.created_at}," f"预计发货 {order.estimated_ship_at},商品 {order.item_title}" for order in ctx.orders ) rules = "\n".join(f"- {rule}" for rule in ctx.business_rules) tools = "\n".join(f"- {tool['name']}: {tool['description']}" for tool in ctx.tool_schemas) prompt = f""" 你是一名企业客服助手。请严格基于下面的业务上下文回答用户问题。不要假设上下文之外的数据。 如果上下文信息不足以回答,请明确说需要哪些信息。 【当前用户】 用户ID: {user.user_id} 姓名: {user.name} 等级: {user.level} 邮箱: {user.email} 【订单信息】 {order_lines or "无"} 【业务规则】 {rules or "无"} 【可调用的工具】 {tools or "无"} 【用户问题】 {ctx.raw_query} 请用简洁、专业的中文回复。 """ return prompt.strip()最后是 FastAPI 入口main.py:
from fastapi import FastAPI from pydantic import BaseModel from pipeline import chat app = FastAPI(title="odyssey-mini") class ChatRequest(BaseModel): user_id: str message: str class ChatResponse(BaseModel): reply: str @app.post("/api/v1/chat", response_model=ChatResponse) async def chat_api(req: ChatRequest): reply = await chat(req.user_id, req.message) return ChatResponse(reply=reply)到这一步,最小链路已经完整:请求进入接口,加载上下文,注入规则,过滤权限,渲染 Prompt,调用模型。
5. 运行验证:从日志看上下文是否真正生效
5.1 启动服务
在项目根目录执行:
pip install -r requirements.txt uvicorn app.main:app --reload --port 8000启动后,FastAPI 会监听8000端口。不要只验证服务能启动,还要验证一次完整请求是否输出了正确的上下文。
5.2 发一个测试请求
打开另一个终端,发送一条标准客服问题:
curl -X POST http://127.0.0.1:8000/api/v1/chat \ -H "Content-Type: application/json" \ -d '{"user_id":"user_001","message":"我的订单为什么还没发货?"}'如果没有配置LLM_API_KEY,接口会返回一条提示,说明真实模型调用被跳过:
{ "reply": "(未配置 LLM_API_KEY,已跳过真实模型调用。上下文装配成功,接下来模型会基于订单信息和发货规则回答。)" }5.3 检查日志中的上下文来源
服务端控制台会打印两段关键日志。第一段说明装配完成:
[context] build finished, sources=user,orders,business_rules,tool_schemas, elapsed_ms=31.2第二段是渲染后的完整 Prompt。这段 Prompt 里应该能看到当前用户、订单信息、业务规则和工具描述。如果这段 Prompt 里出现空列表,说明上下文加载链路没有生效。
5.4 对比:无上下文和有上下文的效果差异
为了直观理解业务上下文的作用,可以对比两版 Prompt。
无上下文时的模型输入相当于:
你是一名企业客服助手。用户问题:我的订单为什么还没发货?请回答。有上下文时的模型输入则包含:
【当前用户】 user_001,张明,vip 【订单信息】 SO202507130001,status=paid,预计发货 2025-07-15 18:00:00 【业务规则】 已支付订单默认在 48 小时内发货。VIP 用户订单优先安排发货。后者会让模型知道:用户是 VIP、订单已支付但尚未到 48 小时承诺期、有权告知优先处理通道。前者只能给出泛泛的安抚话术。这就是业务上下文在工程上的实际收益。
6. 关键参数和配置详解
6.1 上下文超时时间
参数名:CONTEXT_TIMEOUT_MS,默认2000毫秒。
这个参数控制数据加载器的总超时时间。调小会让系统更快失败,避免用户长时间等待,但也可能导致订单接口偶发抖动时上下文不完整。调大能提高数据完整性,但会增加接口响应时间。
推荐做法:本地调试用2000,生产环境根据实际接口 P99 延迟设置。超时后应该有降级逻辑,比如跳过非关键上下文,而不是直接报错。
6.2 上下文长度上限
参数名:MAX_CONTEXT_CHARS,默认6000字符。
模型上下文窗口虽然越来越大,但并不是越长越好。上下文越长,模型越容易受到无关信息干扰,成本和延迟也会上升。建议把上下文按优先级排序:
- 用户问题。
- 当前订单或当前文档。
- 关键业务规则。
- 可调用工具。
- 可选背景资料。
超过长度上限时,从低优先级开始丢弃,保证最核心信息始终进入模型。
6.3 缓存策略
参数名:CACHE_TTL_SECONDS,默认60秒。
用户基础信息、组织架构这类低频变化数据适合缓存。订单状态、实时库存这类高频变化数据不适合缓存。在真实项目里,不要对所有 Loader 使用同一套缓存策略,建议为每个 Loader 单独配置 TTL。
6.4 权限过滤开关
参数名:ENABLE_POLICY_FILTER,默认true。
这个开关只建议在本地开发环境关闭,方便调试数据结构。生产环境必须保持开启,并且建议在 CI 里加入权限过滤的测试用例,防止后续改动出现越权回归。
下面用一张表汇总关键参数:
| 参数 | 默认值 | 含义 | 调低影响 | 调高影响 |
|---|---|---|---|---|
| CONTEXT_TIMEOUT_MS | 2000 | 上下文装配总超时 | 失败率升高 | 响应时间变长 |
| MAX_CONTEXT_CHARS | 6000 | 进入 Prompt 的文本上限 | 信息可能被裁掉 | token 消耗和成本上升 |
| CACHE_TTL_SECONDS | 60 | 低频数据缓存时长 | 数据更新及时但压力大 | 数据过期且占用缓存 |
| ENABLE_POLICY_FILTER | true | 是否执行权限过滤 | 本地调试方便 | 更安全但增加过滤耗时 |
生产环境还需要额外考虑配置外置化,不要把数据库连接串和模型 API Key 直接写进代码或镜像。建议使用环境变量或配置中心管理。
7. 常见问题排查
7.1 模型回答仍然像没有业务上下文
现象:Prompt 已经打印出来,但模型回答还是泛泛而谈。
排查顺序:
- 先检查
build_context日志中sources是否包含预期来源。 - 再检查
render_prompt输出的文本,确认订单、规则确实在 Prompt 中。 - 确认模型版本是否支持足够长的输入,是否有内容被系统截断。
- 检查温度设置,如果温度过高,模型可能不严格遵循上下文约束。建议降到
0.2以下。
一个很常见的坑是:上下文装配成功,但 Prompt 渲染时把关键字段拼错了,比如从ctx.user.name取不到值,渲染成空字符串。出现这种情况时,优先查看渲染后的完整文本,不要只看控制台的缩短日志。
7.2 上下文装配太慢
现象:日志显示elapsed_ms达到几百毫秒甚至上千毫秒。
常见原因有三个:
- Loader 串行执行,没有使用
asyncio.gather。 - 某个接口超时没有设置默认值。
- 高延迟接口被放在关键路径上。
处理方式:
- 把互相独立的 Loader 改为并行执行。
- 给每个 Loader 设置独立的超时时间。
- 对非关键上下文做异步降级,比如用户历史偏好加载失败时,不阻断主流程。
7.3 用户 A 看到了用户 B 的订单数据
这是最严重的问题,通常不是模型导致的,而是上下文装配阶段已经发生越权。
检查路径:
- Loader 是否只按当前
user_id查询数据。 - 后端服务是否验证了身份令牌中的用户和请求参数中的用户一致。
- Policy Filter 是否真的在渲染前执行,而不是只写在代码里没有被调用。
- 测试环境是否用多个账号验证过数据隔离。
防止越权的关键原则是:兜底过滤永远不能依赖模型判断。凡是会进入 Prompt 的数据,后端必须先过滤。
7.4 上下文太长导致 token 超限
现象:调用模型接口时报token limit exceeded或类似错误。
处理方式:
- 遵循“先核心、后补充”的顺序截断。
- 优先保留订单号、状态、发货时间,裁剪商品备注和内部字段。
- 对列表型数据,先取最近的 N 条,而不是全部返回。
- 如果确实需要长文本,先做摘要,再把摘要放入上下文。
下面的表格汇总了这几类高频问题:
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 回答没有业务信息 | 上下文未装配或渲染遗漏 | 看 build_context 日志和渲染后的 Prompt | 修复 Loader 或 render_prompt |
| 上下文装配慢 | Loader 串行、接口超时 | 看 elapsed_ms 和每个 Loader 耗时 | 改为并行、设置超时和降级 |
| 跨用户数据泄露 | 身份校验缺失或过滤未生效 | 用多个账号做权限回归测试 | 在渲染前强制执行 Policy Filter |
| token 超限 | 上下文过长且无截断 | 检查 Prompt 字符数和模型限制 | 按优先级截断,保留核心字段 |
8. 生产环境最佳实践与扩展方向
8.1 学习环境和生产环境的差距
上面的最小示例可以在本地快速跑通,但生产环境不能直接照搬。下面列出两者的关键差异:
| 关注点 | 学习环境 | 生产环境 |
|---|---|---|
| 数据源 | mock 数据 | 真实数据库、微服务 API、消息队列 |
| 配置 | 环境变量 | 配置中心、密钥管理、动态刷新 |
| 日志 | print 输出 | 结构化日志、链路追踪、指标监控 |
| 权限 | 简单 user_id 校验 | SSO、RBAC、租户隔离、审计日志 |
| 模型调用 | 无 Key 可跳过 | 限流、重试、熔断、敏感词过滤 |
| 缓存 | 不需要 | 多级缓存、缓存失效和预热 |
| 回滚 | 重启服务 | 版本发布、开关控制、灰度发布 |
生产环境的上下文装配链路,本质上是一个有性能要求、有安全边界、有审计需求的数据服务。不能只把它当成“拼 Prompt 的临时脚本”。
8.2 可复用的上下文工程检查清单
在每次上线或评审上下文改动时,可以按下面这份清单检查:
- [ ] 每个 Loader 的数据来源都有日志记录。
- [ ] 用户身份校验发生在所有上下文加载之前。
- [ ] 权限过滤在渲染 Prompt 之前执行,且有单元测试覆盖。
- [ ] 上下文超时和降级策略已经配置。
- [ ] 上下文长度上限和截断顺序明确。
- [ ] 进入 Prompt 的数据不包含 API Key、数据库连接串、内部成本字段。
- [ ] 模型回答可追踪到对应上下文来源。
- [ ] 缓存策略区分低频和高频数据。
- [ ] 有至少两个不同权限账号的端到端测试用例。
- [ ] 上下文装配耗时已接入监控和告警。
这份清单可以直接贴进项目的代码评审模板里,避免上下文相关的改动只凭“我感觉没问题”就上线。
8.3 扩展方向
Odyssey Framework 的核心思想打通之后,可以朝几个方向深入。
第一个方向是接入 RAG 检索。当业务知识超过上下文窗口时,可以用向量数据库召回与用户问题相关的文档片段,再作为 Context Loader 的一种补充来源。
第二个方向是增强工具调用。让模型不只回答问题,还能通过 Tool Registry 调用查物流、修改地址、申请退款等操作,并在操作前后继续校验权限。
第三个方向是会话记忆落地。把 Session Memory 从简单缓存升级为短期记忆和用户偏好画像,多轮对话时只补充增量上下文,而不是每次重复拼接全量数据。
第四个方向是观测和调优。为每条上下文记录来源标识,例如source=order_service、source=business_rule,在模型回答不符合预期时,可以通过日志快速定位是哪一条上下文造成的。
最终需要记住的技术判断是:给大模型更强的模型能力,不如给它更准确的业务上下文。Odyssey Framework 这类方案的价值,不是帮你写一个更长的 Prompt,而是把“让 AI 理解业务”变成一条可持续维护、可安全执行、可快速排查的工程链路。新手实践时,从最小客服场景开始,先把一条上下文链路跑通,再加入权限、缓存、监控和工具调用,逐步完善。